io_mesh_uv_layout: lazy import exporter modules
[blender-addons.git] / mesh_tiny_cad / cad_module.py
blob575a6896f31ed80333178383f93d325124d6afba
1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
19 # <pep8 compliant>
22 import bmesh
24 from mathutils import Vector, geometry
25 from mathutils.geometry import intersect_line_line as LineIntersect
26 from mathutils.geometry import intersect_point_line as PtLineIntersect
29 class CAD_prefs:
30 VTX_PRECISION = 1.0e-5
31 VTX_DOUBLES_THRSHLD = 0.0001
34 def point_on_edge(p, edge):
35 '''
36 > p: vector
37 > edge: tuple of 2 vectors
38 < returns: True / False if a point happens to lie on an edge
39 '''
40 pt, _percent = PtLineIntersect(p, *edge)
41 on_line = (pt - p).length < CAD_prefs.VTX_PRECISION
42 return on_line and (0.0 <= _percent <= 1.0)
45 def line_from_edge_intersect(edge1, edge2):
46 '''
47 > takes 2 tuples, each tuple contains 2 vectors
48 - prepares input for sending to intersect_line_line
49 < returns output of intersect_line_line
50 '''
51 [p1, p2], [p3, p4] = edge1, edge2
52 return LineIntersect(p1, p2, p3, p4)
55 def get_intersection(edge1, edge2):
56 '''
57 > takes 2 tuples, each tuple contains 2 vectors
58 < returns the point halfway on line. See intersect_line_line
59 '''
60 line = line_from_edge_intersect(edge1, edge2)
61 if line:
62 return (line[0] + line[1]) / 2
65 def test_coplanar(edge1, edge2):
66 '''
67 the line that describes the shortest line between the two edges
68 would be short if the lines intersect mathematically. If this
69 line is longer than the VTX_PRECISION then they are either
70 coplanar or parallel.
71 '''
72 line = line_from_edge_intersect(edge1, edge2)
73 if line:
74 return (line[0] - line[1]).length < CAD_prefs.VTX_PRECISION
77 def closest_idx(pt, e):
78 '''
79 > pt: vector
80 > e: bmesh edge
81 < returns: returns index of vertex closest to pt.
83 if both points in e are equally far from pt, then v1 is returned.
84 '''
85 if isinstance(e, bmesh.types.BMEdge):
86 ev = e.verts
87 v1 = ev[0].co
88 v2 = ev[1].co
89 distance_test = (v1 - pt).length <= (v2 - pt).length
90 return ev[0].index if distance_test else ev[1].index
92 print("received {0}, check expected input in docstring ".format(e))
95 def closest_vector(pt, e):
96 '''
97 > pt: vector
98 > e: 2 vector tuple
99 < returns:
100 pt, 2 vector tuple: returns closest vector to pt
102 if both points in e are equally far from pt, then v1 is returned.
104 if isinstance(e, tuple) and all([isinstance(co, Vector) for co in e]):
105 v1, v2 = e
106 distance_test = (v1 - pt).length <= (v2 - pt).length
107 return v1 if distance_test else v2
109 print("received {0}, check expected input in docstring ".format(e))
112 def coords_tuple_from_edge_idx(bm, idx):
113 ''' bm is a bmesh representation '''
114 return tuple(v.co for v in bm.edges[idx].verts)
117 def vectors_from_indices(bm, raw_vert_indices):
118 ''' bm is a bmesh representation '''
119 return [bm.verts[i].co for i in raw_vert_indices]
122 def vertex_indices_from_edges_tuple(bm, edge_tuple):
124 > bm: is a bmesh representation
125 > edge_tuple: contains two edge indices.
126 < returns the vertex indices of edge_tuple
128 def k(v, w):
129 return bm.edges[edge_tuple[v]].verts[w].index
131 return [k(i >> 1, i % 2) for i in range(4)]
134 def get_vert_indices_from_bmedges(edges):
136 > bmedges: a list of two bm edges
137 < returns the vertex indices of edge_tuple as a flat list.
139 temp_edges = []
140 print(edges)
141 for e in edges:
142 for v in e.verts:
143 temp_edges.append(v.index)
144 return temp_edges
147 def num_edges_point_lies_on(pt, edges):
148 ''' returns the number of edges that a point lies on. '''
149 res = [point_on_edge(pt, edge) for edge in [edges[:2], edges[2:]]]
150 return len([i for i in res if i])
153 def find_intersecting_edges(bm, pt, idx1, idx2):
155 > pt: Vector
156 > idx1, ix2: edge indices
157 < returns the list of edge indices where pt is on those edges
159 if not pt:
160 return []
161 idxs = [idx1, idx2]
162 edges = [coords_tuple_from_edge_idx(bm, idx) for idx in idxs]
163 return [idx for edge, idx in zip(edges, idxs) if point_on_edge(pt, edge)]
166 def duplicates(indices):
167 return len(set(indices)) < 4
170 def vert_idxs_from_edge_idx(bm, idx):
171 edge = bm.edges[idx]
172 return edge.verts[0].index, edge.verts[1].index