Node Wrangler: Add more specific poll methods
[blender-addons.git] / mesh_tiny_cad / cad_module.py
blob84e3776de120e4b708930ab8ac105d182f322d46
1 # SPDX-FileCopyrightText: 2016-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
6 import bmesh
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
13 class CAD_prefs:
14 VTX_PRECISION = 1.0e-5
15 VTX_DOUBLES_THRSHLD = 0.0001
18 def point_on_edge(p, edge):
19 '''
20 > p: vector
21 > edge: tuple of 2 vectors
22 < returns: True / False if a point happens to lie on an edge
23 '''
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):
30 '''
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
34 '''
35 [p1, p2], [p3, p4] = edge1, edge2
36 return LineIntersect(p1, p2, p3, p4)
39 def get_intersection(edge1, edge2):
40 '''
41 > takes 2 tuples, each tuple contains 2 vectors
42 < returns the point halfway on line. See intersect_line_line
43 '''
44 line = line_from_edge_intersect(edge1, edge2)
45 if line:
46 return (line[0] + line[1]) / 2
49 def test_coplanar(edge1, edge2):
50 '''
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
54 coplanar or parallel.
55 '''
56 line = line_from_edge_intersect(edge1, edge2)
57 if line:
58 return (line[0] - line[1]).length < CAD_prefs.VTX_PRECISION
61 def closest_idx(pt, e):
62 '''
63 > pt: vector
64 > e: bmesh edge
65 < returns: returns index of vertex closest to pt.
67 if both points in e are equally far from pt, then v1 is returned.
68 '''
69 if isinstance(e, bmesh.types.BMEdge):
70 ev = e.verts
71 v1 = ev[0].co
72 v2 = ev[1].co
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):
80 '''
81 > pt: vector
82 > e: 2 vector tuple
83 < returns:
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.
87 '''
88 if isinstance(e, tuple) and all([isinstance(co, Vector) for co in e]):
89 v1, v2 = 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
112 def k(v, w):
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.
123 temp_edges = []
124 print(edges)
125 for e in edges:
126 for v in e.verts:
127 temp_edges.append(v.index)
128 return temp_edges
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):
139 > pt: Vector
140 > idx1, ix2: edge indices
141 < returns the list of edge indices where pt is on those edges
143 if not pt:
144 return []
145 idxs = [idx1, idx2]
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):
155 edge = bm.edges[idx]
156 return edge.verts[0].index, edge.verts[1].index