1 # SPDX-License-Identifier: GPL-2.0-or-later
3 # -----------------------------------------------------------------------
4 # Author: Alan Odom (Clockmender), Rune Morling (ermo) Copyright (c) 2019
5 # -----------------------------------------------------------------------
9 from bpy
.types
import Operator
, SpaceView3D
10 from mathutils
import Vector
, Matrix
12 from .pdt_functions
import view_coords
, draw_callback_3d
13 from .pdt_msg_strings
import (
23 class PDT_OT_ModalDrawOperator(bpy
.types
.Operator
):
24 """Show/Hide Pivot Point"""
26 bl_idname
= "pdt.modaldraw"
27 bl_label
= "PDT Modal Draw"
28 bl_options
= {"REGISTER", "UNDO"}
30 _handle
= None # keep function handler
33 def handle_add(self
, context
):
34 """Draw Pivot Point Graphic if not displayed.
37 Draws 7 element Pivot Point Graphic
40 context: Blender bpy.context instance.
46 if PDT_OT_ModalDrawOperator
._handle
is None:
47 PDT_OT_ModalDrawOperator
._handle
= SpaceView3D
.draw_handler_add(
48 draw_callback_3d
, (self
, context
), "WINDOW", "POST_VIEW"
50 context
.window_manager
.pdt_run_opengl
= True
53 def handle_remove(self
, context
):
54 """Remove Pivot Point Graphic if displayed.
57 Removes 7 element Pivot Point Graphic
60 context: Blender bpy.context instance.
66 if PDT_OT_ModalDrawOperator
._handle
is not None:
67 SpaceView3D
.draw_handler_remove(PDT_OT_ModalDrawOperator
._handle
, "WINDOW")
68 PDT_OT_ModalDrawOperator
._handle
= None
69 context
.window_manager
.pdt_run_opengl
= False
71 def execute(self
, context
):
72 """Pivot Point Show/Hide Button Function.
75 Operational execute function for Show/Hide Pivot Point function
78 context: Blender bpy.context instance.
84 if context
.area
.type == "VIEW_3D":
85 if context
.window_manager
.pdt_run_opengl
is False:
86 self
.handle_add(self
, context
)
87 context
.area
.tag_redraw()
89 self
.handle_remove(self
, context
)
90 context
.area
.tag_redraw()
94 self
.report({"ERROR"}, PDT_ERR_NO3DVIEW
)
98 class PDT_OT_ViewPlaneRotate(Operator
):
99 """Rotate Selected Vertices about Pivot Point in View Plane"""
101 bl_idname
= "pdt.viewplanerot"
102 bl_label
= "PDT View Rotate"
103 bl_options
= {"REGISTER", "UNDO"}
106 def poll(cls
, context
):
107 """Check Object Status.
110 context: Blender bpy.context instance.
119 return all([bool(obj
), obj
.type == "MESH", obj
.mode
== "EDIT"])
122 def execute(self
, context
):
123 """Rotate Selected Vertices about Pivot Point.
126 Rotates any selected vertices about the Pivot Point
127 in View Oriented coordinates, works in any view orientation.
130 context: Blender bpy.context instance.
133 Uses pg.pivot_loc, pg.pivot_ang scene variables
139 scene
= context
.scene
141 obj
= bpy
.context
.view_layer
.objects
.active
143 self
.report({"ERROR"}, PDT_ERR_NO_ACT_OBJ
)
145 if obj
.mode
!= "EDIT":
146 error_message
= f
"{PDT_ERR_EDIT_MODE} {obj.mode})"
147 self
.report({"ERROR"}, error_message
)
149 bm
= bmesh
.from_edit_mesh(obj
.data
)
150 v1
= Vector((0, 0, 0))
151 v2
= view_coords(0, 0, 1)
152 axis
= (v2
- v1
).normalized()
153 rot
= Matrix
.Rotation((pg
.pivot_ang
* pi
/ 180), 4, axis
)
154 verts
= verts
= [v
for v
in bm
.verts
if v
.select
]
156 bm
, cent
=pg
.pivot_loc
- obj
.matrix_world
.decompose()[0], matrix
=rot
, verts
=verts
158 bmesh
.update_edit_mesh(obj
.data
)
162 class PDT_OT_ViewPlaneScale(Operator
):
163 """Scale Selected Vertices about Pivot Point"""
165 bl_idname
= "pdt.viewscale"
166 bl_label
= "PDT View Scale"
167 bl_options
= {"REGISTER", "UNDO"}
170 def poll(cls
, context
):
171 """Check Object Status.
174 context: Blender bpy.context instance.
183 return all([bool(obj
), obj
.type == "MESH", obj
.mode
== "EDIT"])
186 def execute(self
, context
):
187 """Scales Selected Vertices about Pivot Point.
190 Scales any selected vertices about the Pivot Point
191 in View Oriented coordinates, works in any view orientation
194 context: Blender bpy.context instance.
197 Uses pg.pivot_loc, pg.pivot_scale scene variables
203 scene
= context
.scene
205 obj
= bpy
.context
.view_layer
.objects
.active
207 self
.report({"ERROR"}, PDT_ERR_NO_ACT_OBJ
)
209 if obj
.mode
!= "EDIT":
210 error_message
= f
"{PDT_ERR_EDIT_MODE} {obj.mode})"
211 self
.report({"ERROR"}, error_message
)
213 bm
= bmesh
.from_edit_mesh(obj
.data
)
214 verts
= verts
= [v
for v
in bm
.verts
if v
.select
]
216 delta_x
= (pg
.pivot_loc
.x
- obj
.matrix_world
.decompose()[0].x
- v
.co
.x
) * (
219 delta_y
= (pg
.pivot_loc
.y
- obj
.matrix_world
.decompose()[0].y
- v
.co
.y
) * (
222 delta_z
= (pg
.pivot_loc
.z
- obj
.matrix_world
.decompose()[0].z
- v
.co
.z
) * (
225 delta_v
= Vector((delta_x
, delta_y
, delta_z
))
226 v
.co
= v
.co
+ delta_v
227 bmesh
.update_edit_mesh(obj
.data
)
231 class PDT_OT_PivotToCursor(Operator
):
232 """Set The Pivot Point to Cursor Location"""
234 bl_idname
= "pdt.pivotcursor"
235 bl_label
= "PDT Pivot To Cursor"
236 bl_options
= {"REGISTER", "UNDO"}
238 def execute(self
, context
):
239 """Moves Pivot Point to Cursor Location.
242 Moves Pivot Point to Cursor Location in active scene
245 context: Blender bpy.context instance.
251 scene
= context
.scene
253 old_cursor_loc
= scene
.cursor
.location
.copy()
254 pg
.pivot_loc
= scene
.cursor
.location
255 scene
.cursor
.location
= old_cursor_loc
259 class PDT_OT_CursorToPivot(Operator
):
260 """Set The Cursor Location to Pivot Point"""
262 bl_idname
= "pdt.cursorpivot"
263 bl_label
= "PDT Cursor To Pivot"
264 bl_options
= {"REGISTER", "UNDO"}
266 def execute(self
, context
):
267 """Moves Cursor to Pivot Point Location.
270 Moves Cursor to Pivot Point Location in active scene
273 context: Blender bpy.context instance.
279 scene
= context
.scene
281 scene
.cursor
.location
= pg
.pivot_loc
285 class PDT_OT_PivotSelected(Operator
):
286 """Set Pivot Point to Selected Geometry"""
288 bl_idname
= "pdt.pivotselected"
289 bl_label
= "PDT Pivot to Selected"
290 bl_options
= {"REGISTER", "UNDO"}
293 def poll(cls
, context
):
294 """Check Object Status.
297 context: Blender bpy.context instance.
306 return all([bool(obj
), obj
.type == "MESH", obj
.mode
== "EDIT"])
309 def execute(self
, context
):
310 """Moves Pivot Point centroid of Selected Geometry.
313 Moves Pivot Point centroid of Selected Geometry in active scene
314 using Snap_Cursor_To_Selected, then puts cursor back to original location.
317 context: Blender bpy.context instance.
323 scene
= context
.scene
325 obj
= bpy
.context
.view_layer
.objects
.active
327 self
.report({"ERROR"}, PDT_ERR_NO_ACT_OBJ
)
329 if obj
.mode
!= "EDIT":
330 error_message
= f
"{PDT_ERR_EDIT_MODE} {obj.mode})"
331 self
.report({"ERROR"}, error_message
)
333 bm
= bmesh
.from_edit_mesh(obj
.data
)
334 verts
= verts
= [v
for v
in bm
.verts
if v
.select
]
336 old_cursor_loc
= scene
.cursor
.location
.copy()
337 bpy
.ops
.view3d
.snap_cursor_to_selected()
338 pg
.pivot_loc
= scene
.cursor
.location
339 scene
.cursor
.location
= old_cursor_loc
342 self
.report({"ERROR"}, PDT_ERR_NO_SEL_GEOM
)
346 class PDT_OT_PivotOrigin(Operator
):
347 """Set Pivot Point at Object Origin"""
349 bl_idname
= "pdt.pivotorigin"
350 bl_label
= "PDT Pivot to Object Origin"
351 bl_options
= {"REGISTER", "UNDO"}
354 def poll(cls
, context
):
355 """Check Object Status.
358 context: Blender bpy.context instance.
367 return all([bool(obj
), obj
.type == "MESH"])
369 def execute(self
, context
):
370 """Moves Pivot Point to Object Origin.
373 Moves Pivot Point to Object Origin in active scene
376 context: Blender bpy.context instance.
382 scene
= context
.scene
384 obj
= bpy
.context
.view_layer
.objects
.active
386 self
.report({"ERROR"}, PDT_ERR_NO_ACT_OBJ
)
388 old_cursor_loc
= scene
.cursor
.location
.copy()
389 obj_loc
= obj
.matrix_world
.decompose()[0]
390 pg
.pivot_loc
= obj_loc
391 scene
.cursor
.location
= old_cursor_loc
395 class PDT_OT_PivotWrite(Operator
):
396 """Write Pivot Point Location to Object"""
398 bl_idname
= "pdt.pivotwrite"
399 bl_label
= "PDT Write PP to Object?"
400 bl_options
= {"REGISTER", "UNDO"}
403 def poll(cls
, context
):
404 """Check Object Status.
407 context: Blender bpy.context instance.
416 return all([bool(obj
), obj
.type == "MESH"])
418 def execute(self
, context
):
419 """Writes Pivot Point Location to Object's Custom Properties.
422 Writes Pivot Point Location to Object's Custom Properties
423 as Vector to 'PDT_PP_LOC' - Requires Confirmation through dialogue
426 context: Blender bpy.context instance.
429 Uses pg.pivot_loc scene variable
435 scene
= context
.scene
437 obj
= bpy
.context
.view_layer
.objects
.active
439 self
.report({"ERROR"}, PDT_ERR_NO_ACT_OBJ
)
441 obj
["PDT_PP_LOC"] = pg
.pivot_loc
444 def invoke(self
, context
, event
):
445 return context
.window_manager
.invoke_props_dialog(self
)
447 def draw(self
, context
):
449 row
.label(text
=PDT_CON_AREYOURSURE
)
452 class PDT_OT_PivotRead(Operator
):
453 """Read Pivot Point Location from Object"""
455 bl_idname
= "pdt.pivotread"
456 bl_label
= "PDT Read PP"
457 bl_options
= {"REGISTER", "UNDO"}
460 def poll(cls
, context
):
461 """Check Object Status.
464 context: Blender bpy.context instance.
473 return all([bool(obj
), obj
.type == "MESH"])
475 def execute(self
, context
):
476 """Reads Pivot Point Location from Object's Custom Properties.
479 Sets Pivot Point Location from Object's Custom Properties
483 context: Blender bpy.context instance.
486 Uses pg.pivot_loc scene variable
492 scene
= context
.scene
494 obj
= bpy
.context
.view_layer
.objects
.active
496 self
.report({"ERROR"}, PDT_ERR_NO_ACT_OBJ
)
498 if "PDT_PP_LOC" in obj
:
499 pg
.pivot_loc
= obj
["PDT_PP_LOC"]
502 self
.report({"ERROR"}, PDT_ERR_NOPPLOC
)