Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'object_print3d_utils/operators.py')
-rw-r--r--object_print3d_utils/operators.py86
1 files changed, 69 insertions, 17 deletions
diff --git a/object_print3d_utils/operators.py b/object_print3d_utils/operators.py
index afc7b83d..50988163 100644
--- a/object_print3d_utils/operators.py
+++ b/object_print3d_utils/operators.py
@@ -1,20 +1,4 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
+# SPDX-License-Identifier: GPL-2.0-or-later
# <pep8-80 compliant>
@@ -740,6 +724,74 @@ class MESH_OT_print3d_scale_to_bounds(Operator):
return wm.invoke_props_dialog(self)
+class MESH_OT_print3d_align_to_xy(Operator):
+ bl_idname = "mesh.print3d_align_to_xy"
+ bl_label = "Align (rotate) object to XY plane"
+ bl_description = (
+ "Rotates entire object (not mesh) so the selected faces/vertices lie, on average, parallel to the XY plane "
+ "(it does not adjust Z location)"
+ )
+ bl_options = {'REGISTER', 'UNDO'}
+
+ def execute(self, context):
+ # FIXME: Undo is inconsistent.
+ # FIXME: Would be nicer if rotate could pick some object-local axis.
+
+ from mathutils import Vector
+
+ print_3d = context.scene.print_3d
+ face_areas = print_3d.use_alignxy_face_area
+
+ self.context = context
+ mode_orig = context.mode
+ skip_invalid = []
+
+ for obj in context.selected_objects:
+ orig_loc = obj.location.copy()
+ orig_scale = obj.scale.copy()
+
+ # When in edit mode, do as the edit mode does.
+ if mode_orig == 'EDIT_MESH':
+ bm = bmesh.from_edit_mesh(obj.data)
+ faces = [f for f in bm.faces if f.select]
+ else:
+ faces = [p for p in obj.data.polygons if p.select]
+
+ if not faces:
+ skip_invalid.append(obj.name)
+ continue
+
+ # Rotate object so average normal of selected faces points down.
+ normal = Vector((0.0, 0.0, 0.0))
+ if face_areas:
+ for face in faces:
+ normal += (face.normal * face.calc_area())
+ else:
+ for face in faces:
+ normal += face.normal
+ normal = normal.normalized()
+ normal.rotate(obj.matrix_world) # local -> world.
+ offset = normal.rotation_difference(Vector((0.0, 0.0, -1.0)))
+ offset = offset.to_matrix().to_4x4()
+ obj.matrix_world = offset @ obj.matrix_world
+ obj.scale = orig_scale
+ obj.location = orig_loc
+
+ if len(skip_invalid) > 0:
+ for name in skip_invalid:
+ print(f"Align to XY: Skipping object {name}. No faces selected.")
+ if len(skip_invalid) == 1:
+ self.report({'WARNING'}, f"Skipping object {skip_invalid[0]}. No faces selected.")
+ else:
+ self.report({'WARNING'}, f"Skipping some objects. No faces selected. See terminal.")
+ return {'FINISHED'}
+
+ def invoke(self, context, event):
+ if context.mode not in {'EDIT_MESH', 'OBJECT'}:
+ return {'CANCELLED'}
+ return self.execute(context)
+
+
# ------
# Export