1 # SPDX-FileCopyrightText: 2016-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
8 from mathutils
import Vector
, geometry
9 from mathutils
.geometry
import intersect_line_line
as LineIntersect
10 from mathutils
.geometry
import intersect_point_line
as PtLineIntersect
14 VTX_PRECISION
= 1.0e-5
15 VTX_DOUBLES_THRSHLD
= 0.0001
18 def point_on_edge(p
, edge
):
21 > edge: tuple of 2 vectors
22 < returns: True / False if a point happens to lie on an edge
24 pt
, _percent
= PtLineIntersect(p
, *edge
)
25 on_line
= (pt
- p
).length
< CAD_prefs
.VTX_PRECISION
26 return on_line
and (0.0 <= _percent
<= 1.0)
29 def line_from_edge_intersect(edge1
, edge2
):
31 > takes 2 tuples, each tuple contains 2 vectors
32 - prepares input for sending to intersect_line_line
33 < returns output of intersect_line_line
35 [p1
, p2
], [p3
, p4
] = edge1
, edge2
36 return LineIntersect(p1
, p2
, p3
, p4
)
39 def get_intersection(edge1
, edge2
):
41 > takes 2 tuples, each tuple contains 2 vectors
42 < returns the point halfway on line. See intersect_line_line
44 line
= line_from_edge_intersect(edge1
, edge2
)
46 return (line
[0] + line
[1]) / 2
49 def test_coplanar(edge1
, edge2
):
51 the line that describes the shortest line between the two edges
52 would be short if the lines intersect mathematically. If this
53 line is longer than the VTX_PRECISION then they are either
56 line
= line_from_edge_intersect(edge1
, edge2
)
58 return (line
[0] - line
[1]).length
< CAD_prefs
.VTX_PRECISION
61 def closest_idx(pt
, e
):
65 < returns: returns index of vertex closest to pt.
67 if both points in e are equally far from pt, then v1 is returned.
69 if isinstance(e
, bmesh
.types
.BMEdge
):
73 distance_test
= (v1
- pt
).length
<= (v2
- pt
).length
74 return ev
[0].index
if distance_test
else ev
[1].index
76 print("received {0}, check expected input in docstring ".format(e
))
79 def closest_vector(pt
, e
):
84 pt, 2 vector tuple: returns closest vector to pt
86 if both points in e are equally far from pt, then v1 is returned.
88 if isinstance(e
, tuple) and all([isinstance(co
, Vector
) for co
in e
]):
90 distance_test
= (v1
- pt
).length
<= (v2
- pt
).length
91 return v1
if distance_test
else v2
93 print("received {0}, check expected input in docstring ".format(e
))
96 def coords_tuple_from_edge_idx(bm
, idx
):
97 ''' bm is a bmesh representation '''
98 return tuple(v
.co
for v
in bm
.edges
[idx
].verts
)
101 def vectors_from_indices(bm
, raw_vert_indices
):
102 ''' bm is a bmesh representation '''
103 return [bm
.verts
[i
].co
for i
in raw_vert_indices
]
106 def vertex_indices_from_edges_tuple(bm
, edge_tuple
):
108 > bm: is a bmesh representation
109 > edge_tuple: contains two edge indices.
110 < returns the vertex indices of edge_tuple
113 return bm
.edges
[edge_tuple
[v
]].verts
[w
].index
115 return [k(i
>> 1, i
% 2) for i
in range(4)]
118 def get_vert_indices_from_bmedges(edges
):
120 > bmedges: a list of two bm edges
121 < returns the vertex indices of edge_tuple as a flat list.
127 temp_edges
.append(v
.index
)
131 def num_edges_point_lies_on(pt
, edges
):
132 ''' returns the number of edges that a point lies on. '''
133 res
= [point_on_edge(pt
, edge
) for edge
in [edges
[:2], edges
[2:]]]
134 return len([i
for i
in res
if i
])
137 def find_intersecting_edges(bm
, pt
, idx1
, idx2
):
140 > idx1, ix2: edge indices
141 < returns the list of edge indices where pt is on those edges
146 edges
= [coords_tuple_from_edge_idx(bm
, idx
) for idx
in idxs
]
147 return [idx
for edge
, idx
in zip(edges
, idxs
) if point_on_edge(pt
, edge
)]
150 def duplicates(indices
):
151 return len(set(indices
)) < 4
154 def vert_idxs_from_edge_idx(bm
, idx
):
156 return edge
.verts
[0].index
, edge
.verts
[1].index