Skip to content

Commit 1b32445

Browse files
committed
moved source code
1 parent 15b80be commit 1b32445

File tree

4 files changed

+198
-1
lines changed

4 files changed

+198
-1
lines changed

.github/workflows/python-test.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ jobs:
2323
- name: Install dependencies
2424
run: |
2525
python3 -m pip install poetry
26-
sudo apt-get install -y admesh
2726
poetry install
2827
- name: Lint with black and isort
2928
run: |

stl2step/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from stl2step._version import __version__

stl2step/__main__.py

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
import sys
2+
3+
import cadquery as cq
4+
import numpy as np
5+
from stl import mesh
6+
7+
8+
def roundvec(x):
9+
return np.round(x * 100000000.0) / 100000000.0
10+
11+
12+
def merge_poly(face_idx_lst, face_idx2edge_idx_lst):
13+
edge_idx_set = set()
14+
for f in face_idx_lst:
15+
for e in face_idx2edge_idx_lst[f]:
16+
if e not in edge_idx_set:
17+
edge_idx_set.add(e)
18+
else:
19+
edge_idx_set.remove(e)
20+
return edge_idx_set
21+
22+
23+
def cluster_planes(faces_arr):
24+
a = faces_arr[:, 0, :]
25+
b = faces_arr[:, 1, :]
26+
c = faces_arr[:, 2, :]
27+
ab = b - a
28+
ac = c - a
29+
nrm = np.cross(ab, ac)
30+
nrm2 = nrm / np.linalg.norm(nrm, axis=1)[:, np.newaxis]
31+
dist = np.einsum("ij,ij->i", a, nrm2)
32+
v = roundvec(np.column_stack((nrm2, dist)))
33+
clust = {(e[0], e[1], e[2], e[3]): [] for e in v}
34+
for i, e in enumerate(v):
35+
if np.isnan(e[0]):
36+
continue
37+
clust[(e[0], e[1], e[2], e[3])].append(i)
38+
return list(clust.values())
39+
40+
41+
def sort_edges(edges_merged):
42+
i = 0
43+
sorted_edges = []
44+
first_last = 0
45+
while True:
46+
current_edge = edges_merged.pop(i)
47+
sorted_edges.append(current_edge)
48+
current_pnt = current_edge[first_last]
49+
for i, e in enumerate(edges_merged):
50+
if current_pnt in e:
51+
first_last = 1 if e[0] == current_pnt else 0
52+
break
53+
else:
54+
break
55+
return sorted_edges
56+
57+
58+
if __name__ == "__main__":
59+
60+
filename = sys.argv[1]
61+
62+
input_mesh = mesh.Mesh.from_file(filename)
63+
faces = [[roundvec(f) for f in e] for e in input_mesh.vectors]
64+
pnt2face_idx_lst = {(f[0], f[1], f[2]): [] for e in faces for f in e}
65+
66+
for i, e in enumerate(faces):
67+
for f in e:
68+
pnt2face_idx_lst[(f[0], f[1], f[2])].append(i)
69+
70+
pnts = list(pnt2face_idx_lst.keys())
71+
72+
pnt_idx2face_idx_lst = list(pnt2face_idx_lst.values())
73+
face_idx2pnt_idx_lst = [[] for i in range(max(map(max, pnt_idx2face_idx_lst)) + 1)]
74+
for i, face_idx_lst in enumerate(pnt_idx2face_idx_lst):
75+
for face_idx in face_idx_lst:
76+
face_idx2pnt_idx_lst[face_idx].append(i)
77+
78+
edge2faces_idx = {}
79+
for j, f in enumerate(face_idx2pnt_idx_lst):
80+
for i in range(len(f)):
81+
if f[i - 1] < f[i]:
82+
edge = (f[i - 1], f[i])
83+
elif f[i - 1] > f[i]:
84+
edge = (f[i], f[i - 1])
85+
else:
86+
print("edge with one point only")
87+
print((f[i - 1], f[i]))
88+
continue
89+
# raise BaseException("edge with one point only")
90+
91+
if edge not in edge2faces_idx:
92+
edge2faces_idx[edge] = []
93+
edge2faces_idx[edge].append(j)
94+
95+
edge_idx2edge = list(edge2faces_idx.keys())
96+
edge_idx2faces_idx = list(edge2faces_idx.values())
97+
face_idx2edge_idx_list = [
98+
[] for i in range(max(map(max, pnt_idx2face_idx_lst)) + 1)
99+
]
100+
for i, f in enumerate(edge_idx2faces_idx):
101+
for e in f:
102+
face_idx2edge_idx_list[e].append(i)
103+
104+
faces_arr = np.array(faces)
105+
106+
faces_to_be_merged_list = cluster_planes(faces_arr)
107+
108+
edges_idx_merged_list = [
109+
[e for e in list(merge_poly(f, face_idx2edge_idx_list))]
110+
for f in faces_to_be_merged_list
111+
]
112+
edges_merged_list = [
113+
[edge_idx2edge[e] for e in edges_idx_merged]
114+
for edges_idx_merged in edges_idx_merged_list
115+
]
116+
117+
faces_merged = [f for m in faces_to_be_merged_list for f in m]
118+
remaining_faces = [
119+
e for i, e in enumerate(face_idx2pnt_idx_lst) if i not in faces_merged
120+
]
121+
122+
sorted_edges_polygons = []
123+
for edges_merged in edges_merged_list:
124+
while len(edges_merged) > 0:
125+
sorted_edges = sort_edges(edges_merged)
126+
sorted_edges_polygons.append(sorted_edges)
127+
128+
polygons_pts_idx = [
129+
[
130+
(set(sorted_edges[i - 1]).intersection(set(sorted_edges[i]))).pop()
131+
for i in range(len(sorted_edges))
132+
]
133+
for sorted_edges in sorted_edges_polygons
134+
]
135+
all_polygons = polygons_pts_idx + remaining_faces
136+
137+
edge2polygon_idx = {}
138+
for j, p in enumerate(all_polygons):
139+
for i in range(len(p)):
140+
edge = (p[i - 1], p[i])
141+
if edge not in edge2polygon_idx:
142+
edge2polygon_idx[edge] = []
143+
edge2 = (p[i], p[i - 1])
144+
if edge2 not in edge2polygon_idx:
145+
edge2polygon_idx[edge2] = []
146+
147+
edge2polygon_idx[edge].append(j)
148+
149+
all_poly_idx_set = set(range(len(all_polygons)))
150+
151+
nxt_polys = set({0})
152+
poly_res = []
153+
154+
while len(nxt_polys) > 0:
155+
current_poly_idx = nxt_polys.pop()
156+
if current_poly_idx >= 0:
157+
current_poly = all_polygons[current_poly_idx]
158+
else:
159+
current_poly = all_polygons[-current_poly_idx][::-1]
160+
for i in range(len(current_poly)):
161+
edge = (current_poly[i], current_poly[i - 1])
162+
edge_wrong = (current_poly[i - 1], current_poly[i])
163+
adjacent_poly = edge2polygon_idx[edge]
164+
adjacent_poly_wrong = edge2polygon_idx[edge_wrong]
165+
for e in adjacent_poly:
166+
if e != i:
167+
if e in all_poly_idx_set:
168+
nxt_polys.add(e)
169+
all_poly_idx_set.remove(e)
170+
poly_res.append(e)
171+
for e in adjacent_poly_wrong:
172+
if e != i:
173+
if e in all_poly_idx_set:
174+
nxt_polys.add(-e)
175+
all_poly_idx_set.remove(e)
176+
poly_res.append(-e)
177+
178+
all_poly_correct = [
179+
all_polygons[e] if e >= 0 else all_polygons[-e][::-1] for e in poly_res
180+
]
181+
182+
print(all_poly_correct)
183+
184+
all_poly_coord = [[pnts[f] for f in e] for e in all_poly_correct]
185+
186+
wire = []
187+
for p in all_poly_coord:
188+
wire.append(
189+
cq.Wire.makePolygon(
190+
[[c for c in p[i - 1]] for i in range(len(p))], close=True
191+
)
192+
)
193+
194+
f = [cq.Face.makeFromWires(e, []) for e in wire]
195+
shell = cq.Shell.makeShell(f)
196+
cq.exporters.export(shell, f"{filename[:-4]}.step")

stl2step/_version.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__version__ = "0.0.0+devel"

0 commit comments

Comments
 (0)