|
1 | 1 | import cadquery as cq |
2 | 2 |
|
| 3 | + |
3 | 4 | def applyToEachFace(wp, f_workplane_selector, f_draw): |
4 | 5 | def each_callback(face): |
5 | 6 | wp_face = f_workplane_selector(face) |
6 | | - |
| 7 | + |
7 | 8 | return f_draw(wp_face, face).vals()[0] |
8 | | - |
| 9 | + |
9 | 10 | return wp.each(each_callback) |
10 | 11 |
|
11 | 12 |
|
12 | | -v_x_unit = cq.Vector(1,0,0) |
13 | | -v_y_unit = cq.Vector(0,1,0) |
14 | | -v_z_unit = cq.Vector(0,0,1) |
| 13 | +v_x_unit = cq.Vector(1, 0, 0) |
| 14 | +v_y_unit = cq.Vector(0, 1, 0) |
| 15 | +v_z_unit = cq.Vector(0, 0, 1) |
15 | 16 |
|
16 | 17 | # ---- VECTORS ---- |
17 | 18 |
|
18 | | -WORLD_AXIS_UNIT_VECTORS_XYZ = \ |
19 | | - [v_x_unit, |
20 | | - v_y_unit, |
21 | | - v_z_unit] |
22 | | - |
23 | | -WORLD_AXIS_UNIT_VECTORS_XZY = \ |
24 | | - [v_x_unit, |
25 | | - v_z_unit, |
26 | | - v_y_unit] |
27 | | - |
28 | | -WORLD_AXIS_UNIT_VECTORS_YXZ = \ |
29 | | - [v_y_unit, |
30 | | - v_x_unit, |
31 | | - v_z_unit] |
32 | | - |
33 | | -WORLD_AXIS_UNIT_VECTORS_YZX = \ |
34 | | - [v_y_unit, |
35 | | - v_z_unit, |
36 | | - v_x_unit] |
37 | | - |
38 | | -WORLD_AXIS_UNIT_VECTORS_ZXY = \ |
39 | | - [v_z_unit, |
40 | | - v_x_unit, |
41 | | - v_y_unit] |
42 | | - |
43 | | -WORLD_AXIS_UNIT_VECTORS_ZYX = \ |
44 | | - [v_z_unit, |
45 | | - v_y_unit, |
46 | | - v_x_unit] |
| 19 | +WORLD_AXIS_UNIT_VECTORS_XYZ = [v_x_unit, v_y_unit, v_z_unit] |
| 20 | + |
| 21 | +WORLD_AXIS_UNIT_VECTORS_XZY = [v_x_unit, v_z_unit, v_y_unit] |
| 22 | + |
| 23 | +WORLD_AXIS_UNIT_VECTORS_YXZ = [v_y_unit, v_x_unit, v_z_unit] |
| 24 | + |
| 25 | +WORLD_AXIS_UNIT_VECTORS_YZX = [v_y_unit, v_z_unit, v_x_unit] |
| 26 | + |
| 27 | +WORLD_AXIS_UNIT_VECTORS_ZXY = [v_z_unit, v_x_unit, v_y_unit] |
| 28 | + |
| 29 | +WORLD_AXIS_UNIT_VECTORS_ZYX = [v_z_unit, v_y_unit, v_x_unit] |
47 | 30 |
|
48 | 31 | # ---- PLANES ---- |
49 | 32 |
|
50 | | -WORLD_XY_NORMAL = v_z_unit |
51 | | -WORLD_ZX_NORMAL = v_y_unit |
52 | | -WORLD_YZ_NORMAL = v_x_unit |
| 33 | +WORLD_XY_NORMAL = v_z_unit |
| 34 | +WORLD_ZX_NORMAL = v_y_unit |
| 35 | +WORLD_YZ_NORMAL = v_x_unit |
| 36 | + |
| 37 | +WORLD_AXIS_PLANES_XY_ZX_YZ = [WORLD_XY_NORMAL, WORLD_ZX_NORMAL, WORLD_YZ_NORMAL] |
53 | 38 |
|
54 | | -WORLD_AXIS_PLANES_XY_ZX_YZ = \ |
55 | | - [WORLD_XY_NORMAL, |
56 | | - WORLD_ZX_NORMAL, |
57 | | - WORLD_YZ_NORMAL] |
| 39 | +WORLD_AXIS_PLANES_XY_YZ_ZX = [WORLD_XY_NORMAL, WORLD_YZ_NORMAL, WORLD_ZX_NORMAL] |
58 | 40 |
|
59 | | -WORLD_AXIS_PLANES_XY_YZ_ZX = \ |
60 | | - [WORLD_XY_NORMAL, |
61 | | - WORLD_YZ_NORMAL, |
62 | | - WORLD_ZX_NORMAL] |
| 41 | +WORLD_AXIS_PLANES_YZ_XY_ZX = [WORLD_YZ_NORMAL, WORLD_XY_NORMAL, WORLD_ZX_NORMAL] |
63 | 42 |
|
64 | | -WORLD_AXIS_PLANES_YZ_XY_ZX = \ |
65 | | - [WORLD_YZ_NORMAL, |
66 | | - WORLD_XY_NORMAL, |
67 | | - WORLD_ZX_NORMAL] |
| 43 | +WORLD_AXIS_PLANES_YZ_ZX_XY = [WORLD_YZ_NORMAL, WORLD_ZX_NORMAL, WORLD_XY_NORMAL] |
68 | 44 |
|
69 | | -WORLD_AXIS_PLANES_YZ_ZX_XY = \ |
70 | | - [WORLD_YZ_NORMAL, |
71 | | - WORLD_ZX_NORMAL, |
72 | | - WORLD_XY_NORMAL] |
| 45 | +WORLD_AXIS_PLANES_ZX_XY_YZ = [WORLD_ZX_NORMAL, WORLD_XY_NORMAL, WORLD_YZ_NORMAL] |
73 | 46 |
|
74 | | -WORLD_AXIS_PLANES_ZX_XY_YZ = \ |
75 | | - [WORLD_ZX_NORMAL, |
76 | | - WORLD_XY_NORMAL, |
77 | | - WORLD_YZ_NORMAL] |
| 47 | +WORLD_AXIS_PLANES_ZX_YZ_XY = [WORLD_ZX_NORMAL, WORLD_YZ_NORMAL, WORLD_XY_NORMAL] |
78 | 48 |
|
79 | | -WORLD_AXIS_PLANES_ZX_YZ_XY = \ |
80 | | - [WORLD_ZX_NORMAL, |
81 | | - WORLD_YZ_NORMAL, |
82 | | - WORLD_XY_NORMAL] |
83 | 49 |
|
84 | 50 | def _create_workplane(v_center, v_xaxis, v_zaxis): |
85 | | - return cq.Workplane( |
86 | | - cq.Plane( |
87 | | - v_center, |
88 | | - v_xaxis, |
89 | | - v_zaxis), |
90 | | - origin=v_center) |
| 51 | + return cq.Workplane(cq.Plane(v_center, v_xaxis, v_zaxis), origin=v_center) |
| 52 | + |
91 | 53 |
|
92 | 54 | class XAxisInPlane: |
93 | | - def __init__(self, plane_normals, tolerance=1e-3): |
94 | | - self.__plane_normals = [x.normalized() for x in plane_normals] |
95 | | - self.__tolerance = tolerance |
96 | | - |
97 | | - def __call__(self, face): |
98 | | - v_zaxis = face.normalAt() |
99 | | - |
100 | | - selected_plane_normal = None |
101 | | - for plane_normal in self.__plane_normals: |
102 | | - plane_normal_projection = plane_normal.dot(v_zaxis) |
103 | | - if (1-abs(plane_normal_projection)) > self.__tolerance: |
104 | | - selected_plane_normal = plane_normal |
105 | | - break |
106 | | - if selected_plane_normal is None: |
107 | | - raise ValueError( |
108 | | - "All plane normals are too close to face normal %s" % v_zaxis) |
109 | | - v_xaxis = selected_plane_normal.cross(v_zaxis) |
110 | | - |
111 | | - return _create_workplane( |
112 | | - face.Center(), |
113 | | - v_xaxis, |
114 | | - v_zaxis) |
| 55 | + def __init__(self, plane_normals, tolerance=1e-3): |
| 56 | + self.__plane_normals = [x.normalized() for x in plane_normals] |
| 57 | + self.__tolerance = tolerance |
| 58 | + |
| 59 | + def __call__(self, face): |
| 60 | + v_zaxis = face.normalAt() |
| 61 | + |
| 62 | + selected_plane_normal = None |
| 63 | + for plane_normal in self.__plane_normals: |
| 64 | + plane_normal_projection = plane_normal.dot(v_zaxis) |
| 65 | + if (1 - abs(plane_normal_projection)) > self.__tolerance: |
| 66 | + selected_plane_normal = plane_normal |
| 67 | + break |
| 68 | + if selected_plane_normal is None: |
| 69 | + raise ValueError( |
| 70 | + "All plane normals are too close to face normal %s" % v_zaxis |
| 71 | + ) |
| 72 | + v_xaxis = selected_plane_normal.cross(v_zaxis) |
| 73 | + |
| 74 | + return _create_workplane(face.Center(), v_xaxis, v_zaxis) |
| 75 | + |
115 | 76 |
|
116 | 77 | class XAxisClosestTo: |
117 | | - def __init__(self, |
118 | | - candidate_vectors, |
119 | | - tolerance = 1e-3): |
120 | | - |
121 | | - self.__tolerance = tolerance |
122 | | - self.__weighted_candidate_vectors = \ |
123 | | - [(i, x.normalized()) \ |
124 | | - for i, x in enumerate(candidate_vectors)] |
125 | | - |
126 | | - def __get_best_candidate( |
127 | | - self, |
128 | | - objectlist, |
129 | | - key_selector, |
130 | | - cluster_sort_key): |
131 | | - # idea borrowed from |
132 | | - # https://github.com/CadQuery/cadquery/blob/a71a93ea274089ddbd48dbbd84d84710fc82a432/cadquery/selectors.py#L343 |
133 | | - key_and_obj = [] |
134 | | - for obj in objectlist: |
135 | | - key_and_obj.append((key_selector(obj), obj)) |
136 | | - key_and_obj.sort(key=lambda x: x[0]) |
137 | | - |
138 | | - first_cluster = [] |
139 | | - start = key_and_obj[0][0] |
140 | | - for key, obj in key_and_obj: |
141 | | - if abs(key - start) <= self.__tolerance: |
142 | | - first_cluster.append(obj) |
143 | | - else: |
144 | | - break |
145 | | - first_cluster.sort(key=cluster_sort_key) |
146 | | - |
147 | | - return first_cluster[0] |
148 | | - |
149 | | - def __call__(self, face): |
150 | | - v_zaxis = face.normalAt() |
151 | | - |
152 | | - best_xax_candidate = \ |
153 | | - self.__get_best_candidate( |
154 | | - self.__weighted_candidate_vectors, |
155 | | - lambda x: abs(x[1].dot(v_zaxis)), |
156 | | - lambda x: x[0])[1] |
157 | | - |
158 | | - v_xaxis = (best_xax_candidate \ |
159 | | - - v_zaxis.multiply(best_xax_candidate.dot(v_zaxis)))\ |
160 | | - .normalized() |
161 | | - |
162 | | - return _create_workplane( |
163 | | - face.Center(), |
164 | | - v_xaxis, |
165 | | - v_zaxis) |
| 78 | + def __init__(self, candidate_vectors, tolerance=1e-3): |
| 79 | + |
| 80 | + self.__tolerance = tolerance |
| 81 | + self.__weighted_candidate_vectors = [ |
| 82 | + (i, x.normalized()) for i, x in enumerate(candidate_vectors) |
| 83 | + ] |
| 84 | + |
| 85 | + def __get_best_candidate(self, objectlist, key_selector, cluster_sort_key): |
| 86 | + # idea borrowed from |
| 87 | + # https://github.com/CadQuery/cadquery/blob/a71a93ea274089ddbd48dbbd84d84710fc82a432/cadquery/selectors.py#L343 |
| 88 | + key_and_obj = [] |
| 89 | + for obj in objectlist: |
| 90 | + key_and_obj.append((key_selector(obj), obj)) |
| 91 | + key_and_obj.sort(key=lambda x: x[0]) |
| 92 | + |
| 93 | + first_cluster = [] |
| 94 | + start = key_and_obj[0][0] |
| 95 | + for key, obj in key_and_obj: |
| 96 | + if abs(key - start) <= self.__tolerance: |
| 97 | + first_cluster.append(obj) |
| 98 | + else: |
| 99 | + break |
| 100 | + first_cluster.sort(key=cluster_sort_key) |
| 101 | + |
| 102 | + return first_cluster[0] |
| 103 | + |
| 104 | + def __call__(self, face): |
| 105 | + v_zaxis = face.normalAt() |
| 106 | + |
| 107 | + best_xax_candidate = self.__get_best_candidate( |
| 108 | + self.__weighted_candidate_vectors, |
| 109 | + lambda x: abs(x[1].dot(v_zaxis)), |
| 110 | + lambda x: x[0], |
| 111 | + )[1] |
| 112 | + |
| 113 | + v_xaxis = ( |
| 114 | + best_xax_candidate - v_zaxis.multiply(best_xax_candidate.dot(v_zaxis)) |
| 115 | + ).normalized() |
| 116 | + |
| 117 | + return _create_workplane(face.Center(), v_xaxis, v_zaxis) |
166 | 118 |
|
167 | 119 |
|
168 | 120 | cq.Workplane.applyToEachFace = applyToEachFace |
0 commit comments