@@ -534,31 +534,49 @@ def is_near(self, point1, point2):
534534 return (point1 - point2 ).length < 0.1
535535
536536 def derive_from_cursor (self ):
537+ RAYCAST_PRECISION = 0.01
537538 self .location = bpy .context .scene .cursor .location
538539 if self .collection :
539540 for sibling_obj in self .collection .objects :
540541 if not isinstance (sibling_obj .data , bpy .types .Mesh ):
541542 continue
542543 if "IfcWall" not in sibling_obj .name :
543544 continue
544- local_location = sibling_obj .matrix_world .inverted () @ self .location
545+ inv_obj_matrix = sibling_obj .matrix_world .inverted ()
546+ local_location = inv_obj_matrix @ self .location
545547 try :
546- raycast = sibling_obj .closest_point_on_mesh (local_location , distance = 0.01 )
548+ raycast = sibling_obj .closest_point_on_mesh (local_location , distance = RAYCAST_PRECISION )
547549 except :
548550 # If the mesh has no faces
549551 raycast = [None ]
550552 if not raycast [0 ]:
551553 continue
552554 for face in sibling_obj .data .polygons :
553- if (
554- abs (face .normal .y ) >= 0.75
555- and abs (mathutils .geometry .distance_point_to_plane (local_location , face .center , face .normal ))
556- < 0.01
557- ):
558- # Rotate the wall in the direction of the face normal
559- normal = (sibling_obj .matrix_world .to_quaternion () @ face .normal ).normalized ()
560- self .rotation = math .atan2 (normal [1 ], normal [0 ])
561- break
555+ normal = (sibling_obj .matrix_world .to_quaternion () @ face .normal ).normalized ()
556+ face_center = sibling_obj .matrix_world @ face .center
557+ if normal .z != 0 or abs (mathutils .geometry .distance_point_to_plane (self .location , face_center , normal )) > 0.01 :
558+ continue
559+
560+ rotation = math .atan2 (normal [1 ], normal [0 ])
561+ rotated_y_axis = Matrix .Rotation (- rotation , 4 , "Z" )[1 ].xyz
562+
563+ # since wall thickness goes by local Y+ axis
564+ # we find best position for the next wall
565+ # by finding the face of another wall that will be very close to the some test point.
566+ # test point is calculated by applying to cursor position some little offset along the face
567+ #
568+ # a bit different offset to be safe on raycast
569+ test_pos = self .location + rotated_y_axis * RAYCAST_PRECISION * 1.1
570+ test_pos_local = inv_obj_matrix @ test_pos
571+ raycast = sibling_obj .closest_point_on_mesh (test_pos_local , distance = RAYCAST_PRECISION )
572+
573+ if not raycast [0 ]:
574+ continue
575+ self .rotation = rotation
576+ break
577+
578+ if self .rotation != 0 :
579+ break
562580 return self .create_wall ()
563581
564582 def create_wall (self ):
0 commit comments