Skip to content

Commit 2afd610

Browse files
committed
Add STL linking with bounding box and edge verticies. Experimental.
1 parent a97b77c commit 2afd610

5 files changed

Lines changed: 228 additions & 1 deletion

File tree

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ set(solvespace_core_SOURCES
176176
groupmesh.cpp
177177
importdxf.cpp
178178
importidf.cpp
179+
importmesh.cpp
179180
mesh.cpp
180181
modify.cpp
181182
mouse.cpp

src/file.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,9 @@ bool SolveSpaceUI::LoadEntitiesFromFile(const Platform::Path &filename, EntityLi
710710
SMesh *m, SShell *sh)
711711
{
712712
if(strcmp(filename.Extension().c_str(), "emn")==0) {
713-
return LinkIDF(filename, le, m, sh);
713+
return LinkIDF(filename, le, m, sh);
714+
} else if(strcmp(filename.Extension().c_str(), "stl")==0) {
715+
return LinkStl(filename, le, m, sh);
714716
} else {
715717
return LoadEntitiesFromSlvs(filename, le, m, sh);
716718
}

src/importmesh.cpp

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
//-----------------------------------------------------------------------------
2+
// Triangle mesh file reader. Reads an STL file triangle mesh and creates
3+
// a SovleSpace SMesh from it. Supports only Linking, not import.
4+
//
5+
// Copyright 2020 Paul Kahler.
6+
//-----------------------------------------------------------------------------
7+
#include "solvespace.h"
8+
#include "sketch.h"
9+
#include <vector>
10+
11+
#define MIN_POINT_DISTANCE 0.001
12+
13+
// we will check for duplicate verticies and keep all their normals
14+
class vertex {
15+
public:
16+
Vector p;
17+
std::vector<Vector> normal;
18+
};
19+
20+
static bool isEdgeVertex(vertex &v) {
21+
unsigned int i,j;
22+
bool result = false;
23+
for(i=0;i<v.normal.size();i++) {
24+
for(j=i;j<v.normal.size();j++) {
25+
if(v.normal[i].Dot(v.normal[j]) < 0.9) {
26+
result = true;
27+
}
28+
}
29+
}
30+
return result;
31+
}
32+
// This function has poor performance, used inside a loop it is O(n**2)
33+
static void addUnique(std::vector<vertex> &lv, Vector &p, Vector &n) {
34+
unsigned int i;
35+
for(i=0; i<lv.size(); i++) {
36+
if(lv[i].p.Equals(p, MIN_POINT_DISTANCE)) {
37+
break;
38+
}
39+
}
40+
if(i==lv.size()) {
41+
vertex v;
42+
v.p = p;
43+
lv.push_back(v);
44+
}
45+
// we could improve a little by only storing unique normals
46+
lv[i].normal.push_back(n);
47+
};
48+
49+
// Make a new point - type doesn't matter since we will make a copy later
50+
static hEntity newPoint(EntityList *el, int id, Vector p) {
51+
Entity en = {};
52+
en.type = Entity::Type::POINT_N_COPY;
53+
en.extraPoints = 0;
54+
en.timesApplied = 0;
55+
en.group.v = 462;
56+
en.actPoint = p;
57+
en.construction = false;
58+
en.style.v = Style::DATUM;
59+
en.actVisible = true;
60+
en.forceHidden = false;
61+
62+
en.h.v = id + en.group.v*65536;
63+
el->Add(&en);
64+
return en.h;
65+
}
66+
67+
// check if a vertex is unique and add it via newPoint if it is.
68+
static void addVertex(EntityList *el, Vector v) {
69+
if(el->n < 15000) {
70+
int id = el->n+2;
71+
newPoint(el, id, v);
72+
}
73+
}
74+
75+
static hEntity newLine(EntityList *el, int id, hEntity p0, hEntity p1) {
76+
Entity en = {};
77+
en.type = Entity::Type::LINE_SEGMENT;
78+
en.point[0] = p0;
79+
en.point[1] = p1;
80+
en.extraPoints = 0;
81+
en.timesApplied = 0;
82+
en.group.v = 493;
83+
en.construction = true;
84+
en.style.v = Style::CONSTRUCTION;
85+
en.actVisible = true;
86+
en.forceHidden = false;
87+
88+
en.h.v = id + en.group.v*65536;
89+
el->Add(&en);
90+
return en.h;
91+
}
92+
93+
namespace SolveSpace {
94+
95+
bool LinkStl(const Platform::Path &filename, EntityList *el, SMesh *m, SShell *sh) {
96+
dbp("\nLink STL triangle mesh.");
97+
el->Clear();
98+
std::string data;
99+
if(!ReadFile(filename, &data)) {
100+
Error("Couldn't read from '%s'", filename.raw.c_str());
101+
return false;
102+
}
103+
104+
std::stringstream f(data);
105+
106+
char str[80] = {};
107+
f.read(str, 80);
108+
109+
uint32_t n;
110+
uint32_t color;
111+
112+
f.read((char*)&n, 4);
113+
dbp("%d triangles", n);
114+
115+
float x,y,z;
116+
float xn,yn,zn;
117+
118+
//add the STL origin as an entity
119+
addVertex(el, Vector::From(0.0, 0.0, 0.0));
120+
121+
std::vector<vertex> verts = {};
122+
123+
for(uint32_t i = 0; i<n; i++) {
124+
STriangle tr = {};
125+
126+
// read the triangle normal
127+
f.read((char*)&xn, 4);
128+
f.read((char*)&yn, 4);
129+
f.read((char*)&zn, 4);
130+
tr.an = Vector::From(xn,yn,zn);
131+
tr.bn = tr.an;
132+
tr.cn = tr.an;
133+
134+
f.read((char*)&x, 4);
135+
f.read((char*)&y, 4);
136+
f.read((char*)&z, 4);
137+
tr.a.x = x;
138+
tr.a.y = y;
139+
tr.a.z = z;
140+
141+
f.read((char*)&x, 4);
142+
f.read((char*)&y, 4);
143+
f.read((char*)&z, 4);
144+
tr.b.x = x;
145+
tr.b.y = y;
146+
tr.b.z = z;
147+
148+
f.read((char*)&x, 4);
149+
f.read((char*)&y, 4);
150+
f.read((char*)&z, 4);
151+
tr.c.x = x;
152+
tr.c.y = y;
153+
tr.c.z = z;
154+
155+
f.read((char*)&color,2);
156+
if(color & 0x8000) {
157+
tr.meta.color.red = (color >> 7) & 0xf8;
158+
tr.meta.color.green = (color >> 2) & 0xf8;
159+
tr.meta.color.blue = (color << 3);
160+
tr.meta.color.alpha = 255;
161+
} else {
162+
tr.meta.color.red = 90;
163+
tr.meta.color.green = 120;
164+
tr.meta.color.blue = 140;
165+
tr.meta.color.alpha = 255;
166+
}
167+
168+
m->AddTriangle(&tr);
169+
Vector normal = tr.Normal().WithMagnitude(1.0);
170+
addUnique(verts, tr.a, normal);
171+
addUnique(verts, tr.b, normal);
172+
addUnique(verts, tr.c, normal);
173+
}
174+
SK.GetGroup(SS.GW.activeGroup)->forceToMesh = true;
175+
dbp("%d verticies", verts.size());
176+
177+
BBox box = {};
178+
box.minp = verts[0].p;
179+
box.maxp = verts[0].p;
180+
181+
// determine the bounding box for all vertexes
182+
for(unsigned int i=1; i<verts.size(); i++) {
183+
box.Include(verts[i].p);
184+
}
185+
186+
hEntity p[8];
187+
int id = el->n+2;
188+
p[0] = newPoint(el, id++, Vector::From(box.minp.x, box.minp.y, box.minp.z));
189+
p[1] = newPoint(el, id++, Vector::From(box.maxp.x, box.minp.y, box.minp.z));
190+
p[2] = newPoint(el, id++, Vector::From(box.minp.x, box.maxp.y, box.minp.z));
191+
p[3] = newPoint(el, id++, Vector::From(box.maxp.x, box.maxp.y, box.minp.z));
192+
p[4] = newPoint(el, id++, Vector::From(box.minp.x, box.minp.y, box.maxp.z));
193+
p[5] = newPoint(el, id++, Vector::From(box.maxp.x, box.minp.y, box.maxp.z));
194+
p[6] = newPoint(el, id++, Vector::From(box.minp.x, box.maxp.y, box.maxp.z));
195+
p[7] = newPoint(el, id++, Vector::From(box.maxp.x, box.maxp.y, box.maxp.z));
196+
197+
newLine(el, id++, p[0], p[1]);
198+
newLine(el, id++, p[0], p[2]);
199+
newLine(el, id++, p[3], p[1]);
200+
newLine(el, id++, p[3], p[2]);
201+
202+
newLine(el, id++, p[4], p[5]);
203+
newLine(el, id++, p[4], p[6]);
204+
newLine(el, id++, p[7], p[5]);
205+
newLine(el, id++, p[7], p[6]);
206+
207+
newLine(el, id++, p[0], p[4]);
208+
newLine(el, id++, p[1], p[5]);
209+
newLine(el, id++, p[2], p[6]);
210+
newLine(el, id++, p[3], p[7]);
211+
212+
for(unsigned int i=0; i<verts.size(); i++) {
213+
// create point entities for edge vertexes
214+
if(isEdgeVertex(verts[i])) {
215+
addVertex(el, verts[i].p);
216+
}
217+
}
218+
219+
return true;
220+
}
221+
222+
}

src/platform/gui.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ std::vector<FileFilter> SolveSpaceModelFileFilters = {
8888
std::vector<FileFilter> SolveSpaceLinkFileFilters = {
8989
{ CN_("file-type", "SolveSpace models"), { "slvs" } },
9090
{ CN_("file-type", "IDF circuit board"), { "emn" } },
91+
{ CN_("file-type", "STL triangle mesh"), { "stl" } },
9192
};
9293

9394
std::vector<FileFilter> RasterFileFilters = {

src/solvespace.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,7 @@ class SolveSpaceUI {
812812
void ImportDxf(const Platform::Path &file);
813813
void ImportDwg(const Platform::Path &file);
814814
bool LinkIDF(const Platform::Path &filename, EntityList *le, SMesh *m, SShell *sh);
815+
bool LinkStl(const Platform::Path &filename, EntityList *le, SMesh *m, SShell *sh);
815816

816817
extern SolveSpaceUI SS;
817818
extern Sketch SK;

0 commit comments

Comments
 (0)