License Headers: use SPDX-FileCopyrightText for mesh_tissue
[blender-addons.git] / mesh_tiny_cad / CCEN.py
blob479bd3b6a964d1725c9da3991d170263f5056946
1 # SPDX-FileCopyrightText: 2016-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
6 import math
8 import bpy
9 import bmesh
10 import mathutils
11 from mathutils import geometry
12 from mathutils import Vector
15 def generate_bmesh_repr(p1, v1, axis, num_verts):
16 '''
17 p1: center of circle (local coordinates)
18 v1: first vertex of circle in (local coordinates)
19 axis: orientation matrix
20 origin: obj.location
21 '''
22 props = bpy.context.scene.tinycad_props
23 rescale = props.rescale
25 # generate geometry up front
26 chain = []
27 gamma = 2 * math.pi / num_verts
28 for i in range(num_verts + 1):
29 theta = gamma * i
30 mat_rot = mathutils.Matrix.Rotation(theta, 4, axis)
31 local_point = (mat_rot @ ((v1 - p1) * rescale))
32 chain.append(local_point + p1)
34 obj = bpy.context.edit_object
35 me = obj.data
36 bm = bmesh.from_edit_mesh(me)
38 # add verts
39 v_refs = []
40 for p in chain:
41 v = bm.verts.new(p)
42 v.select = False # this might be a default.. redundant?
43 v_refs.append(v)
45 # join verts, daisy chain
46 num_verts = len(v_refs)
47 for i in range(num_verts):
48 idx1 = i
49 idx2 = (i + 1) % num_verts
50 bm.edges.new([v_refs[idx1], v_refs[idx2]])
52 bmesh.update_edit_mesh(me, loop_triangles=True)
55 def generate_3PT(pts, obj, nv, mode=1):
56 mw = obj.matrix_world
57 V = Vector
58 nv = max(3, nv)
60 # construction
61 v1, v2, v3, v4 = V(pts[0]), V(pts[1]), V(pts[1]), V(pts[2])
62 edge1_mid = v1.lerp(v2, 0.5)
63 edge2_mid = v3.lerp(v4, 0.5)
64 axis = geometry.normal(v1, v2, v4)
65 mat_rot = mathutils.Matrix.Rotation(math.radians(90.0), 4, axis)
67 # triangle edges
68 v1_ = ((v1 - edge1_mid) @ mat_rot) + edge1_mid
69 v2_ = ((v2 - edge1_mid) @ mat_rot) + edge1_mid
70 v3_ = ((v3 - edge2_mid) @ mat_rot) + edge2_mid
71 v4_ = ((v4 - edge2_mid) @ mat_rot) + edge2_mid
73 r = geometry.intersect_line_line(v1_, v2_, v3_, v4_)
74 if r:
75 p1, _ = r
76 cp = mw @ p1
77 bpy.context.scene.cursor.location = cp
79 if mode == 0:
80 pass
82 elif mode == 1:
83 generate_bmesh_repr(p1, v1, axis, nv)
85 else:
86 print('not on a circle')
89 def get_three_verts_from_selection(obj):
90 me = obj.data
91 bm = bmesh.from_edit_mesh(me)
93 bm.verts.ensure_lookup_table()
94 bm.edges.ensure_lookup_table()
96 return [v.co[:] for v in bm.verts if v.select]
99 def dispatch(context, mode=0):
100 try:
101 obj = context.edit_object
102 pts = get_three_verts_from_selection(obj)
103 props = context.scene.tinycad_props
104 generate_3PT(pts, obj, props.num_verts, mode)
105 except:
106 print('dispatch failed', mode)
109 class TCCallBackCCEN(bpy.types.Operator):
110 bl_idname = 'tinycad.reset_circlescale'
111 bl_label = 'CCEN circle reset'
112 bl_options = {'REGISTER'}
114 def execute(self, context):
115 context.scene.tinycad_props.rescale = 1
116 return {'FINISHED'}
119 class TCCircleCenter(bpy.types.Operator):
120 '''Recreate a Circle from 3 selected verts, move 3dcursor to its center'''
122 bl_idname = 'tinycad.circlecenter'
123 bl_label = 'CCEN circle center from selected'
124 bl_options = {'REGISTER', 'UNDO'}
126 def draw(self, context):
127 scn = context.scene
128 l = self.layout
129 col = l.column()
131 col.prop(scn.tinycad_props, 'num_verts', text='num verts')
132 row = col.row(align=True)
133 row.prop(scn.tinycad_props, 'rescale', text='rescale')
134 row.operator('tinycad.reset_circlescale', text="", icon="PIVOT_CURSOR")
136 @classmethod
137 def poll(cls, context):
138 obj = context.edit_object
139 return obj is not None and obj.type == 'MESH'
141 def execute(self, context):
142 dispatch(context, mode=1)
143 return {'FINISHED'}