222 lines
6.0 KiB
C++
222 lines
6.0 KiB
C++
//-----------------------------------------------------------------------------
|
|
// Triangle mesh file reader. Reads an STL file triangle mesh and creates
|
|
// a SovleSpace SMesh from it. Supports only Linking, not import.
|
|
//
|
|
// Copyright 2020 Paul Kahler.
|
|
//-----------------------------------------------------------------------------
|
|
#include "solvespace.h"
|
|
#include "sketch.h"
|
|
#include <vector>
|
|
|
|
#define MIN_POINT_DISTANCE 0.001
|
|
|
|
// we will check for duplicate verticies and keep all their normals
|
|
class vertex {
|
|
public:
|
|
Vector p;
|
|
std::vector<Vector> normal;
|
|
};
|
|
|
|
static bool isEdgeVertex(vertex &v) {
|
|
unsigned int i,j;
|
|
bool result = false;
|
|
for(i=0;i<v.normal.size();i++) {
|
|
for(j=i;j<v.normal.size();j++) {
|
|
if(v.normal[i].Dot(v.normal[j]) < 0.9) {
|
|
result = true;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
// This function has poor performance, used inside a loop it is O(n**2)
|
|
static void addUnique(std::vector<vertex> &lv, Vector &p, Vector &n) {
|
|
unsigned int i;
|
|
for(i=0; i<lv.size(); i++) {
|
|
if(lv[i].p.Equals(p, MIN_POINT_DISTANCE)) {
|
|
break;
|
|
}
|
|
}
|
|
if(i==lv.size()) {
|
|
vertex v;
|
|
v.p = p;
|
|
lv.push_back(v);
|
|
}
|
|
// we could improve a little by only storing unique normals
|
|
lv[i].normal.push_back(n);
|
|
};
|
|
|
|
// Make a new point - type doesn't matter since we will make a copy later
|
|
static hEntity newPoint(EntityList *el, int id, Vector p) {
|
|
Entity en = {};
|
|
en.type = Entity::Type::POINT_N_COPY;
|
|
en.extraPoints = 0;
|
|
en.timesApplied = 0;
|
|
en.group.v = 462;
|
|
en.actPoint = p;
|
|
en.construction = false;
|
|
en.style.v = Style::DATUM;
|
|
en.actVisible = true;
|
|
en.forceHidden = false;
|
|
|
|
en.h.v = id + en.group.v*65536;
|
|
el->Add(&en);
|
|
return en.h;
|
|
}
|
|
|
|
// check if a vertex is unique and add it via newPoint if it is.
|
|
static void addVertex(EntityList *el, Vector v) {
|
|
if(el->n < 15000) {
|
|
int id = el->n+2;
|
|
newPoint(el, id, v);
|
|
}
|
|
}
|
|
|
|
static hEntity newLine(EntityList *el, int id, hEntity p0, hEntity p1) {
|
|
Entity en = {};
|
|
en.type = Entity::Type::LINE_SEGMENT;
|
|
en.point[0] = p0;
|
|
en.point[1] = p1;
|
|
en.extraPoints = 0;
|
|
en.timesApplied = 0;
|
|
en.group.v = 493;
|
|
en.construction = true;
|
|
en.style.v = Style::CONSTRUCTION;
|
|
en.actVisible = true;
|
|
en.forceHidden = false;
|
|
|
|
en.h.v = id + en.group.v*65536;
|
|
el->Add(&en);
|
|
return en.h;
|
|
}
|
|
|
|
namespace SolveSpace {
|
|
|
|
bool LinkStl(const Platform::Path &filename, EntityList *el, SMesh *m, SShell *sh) {
|
|
dbp("\nLink STL triangle mesh.");
|
|
el->Clear();
|
|
std::string data;
|
|
if(!ReadFile(filename, &data)) {
|
|
Error("Couldn't read from '%s'", filename.raw.c_str());
|
|
return false;
|
|
}
|
|
|
|
std::stringstream f(data);
|
|
|
|
char str[80] = {};
|
|
f.read(str, 80);
|
|
|
|
uint32_t n;
|
|
uint32_t color;
|
|
|
|
f.read((char*)&n, 4);
|
|
dbp("%d triangles", n);
|
|
|
|
float x,y,z;
|
|
float xn,yn,zn;
|
|
|
|
//add the STL origin as an entity
|
|
addVertex(el, Vector::From(0.0, 0.0, 0.0));
|
|
|
|
std::vector<vertex> verts = {};
|
|
|
|
for(uint32_t i = 0; i<n; i++) {
|
|
STriangle tr = {};
|
|
|
|
// read the triangle normal
|
|
f.read((char*)&xn, 4);
|
|
f.read((char*)&yn, 4);
|
|
f.read((char*)&zn, 4);
|
|
tr.an = Vector::From(xn,yn,zn);
|
|
tr.bn = tr.an;
|
|
tr.cn = tr.an;
|
|
|
|
f.read((char*)&x, 4);
|
|
f.read((char*)&y, 4);
|
|
f.read((char*)&z, 4);
|
|
tr.a.x = x;
|
|
tr.a.y = y;
|
|
tr.a.z = z;
|
|
|
|
f.read((char*)&x, 4);
|
|
f.read((char*)&y, 4);
|
|
f.read((char*)&z, 4);
|
|
tr.b.x = x;
|
|
tr.b.y = y;
|
|
tr.b.z = z;
|
|
|
|
f.read((char*)&x, 4);
|
|
f.read((char*)&y, 4);
|
|
f.read((char*)&z, 4);
|
|
tr.c.x = x;
|
|
tr.c.y = y;
|
|
tr.c.z = z;
|
|
|
|
f.read((char*)&color,2);
|
|
if(color & 0x8000) {
|
|
tr.meta.color.red = (color >> 7) & 0xf8;
|
|
tr.meta.color.green = (color >> 2) & 0xf8;
|
|
tr.meta.color.blue = (color << 3);
|
|
tr.meta.color.alpha = 255;
|
|
} else {
|
|
tr.meta.color.red = 90;
|
|
tr.meta.color.green = 120;
|
|
tr.meta.color.blue = 140;
|
|
tr.meta.color.alpha = 255;
|
|
}
|
|
|
|
m->AddTriangle(&tr);
|
|
Vector normal = tr.Normal().WithMagnitude(1.0);
|
|
addUnique(verts, tr.a, normal);
|
|
addUnique(verts, tr.b, normal);
|
|
addUnique(verts, tr.c, normal);
|
|
}
|
|
dbp("%d verticies", verts.size());
|
|
|
|
BBox box = {};
|
|
box.minp = verts[0].p;
|
|
box.maxp = verts[0].p;
|
|
|
|
// determine the bounding box for all vertexes
|
|
for(unsigned int i=1; i<verts.size(); i++) {
|
|
box.Include(verts[i].p);
|
|
}
|
|
|
|
hEntity p[8];
|
|
int id = el->n+2;
|
|
p[0] = newPoint(el, id++, Vector::From(box.minp.x, box.minp.y, box.minp.z));
|
|
p[1] = newPoint(el, id++, Vector::From(box.maxp.x, box.minp.y, box.minp.z));
|
|
p[2] = newPoint(el, id++, Vector::From(box.minp.x, box.maxp.y, box.minp.z));
|
|
p[3] = newPoint(el, id++, Vector::From(box.maxp.x, box.maxp.y, box.minp.z));
|
|
p[4] = newPoint(el, id++, Vector::From(box.minp.x, box.minp.y, box.maxp.z));
|
|
p[5] = newPoint(el, id++, Vector::From(box.maxp.x, box.minp.y, box.maxp.z));
|
|
p[6] = newPoint(el, id++, Vector::From(box.minp.x, box.maxp.y, box.maxp.z));
|
|
p[7] = newPoint(el, id++, Vector::From(box.maxp.x, box.maxp.y, box.maxp.z));
|
|
|
|
newLine(el, id++, p[0], p[1]);
|
|
newLine(el, id++, p[0], p[2]);
|
|
newLine(el, id++, p[3], p[1]);
|
|
newLine(el, id++, p[3], p[2]);
|
|
|
|
newLine(el, id++, p[4], p[5]);
|
|
newLine(el, id++, p[4], p[6]);
|
|
newLine(el, id++, p[7], p[5]);
|
|
newLine(el, id++, p[7], p[6]);
|
|
|
|
newLine(el, id++, p[0], p[4]);
|
|
newLine(el, id++, p[1], p[5]);
|
|
newLine(el, id++, p[2], p[6]);
|
|
newLine(el, id++, p[3], p[7]);
|
|
|
|
for(unsigned int i=0; i<verts.size(); i++) {
|
|
// create point entities for edge vertexes
|
|
if(isEdgeVertex(verts[i])) {
|
|
addVertex(el, verts[i].p);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
}
|