Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import bpy
import sys
import bmesh
from mathutils import Vector
from mathutils.geometry import intersect_line_line as LineIntersect
from mathutils.geometry import intersect_point_line as PtLineIntersect
from mesh_tinyCAD import cad_module as cm
def getVTX(self):
self.idx1, self.idx2 = self.selected_edges
self.edge1 = cm.coords_tuple_from_edge_idx(self.bm, self.idx1)
self.edge2 = cm.coords_tuple_from_edge_idx(self.bm, self.idx2)
self.point = cm.get_intersection(self.edge1, self.edge2)
self.edges = cm.find_intersecting_edges(
self.bm, self.point, self.idx1, self.idx2)
def add_edges(self, idxs):
for e in idxs:
v1 = self.bm.verts[-1]
v2 = self.bm.verts[e]
self.bm.edges.new((v1, v2))
def remove_earmarked_edges(self, earmarked):
edges_select = [e for e in self.bm.edges if e.index in earmarked]
bmesh.ops.delete(self.bm, geom=edges_select, context=2)
def checkVTX(self, context):
'''
- decides VTX automatically.
- remembers edges attached to current selection, for later.
'''
# [x] if either of these edges share a vertex, return early.
indices = cm.vertex_indices_from_edges_tuple(self.bm, self.selected_edges)
if cm.duplicates(indices):
msg = "edges share a vertex, degenerate case, returning early"
self.report({"WARNING"}, msg)
return False
# [x] find which edges intersect
getVTX(self)
# [x] check coplanar, or parallel.
if [] == self.edges:
coplanar = cm.test_coplanar(self.edge1, self.edge2)
if not coplanar:
msg = "parallel or not coplanar! returning early"
self.report({"WARNING"}, msg)
return False
return True
def doVTX(self):
'''
At this point we know that there is an intersection, and if it
is V, T or X.
- If both are None, then both edges are projected towards point. (V)
- If only one is None, then it's a projection onto a real edge (T)
- Else, then the intersection lies on both edges (X)
'''
print('point:', self.point)
print('edges selected:', self.idx1, self.idx2)
print('edges to use:', self.edges)
self.bm.verts.new((self.point))
earmarked = self.edges
pt = self.point
# V (projection of both edges)
if [] == earmarked:
cl_vert1 = cm.closest_idx(pt, self.bm.edges[self.idx1])
cl_vert2 = cm.closest_idx(pt, self.bm.edges[self.idx2])
add_edges(self, [cl_vert1, cl_vert2])
# X (weld intersection)
elif len(earmarked) == 2:
vector_indices = cm.vertex_indices_from_edges_tuple(self.bm, earmarked)
add_edges(self, vector_indices)
# T (extend towards)
else:
to_edge_idx = self.edges[0]
from_edge_idx = self.idx1 if to_edge_idx == self.idx2 else self.idx2
# make 3 new edges: 2 on the towards, 1 as extender
cl_vert = cm.closest_idx(pt, self.bm.edges[from_edge_idx])
to_vert1, to_vert2 = cm.vert_idxs_from_edge_idx(self.bm, to_edge_idx)
roto_indices = [cl_vert, to_vert1, to_vert2]
add_edges(self, roto_indices)
# final refresh before returning to user.
if earmarked:
remove_earmarked_edges(self, earmarked)
bmesh.update_edit_mesh(self.me, True)
class AutoVTX(bpy.types.Operator):
bl_idname = 'view3d.autovtx'
bl_label = 'autoVTX'
# bl_options = {'REGISTER', 'UNDO'}
VTX_PRECISION = 1.0e-5 # or 1.0e-6 ..if you need
@classmethod
def poll(self, context):
'''
- only activate if two selected edges
- and both are not hidden
'''
obj = context.active_object
self.me = obj.data
self.bm = bmesh.from_edit_mesh(self.me)
self.me.update()
if obj is not None and obj.type == 'MESH':
edges = self.bm.edges
ok = lambda v: v.select and not v.hide
idxs = [v.index for v in edges if ok(v)]
if len(idxs) is 2:
self.selected_edges = idxs
return True
def execute(self, context):
if checkVTX(self, context):
doVTX(self)
return {'FINISHED'}