1 # SPDX-License-Identifier: GPL-2.0-or-later
3 # -----------------------------------------------------------------------
4 # Author: Alan Odom (Clockmender), Rune Morling (ermo) Copyright (c) 2019
5 # -----------------------------------------------------------------------
7 from bpy
.types
import Operator
8 from .pdt_msg_strings
import (
18 class PDT_OT_PlacementAbs(Operator
):
19 """Use Absolute, or Global Placement"""
21 bl_idname
= "pdt.absolute"
22 bl_label
= "Absolute Mode"
23 bl_options
= {"REGISTER", "UNDO"}
25 def execute(self
, context
):
26 """Manipulates Geometry, or Objects by Absolute (World) Coordinates.
29 - Reads pg.operate from Operation Mode Selector as 'operation'
30 - Reads pg.cartesian_coords scene variables to:
31 -- set position of Cursor (CU)
32 -- set position of Pivot Point (PP)
33 -- MoVe geometry/objects (MV)
34 -- Extrude Vertices (EV)
36 -- add a New Vertex (NV)
38 Invalid Options result in self.report Error.
41 context: Blender bpy.context instance.
47 pg
= context
.scene
.pdt_pg
48 operation
= pg
.operation
49 decimal_places
= context
.preferences
.addons
[__package__
].preferences
.pdt_input_round
54 f
"ca{str(round(pg.cartesian_coords.x, decimal_places))}"
55 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
56 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
58 elif operation
== "PP":
61 f
"pa{str(round(pg.cartesian_coords.x, decimal_places))}"
62 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
63 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
65 elif operation
== "MV":
68 f
"ga{str(round(pg.cartesian_coords.x, decimal_places))}"
69 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
70 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
72 elif operation
== "SE":
75 f
"sa{str(round(pg.cartesian_coords.x, decimal_places))}"
76 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
77 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
79 elif operation
== "NV":
82 f
"na{str(round(pg.cartesian_coords.x, decimal_places))}"
83 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
84 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
86 elif operation
== "EV":
89 f
"va{str(round(pg.cartesian_coords.x, decimal_places))}"
90 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
91 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
94 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_ABS}"
95 self
.report({"ERROR"}, error_message
)
99 class PDT_OT_PlacementDelta(Operator
):
100 """Use Delta, or Incremental Placement"""
102 bl_idname
= "pdt.delta"
103 bl_label
= "Delta Mode"
104 bl_options
= {"REGISTER", "UNDO"}
106 def execute(self
, context
):
107 """Manipulates Geometry, or Objects by Delta Offset (Increment).
110 - Reads pg.operation from Operation Mode Selector as 'operation'
111 - Reads pg.select, pg.plane, pg.cartesian_coords scene variables to:
112 -- set position of CUrsor (CU)
113 -- set position of Pivot Point (PP)
114 -- MoVe geometry/objects (MV)
115 -- Extrude Vertices (EV)
117 -- add a New Vertex (NV)
118 -- Duplicate Geometry (DG)
119 -- Extrude Geometry (EG)
121 Invalid Options result in self.report Error.
124 context: Blender bpy.context instance.
130 pg
= context
.scene
.pdt_pg
131 operation
= pg
.operation
132 decimal_places
= context
.preferences
.addons
[__package__
].preferences
.pdt_input_round
134 if operation
== "CU":
137 f
"cd{str(round(pg.cartesian_coords.x, decimal_places))}"
138 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
139 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
141 elif operation
== "PP":
144 f
"pd{str(round(pg.cartesian_coords.x, decimal_places))}"
145 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
146 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
148 elif operation
== "MV":
151 f
"gd{str(round(pg.cartesian_coords.x, decimal_places))}"
152 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
153 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
155 elif operation
== "SE":
158 f
"sd{str(round(pg.cartesian_coords.x, decimal_places))}"
159 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
160 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
162 elif operation
== "NV":
165 f
"nd{str(round(pg.cartesian_coords.x, decimal_places))}"
166 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
167 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
169 elif operation
== "EV":
172 f
"vd{str(round(pg.cartesian_coords.x, decimal_places))}"
173 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
174 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
176 elif operation
== "DG":
179 f
"dd{str(round(pg.cartesian_coords.x, decimal_places))}"
180 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
181 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
183 elif operation
== "EG":
186 f
"ed{str(round(pg.cartesian_coords.x, decimal_places))}"
187 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
188 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
191 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_DEL}"
192 self
.report({"ERROR"}, error_message
)
196 class PDT_OT_PlacementDis(Operator
):
197 """Use Directional, or Distance @ Angle Placement"""
199 bl_idname
= "pdt.distance"
200 bl_label
= "Distance@Angle Mode"
201 bl_options
= {"REGISTER", "UNDO"}
203 def execute(self
, context
):
204 """Manipulates Geometry, or Objects by Distance at Angle (Direction).
207 - Reads pg.operation from Operation Mode Selector as 'operation'
208 - Reads pg.select, pg.distance, pg.angle, pg.plane & pg.flip_angle scene variables to:
209 -- set position of CUrsor (CU)
210 -- set position of Pivot Point (PP)
211 -- MoVe geometry/objects (MV)
212 -- Extrude Vertices (EV)
214 -- add a New Vertex (NV)
215 -- Duplicate Geometry (DG)
216 -- Extrude Geometry (EG)
218 Invalid Options result in self.report Error.
221 context: Blender bpy.context instance.
227 pg
= context
.scene
.pdt_pg
228 operation
= pg
.operation
229 decimal_places
= context
.preferences
.addons
[__package__
].preferences
.pdt_input_round
231 if operation
== "CU":
234 f
"ci{str(round(pg.distance, decimal_places))}"
235 f
",{str(round(pg.angle, decimal_places))}"
237 elif operation
== "PP":
240 f
"pi{str(round(pg.distance, decimal_places))}"
241 f
",{str(round(pg.angle, decimal_places))}"
243 elif operation
== "MV":
246 f
"gi{str(round(pg.distance, decimal_places))}"
247 f
",{str(round(pg.angle, decimal_places))}"
249 elif operation
== "SE":
252 f
"si{str(round(pg.distance, decimal_places))}"
253 f
",{str(round(pg.angle, decimal_places))}"
255 elif operation
== "NV":
258 f
"ni{str(round(pg.distance, decimal_places))}"
259 f
",{str(round(pg.angle, decimal_places))}"
261 elif operation
== "EV":
264 f
"vi{str(round(pg.distance, decimal_places))}"
265 f
",{str(round(pg.angle, decimal_places))}"
267 elif operation
== "DG":
270 f
"di{str(round(pg.distance, decimal_places))}"
271 f
",{str(round(pg.angle, decimal_places))}"
273 elif operation
== "EG":
276 f
"ei{str(round(pg.distance, decimal_places))}"
277 f
",{str(round(pg.angle, decimal_places))}"
280 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_DIR}"
281 self
.report({"ERROR"}, error_message
)
285 class PDT_OT_PlacementView(Operator
):
286 """Use Distance Input for View Normal Axis Operations"""
288 bl_idname
= "pdt.view_axis"
289 bl_label
= "View Normal Axis Mode"
290 bl_options
= {"REGISTER", "UNDO"}
292 def execute(self
, context
):
293 """Manipulates Geometry, or Objects by View Normal Axis Offset (Increment).
296 - Reads pg.operation from Operation Mode Selector as 'operation'
297 - Reads pg.select, pg.plane, pg.cartesian_coords scene variables to:
298 -- set position of CUrsor (CU)
299 -- set position of Pivot Point (PP)
300 -- MoVe geometry/objects (MV)
301 -- Extrude Vertices (EV)
303 -- add a New Vertex (NV)
304 -- Duplicate Geometry (DG)
305 -- Extrude Geometry (EG)
307 Invalid Options result in self.report Error.
310 context: Blender bpy.context instance.
316 pg
= context
.scene
.pdt_pg
317 operation
= pg
.operation
318 decimal_places
= context
.preferences
.addons
[__package__
].preferences
.pdt_input_round
320 if operation
== "CU":
323 f
"cn{str(round(pg.distance, decimal_places))}"
325 elif operation
== "PP":
328 f
"pn{str(round(pg.distance, decimal_places))}"
330 elif operation
== "MV":
333 f
"gn{str(round(pg.distance, decimal_places))}"
335 elif operation
== "NV":
338 f
"nn{str(round(pg.distance, decimal_places))}"
340 elif operation
== "EV":
343 f
"vn{str(round(pg.distance, decimal_places))}"
345 elif operation
== "DG":
348 f
"dn{str(round(pg.distance, decimal_places))}"
350 elif operation
== "EG":
353 f
"en{str(round(pg.distance, decimal_places))}"
356 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_DEL}"
357 self
.report({"ERROR"}, error_message
)
361 class PDT_OT_PlacementPer(Operator
):
362 """Use Percentage Placement"""
364 bl_idname
= "pdt.percent"
365 bl_label
= "Percentage Mode"
366 bl_options
= {"REGISTER", "UNDO"}
368 def execute(self
, context
):
369 """Manipulates Geometry, or Objects by Percentage between 2 points.
372 - Reads pg.operation from Operation Mode Selector as 'operation'
373 - Reads pg.percent, pg.extend & pg.flip_percent scene variables to:
374 -- set position of CUrsor (CU)
375 -- set position of Pivot Point (PP)
376 -- MoVe geometry/objects (MV)
377 -- Extrude Vertices (EV)
379 -- add a New Vertex (NV)
381 Invalid Options result in self.report Error.
384 context: Blender bpy.context instance.
390 pg
= context
.scene
.pdt_pg
391 operation
= pg
.operation
392 decimal_places
= context
.preferences
.addons
[__package__
].preferences
.pdt_input_round
394 if operation
== "CU":
396 pg
.command
= f
"cp{str(round(pg.percent, decimal_places))}"
397 elif operation
== "PP":
399 pg
.command
= f
"pp{str(round(pg.percent, decimal_places))}"
400 elif operation
== "MV":
402 pg
.command
= f
"gp{str(round(pg.percent, decimal_places))}"
403 elif operation
== "SE":
405 pg
.command
= f
"sp{str(round(pg.percent, decimal_places))}"
406 elif operation
== "NV":
408 pg
.command
= f
"np{str(round(pg.percent, decimal_places))}"
409 elif operation
== "EV":
411 pg
.command
= f
"vp{str(round(pg.percent, decimal_places))}"
413 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_PERCENT}"
414 self
.report({"ERROR"}, error_message
)
418 class PDT_OT_PlacementNormal(Operator
):
419 """Use Normal, or Perpendicular Placement"""
421 bl_idname
= "pdt.normal"
422 bl_label
= "Normal Mode"
423 bl_options
= {"REGISTER", "UNDO"}
425 def execute(self
, context
):
426 """Manipulates Geometry, or Objects by Normal Intersection between 3 points.
429 - Reads pg.operation from Operation Mode Selector as 'operation'
430 - Reads pg.extend scene variable to:
431 -- set position of CUrsor (CU)
432 -- set position of Pivot Point (PP)
433 -- MoVe geometry/objects (MV)
434 -- Extrude Vertices (EV)
436 -- add a New Vertex (NV)
438 Invalid Options result in self.report Error.
441 context: Blender bpy.context instance.
447 pg
= context
.scene
.pdt_pg
448 operation
= pg
.operation
449 if operation
== "CU":
451 elif operation
== "PP":
453 elif operation
== "MV":
455 elif operation
== "EV":
457 elif operation
== "SE":
459 elif operation
== "NV":
462 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_INTERSECT}"
463 self
.report({"ERROR"}, error_message
)
467 class PDT_OT_PlacementCen(Operator
):
468 """Use Placement at Arc Centre"""
470 bl_idname
= "pdt.centre"
471 bl_label
= "Centre Mode"
472 bl_options
= {"REGISTER", "UNDO"}
474 def execute(self
, context
):
475 """Manipulates Geometry, or Objects to an Arc Centre defined by 3 points on an Imaginary Arc.
478 - Reads pg.operation from Operation Mode Selector as 'operation'
479 -- set position of CUrsor (CU)
480 -- set position of Pivot Point (PP)
481 -- MoVe geometry/objects (MV)
482 -- Extrude Vertices (EV)
483 -- add a New vertex (NV)
485 Invalid Options result in self.report Error.
488 context: Blender bpy.context instance.
494 pg
= context
.scene
.pdt_pg
495 operation
= pg
.operation
496 if operation
== "CU":
498 elif operation
== "PP":
500 elif operation
== "MV":
502 elif operation
== "EV":
504 elif operation
== "NV":
507 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_INTERSECT}"
508 self
.report({"ERROR"}, error_message
)
512 class PDT_OT_PlacementInt(Operator
):
513 """Use Intersection, or Convergence Placement"""
515 bl_idname
= "pdt.intersect"
516 bl_label
= "Intersect Mode"
517 bl_options
= {"REGISTER", "UNDO"}
519 def execute(self
, context
):
520 """Manipulates Geometry, or Objects by Convergence Intersection between 4 points, or 2 Edges.
523 - Reads pg.operation from Operation Mode Selector as 'operation'
524 - Reads pg.plane scene variable and operates in Working Plane to:
525 -- set position of CUrsor (CU)
526 -- set position of Pivot Point (PP)
527 -- MoVe geometry/objects (MV)
528 -- Extrude Vertices (EV)
529 -- add a New vertex (NV)
531 Invalid Options result in "self.report" Error.
534 context: Blender bpy.context instance.
540 pg
= context
.scene
.pdt_pg
541 operation
= pg
.operation
542 if operation
== "CU":
544 elif operation
== "PP":
546 elif operation
== "MV":
548 elif operation
== "EV":
550 elif operation
== "NV":
553 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_INTERSECT}"
554 self
.report({"ERROR"}, error_message
)
558 class PDT_OT_JoinVerts(Operator
):
559 """Join 2 Free Vertices into an Edge"""
561 bl_idname
= "pdt.join"
562 bl_label
= "Join 2 Vertices"
563 bl_options
= {"REGISTER", "UNDO"}
566 def poll(cls
, context
):
570 return all([bool(ob
), ob
.type == "MESH", ob
.mode
== "EDIT"])
572 def execute(self
, context
):
573 """Joins 2 Free Vertices that do not form part of a Face.
576 Joins two vertices that do not form part of a single face
577 It is designed to close open Edge Loops, where a face is not required
578 or to join two disconnected Edges.
581 context: Blender bpy.context instance.
587 pg
= context
.scene
.pdt_pg
592 class PDT_OT_Fillet(Operator
):
593 """Fillet Edges by Vertex, Set Use Verts to False for Extruded Structure"""
595 bl_idname
= "pdt.fillet"
597 bl_options
= {"REGISTER", "UNDO"}
600 def poll(cls
, context
):
604 return all([bool(ob
), ob
.type == "MESH", ob
.mode
== "EDIT"])
606 def execute(self
, context
):
607 """Create Fillets by Vertex or by Geometry.
610 Fillets connected edges, or connected faces
612 - pg.fillet_radius ; Radius of fillet
613 - pg.fillet_segments ; Number of segments
614 - pg.fillet_profile ; Profile, values 0 to 1
615 - pg.fillet_vertices_only ; Vertices (True), or Face/Edges
616 - pg.fillet_intersect ; Intersect dges first (True), or not
619 context: Blender bpy.context instance.
625 pg
= context
.scene
.pdt_pg
626 decimal_places
= context
.preferences
.addons
[__package__
].preferences
.pdt_input_round
627 if pg
.fillet_intersect
:
629 f
"fi{str(round(pg.fillet_radius, decimal_places))}"
630 f
",{str(round(pg.fillet_segments, decimal_places))}"
631 f
",{str(round(pg.fillet_profile, decimal_places))}"
633 elif pg
.fillet_vertices_only
:
635 f
"fv{str(round(pg.fillet_radius, decimal_places))}"
636 f
",{str(round(pg.fillet_segments, decimal_places))}"
637 f
",{str(round(pg.fillet_profile, decimal_places))}"
641 f
"fe{str(round(pg.fillet_radius, decimal_places))}"
642 f
",{str(round(pg.fillet_segments, decimal_places))}"
643 f
",{str(round(pg.fillet_profile, decimal_places))}"
648 class PDT_OT_Angle2(Operator
):
649 """Measure Distance and Angle in Working Plane, Also sets Deltas"""
651 bl_idname
= "pdt.angle2"
652 bl_label
= "Measure 2D"
653 bl_options
= {"REGISTER", "UNDO"}
655 def execute(self
, context
):
656 """Measures Angle and Offsets between 2 Points in View Plane.
659 Uses 2 Selected Vertices to set pg.angle and pg.distance scene variables
660 also sets delta offset from these 2 points using standard Numpy Routines
661 Works in Edit and Oject Modes.
664 context: Blender bpy.context instance.
670 pg
= context
.scene
.pdt_pg
675 class PDT_OT_Angle3(Operator
):
676 """Measure Distance and Angle in 3D Space"""
678 bl_idname
= "pdt.angle3"
679 bl_label
= "Measure 3D"
680 bl_options
= {"REGISTER", "UNDO"}
682 def execute(self
, context
):
683 """Measures Angle and Offsets between 3 Points in World Space, Also sets Deltas.
686 Uses 3 Selected Vertices to set pg.angle and pg.distance scene variables
687 also sets delta offset from these 3 points using standard Numpy Routines
688 Works in Edit and Oject Modes.
691 context: Blender bpy.context instance.
697 pg
= context
.scene
.pdt_pg
702 class PDT_OT_Origin(Operator
):
703 """Move Object Origin to Cursor Location"""
705 bl_idname
= "pdt.origin"
706 bl_label
= "Move Origin"
707 bl_options
= {"REGISTER", "UNDO"}
709 def execute(self
, context
):
710 """Sets Object Origin in Edit Mode to Cursor Location.
713 Keeps geometry static in World Space whilst moving Object Origin
714 Requires cursor location
715 Works in Edit and Object Modes.
718 context: Blender bpy.context instance.
724 pg
= context
.scene
.pdt_pg
729 class PDT_OT_Taper(Operator
):
730 """Taper Vertices at Angle in Chosen Axis Mode"""
732 bl_idname
= "pdt.taper"
734 bl_options
= {"REGISTER", "UNDO"}
737 def poll(cls
, context
):
741 return all([bool(ob
), ob
.type == "MESH", ob
.mode
== "EDIT"])
743 def execute(self
, context
):
744 """Taper Geometry along World Axes.
747 Similar to Blender Shear command except that it shears by angle rather than displacement.
748 Rotates about World Axes and displaces along World Axes, angle must not exceed +-80 degrees.
749 Rotation axis is centred on Active Vertex.
750 Works only in Edit mode.
753 context: Blender bpy.context instance.
756 Uses pg.taper & pg.angle scene variables
762 pg
= context
.scene
.pdt_pg
766 #class PDT_Extrude_Modal(Operator):
767 # """Extrude Modal Plane Along Normal Axis"""
768 # bl_idname = "pdt.extrude_modal"
769 # bl_label = "Extrude Modal Normal"
770 # bl_options = {"REGISTER", "UNDO"}