Remove deprecated 2D_/3D_ prefix
[blender-addons.git] / mesh_tiny_cad / cad_module.py
blob01e86f5734b05f23b7ae0b2b9df84fe67a248960
1 # SPDX-License-Identifier: GPL-2.0-or-later
4 import bmesh
6 from mathutils import Vector, geometry
7 from mathutils.geometry import intersect_line_line as LineIntersect
8 from mathutils.geometry import intersect_point_line as PtLineIntersect
11 class CAD_prefs:
12 VTX_PRECISION = 1.0e-5
13 VTX_DOUBLES_THRSHLD = 0.0001
16 def point_on_edge(p, edge):
17 '''
18 > p: vector
19 > edge: tuple of 2 vectors
20 < returns: True / False if a point happens to lie on an edge
21 '''
22 pt, _percent = PtLineIntersect(p, *edge)
23 on_line = (pt - p).length < CAD_prefs.VTX_PRECISION
24 return on_line and (0.0 <= _percent <= 1.0)
27 def line_from_edge_intersect(edge1, edge2):
28 '''
29 > takes 2 tuples, each tuple contains 2 vectors
30 - prepares input for sending to intersect_line_line
31 < returns output of intersect_line_line
32 '''
33 [p1, p2], [p3, p4] = edge1, edge2
34 return LineIntersect(p1, p2, p3, p4)
37 def get_intersection(edge1, edge2):
38 '''
39 > takes 2 tuples, each tuple contains 2 vectors
40 < returns the point halfway on line. See intersect_line_line
41 '''
42 line = line_from_edge_intersect(edge1, edge2)
43 if line:
44 return (line[0] + line[1]) / 2
47 def test_coplanar(edge1, edge2):
48 '''
49 the line that describes the shortest line between the two edges
50 would be short if the lines intersect mathematically. If this
51 line is longer than the VTX_PRECISION then they are either
52 coplanar or parallel.
53 '''
54 line = line_from_edge_intersect(edge1, edge2)
55 if line:
56 return (line[0] - line[1]).length < CAD_prefs.VTX_PRECISION
59 def closest_idx(pt, e):
60 '''
61 > pt: vector
62 > e: bmesh edge
63 < returns: returns index of vertex closest to pt.
65 if both points in e are equally far from pt, then v1 is returned.
66 '''
67 if isinstance(e, bmesh.types.BMEdge):
68 ev = e.verts
69 v1 = ev[0].co
70 v2 = ev[1].co
71 distance_test = (v1 - pt).length <= (v2 - pt).length
72 return ev[0].index if distance_test else ev[1].index
74 print("received {0}, check expected input in docstring ".format(e))
77 def closest_vector(pt, e):
78 '''
79 > pt: vector
80 > e: 2 vector tuple
81 < returns:
82 pt, 2 vector tuple: returns closest vector to pt
84 if both points in e are equally far from pt, then v1 is returned.
85 '''
86 if isinstance(e, tuple) and all([isinstance(co, Vector) for co in e]):
87 v1, v2 = e
88 distance_test = (v1 - pt).length <= (v2 - pt).length
89 return v1 if distance_test else v2
91 print("received {0}, check expected input in docstring ".format(e))
94 def coords_tuple_from_edge_idx(bm, idx):
95 ''' bm is a bmesh representation '''
96 return tuple(v.co for v in bm.edges[idx].verts)
99 def vectors_from_indices(bm, raw_vert_indices):
100 ''' bm is a bmesh representation '''
101 return [bm.verts[i].co for i in raw_vert_indices]
104 def vertex_indices_from_edges_tuple(bm, edge_tuple):
106 > bm: is a bmesh representation
107 > edge_tuple: contains two edge indices.
108 < returns the vertex indices of edge_tuple
110 def k(v, w):
111 return bm.edges[edge_tuple[v]].verts[w].index
113 return [k(i >> 1, i % 2) for i in range(4)]
116 def get_vert_indices_from_bmedges(edges):
118 > bmedges: a list of two bm edges
119 < returns the vertex indices of edge_tuple as a flat list.
121 temp_edges = []
122 print(edges)
123 for e in edges:
124 for v in e.verts:
125 temp_edges.append(v.index)
126 return temp_edges
129 def num_edges_point_lies_on(pt, edges):
130 ''' returns the number of edges that a point lies on. '''
131 res = [point_on_edge(pt, edge) for edge in [edges[:2], edges[2:]]]
132 return len([i for i in res if i])
135 def find_intersecting_edges(bm, pt, idx1, idx2):
137 > pt: Vector
138 > idx1, ix2: edge indices
139 < returns the list of edge indices where pt is on those edges
141 if not pt:
142 return []
143 idxs = [idx1, idx2]
144 edges = [coords_tuple_from_edge_idx(bm, idx) for idx in idxs]
145 return [idx for edge, idx in zip(edges, idxs) if point_on_edge(pt, edge)]
148 def duplicates(indices):
149 return len(set(indices)) < 4
152 def vert_idxs_from_edge_idx(bm, idx):
153 edge = bm.edges[idx]
154 return edge.verts[0].index, edge.verts[1].index