1 # SPDX-FileCopyrightText: 2019-2022 Alan Odom (Clockmender)
2 # SPDX-FileCopyrightText: 2019-2022 Rune Morling (ermo)
4 # SPDX-License-Identifier: GPL-2.0-or-later
6 from bpy
.types
import Operator
7 from .pdt_msg_strings
import (
17 class PDT_OT_PlacementAbs(Operator
):
18 """Use Absolute, or Global Placement"""
20 bl_idname
= "pdt.absolute"
21 bl_label
= "Absolute Mode"
22 bl_options
= {"REGISTER", "UNDO"}
24 def execute(self
, context
):
25 """Manipulates Geometry, or Objects by Absolute (World) Coordinates.
28 - Reads pg.operate from Operation Mode Selector as 'operation'
29 - Reads pg.cartesian_coords scene variables to:
30 -- set position of Cursor (CU)
31 -- set position of Pivot Point (PP)
32 -- MoVe geometry/objects (MV)
33 -- Extrude Vertices (EV)
35 -- add a New Vertex (NV)
37 Invalid Options result in self.report Error.
40 context: Blender bpy.context instance.
46 pg
= context
.scene
.pdt_pg
47 operation
= pg
.operation
48 decimal_places
= context
.preferences
.addons
[__package__
].preferences
.pdt_input_round
53 f
"ca{str(round(pg.cartesian_coords.x, decimal_places))}"
54 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
55 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
57 elif operation
== "PP":
60 f
"pa{str(round(pg.cartesian_coords.x, decimal_places))}"
61 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
62 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
64 elif operation
== "MV":
67 f
"ga{str(round(pg.cartesian_coords.x, decimal_places))}"
68 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
69 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
71 elif operation
== "SE":
74 f
"sa{str(round(pg.cartesian_coords.x, decimal_places))}"
75 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
76 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
78 elif operation
== "NV":
81 f
"na{str(round(pg.cartesian_coords.x, decimal_places))}"
82 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
83 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
85 elif operation
== "EV":
88 f
"va{str(round(pg.cartesian_coords.x, decimal_places))}"
89 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
90 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
93 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_ABS}"
94 self
.report({"ERROR"}, error_message
)
98 class PDT_OT_PlacementDelta(Operator
):
99 """Use Delta, or Incremental Placement"""
101 bl_idname
= "pdt.delta"
102 bl_label
= "Delta Mode"
103 bl_options
= {"REGISTER", "UNDO"}
105 def execute(self
, context
):
106 """Manipulates Geometry, or Objects by Delta Offset (Increment).
109 - Reads pg.operation from Operation Mode Selector as 'operation'
110 - Reads pg.select, pg.plane, pg.cartesian_coords scene variables to:
111 -- set position of CUrsor (CU)
112 -- set position of Pivot Point (PP)
113 -- MoVe geometry/objects (MV)
114 -- Extrude Vertices (EV)
116 -- add a New Vertex (NV)
117 -- Duplicate Geometry (DG)
118 -- Extrude Geometry (EG)
120 Invalid Options result in self.report Error.
123 context: Blender bpy.context instance.
129 pg
= context
.scene
.pdt_pg
130 operation
= pg
.operation
131 decimal_places
= context
.preferences
.addons
[__package__
].preferences
.pdt_input_round
133 if operation
== "CU":
136 f
"cd{str(round(pg.cartesian_coords.x, decimal_places))}"
137 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
138 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
140 elif operation
== "PP":
143 f
"pd{str(round(pg.cartesian_coords.x, decimal_places))}"
144 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
145 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
147 elif operation
== "MV":
150 f
"gd{str(round(pg.cartesian_coords.x, decimal_places))}"
151 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
152 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
154 elif operation
== "SE":
157 f
"sd{str(round(pg.cartesian_coords.x, decimal_places))}"
158 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
159 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
161 elif operation
== "NV":
164 f
"nd{str(round(pg.cartesian_coords.x, decimal_places))}"
165 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
166 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
168 elif operation
== "EV":
171 f
"vd{str(round(pg.cartesian_coords.x, decimal_places))}"
172 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
173 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
175 elif operation
== "DG":
178 f
"dd{str(round(pg.cartesian_coords.x, decimal_places))}"
179 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
180 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
182 elif operation
== "EG":
185 f
"ed{str(round(pg.cartesian_coords.x, decimal_places))}"
186 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
187 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
190 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_DEL}"
191 self
.report({"ERROR"}, error_message
)
195 class PDT_OT_PlacementDis(Operator
):
196 """Use Directional, or Distance @ Angle Placement"""
198 bl_idname
= "pdt.distance"
199 bl_label
= "Distance@Angle Mode"
200 bl_options
= {"REGISTER", "UNDO"}
202 def execute(self
, context
):
203 """Manipulates Geometry, or Objects by Distance at Angle (Direction).
206 - Reads pg.operation from Operation Mode Selector as 'operation'
207 - Reads pg.select, pg.distance, pg.angle, pg.plane & pg.flip_angle scene variables to:
208 -- set position of CUrsor (CU)
209 -- set position of Pivot Point (PP)
210 -- MoVe geometry/objects (MV)
211 -- Extrude Vertices (EV)
213 -- add a New Vertex (NV)
214 -- Duplicate Geometry (DG)
215 -- Extrude Geometry (EG)
217 Invalid Options result in self.report Error.
220 context: Blender bpy.context instance.
226 pg
= context
.scene
.pdt_pg
227 operation
= pg
.operation
228 decimal_places
= context
.preferences
.addons
[__package__
].preferences
.pdt_input_round
230 if operation
== "CU":
233 f
"ci{str(round(pg.distance, decimal_places))}"
234 f
",{str(round(pg.angle, decimal_places))}"
236 elif operation
== "PP":
239 f
"pi{str(round(pg.distance, decimal_places))}"
240 f
",{str(round(pg.angle, decimal_places))}"
242 elif operation
== "MV":
245 f
"gi{str(round(pg.distance, decimal_places))}"
246 f
",{str(round(pg.angle, decimal_places))}"
248 elif operation
== "SE":
251 f
"si{str(round(pg.distance, decimal_places))}"
252 f
",{str(round(pg.angle, decimal_places))}"
254 elif operation
== "NV":
257 f
"ni{str(round(pg.distance, decimal_places))}"
258 f
",{str(round(pg.angle, decimal_places))}"
260 elif operation
== "EV":
263 f
"vi{str(round(pg.distance, decimal_places))}"
264 f
",{str(round(pg.angle, decimal_places))}"
266 elif operation
== "DG":
269 f
"di{str(round(pg.distance, decimal_places))}"
270 f
",{str(round(pg.angle, decimal_places))}"
272 elif operation
== "EG":
275 f
"ei{str(round(pg.distance, decimal_places))}"
276 f
",{str(round(pg.angle, decimal_places))}"
279 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_DIR}"
280 self
.report({"ERROR"}, error_message
)
284 class PDT_OT_PlacementView(Operator
):
285 """Use Distance Input for View Normal Axis Operations"""
287 bl_idname
= "pdt.view_axis"
288 bl_label
= "View Normal Axis Mode"
289 bl_options
= {"REGISTER", "UNDO"}
291 def execute(self
, context
):
292 """Manipulates Geometry, or Objects by View Normal Axis Offset (Increment).
295 - Reads pg.operation from Operation Mode Selector as 'operation'
296 - Reads pg.select, pg.plane, pg.cartesian_coords scene variables to:
297 -- set position of CUrsor (CU)
298 -- set position of Pivot Point (PP)
299 -- MoVe geometry/objects (MV)
300 -- Extrude Vertices (EV)
302 -- add a New Vertex (NV)
303 -- Duplicate Geometry (DG)
304 -- Extrude Geometry (EG)
306 Invalid Options result in self.report Error.
309 context: Blender bpy.context instance.
315 pg
= context
.scene
.pdt_pg
316 operation
= pg
.operation
317 decimal_places
= context
.preferences
.addons
[__package__
].preferences
.pdt_input_round
319 if operation
== "CU":
322 f
"cn{str(round(pg.distance, decimal_places))}"
324 elif operation
== "PP":
327 f
"pn{str(round(pg.distance, decimal_places))}"
329 elif operation
== "MV":
332 f
"gn{str(round(pg.distance, decimal_places))}"
334 elif operation
== "NV":
337 f
"nn{str(round(pg.distance, decimal_places))}"
339 elif operation
== "EV":
342 f
"vn{str(round(pg.distance, decimal_places))}"
344 elif operation
== "DG":
347 f
"dn{str(round(pg.distance, decimal_places))}"
349 elif operation
== "EG":
352 f
"en{str(round(pg.distance, decimal_places))}"
355 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_DEL}"
356 self
.report({"ERROR"}, error_message
)
360 class PDT_OT_PlacementPer(Operator
):
361 """Use Percentage Placement"""
363 bl_idname
= "pdt.percent"
364 bl_label
= "Percentage Mode"
365 bl_options
= {"REGISTER", "UNDO"}
367 def execute(self
, context
):
368 """Manipulates Geometry, or Objects by Percentage between 2 points.
371 - Reads pg.operation from Operation Mode Selector as 'operation'
372 - Reads pg.percent, pg.extend & pg.flip_percent scene variables to:
373 -- set position of CUrsor (CU)
374 -- set position of Pivot Point (PP)
375 -- MoVe geometry/objects (MV)
376 -- Extrude Vertices (EV)
378 -- add a New Vertex (NV)
380 Invalid Options result in self.report Error.
383 context: Blender bpy.context instance.
389 pg
= context
.scene
.pdt_pg
390 operation
= pg
.operation
391 decimal_places
= context
.preferences
.addons
[__package__
].preferences
.pdt_input_round
393 if operation
== "CU":
395 pg
.command
= f
"cp{str(round(pg.percent, decimal_places))}"
396 elif operation
== "PP":
398 pg
.command
= f
"pp{str(round(pg.percent, decimal_places))}"
399 elif operation
== "MV":
401 pg
.command
= f
"gp{str(round(pg.percent, decimal_places))}"
402 elif operation
== "SE":
404 pg
.command
= f
"sp{str(round(pg.percent, decimal_places))}"
405 elif operation
== "NV":
407 pg
.command
= f
"np{str(round(pg.percent, decimal_places))}"
408 elif operation
== "EV":
410 pg
.command
= f
"vp{str(round(pg.percent, decimal_places))}"
412 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_PERCENT}"
413 self
.report({"ERROR"}, error_message
)
417 class PDT_OT_PlacementNormal(Operator
):
418 """Use Normal, or Perpendicular Placement"""
420 bl_idname
= "pdt.normal"
421 bl_label
= "Normal Mode"
422 bl_options
= {"REGISTER", "UNDO"}
424 def execute(self
, context
):
425 """Manipulates Geometry, or Objects by Normal Intersection between 3 points.
428 - Reads pg.operation from Operation Mode Selector as 'operation'
429 - Reads pg.extend scene variable to:
430 -- set position of CUrsor (CU)
431 -- set position of Pivot Point (PP)
432 -- MoVe geometry/objects (MV)
433 -- Extrude Vertices (EV)
435 -- add a New Vertex (NV)
437 Invalid Options result in self.report Error.
440 context: Blender bpy.context instance.
446 pg
= context
.scene
.pdt_pg
447 operation
= pg
.operation
448 if operation
== "CU":
450 elif operation
== "PP":
452 elif operation
== "MV":
454 elif operation
== "EV":
456 elif operation
== "SE":
458 elif operation
== "NV":
461 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_INTERSECT}"
462 self
.report({"ERROR"}, error_message
)
466 class PDT_OT_PlacementCen(Operator
):
467 """Use Placement at Arc Centre"""
469 bl_idname
= "pdt.centre"
470 bl_label
= "Centre Mode"
471 bl_options
= {"REGISTER", "UNDO"}
473 def execute(self
, context
):
474 """Manipulates Geometry, or Objects to an Arc Centre defined by 3 points on an Imaginary Arc.
477 - Reads pg.operation from Operation Mode Selector as 'operation'
478 -- set position of CUrsor (CU)
479 -- set position of Pivot Point (PP)
480 -- MoVe geometry/objects (MV)
481 -- Extrude Vertices (EV)
482 -- add a New vertex (NV)
484 Invalid Options result in self.report Error.
487 context: Blender bpy.context instance.
493 pg
= context
.scene
.pdt_pg
494 operation
= pg
.operation
495 if operation
== "CU":
497 elif operation
== "PP":
499 elif operation
== "MV":
501 elif operation
== "EV":
503 elif operation
== "NV":
506 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_INTERSECT}"
507 self
.report({"ERROR"}, error_message
)
511 class PDT_OT_PlacementInt(Operator
):
512 """Use Intersection, or Convergence Placement"""
514 bl_idname
= "pdt.intersect"
515 bl_label
= "Intersect Mode"
516 bl_options
= {"REGISTER", "UNDO"}
518 def execute(self
, context
):
519 """Manipulates Geometry, or Objects by Convergence Intersection between 4 points, or 2 Edges.
522 - Reads pg.operation from Operation Mode Selector as 'operation'
523 - Reads pg.plane scene variable and operates in Working Plane to:
524 -- set position of CUrsor (CU)
525 -- set position of Pivot Point (PP)
526 -- MoVe geometry/objects (MV)
527 -- Extrude Vertices (EV)
528 -- add a New vertex (NV)
530 Invalid Options result in "self.report" Error.
533 context: Blender bpy.context instance.
539 pg
= context
.scene
.pdt_pg
540 operation
= pg
.operation
541 if operation
== "CU":
543 elif operation
== "PP":
545 elif operation
== "MV":
547 elif operation
== "EV":
549 elif operation
== "NV":
552 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_INTERSECT}"
553 self
.report({"ERROR"}, error_message
)
557 class PDT_OT_JoinVerts(Operator
):
558 """Join 2 Free Vertices into an Edge"""
560 bl_idname
= "pdt.join"
561 bl_label
= "Join 2 Vertices"
562 bl_options
= {"REGISTER", "UNDO"}
565 def poll(cls
, context
):
569 return all([bool(ob
), ob
.type == "MESH", ob
.mode
== "EDIT"])
571 def execute(self
, context
):
572 """Joins 2 Free Vertices that do not form part of a Face.
575 Joins two vertices that do not form part of a single face
576 It is designed to close open Edge Loops, where a face is not required
577 or to join two disconnected Edges.
580 context: Blender bpy.context instance.
586 pg
= context
.scene
.pdt_pg
591 class PDT_OT_Fillet(Operator
):
592 """Fillet Edges by Vertex, Set Use Verts to False for Extruded Structure"""
594 bl_idname
= "pdt.fillet"
596 bl_options
= {"REGISTER", "UNDO"}
599 def poll(cls
, context
):
603 return all([bool(ob
), ob
.type == "MESH", ob
.mode
== "EDIT"])
605 def execute(self
, context
):
606 """Create Fillets by Vertex or by Geometry.
609 Fillets connected edges, or connected faces
611 - pg.fillet_radius ; Radius of fillet
612 - pg.fillet_segments ; Number of segments
613 - pg.fillet_profile ; Profile, values 0 to 1
614 - pg.fillet_vertices_only ; Vertices (True), or Face/Edges
615 - pg.fillet_intersect ; Intersect dges first (True), or not
618 context: Blender bpy.context instance.
624 pg
= context
.scene
.pdt_pg
625 decimal_places
= context
.preferences
.addons
[__package__
].preferences
.pdt_input_round
626 if pg
.fillet_intersect
:
628 f
"fi{str(round(pg.fillet_radius, decimal_places))}"
629 f
",{str(round(pg.fillet_segments, decimal_places))}"
630 f
",{str(round(pg.fillet_profile, decimal_places))}"
632 elif pg
.fillet_vertices_only
:
634 f
"fv{str(round(pg.fillet_radius, decimal_places))}"
635 f
",{str(round(pg.fillet_segments, decimal_places))}"
636 f
",{str(round(pg.fillet_profile, decimal_places))}"
640 f
"fe{str(round(pg.fillet_radius, decimal_places))}"
641 f
",{str(round(pg.fillet_segments, decimal_places))}"
642 f
",{str(round(pg.fillet_profile, decimal_places))}"
647 class PDT_OT_Angle2(Operator
):
648 """Measure Distance and Angle in Working Plane, Also sets Deltas"""
650 bl_idname
= "pdt.angle2"
651 bl_label
= "Measure 2D"
652 bl_options
= {"REGISTER", "UNDO"}
654 def execute(self
, context
):
655 """Measures Angle and Offsets between 2 Points in View Plane.
658 Uses 2 Selected Vertices to set pg.angle and pg.distance scene variables
659 also sets delta offset from these 2 points using standard Numpy Routines
660 Works in Edit and Object Modes.
663 context: Blender bpy.context instance.
669 pg
= context
.scene
.pdt_pg
674 class PDT_OT_Angle3(Operator
):
675 """Measure Distance and Angle in 3D Space"""
677 bl_idname
= "pdt.angle3"
678 bl_label
= "Measure 3D"
679 bl_options
= {"REGISTER", "UNDO"}
681 def execute(self
, context
):
682 """Measures Angle and Offsets between 3 Points in World Space, Also sets Deltas.
685 Uses 3 Selected Vertices to set pg.angle and pg.distance scene variables
686 also sets delta offset from these 3 points using standard Numpy Routines
687 Works in Edit and Object Modes.
690 context: Blender bpy.context instance.
696 pg
= context
.scene
.pdt_pg
701 class PDT_OT_Origin(Operator
):
702 """Move Object Origin to Cursor Location"""
704 bl_idname
= "pdt.origin"
705 bl_label
= "Move Origin"
706 bl_options
= {"REGISTER", "UNDO"}
708 def execute(self
, context
):
709 """Sets Object Origin in Edit Mode to Cursor Location.
712 Keeps geometry static in World Space whilst moving Object Origin
713 Requires cursor location
714 Works in Edit and Object Modes.
717 context: Blender bpy.context instance.
723 pg
= context
.scene
.pdt_pg
728 class PDT_OT_Taper(Operator
):
729 """Taper Vertices at Angle in Chosen Axis Mode"""
731 bl_idname
= "pdt.taper"
733 bl_options
= {"REGISTER", "UNDO"}
736 def poll(cls
, context
):
740 return all([bool(ob
), ob
.type == "MESH", ob
.mode
== "EDIT"])
742 def execute(self
, context
):
743 """Taper Geometry along World Axes.
746 Similar to Blender Shear command except that it shears by angle rather than displacement.
747 Rotates about World Axes and displaces along World Axes, angle must not exceed +-80 degrees.
748 Rotation axis is centred on Active Vertex.
749 Works only in Edit mode.
752 context: Blender bpy.context instance.
755 Uses pg.taper & pg.angle scene variables
761 pg
= context
.scene
.pdt_pg
765 #class PDT_Extrude_Modal(Operator):
766 # """Extrude Modal Plane Along Normal Axis"""
767 # bl_idname = "pdt.extrude_modal"
768 # bl_label = "Extrude Modal Normal"
769 # bl_options = {"REGISTER", "UNDO"}