Skip to content

Commit b602f91

Browse files
committed
Merge branch 'release-0.6.0'
2 parents 8b50479 + 9b984f4 commit b602f91

File tree

11 files changed

+1295
-299
lines changed

11 files changed

+1295
-299
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Some real world examples of things you can do with the addon:
1515
Mesh Align Plus is designed to provide precision modeling capabilities, especially for hard surface modelers, mechanical, architectural and CAD/CAM users. See the simple demo clips below for a general sense of what the addon can do, read the <a href="https://github.com/egtwobits/mesh_mesh_align_plus/wiki">Wiki</a> above (with tons of GIF's), or watch the video tutorial on <a href="https://youtu.be/VBoic2MIC8U">YouTube</a>.
1616

1717
![alt](https://i.imgur.com/r6eBnKN.gif)
18-
![alt](https://i.imgur.com/uuHKHZQ.gif)
18+
![alt](https://i.postimg.cc/4yhvz7x2/face-align-4.gif)
1919
![alt](http://i.imgur.com/VSkjGdN.gif)
2020
![alt](http://i.imgur.com/qlUZwPC.gif)
2121
![alt](http://i.imgur.com/JOa7Fcd.gif)

mesh_mesh_align_plus/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"based on geometry and measurements from your scene."
3434
),
3535
"author": "Eric Gentry",
36-
"version": (0, 5, 3),
36+
"version": (0, 6, 0),
3737
"blender": (2, 80, 0),
3838
"location": (
3939
"3D View > N Panel > Mesh Align Plus tab, and"

mesh_mesh_align_plus/align_lines.py

Lines changed: 89 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,50 @@ class MAPLUS_OT_AlignLinesBase(bpy.types.Operator):
1818
target = None
1919

2020
def execute(self, context):
21-
if not (maplus_geom.get_active_object() and maplus_geom.get_select_state(maplus_geom.get_active_object())):
22-
self.report(
23-
{'ERROR'},
24-
('Cannot complete: need at least'
25-
' one active (and selected) object.')
26-
)
27-
return {'CANCELLED'}
2821
addon_data = bpy.context.scene.maplus_data
2922
prims = addon_data.prim_list
3023
previous_mode = maplus_geom.get_active_object().mode
3124
if hasattr(self, "quick_op_target"):
3225
active_item = addon_data.quick_align_lines_transf
3326
else:
3427
active_item = prims[addon_data.active_list_item]
28+
# Gather selected Blender object(s) to apply the transform to
29+
multi_edit_targets = [
30+
item for item in bpy.context.scene.objects if (
31+
maplus_geom.get_select_state(item)
32+
)
33+
]
34+
# Check prerequisites for mesh level transforms, need an active/selected object
35+
if (self.target != 'OBJECT' and not (maplus_geom.get_active_object()
36+
and maplus_geom.get_select_state(maplus_geom.get_active_object()))):
37+
self.report(
38+
{'ERROR'},
39+
('Cannot complete: cannot perform mesh-level transform'
40+
' without an active (and selected) object.')
41+
)
42+
return {'CANCELLED'}
43+
# Check auto grab prerequisites
44+
if addon_data.quick_align_lines_auto_grab_src:
45+
if not (maplus_geom.get_active_object()
46+
and maplus_geom.get_select_state(maplus_geom.get_active_object())):
47+
self.report(
48+
{'ERROR'},
49+
('Cannot complete: cannot auto-grab source verts '
50+
' without an active (and selected) object.')
51+
)
52+
return {'CANCELLED'}
53+
if maplus_geom.get_active_object().type != 'MESH':
54+
self.report(
55+
{'ERROR'},
56+
('Cannot complete: cannot auto-grab source verts '
57+
' from a non-mesh object.')
58+
)
59+
return {'CANCELLED'}
3560

36-
if (maplus_geom.get_active_object() and
37-
type(maplus_geom.get_active_object().data) == bpy.types.Mesh):
61+
# Proceed only if selected Blender objects are compatible with the transform target
62+
# (Do not allow mesh-level transforms when there are non-mesh objects selected)
63+
if not (self.target in {'MESH_SELECTED', 'WHOLE_MESH', 'OBJECT_ORIGIN'}
64+
and [item for item in multi_edit_targets if item.type != 'MESH']):
3865

3966
if not hasattr(self, "quick_op_target"):
4067
if (prims[active_item.aln_src_line].kind != 'LINE' or
@@ -46,14 +73,15 @@ def execute(self, context):
4673
)
4774
return {'CANCELLED'}
4875

49-
# a bmesh can only be initialized in edit mode...
50-
if previous_mode != 'EDIT':
51-
bpy.ops.object.editmode_toggle()
52-
else:
53-
# else we could already be in edit mode with some stale
54-
# updates, exiting and reentering forces an update
55-
bpy.ops.object.editmode_toggle()
56-
bpy.ops.object.editmode_toggle()
76+
if maplus_geom.get_active_object().type == 'MESH':
77+
# a bmesh can only be initialized in edit mode...
78+
if previous_mode != 'EDIT':
79+
bpy.ops.object.editmode_toggle()
80+
else:
81+
# else we could already be in edit mode with some stale
82+
# updates, exiting and reentering forces an update
83+
bpy.ops.object.editmode_toggle()
84+
bpy.ops.object.editmode_toggle()
5785

5886
# Get global coordinate data for each geometry item, with
5987
# modifiers applied. Grab either directly from the scene data
@@ -112,18 +140,7 @@ def execute(self, context):
112140
dest_start = dest_global_data[0]
113141
dest_end = dest_global_data[1]
114142

115-
# create common vars needed for object and for mesh
116-
# level transforms
117-
active_obj_transf = maplus_geom.get_active_object().matrix_world.copy()
118-
inverse_active = active_obj_transf.copy()
119-
inverse_active.invert()
120-
121-
multi_edit_targets = [
122-
model for model in bpy.context.scene.objects if (
123-
maplus_geom.get_select_state(model) and model.type == 'MESH'
124-
)
125-
]
126-
if self.target == 'OBJECT':
143+
if self.target in {'OBJECT', 'OBJECT_ORIGIN'}:
127144
for item in multi_edit_targets:
128145
# Get the object world matrix before we modify it here
129146
item_matrix_unaltered = item.matrix_world.copy()
@@ -171,7 +188,7 @@ def execute(self, context):
171188
)
172189
bpy.context.view_layer.update()
173190

174-
else:
191+
if self.target in {'MESH_SELECTED', 'WHOLE_MESH', 'OBJECT_ORIGIN'}:
175192
for item in multi_edit_targets:
176193
self.report(
177194
{'WARNING'},
@@ -229,13 +246,20 @@ def execute(self, context):
229246
src_pivot_to_loc_origin
230247
)
231248

232-
if self.target == 'MESHSELECTED':
249+
if self.target == 'MESH_SELECTED':
233250
src_mesh.transform(
234251
loc_make_collinear,
235252
filter={'SELECT'}
236253
)
237-
elif self.target == 'WHOLEMESH':
254+
elif self.target == 'WHOLE_MESH':
238255
src_mesh.transform(loc_make_collinear)
256+
elif self.target == 'OBJECT_ORIGIN':
257+
# Note: a target of 'OBJECT_ORIGIN' is equivalent
258+
# to performing an object transf. + an inverse
259+
# whole mesh level transf. To the user,
260+
# the object appears to stay in the same place,
261+
# while only the object's origin moves.
262+
src_mesh.transform(loc_make_collinear.inverted())
239263

240264
bpy.ops.object.mode_set(mode='OBJECT')
241265
src_mesh.to_mesh(item.data)
@@ -245,9 +269,13 @@ def execute(self, context):
245269
bpy.ops.object.mode_set(mode=previous_mode)
246270

247271
else:
272+
# The selected Blender objects are not compatible with the
273+
# requested transformation type (we can't apply a transform
274+
# to mesh data when there are non-mesh objects selected)
248275
self.report(
249276
{'ERROR'},
250-
'Cannot transform: non-mesh or no active object.'
277+
('Cannot complete: Cannot apply mesh-level'
278+
' transformations to selected non-mesh objects.')
251279
)
252280
return {'CANCELLED'}
253281

@@ -271,12 +299,28 @@ class MAPLUS_OT_QuickAlignLinesObject(MAPLUS_OT_AlignLinesBase):
271299
quick_op_target = True
272300

273301

302+
class MAPLUS_OT_QuickAlignLinesObjectOrigin(MAPLUS_OT_AlignLinesBase):
303+
bl_idname = "maplus.quickalignlinesobjectorigin"
304+
bl_label = "Align Lines"
305+
bl_description = "Makes lines collinear (in line with each other)"
306+
bl_options = {'REGISTER', 'UNDO'}
307+
target = 'OBJECT_ORIGIN'
308+
quick_op_target = True
309+
310+
@classmethod
311+
def poll(cls, context):
312+
addon_data = bpy.context.scene.maplus_data
313+
if not addon_data.use_experimental:
314+
return False
315+
return True
316+
317+
274318
class MAPLUS_OT_AlignLinesMeshSelected(MAPLUS_OT_AlignLinesBase):
275319
bl_idname = "maplus.alignlinesmeshselected"
276320
bl_label = "Align Lines"
277321
bl_description = "Makes lines collinear (in line with each other)"
278322
bl_options = {'REGISTER', 'UNDO'}
279-
target = 'MESHSELECTED'
323+
target = 'MESH_SELECTED'
280324

281325
@classmethod
282326
def poll(cls, context):
@@ -291,7 +335,7 @@ class MAPLUS_OT_AlignLinesWholeMesh(MAPLUS_OT_AlignLinesBase):
291335
bl_label = "Align Lines"
292336
bl_description = "Makes lines collinear (in line with each other)"
293337
bl_options = {'REGISTER', 'UNDO'}
294-
target = 'WHOLEMESH'
338+
target = 'WHOLE_MESH'
295339

296340
@classmethod
297341
def poll(cls, context):
@@ -306,7 +350,7 @@ class MAPLUS_OT_QuickAlignLinesMeshSelected(MAPLUS_OT_AlignLinesBase):
306350
bl_label = "Align Lines"
307351
bl_description = "Makes lines collinear (in line with each other)"
308352
bl_options = {'REGISTER', 'UNDO'}
309-
target = 'MESHSELECTED'
353+
target = 'MESH_SELECTED'
310354
quick_op_target = True
311355

312356
@classmethod
@@ -322,7 +366,7 @@ class MAPLUS_OT_QuickAlignLinesWholeMesh(MAPLUS_OT_AlignLinesBase):
322366
bl_label = "Align Lines"
323367
bl_description = "Makes lines collinear (in line with each other)"
324368
bl_options = {'REGISTER', 'UNDO'}
325-
target = 'WHOLEMESH'
369+
target = 'WHOLE_MESH'
326370
quick_op_target = True
327371

328372
@classmethod
@@ -654,12 +698,17 @@ def draw(self, context):
654698
'use_experimental',
655699
text='Enable Experimental Mesh Ops.'
656700
)
657-
aln_apply_items = aln_gui.split(factor=.33)
658-
aln_apply_items.operator(
701+
aln_apply_items = aln_gui.row()
702+
aln_to_object_and_origin = aln_apply_items.column()
703+
aln_to_object_and_origin.operator(
659704
"maplus.quickalignlinesobject",
660705
text="Object"
661706
)
662-
aln_mesh_apply_items = aln_apply_items.row(align=True)
707+
aln_to_object_and_origin.operator(
708+
"maplus.quickalignlinesobjectorigin",
709+
text="Obj. Origin"
710+
)
711+
aln_mesh_apply_items = aln_apply_items.column(align=True)
663712
aln_mesh_apply_items.operator(
664713
"maplus.quickalignlinesmeshselected",
665714
text="Mesh Piece"

0 commit comments

Comments
 (0)