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
8 from math
import sqrt
, floor
, asin
, sin
, cos
, pi
9 from mathutils
import Vector
10 from bpy
.types
import Operator
12 from .pdt_functions
import (
20 from .pdt_msg_strings
import (
31 from . import pdt_exception
33 PDT_ObjectModeError
= pdt_exception
.ObjectModeError
34 PDT_SelectionError
= pdt_exception
.SelectionError
37 def get_tangent_intersect_outer(hloc_0
, vloc_0
, hloc_1
, vloc_1
, radius_0
, radius_1
):
38 """Return Location in 2 Dimensions of the Intersect Point for Outer Tangents.
41 hloc_0: Horizontal Coordinate of Centre of First Arc
42 vloc_0: Vertical Coordinate of Centre of First Arc
43 hloc_1: Horizontal Coordinate of Centre of Second Arc
44 vloc_1: Vertical Coordinate of Centre of Second Arc
45 radius_0: Radius of First Arc
46 radius_1: Radius of Second Arc
49 hloc_p: Horizontal Coordinate of Centre of Intersection
50 vloc_p: Vertical Coordinate of Centre of Intersection.
53 hloc_p
= ((hloc_1
* radius_0
) - (hloc_0
* radius_1
)) / (radius_0
- radius_1
)
54 vloc_p
= ((vloc_1
* radius_0
) - (vloc_0
* radius_1
)) / (radius_0
- radius_1
)
59 def get_tangent_intersect_inner(hloc_0
, vloc_0
, hloc_1
, vloc_1
, radius_0
, radius_1
):
60 """Return Location in 2 Dimensions of the Intersect Point for Inner Tangents.
63 hloc_0: Horizontal Coordinate of Centre of First Arc
64 vloc_0: Vertical Coordinate of Centre of First Arc
65 hloc_1: Horizontal Coordinate of Centre of Second Arc
66 vloc_1: Vertical Coordinate of Centre of Second Arc
67 radius_0: Radius of First Arc
68 radius_1: Radius of Second Arc
71 hloc_p: Horizontal Coordinate of Centre of Intersection
72 vloc_p: Vertical Coordinate of Centre of Intersection.
75 hloc_p
= ((hloc_1
* radius_0
) + (hloc_0
* radius_1
)) / (radius_0
+ radius_1
)
76 vloc_p
= ((vloc_1
* radius_0
) + (vloc_0
* radius_1
)) / (radius_0
+ radius_1
)
81 def get_tangent_points(context
, hloc_0
, vloc_0
, radius_0
, hloc_p
, vloc_p
):
82 """Return Location in 2 Dimensions of the Tangent Points.
85 context: Blender bpy.context instance
86 hloc_0: Horizontal Coordinate of Centre of First Arc
87 vloc_0: Vertical Coordinate of Centre of First Arc
88 radius_0: Radius of First Arc
89 hloc_p: Horizontal Coordinate of Intersection
90 vloc_p: Vertical Coordinate of Intersection
93 hloc_t1: Horizontal Location of First Tangent Point
94 hloc_t2: Horizontal Location of Second Tangent Point
95 vloc_t1: Vertical Location of First Tangent Point
96 vloc_t2: Vertical Location of Second Tangent Point
99 # Uses basic Pythagorus' theorem to compute locations
101 numerator
= (radius_0
** 2 * (hloc_p
- hloc_0
)) + (
104 * sqrt((hloc_p
- hloc_0
) ** 2 + (vloc_p
- vloc_0
) ** 2 - radius_0
** 2)
106 denominator
= (hloc_p
- hloc_0
) ** 2 + (vloc_p
- vloc_0
) ** 2
107 hloc_t1
= round((numerator
/ denominator
) + hloc_0
, 5)
109 numerator
= (radius_0
** 2 * (hloc_p
- hloc_0
)) - (
112 * sqrt((hloc_p
- hloc_0
) ** 2 + (vloc_p
- vloc_0
) ** 2 - radius_0
** 2)
114 denominator
= (hloc_p
- hloc_0
) ** 2 + (vloc_p
- vloc_0
) ** 2
115 hloc_t2
= round((numerator
/ denominator
) + hloc_0
, 5)
118 numerator
= (radius_0
** 2 * (vloc_p
- vloc_0
)) - (
121 * sqrt((hloc_p
- hloc_0
) ** 2 + (vloc_p
- vloc_0
) ** 2 - radius_0
** 2)
123 denominator
= (hloc_p
- hloc_0
) ** 2 + (vloc_p
- vloc_0
) ** 2
124 vloc_t1
= round((numerator
/ denominator
) + vloc_0
, 5)
126 numerator
= (radius_0
** 2 * (vloc_p
- vloc_0
)) + (
129 * sqrt((hloc_p
- hloc_0
) ** 2 + (vloc_p
- vloc_0
) ** 2 - radius_0
** 2)
131 denominator
= (hloc_p
- hloc_0
) ** 2 + (vloc_p
- vloc_0
) ** 2
132 vloc_t2
= round((numerator
/ denominator
) + vloc_0
, 5)
134 return hloc_t1
, hloc_t2
, vloc_t1
, vloc_t2
137 def make_vectors(coords
, a1
, a2
, a3
, pg
):
138 """Return Vectors of the Tangent Points.
141 coords: A List of Coordinates in 2D space of the tangent points
142 & a third dimension for the vectors
143 a1: Index of horizontal axis
144 a2: Index of vertical axis
145 a3: Index of depth axis
146 pg: PDT Parameters Group - our variables
149 tangent_vector_o1: Location of First Tangent Point
150 tangent_vector_o2: Location of Second Tangent Point
151 tangent_vector_o3: Location of First Tangent Point
152 tangent_vector_o4: Location of Second Tangent Point
155 tangent_vector_o1
= Vector((0, 0, 0))
156 tangent_vector_o1
[a1
] = coords
[0]
157 tangent_vector_o1
[a2
] = coords
[1]
158 tangent_vector_o1
[a3
] = coords
[8]
159 tangent_vector_o2
= Vector((0, 0, 0))
160 tangent_vector_o2
[a1
] = coords
[2]
161 tangent_vector_o2
[a2
] = coords
[3]
162 tangent_vector_o2
[a3
] = coords
[8]
163 tangent_vector_o3
= Vector((0, 0, 0))
164 tangent_vector_o3
[a1
] = coords
[4]
165 tangent_vector_o3
[a2
] = coords
[5]
166 tangent_vector_o3
[a3
] = coords
[8]
167 tangent_vector_o4
= Vector((0, 0, 0))
168 tangent_vector_o4
[a1
] = coords
[6]
169 tangent_vector_o4
[a2
] = coords
[7]
170 tangent_vector_o4
[a3
] = coords
[8]
173 # Reset coordinates from view local (Horiz, Vert, depth) to World XYZ.
175 tangent_vector_o1
= view_coords(
176 tangent_vector_o1
[a1
], tangent_vector_o1
[a2
], tangent_vector_o1
[a3
]
178 tangent_vector_o2
= view_coords(
179 tangent_vector_o2
[a1
], tangent_vector_o2
[a2
], tangent_vector_o2
[a3
]
181 tangent_vector_o3
= view_coords(
182 tangent_vector_o3
[a1
], tangent_vector_o3
[a2
], tangent_vector_o3
[a3
]
184 tangent_vector_o4
= view_coords(
185 tangent_vector_o4
[a1
], tangent_vector_o4
[a2
], tangent_vector_o4
[a3
]
188 return (tangent_vector_o1
, tangent_vector_o2
, tangent_vector_o3
, tangent_vector_o4
)
191 def tangent_setup(context
, pg
, plane
, obj_data
, centre_0
, centre_1
, centre_2
, radius_0
, radius_1
):
192 """This section sets up all the variables required for the tangent functions.
195 context: Blender bpy.context instance
196 pg: PDT Parameter Group of variables
198 obj_data: All the data of the chosen object
199 centre_0: Centre coordinates of the first arc
200 centre_1: Centre coordinates of the second arc
201 centre_2: Coordinates of the point
202 radius_0: Radius of the first Arc
203 radius_1: Radius of the second Arc
209 a1
, a2
, a3
= set_mode(plane
)
210 mode
= pg
.tangent_mode
212 # Translate world coordinates into view local (horiz, vert, depth)
214 centre_0
= view_coords_i(centre_0
[a1
], centre_0
[a2
], centre_0
[a3
])
215 centre_1
= view_coords_i(centre_1
[a1
], centre_1
[a2
], centre_1
[a3
])
216 centre_2
= view_coords_i(centre_2
[a1
], centre_2
[a2
], centre_2
[a3
])
217 if pg
.tangent_mode
== "point":
218 vector_difference
= centre_2
- centre_0
219 distance
= sqrt(vector_difference
[a1
] ** 2 + vector_difference
[a2
] ** 2)
221 vector_difference
= centre_1
- centre_0
222 distance
= sqrt(vector_difference
[a1
] ** 2 + vector_difference
[a2
] ** 2)
225 (distance
<= radius_0
and mode
in {"point"}) or
226 (distance
<= (radius_0
+ radius_1
) and mode
in {"inner", "both"}) or
227 (distance
<= radius_0
or distance
<= radius_1
and mode
in {"outer", "both"})
229 # Cannot execute, centres are too close.
231 pg
.error
= f
"{PDT_ERR_BADDISTANCE}"
232 context
.window_manager
.popup_menu(oops
, title
="Error", icon
="ERROR")
235 """This next section will draw Point based Tangents.
237 These are drawn from a point to an Arc
242 (centre_2
[a1
] - centre_0
[a1
]) ** 2 + (centre_2
[a2
] - centre_0
[a2
]) ** 2 - radius_0
** 2
244 hloc_to1
, hloc_to2
, vloc_to1
, vloc_to2
= get_tangent_points(
245 context
, centre_0
[a1
], centre_0
[a2
], radius_0
, centre_2
[a1
], centre_2
[a2
]
248 pg
.error
= PDT_ERR_MATHSERROR
249 context
.window_manager
.popup_menu(oops
, title
="Error", icon
="ERROR")
253 tangent_vector_o1
= Vector((0, 0, 0))
254 tangent_vector_o1
[a1
] = hloc_to1
255 tangent_vector_o1
[a2
] = vloc_to1
256 tangent_vector_o1
[a3
] = centre_2
[a3
]
257 tangent_vector_o2
= Vector((0, 0, 0))
258 tangent_vector_o2
[a1
] = hloc_to2
259 tangent_vector_o2
[a2
] = vloc_to2
260 tangent_vector_o2
[a3
] = centre_2
[a3
]
262 # Translate view local coordinates (horiz, vert, depth) into World XYZ
264 centre_2
= view_coords(centre_2
[a1
], centre_2
[a2
], centre_2
[a3
])
265 tangent_vector_o1
= view_coords(
266 tangent_vector_o1
[a1
], tangent_vector_o1
[a2
], tangent_vector_o1
[a3
]
268 tangent_vector_o2
= view_coords(
269 tangent_vector_o2
[a1
], tangent_vector_o2
[a2
], tangent_vector_o2
[a3
]
271 tangent_vectors
= (centre_2
, tangent_vector_o1
, tangent_vector_o2
)
272 draw_tangents(tangent_vectors
, obj_data
)
276 """This next section will draw Arc based Outer Tangents.
278 These are drawn from an Arc to another Arc
281 if mode
in {"outer", "both"}:
282 # Uses basic trigonometry and Pythagorus' theorem to compute locations
284 if radius_0
== radius_1
:
285 # No intersection point for outer tangents
287 sin_angle
= (centre_1
[a2
] - centre_0
[a2
]) / distance
288 cos_angle
= (centre_1
[a1
] - centre_0
[a1
]) / distance
289 hloc_to1
= centre_0
[a1
] + (radius_0
* sin_angle
)
290 hloc_to2
= centre_0
[a1
] - (radius_0
* sin_angle
)
291 hloc_to3
= centre_1
[a1
] + (radius_0
* sin_angle
)
292 hloc_to4
= centre_1
[a1
] - (radius_0
* sin_angle
)
293 vloc_to1
= centre_0
[a2
] - (radius_0
* cos_angle
)
294 vloc_to2
= centre_0
[a2
] + (radius_0
* cos_angle
)
295 vloc_to3
= centre_1
[a2
] - (radius_0
* cos_angle
)
296 vloc_to4
= centre_1
[a2
] + (radius_0
* cos_angle
)
298 hloc_po
, vloc_po
= get_tangent_intersect_outer(
299 centre_0
[a1
], centre_0
[a2
], centre_1
[a1
], centre_1
[a2
], radius_0
, radius_1
302 if ((hloc_po
- centre_0
[a1
]) ** 2 + (vloc_po
- centre_0
[a2
]) ** 2 - radius_0
** 2) > 0:
303 hloc_to1
, hloc_to2
, vloc_to1
, vloc_to2
= get_tangent_points(
304 context
, centre_0
[a1
], centre_0
[a2
], radius_0
, hloc_po
, vloc_po
307 pg
.error
= PDT_ERR_MATHSERROR
308 context
.window_manager
.popup_menu(oops
, title
="Error", icon
="ERROR")
310 if ((hloc_po
- centre_0
[a1
]) ** 2 + (vloc_po
- centre_0
[a2
]) ** 2 - radius_1
** 2) > 0:
311 hloc_to3
, hloc_to4
, vloc_to3
, vloc_to4
= get_tangent_points(
312 context
, centre_1
[a1
], centre_1
[a2
], radius_1
, hloc_po
, vloc_po
315 pg
.error
= PDT_ERR_MATHSERROR
316 context
.window_manager
.popup_menu(oops
, title
="Error", icon
="ERROR")
319 dloc_p
= centre_0
[a3
]
331 tangent_vectors
= make_vectors(coords_in
, a1
, a2
, a3
, pg
)
332 draw_tangents(tangent_vectors
, obj_data
)
334 """This next section will draw Arc based Inner Tangents.
336 These are drawn from an Arc to another Arc
339 if mode
in {"inner", "both"}:
340 # Uses basic trigonometry and Pythagorus' theorem to compute locations
342 hloc_pi
, vloc_pi
= get_tangent_intersect_inner(
343 centre_0
[a1
], centre_0
[a2
], centre_1
[a1
], centre_1
[a2
], radius_0
, radius_1
345 if ((hloc_pi
- centre_0
[a1
]) ** 2 + (vloc_pi
- centre_0
[a2
]) ** 2 - radius_0
** 2) > 0:
346 hloc_to1
, hloc_to2
, vloc_to1
, vloc_to2
= get_tangent_points(
347 context
, centre_0
[a1
], centre_0
[a2
], radius_0
, hloc_pi
, vloc_pi
350 pg
.error
= PDT_ERR_MATHSERROR
351 context
.window_manager
.popup_menu(oops
, title
="Error", icon
="ERROR")
353 if ((hloc_pi
- centre_0
[a1
]) ** 2 + (vloc_pi
- centre_0
[a2
]) ** 2 - radius_0
** 2) > 0:
354 hloc_to3
, hloc_to4
, vloc_to3
, vloc_to4
= get_tangent_points(
355 context
, centre_1
[a1
], centre_1
[a2
], radius_1
, hloc_pi
, vloc_pi
358 pg
.error
= PDT_ERR_MATHSERROR
359 context
.window_manager
.popup_menu(oops
, title
="Error", icon
="ERROR")
362 dloc_p
= centre_0
[a3
]
374 tangent_vectors
= make_vectors(coords_in
, a1
, a2
, a3
, pg
)
375 draw_tangents(tangent_vectors
, obj_data
)
380 def draw_tangents(tangent_vectors
, obj_data
):
381 """Add Edges Representing the Tangents.
384 The length of the tanget_vectors determines which tangents will be
385 drawn, 3 gives Point Tangents, 4 gives Inner/Outer tangents
388 tangent_vectors: A list of vectors representing the tangents
389 obj_data: A list giving Object, Object Location and Object Bmesh
395 obj_loc
= obj_data
[1]
397 if len(tangent_vectors
) == 3:
398 point_vertex_outer
= bm
.verts
.new(tangent_vectors
[0] - obj_loc
)
399 tangent_vertex_o1
= bm
.verts
.new(tangent_vectors
[1] - obj_loc
)
400 tangent_vertex_o2
= bm
.verts
.new(tangent_vectors
[2] - obj_loc
)
401 bm
.edges
.new([tangent_vertex_o1
, point_vertex_outer
])
402 bm
.edges
.new([tangent_vertex_o2
, point_vertex_outer
])
404 tangent_vertex_o1
= bm
.verts
.new(tangent_vectors
[0] - obj_loc
)
405 tangent_vertex_o2
= bm
.verts
.new(tangent_vectors
[2] - obj_loc
)
406 tangent_vertex_o3
= bm
.verts
.new(tangent_vectors
[1] - obj_loc
)
407 tangent_vertex_o4
= bm
.verts
.new(tangent_vectors
[3] - obj_loc
)
408 bm
.edges
.new([tangent_vertex_o1
, tangent_vertex_o2
])
409 bm
.edges
.new([tangent_vertex_o3
, tangent_vertex_o4
])
410 bmesh
.update_edit_mesh(obj
.data
)
413 def analyse_arc(context
, pg
):
414 """Analyses an Arc inferred from Selected Vertices.
417 Will work if more than 3 vertices are selected, taking the
418 first, the nearest to the middle and the last.
421 context: Blender bpy.context instance
422 pg: PDT Parameters Group - our variables
425 vector_delta: Location of Arc Centre
426 radius: Radius of Arc.
428 obj
= context
.view_layer
.objects
.active
430 pg
.error
= PDT_ERR_NO_ACT_OBJ
431 context
.window_manager
.popup_menu(oops
, title
="Error", icon
="ERROR")
432 raise PDT_ObjectModeError
433 if obj
.mode
== "EDIT":
434 obj_loc
= obj
.matrix_world
.decompose()[0]
435 bm
= bmesh
.from_edit_mesh(obj
.data
)
436 verts
= [v
for v
in bm
.verts
if v
.select
]
438 pg
.error
= f
"{PDT_ERR_SEL_3_VERTS} {len(verts)})"
439 context
.window_manager
.popup_menu(oops
, title
="Error", icon
="ERROR")
440 raise PDT_SelectionError
441 vector_a
= verts
[0].co
442 # Get the nearest to middle vertex of the arc
444 vector_b
= verts
[int(floor(len(verts
) / 2))].co
445 vector_c
= verts
[-1].co
446 vector_delta
, radius
= arc_centre(vector_a
, vector_b
, vector_c
)
448 return vector_delta
, radius
451 class PDT_OT_TangentOperate(Operator
):
452 """Calculate Tangents from Inputs."""
454 bl_idname
= "pdt.tangentoperate"
455 bl_label
= "Calculate Tangents"
456 bl_options
= {"REGISTER", "UNDO"}
457 bl_description
= "Calculate Tangents to Arcs from Points or Other Arcs"
460 def poll(cls
, context
):
464 return all([bool(ob
), ob
.type == "MESH", ob
.mode
== "EDIT"])
466 def execute(self
, context
):
467 """Calculate Tangents from Inputs.
470 Uses pg.plane, pg.tangent_point0, pg.tangent_radius0, pg.tangent_point1
471 pg.tangent_radius1, pg.tangent_point2 to place tangents.
473 Analyses distance between arc centres, or arc centre and tangent point
474 to determine which mode is possible (Inner, Outer, or Point). If centres are
475 both contained within 1 inferred circle, Inner tangents are not possible.
477 Arcs of same radius will have no intersection for outer tangents so these
478 are calculated differently.
481 context: Blender bpy.context instance.
487 scene
= context
.scene
491 obj
= context
.view_layer
.objects
.active
493 if obj
.mode
not in {"EDIT"} or obj
.type != "MESH":
494 pg
.error
= PDT_OBJ_MODE_ERROR
495 context
.window_manager
.popup_menu(oops
, title
="Error", icon
="ERROR")
498 pg
.error
= PDT_ERR_NO_ACT_OBJ
499 context
.window_manager
.popup_menu(oops
, title
="Error", icon
="ERROR")
501 bm
= bmesh
.from_edit_mesh(obj
.data
)
502 obj_loc
= obj
.matrix_world
.decompose()[0]
503 obj_data
= (obj
, obj_loc
, bm
)
505 radius_0
= pg
.tangent_radius0
506 radius_1
= pg
.tangent_radius1
507 centre_0
= pg
.tangent_point0
508 centre_1
= pg
.tangent_point1
509 centre_2
= pg
.tangent_point2
512 context
, pg
, plane
, obj_data
, centre_0
, centre_1
, centre_2
, radius_0
, radius_1
518 class PDT_OT_TangentOperateSel(Operator
):
519 """Calculate Tangents from Selection."""
521 bl_idname
= "pdt.tangentoperatesel"
522 bl_label
= "Calculate Tangents"
523 bl_options
= {"REGISTER", "UNDO"}
524 bl_description
= "Calculate Tangents to Arcs from 2 Selected Vertices, or 1 & Point in Menu"
527 def poll(cls
, context
):
531 return all([bool(ob
), ob
.type == "MESH", ob
.mode
== "EDIT"])
533 def execute(self
, context
):
534 """Calculate Tangents from Selection.
537 Uses pg.plane & 2 or more selected Vertices to place tangents.
538 One vertex must be on each arc.
540 Analyses distance between arc centres, or arc centre and tangent point
541 to determine which mode is possible (Inner, Outer, or Point). If centres are
542 both contained within 1 inferred circle, Inner tangents are not possible.
544 Arcs of same radius will have no intersection for outer tangents so these
545 are calculated differently.
548 context: Blender bpy.context instance.
554 scene
= context
.scene
558 obj
= context
.view_layer
.objects
.active
560 if obj
.mode
not in {"EDIT"} or obj
.type != "MESH":
561 pg
.error
= PDT_OBJ_MODE_ERROR
562 context
.window_manager
.popup_menu(oops
, title
="Error", icon
="ERROR")
565 pg
.error
= PDT_ERR_NO_ACT_OBJ
566 context
.window_manager
.popup_menu(oops
, title
="Error", icon
="ERROR")
568 bm
= bmesh
.from_edit_mesh(obj
.data
)
569 obj_loc
= obj
.matrix_world
.decompose()[0]
570 obj_data
= (obj
, obj_loc
, bm
)
572 # Get All Values from Selected Vertices
573 verts
= [v
for v
in bm
.verts
if v
.select
]
575 pg
.error
= f
"{PDT_ERR_SEL_1_VERT} 0"
576 context
.window_manager
.popup_menu(oops
, title
="Error", icon
="ERROR")
585 bpy
.ops
.mesh
.select_linked()
586 verts1
= [v
for v
in bm
.verts
if v
.select
].copy()
588 pg
.error
= f
"{PDT_ERR_VERT_MODE} or Less than 3 vertices in your Arc(s)"
589 context
.window_manager
.popup_menu(oops
, title
="Error", icon
="ERROR")
596 bpy
.ops
.mesh
.select_linked()
597 vertsn
= [v
for v
in bm
.verts
if v
.select
].copy()
602 bmesh
.update_edit_mesh(obj
.data
)
603 bm
.select_history
.clear()
604 # Select the nearest to middle vertex in the arc
606 verts1
= [verts1
[0].co
, verts1
[int(floor(len(verts1
) / 2))].co
, verts1
[-1].co
]
607 vertsn
= [vertsn
[0].co
, vertsn
[int(floor(len(vertsn
) / 2))].co
, vertsn
[-1].co
]
608 centre_0
, radius_0
= arc_centre(verts1
[0], verts1
[1], verts1
[2])
609 centre_1
, radius_1
= arc_centre(vertsn
[0], vertsn
[1], vertsn
[2])
610 centre_2
= pg
.tangent_point2
613 context
, pg
, plane
, obj_data
, centre_0
, centre_1
, centre_2
, radius_0
, radius_1
619 class PDT_OT_TangentSet1(Operator
):
620 """Calculates Centres & Radii from 3 Vectors."""
622 bl_idname
= "pdt.tangentset1"
623 bl_label
= "Calculate Centres & Radii"
624 bl_options
= {"REGISTER", "UNDO"}
625 bl_description
= "Calculate Centres & Radii from Selected Vertices"
628 def poll(cls
, context
):
632 return all([bool(ob
), ob
.type == "MESH", ob
.mode
== "EDIT"])
634 def execute(self
, context
):
635 """Sets Input Tangent Point 1 to analysis of Arc.
638 context: Blender bpy.context instance.
643 scene
= context
.scene
645 vector_delta
, radius
= analyse_arc(context
, pg
)
646 pg
.tangent_point0
= vector_delta
647 pg
.tangent_radius0
= radius
651 class PDT_OT_TangentSet2(Operator
):
652 """Calculates Centres & Radii from 3 Vectors."""
654 bl_idname
= "pdt.tangentset2"
655 bl_label
= "Calculate Centres & Radii"
656 bl_options
= {"REGISTER", "UNDO"}
657 bl_description
= "Calculate Centres & Radii from Selected Vertices"
660 def poll(cls
, context
):
664 return all([bool(obj
), obj
.type == "MESH", obj
.mode
== "EDIT"])
666 def execute(self
, context
):
667 """Sets Input Tangent Point 2 to analysis of Arc.
670 context: Blender bpy.context instance.
675 scene
= context
.scene
677 vector_delta
, radius
= analyse_arc(context
, pg
)
678 pg
.tangent_point1
= vector_delta
679 pg
.tangent_radius1
= radius
683 class PDT_OT_TangentSet3(Operator
):
684 """Set Tangent Origin Point from Cursor."""
686 bl_idname
= "pdt.tangentset3"
687 bl_label
= "Set Tangent Origin Point from Cursor"
688 bl_options
= {"REGISTER", "UNDO"}
689 bl_description
= "Set Tangent Origin Point from Cursor"
692 def poll(cls
, context
):
696 return all([bool(obj
), obj
.type == "MESH", obj
.mode
== "EDIT"])
698 def execute(self
, context
):
699 """Sets Input Tangent Point 3 to analysis of Arc.
702 context: Blender bpy.context instance.
707 scene
= context
.scene
709 pg
.tangent_point2
= scene
.cursor
.location
713 class PDT_OT_TangentSet4(Operator
):
714 """Set Tangent Origin Point from Cursor."""
716 bl_idname
= "pdt.tangentset4"
717 bl_label
= "Set Tangent Origin Point from Vertex"
718 bl_options
= {"REGISTER", "UNDO"}
719 bl_description
= "Set Tangent Origin Point from Vertex"
722 def poll(cls
, context
):
726 return all([bool(obj
), obj
.type == "MESH", obj
.mode
== "EDIT"])
728 def execute(self
, context
):
729 """Sets Input Tangent Point 2 to selected Vertex.
732 context: Blender bpy.context instance.
737 scene
= context
.scene
740 bm
= bmesh
.from_edit_mesh(obj
.data
)
741 verts
= [v
for v
in bm
.verts
if v
.select
]
743 pg
.error
= f
"{PDT_ERR_SEL_1_VERT} {len(verts)})"
744 context
.window_manager
.popup_menu(oops
, title
="Error", icon
="ERROR")
745 raise PDT_SelectionError
746 pg
.tangent_point2
= verts
[0].co
750 class PDT_OT_TangentExpandMenu(Operator
):
751 """Expand/Collapse Tangent Menu."""
753 bl_idname
= "pdt.tangentexpandmenu"
754 bl_label
= "Expand/Collapse Tangent Menu"
755 bl_options
= {"REGISTER", "UNDO"}
756 bl_description
= "Expand/Collapse Tangent Menu to Show/Hide Input Options"
758 def execute(self
, context
):
759 """Expand/Collapse Tangent Menu.
762 This is used to add further options to the menu.
765 context: Blender bpy.context instance.
770 scene
= context
.scene
773 pg
.menu_expand
= False
775 pg
.menu_expand
= True