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