1 # ***** BEGIN GPL LICENSE BLOCK *****
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software Foundation,
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # ***** END GPL LICENCE BLOCK *****
20 # -----------------------------------------------------------------------
21 # Author: Alan Odom (Clockmender), Rune Morling (ermo) Copyright (c) 2019
22 # -----------------------------------------------------------------------
24 from bpy
.types
import Operator
25 from .pdt_msg_strings
import (
35 class PDT_OT_PlacementAbs(Operator
):
36 """Use Absolute, or Global Placement"""
38 bl_idname
= "pdt.absolute"
39 bl_label
= "Absolute Mode"
40 bl_options
= {"REGISTER", "UNDO"}
42 def execute(self
, context
):
43 """Manipulates Geometry, or Objects by Absolute (World) Coordinates.
46 - Reads pg.operate from Operation Mode Selector as 'operation'
47 - Reads pg.cartesian_coords scene variables to:
48 -- set position of CUrsor (CU)
49 -- set postion of Pivot Point (PP)
50 -- MoVe geometry/objects (MV)
51 -- Extrude Vertices (EV)
53 -- add a New Vertex (NV)
55 Invalid Options result in self.report Error.
58 context: Blender bpy.context instance.
64 pg
= context
.scene
.pdt_pg
65 operation
= pg
.operation
66 decimal_places
= context
.preferences
.addons
[__package__
].preferences
.pdt_input_round
71 f
"ca{str(round(pg.cartesian_coords.x, decimal_places))}"
72 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
73 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
75 elif operation
== "PP":
78 f
"pa{str(round(pg.cartesian_coords.x, decimal_places))}"
79 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
80 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
82 elif operation
== "MV":
85 f
"ga{str(round(pg.cartesian_coords.x, decimal_places))}"
86 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
87 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
89 elif operation
== "SE":
92 f
"sa{str(round(pg.cartesian_coords.x, decimal_places))}"
93 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
94 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
96 elif operation
== "NV":
99 f
"na{str(round(pg.cartesian_coords.x, decimal_places))}"
100 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
101 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
103 elif operation
== "EV":
106 f
"va{str(round(pg.cartesian_coords.x, decimal_places))}"
107 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
108 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
111 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_ABS}"
112 self
.report({"ERROR"}, error_message
)
116 class PDT_OT_PlacementDelta(Operator
):
117 """Use Delta, or Incremental Placement"""
119 bl_idname
= "pdt.delta"
120 bl_label
= "Delta Mode"
121 bl_options
= {"REGISTER", "UNDO"}
123 def execute(self
, context
):
124 """Manipulates Geometry, or Objects by Delta Offset (Increment).
127 - Reads pg.operation from Operation Mode Selector as 'operation'
128 - Reads pg.select, pg.plane, pg.cartesian_coords scene variables to:
129 -- set position of CUrsor (CU)
130 -- set position of Pivot Point (PP)
131 -- MoVe geometry/objects (MV)
132 -- Extrude Vertices (EV)
134 -- add a New Vertex (NV)
135 -- Duplicate Geometry (DG)
136 -- Extrude Geometry (EG)
138 Invalid Options result in self.report Error.
141 context: Blender bpy.context instance.
147 pg
= context
.scene
.pdt_pg
148 operation
= pg
.operation
149 decimal_places
= context
.preferences
.addons
[__package__
].preferences
.pdt_input_round
151 if operation
== "CU":
154 f
"cd{str(round(pg.cartesian_coords.x, decimal_places))}"
155 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
156 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
158 elif operation
== "PP":
161 f
"pd{str(round(pg.cartesian_coords.x, decimal_places))}"
162 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
163 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
165 elif operation
== "MV":
168 f
"gd{str(round(pg.cartesian_coords.x, decimal_places))}"
169 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
170 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
172 elif operation
== "SE":
175 f
"sd{str(round(pg.cartesian_coords.x, decimal_places))}"
176 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
177 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
179 elif operation
== "NV":
182 f
"nd{str(round(pg.cartesian_coords.x, decimal_places))}"
183 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
184 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
186 elif operation
== "EV":
189 f
"vd{str(round(pg.cartesian_coords.x, decimal_places))}"
190 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
191 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
193 elif operation
== "DG":
196 f
"dd{str(round(pg.cartesian_coords.x, decimal_places))}"
197 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
198 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
200 elif operation
== "EG":
203 f
"ed{str(round(pg.cartesian_coords.x, decimal_places))}"
204 f
",{str(round(pg.cartesian_coords.y, decimal_places))}"
205 f
",{str(round(pg.cartesian_coords.z, decimal_places))}"
208 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_DEL}"
209 self
.report({"ERROR"}, error_message
)
213 class PDT_OT_PlacementDis(Operator
):
214 """Use Directional, or Distance @ Angle Placement"""
216 bl_idname
= "pdt.distance"
217 bl_label
= "Distance@Angle Mode"
218 bl_options
= {"REGISTER", "UNDO"}
220 def execute(self
, context
):
221 """Manipulates Geometry, or Objects by Distance at Angle (Direction).
224 - Reads pg.operation from Operation Mode Selector as 'operation'
225 - Reads pg.select, pg.distance, pg.angle, pg.plane & pg.flip_angle scene variables to:
226 -- set position of CUrsor (CU)
227 -- set position of Pivot Point (PP)
228 -- MoVe geometry/objects (MV)
229 -- Extrude Vertices (EV)
231 -- add a New Vertex (NV)
232 -- Duplicate Geometry (DG)
233 -- Extrude Geometry (EG)
235 Invalid Options result in self.report Error.
238 context: Blender bpy.context instance.
244 pg
= context
.scene
.pdt_pg
245 operation
= pg
.operation
246 decimal_places
= context
.preferences
.addons
[__package__
].preferences
.pdt_input_round
248 if operation
== "CU":
251 f
"ci{str(round(pg.distance, decimal_places))}"
252 f
",{str(round(pg.angle, decimal_places))}"
254 elif operation
== "PP":
257 f
"pi{str(round(pg.distance, decimal_places))}"
258 f
",{str(round(pg.angle, decimal_places))}"
260 elif operation
== "MV":
263 f
"gi{str(round(pg.distance, decimal_places))}"
264 f
",{str(round(pg.angle, decimal_places))}"
266 elif operation
== "SE":
269 f
"si{str(round(pg.distance, decimal_places))}"
270 f
",{str(round(pg.angle, decimal_places))}"
272 elif operation
== "NV":
275 f
"ni{str(round(pg.distance, decimal_places))}"
276 f
",{str(round(pg.angle, decimal_places))}"
278 elif operation
== "EV":
281 f
"vi{str(round(pg.distance, decimal_places))}"
282 f
",{str(round(pg.angle, decimal_places))}"
284 elif operation
== "DG":
287 f
"di{str(round(pg.distance, decimal_places))}"
288 f
",{str(round(pg.angle, decimal_places))}"
290 elif operation
== "EG":
293 f
"ei{str(round(pg.distance, decimal_places))}"
294 f
",{str(round(pg.angle, decimal_places))}"
297 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_DIR}"
298 self
.report({"ERROR"}, error_message
)
302 class PDT_OT_PlacementView(Operator
):
303 """Use Distance Input for View Normal Axis Operations"""
305 bl_idname
= "pdt.view_axis"
306 bl_label
= "View Normal Axis Mode"
307 bl_options
= {"REGISTER", "UNDO"}
309 def execute(self
, context
):
310 """Manipulates Geometry, or Objects by View Normal Axis Offset (Increment).
313 - Reads pg.operation from Operation Mode Selector as 'operation'
314 - Reads pg.select, pg.plane, pg.cartesian_coords scene variables to:
315 -- set position of CUrsor (CU)
316 -- set position of Pivot Point (PP)
317 -- MoVe geometry/objects (MV)
318 -- Extrude Vertices (EV)
320 -- add a New Vertex (NV)
321 -- Duplicate Geometry (DG)
322 -- Extrude Geometry (EG)
324 Invalid Options result in self.report Error.
327 context: Blender bpy.context instance.
333 pg
= context
.scene
.pdt_pg
334 operation
= pg
.operation
335 decimal_places
= context
.preferences
.addons
[__package__
].preferences
.pdt_input_round
337 if operation
== "CU":
340 f
"cn{str(round(pg.distance, decimal_places))}"
342 elif operation
== "PP":
345 f
"pn{str(round(pg.distance, decimal_places))}"
347 elif operation
== "MV":
350 f
"gn{str(round(pg.distance, decimal_places))}"
352 elif operation
== "NV":
355 f
"nn{str(round(pg.distance, decimal_places))}"
357 elif operation
== "EV":
360 f
"vn{str(round(pg.distance, decimal_places))}"
362 elif operation
== "DG":
365 f
"dn{str(round(pg.distance, decimal_places))}"
367 elif operation
== "EG":
370 f
"en{str(round(pg.distance, decimal_places))}"
373 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_DEL}"
374 self
.report({"ERROR"}, error_message
)
378 class PDT_OT_PlacementPer(Operator
):
379 """Use Percentage Placement"""
381 bl_idname
= "pdt.percent"
382 bl_label
= "Percentage Mode"
383 bl_options
= {"REGISTER", "UNDO"}
385 def execute(self
, context
):
386 """Manipulates Geometry, or Objects by Percentage between 2 points.
389 - Reads pg.operation from Operation Mode Selector as 'operation'
390 - Reads pg.percent, pg.extend & pg.flip_percent scene variables to:
391 -- set position of CUrsor (CU)
392 -- set position of Pivot Point (PP)
393 -- MoVe geometry/objects (MV)
394 -- Extrude Vertices (EV)
396 -- add a New Vertex (NV)
398 Invalid Options result in self.report Error.
401 context: Blender bpy.context instance.
407 pg
= context
.scene
.pdt_pg
408 operation
= pg
.operation
409 decimal_places
= context
.preferences
.addons
[__package__
].preferences
.pdt_input_round
411 if operation
== "CU":
413 pg
.command
= f
"cp{str(round(pg.percent, decimal_places))}"
414 elif operation
== "PP":
416 pg
.command
= f
"pp{str(round(pg.percent, decimal_places))}"
417 elif operation
== "MV":
419 pg
.command
= f
"gp{str(round(pg.percent, decimal_places))}"
420 elif operation
== "SE":
422 pg
.command
= f
"sp{str(round(pg.percent, decimal_places))}"
423 elif operation
== "NV":
425 pg
.command
= f
"np{str(round(pg.percent, decimal_places))}"
426 elif operation
== "EV":
428 pg
.command
= f
"vp{str(round(pg.percent, decimal_places))}"
430 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_PERCENT}"
431 self
.report({"ERROR"}, error_message
)
435 class PDT_OT_PlacementNormal(Operator
):
436 """Use Normal, or Perpendicular Placement"""
438 bl_idname
= "pdt.normal"
439 bl_label
= "Normal Mode"
440 bl_options
= {"REGISTER", "UNDO"}
442 def execute(self
, context
):
443 """Manipulates Geometry, or Objects by Normal Intersection between 3 points.
446 - Reads pg.operation from Operation Mode Selector as 'operation'
447 - Reads pg.extend scene variable to:
448 -- set position of CUrsor (CU)
449 -- set position of Pivot Point (PP)
450 -- MoVe geometry/objects (MV)
451 -- Extrude Vertices (EV)
453 -- add a New Vertex (NV)
455 Invalid Options result in self.report Error.
458 context: Blender bpy.context instance.
464 pg
= context
.scene
.pdt_pg
465 operation
= pg
.operation
466 if operation
== "CU":
468 elif operation
== "PP":
470 elif operation
== "MV":
472 elif operation
== "EV":
474 elif operation
== "SE":
476 elif operation
== "NV":
479 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_INTERSECT}"
480 self
.report({"ERROR"}, error_message
)
484 class PDT_OT_PlacementCen(Operator
):
485 """Use Placement at Arc Centre"""
487 bl_idname
= "pdt.centre"
488 bl_label
= "Centre Mode"
489 bl_options
= {"REGISTER", "UNDO"}
491 def execute(self
, context
):
492 """Manipulates Geometry, or Objects to an Arc Centre defined by 3 points on an Imaginary Arc.
495 - Reads pg.operation from Operation Mode Selector as 'operation'
496 -- set position of CUrsor (CU)
497 -- set position of Pivot Point (PP)
498 -- MoVe geometry/objects (MV)
499 -- Extrude Vertices (EV)
500 -- add a New vertex (NV)
502 Invalid Options result in self.report Error.
505 context: Blender bpy.context instance.
511 pg
= context
.scene
.pdt_pg
512 operation
= pg
.operation
513 if operation
== "CU":
515 elif operation
== "PP":
517 elif operation
== "MV":
519 elif operation
== "EV":
521 elif operation
== "NV":
524 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_INTERSECT}"
525 self
.report({"ERROR"}, error_message
)
529 class PDT_OT_PlacementInt(Operator
):
530 """Use Intersection, or Convergence Placement"""
532 bl_idname
= "pdt.intersect"
533 bl_label
= "Intersect Mode"
534 bl_options
= {"REGISTER", "UNDO"}
536 def execute(self
, context
):
537 """Manipulates Geometry, or Objects by Convergance Intersection between 4 points, or 2 Edges.
540 - Reads pg.operation from Operation Mode Selector as 'operation'
541 - Reads pg.plane scene variable and operates in Working Plane to:
542 -- set position of CUrsor (CU)
543 -- set position of Pivot Point (PP)
544 -- MoVe geometry/objects (MV)
545 -- Extrude Vertices (EV)
546 -- add a New vertex (NV)
548 Invalid Options result in "self.report" Error.
551 context: Blender bpy.context instance.
557 pg
= context
.scene
.pdt_pg
558 operation
= pg
.operation
559 if operation
== "CU":
561 elif operation
== "PP":
563 elif operation
== "MV":
565 elif operation
== "EV":
567 elif operation
== "NV":
570 error_message
= f
"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_INTERSECT}"
571 self
.report({"ERROR"}, error_message
)
575 class PDT_OT_JoinVerts(Operator
):
576 """Join 2 Free Vertices into an Edge"""
578 bl_idname
= "pdt.join"
579 bl_label
= "Join 2 Vertices"
580 bl_options
= {"REGISTER", "UNDO"}
583 def poll(cls
, context
):
587 return all([bool(ob
), ob
.type == "MESH", ob
.mode
== "EDIT"])
589 def execute(self
, context
):
590 """Joins 2 Free Vertices that do not form part of a Face.
593 Joins two vertices that do not form part of a single face
594 It is designed to close open Edge Loops, where a face is not required
595 or to join two disconnected Edges.
598 context: Blender bpy.context instance.
604 pg
= context
.scene
.pdt_pg
609 class PDT_OT_Fillet(Operator
):
610 """Fillet Edges by Vertex, Set Use Verts to False for Extruded Structure"""
612 bl_idname
= "pdt.fillet"
614 bl_options
= {"REGISTER", "UNDO"}
617 def poll(cls
, context
):
621 return all([bool(ob
), ob
.type == "MESH", ob
.mode
== "EDIT"])
623 def execute(self
, context
):
624 """Create Fillets by Vertex or by Geometry.
627 Fillets connected edges, or connected faces
629 - pg.fillet_radius ; Radius of fillet
630 - pg.fillet_segments ; Number of segments
631 - pg.fillet_profile ; Profile, values 0 to 1
632 - pg.fillet_vertices_only ; Vertices (True), or Face/Edges
633 - pg.fillet_intersect ; Intersect dges first (True), or not
636 context: Blender bpy.context instance.
642 pg
= context
.scene
.pdt_pg
643 decimal_places
= context
.preferences
.addons
[__package__
].preferences
.pdt_input_round
644 if pg
.fillet_intersect
:
646 f
"fi{str(round(pg.fillet_radius, decimal_places))}"
647 f
",{str(round(pg.fillet_segments, decimal_places))}"
648 f
",{str(round(pg.fillet_profile, decimal_places))}"
650 elif pg
.fillet_vertices_only
:
652 f
"fv{str(round(pg.fillet_radius, decimal_places))}"
653 f
",{str(round(pg.fillet_segments, decimal_places))}"
654 f
",{str(round(pg.fillet_profile, decimal_places))}"
658 f
"fe{str(round(pg.fillet_radius, decimal_places))}"
659 f
",{str(round(pg.fillet_segments, decimal_places))}"
660 f
",{str(round(pg.fillet_profile, decimal_places))}"
665 class PDT_OT_Angle2(Operator
):
666 """Measure Distance and Angle in Working Plane, Also sets Deltas"""
668 bl_idname
= "pdt.angle2"
669 bl_label
= "Measure 2D"
670 bl_options
= {"REGISTER", "UNDO"}
672 def execute(self
, context
):
673 """Measures Angle and Offsets between 2 Points in View Plane.
676 Uses 2 Selected Vertices to set pg.angle and pg.distance scene variables
677 also sets delta offset from these 2 points using standard Numpy Routines
678 Works in Edit and Oject Modes.
681 context: Blender bpy.context instance.
687 pg
= context
.scene
.pdt_pg
692 class PDT_OT_Angle3(Operator
):
693 """Measure Distance and Angle in 3D Space"""
695 bl_idname
= "pdt.angle3"
696 bl_label
= "Measure 3D"
697 bl_options
= {"REGISTER", "UNDO"}
699 def execute(self
, context
):
700 """Measures Angle and Offsets between 3 Points in World Space, Also sets Deltas.
703 Uses 3 Selected Vertices to set pg.angle and pg.distance scene variables
704 also sets delta offset from these 3 points using standard Numpy Routines
705 Works in Edit and Oject Modes.
708 context: Blender bpy.context instance.
714 pg
= context
.scene
.pdt_pg
719 class PDT_OT_Origin(Operator
):
720 """Move Object Origin to Cursor Location"""
722 bl_idname
= "pdt.origin"
723 bl_label
= "Move Origin"
724 bl_options
= {"REGISTER", "UNDO"}
726 def execute(self
, context
):
727 """Sets Object Origin in Edit Mode to Cursor Location.
730 Keeps geometry static in World Space whilst moving Object Origin
731 Requires cursor location
732 Works in Edit and Object Modes.
735 context: Blender bpy.context instance.
741 pg
= context
.scene
.pdt_pg
746 class PDT_OT_Taper(Operator
):
747 """Taper Vertices at Angle in Chosen Axis Mode"""
749 bl_idname
= "pdt.taper"
751 bl_options
= {"REGISTER", "UNDO"}
754 def poll(cls
, context
):
758 return all([bool(ob
), ob
.type == "MESH", ob
.mode
== "EDIT"])
760 def execute(self
, context
):
761 """Taper Geometry along World Axes.
764 Similar to Blender Shear command except that it shears by angle rather than displacement.
765 Rotates about World Axes and displaces along World Axes, angle must not exceed +-80 degrees.
766 Rotation axis is centred on Active Vertex.
767 Works only in Edit mode.
770 context: Blender bpy.context instance.
773 Uses pg.taper & pg.angle scene variables
779 pg
= context
.scene
.pdt_pg
783 #class PDT_Extrude_Modal(Operator):
784 # """Extrude Modal Plane Along Normal Axis"""
785 # bl_idname = "pdt.extrude_modal"
786 # bl_label = "Extrude Modal Normal"
787 # bl_options = {"REGISTER", "UNDO"}