Add STL linking with bounding box and edge verticies. Experimental.
This commit is contained in:
parent
a97b77c1e5
commit
2afd6103d9
@ -176,6 +176,7 @@ set(solvespace_core_SOURCES
|
|||||||
groupmesh.cpp
|
groupmesh.cpp
|
||||||
importdxf.cpp
|
importdxf.cpp
|
||||||
importidf.cpp
|
importidf.cpp
|
||||||
|
importmesh.cpp
|
||||||
mesh.cpp
|
mesh.cpp
|
||||||
modify.cpp
|
modify.cpp
|
||||||
mouse.cpp
|
mouse.cpp
|
||||||
|
@ -711,6 +711,8 @@ bool SolveSpaceUI::LoadEntitiesFromFile(const Platform::Path &filename, EntityLi
|
|||||||
{
|
{
|
||||||
if(strcmp(filename.Extension().c_str(), "emn")==0) {
|
if(strcmp(filename.Extension().c_str(), "emn")==0) {
|
||||||
return LinkIDF(filename, le, m, sh);
|
return LinkIDF(filename, le, m, sh);
|
||||||
|
} else if(strcmp(filename.Extension().c_str(), "stl")==0) {
|
||||||
|
return LinkStl(filename, le, m, sh);
|
||||||
} else {
|
} else {
|
||||||
return LoadEntitiesFromSlvs(filename, le, m, sh);
|
return LoadEntitiesFromSlvs(filename, le, m, sh);
|
||||||
}
|
}
|
||||||
|
222
src/importmesh.cpp
Normal file
222
src/importmesh.cpp
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
SK.GetGroup(SS.GW.activeGroup)->forceToMesh = true;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -88,6 +88,7 @@ std::vector<FileFilter> SolveSpaceModelFileFilters = {
|
|||||||
std::vector<FileFilter> SolveSpaceLinkFileFilters = {
|
std::vector<FileFilter> SolveSpaceLinkFileFilters = {
|
||||||
{ CN_("file-type", "SolveSpace models"), { "slvs" } },
|
{ CN_("file-type", "SolveSpace models"), { "slvs" } },
|
||||||
{ CN_("file-type", "IDF circuit board"), { "emn" } },
|
{ CN_("file-type", "IDF circuit board"), { "emn" } },
|
||||||
|
{ CN_("file-type", "STL triangle mesh"), { "stl" } },
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<FileFilter> RasterFileFilters = {
|
std::vector<FileFilter> RasterFileFilters = {
|
||||||
|
@ -812,6 +812,7 @@ public:
|
|||||||
void ImportDxf(const Platform::Path &file);
|
void ImportDxf(const Platform::Path &file);
|
||||||
void ImportDwg(const Platform::Path &file);
|
void ImportDwg(const Platform::Path &file);
|
||||||
bool LinkIDF(const Platform::Path &filename, EntityList *le, SMesh *m, SShell *sh);
|
bool LinkIDF(const Platform::Path &filename, EntityList *le, SMesh *m, SShell *sh);
|
||||||
|
bool LinkStl(const Platform::Path &filename, EntityList *le, SMesh *m, SShell *sh);
|
||||||
|
|
||||||
extern SolveSpaceUI SS;
|
extern SolveSpaceUI SS;
|
||||||
extern Sketch SK;
|
extern Sketch SK;
|
||||||
|
Loading…
Reference in New Issue
Block a user