Remove deprecated 2D_/3D_ prefix
[blender-addons.git] / mesh_tiny_cad / CCEN.py
blobc1217f6576a6a5b77e0242b287cc2e2a75611cfc
1 # SPDX-License-Identifier: GPL-2.0-or-later
4 import math
6 import bpy
7 import bmesh
8 import mathutils
9 from mathutils import geometry
10 from mathutils import Vector
13 def generate_bmesh_repr(p1, v1, axis, num_verts):
14 '''
15 p1: center of circle (local coordinates)
16 v1: first vertex of circle in (local coordinates)
17 axis: orientation matrix
18 origin: obj.location
19 '''
20 props = bpy.context.scene.tinycad_props
21 rescale = props.rescale
23 # generate geometry up front
24 chain = []
25 gamma = 2 * math.pi / num_verts
26 for i in range(num_verts + 1):
27 theta = gamma * i
28 mat_rot = mathutils.Matrix.Rotation(theta, 4, axis)
29 local_point = (mat_rot @ ((v1 - p1) * rescale))
30 chain.append(local_point + p1)
32 obj = bpy.context.edit_object
33 me = obj.data
34 bm = bmesh.from_edit_mesh(me)
36 # add verts
37 v_refs = []
38 for p in chain:
39 v = bm.verts.new(p)
40 v.select = False # this might be a default.. redundant?
41 v_refs.append(v)
43 # join verts, daisy chain
44 num_verts = len(v_refs)
45 for i in range(num_verts):
46 idx1 = i
47 idx2 = (i + 1) % num_verts
48 bm.edges.new([v_refs[idx1], v_refs[idx2]])
50 bmesh.update_edit_mesh(me, loop_triangles=True)
53 def generate_3PT(pts, obj, nv, mode=1):
54 mw = obj.matrix_world
55 V = Vector
56 nv = max(3, nv)
58 # construction
59 v1, v2, v3, v4 = V(pts[0]), V(pts[1]), V(pts[1]), V(pts[2])
60 edge1_mid = v1.lerp(v2, 0.5)
61 edge2_mid = v3.lerp(v4, 0.5)
62 axis = geometry.normal(v1, v2, v4)
63 mat_rot = mathutils.Matrix.Rotation(math.radians(90.0), 4, axis)
65 # triangle edges
66 v1_ = ((v1 - edge1_mid) @ mat_rot) + edge1_mid
67 v2_ = ((v2 - edge1_mid) @ mat_rot) + edge1_mid
68 v3_ = ((v3 - edge2_mid) @ mat_rot) + edge2_mid
69 v4_ = ((v4 - edge2_mid) @ mat_rot) + edge2_mid
71 r = geometry.intersect_line_line(v1_, v2_, v3_, v4_)
72 if r:
73 p1, _ = r
74 cp = mw @ p1
75 bpy.context.scene.cursor.location = cp
77 if mode == 0:
78 pass
80 elif mode == 1:
81 generate_bmesh_repr(p1, v1, axis, nv)
83 else:
84 print('not on a circle')
87 def get_three_verts_from_selection(obj):
88 me = obj.data
89 bm = bmesh.from_edit_mesh(me)
91 bm.verts.ensure_lookup_table()
92 bm.edges.ensure_lookup_table()
94 return [v.co[:] for v in bm.verts if v.select]
97 def dispatch(context, mode=0):
98 try:
99 obj = context.edit_object
100 pts = get_three_verts_from_selection(obj)
101 props = context.scene.tinycad_props
102 generate_3PT(pts, obj, props.num_verts, mode)
103 except:
104 print('dispatch failed', mode)
107 class TCCallBackCCEN(bpy.types.Operator):
108 bl_idname = 'tinycad.reset_circlescale'
109 bl_label = 'CCEN circle reset'
110 bl_options = {'REGISTER'}
112 def execute(self, context):
113 context.scene.tinycad_props.rescale = 1
114 return {'FINISHED'}
117 class TCCircleCenter(bpy.types.Operator):
118 '''Recreate a Circle from 3 selected verts, move 3dcursor to its center'''
120 bl_idname = 'tinycad.circlecenter'
121 bl_label = 'CCEN circle center from selected'
122 bl_options = {'REGISTER', 'UNDO'}
124 def draw(self, context):
125 scn = context.scene
126 l = self.layout
127 col = l.column()
129 col.prop(scn.tinycad_props, 'num_verts', text='num verts')
130 row = col.row(align=True)
131 row.prop(scn.tinycad_props, 'rescale', text='rescale')
132 row.operator('tinycad.reset_circlescale', text="", icon="PIVOT_CURSOR")
134 @classmethod
135 def poll(cls, context):
136 obj = context.edit_object
137 return obj is not None and obj.type == 'MESH'
139 def execute(self, context):
140 dispatch(context, mode=1)
141 return {'FINISHED'}