1 # SPDX-License-Identifier: GPL-2.0-or-later
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
12 VTX_PRECISION
= 1.0e-5
13 VTX_DOUBLES_THRSHLD
= 0.0001
16 def point_on_edge(p
, edge
):
19 > edge: tuple of 2 vectors
20 < returns: True / False if a point happens to lie on an edge
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
):
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
33 [p1
, p2
], [p3
, p4
] = edge1
, edge2
34 return LineIntersect(p1
, p2
, p3
, p4
)
37 def get_intersection(edge1
, edge2
):
39 > takes 2 tuples, each tuple contains 2 vectors
40 < returns the point halfway on line. See intersect_line_line
42 line
= line_from_edge_intersect(edge1
, edge2
)
44 return (line
[0] + line
[1]) / 2
47 def test_coplanar(edge1
, edge2
):
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
54 line
= line_from_edge_intersect(edge1
, edge2
)
56 return (line
[0] - line
[1]).length
< CAD_prefs
.VTX_PRECISION
59 def closest_idx(pt
, e
):
63 < returns: returns index of vertex closest to pt.
65 if both points in e are equally far from pt, then v1 is returned.
67 if isinstance(e
, bmesh
.types
.BMEdge
):
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
):
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.
86 if isinstance(e
, tuple) and all([isinstance(co
, Vector
) for co
in 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
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.
125 temp_edges
.append(v
.index
)
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
):
138 > idx1, ix2: edge indices
139 < returns the list of edge indices where pt is on those edges
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
):
154 return edge
.verts
[0].index
, edge
.verts
[1].index