mirror of https://github.com/vitalif/openscad
import OBJ format. also improved OFF import
parent
79f6baf264
commit
f60548462b
|
@ -14,6 +14,8 @@
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/format.hpp>
|
||||||
|
using boost::format;
|
||||||
|
|
||||||
namespace CGALUtils {
|
namespace CGALUtils {
|
||||||
|
|
||||||
|
@ -590,7 +592,7 @@ holding the polygon and it's holes. */
|
||||||
bool tessellate_3d_face_with_holes( std::vector<CGAL_Polygon_3> &polygons, std::vector<CGAL_Polygon_3> &triangles, CGAL_Plane_3 &plane )
|
bool tessellate_3d_face_with_holes( std::vector<CGAL_Polygon_3> &polygons, std::vector<CGAL_Polygon_3> &triangles, CGAL_Plane_3 &plane )
|
||||||
{
|
{
|
||||||
if (polygons.size()==1 && polygons[0].size()==3) {
|
if (polygons.size()==1 && polygons[0].size()==3) {
|
||||||
PRINT("input polygon has 3 points. shortcut tessellation.");
|
PRINTD("input polygon has 3 points. shortcut tessellation.");
|
||||||
CGAL_Polygon_3 t;
|
CGAL_Polygon_3 t;
|
||||||
t.push_back(polygons[0][2]);
|
t.push_back(polygons[0][2]);
|
||||||
t.push_back(polygons[0][1]);
|
t.push_back(polygons[0][1]);
|
||||||
|
@ -602,12 +604,12 @@ bool tessellate_3d_face_with_holes( std::vector<CGAL_Polygon_3> &polygons, std::
|
||||||
CDT cdt;
|
CDT cdt;
|
||||||
std::map<CDTPoint,CGAL_Point_3> vertmap;
|
std::map<CDTPoint,CGAL_Point_3> vertmap;
|
||||||
|
|
||||||
PRINT("finding good projection");
|
PRINTD("finding good projection");
|
||||||
projection_t goodproj = find_good_projection( plane );
|
projection_t goodproj = find_good_projection( plane );
|
||||||
|
|
||||||
PRINTB("plane %s",plane );
|
PRINTDB("plane %s",plane );
|
||||||
PRINTB("proj: %i %i",goodproj.plane % goodproj.flip);
|
PRINTDB("proj: %i %i",goodproj.plane % goodproj.flip);
|
||||||
PRINT("Inserting points and edges into Constrained Delaunay Triangulation");
|
PRINTD("Inserting points and edges into Constrained Delaunay Triangulation");
|
||||||
std::vector< std::vector<CGAL_Point_2> > polygons2d;
|
std::vector< std::vector<CGAL_Point_2> > polygons2d;
|
||||||
for (size_t i=0;i<polygons.size();i++) {
|
for (size_t i=0;i<polygons.size();i++) {
|
||||||
std::vector<Vertex_handle> vhandles;
|
std::vector<Vertex_handle> vhandles;
|
||||||
|
@ -636,7 +638,7 @@ bool tessellate_3d_face_with_holes( std::vector<CGAL_Polygon_3> &polygons, std::
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t numholes = polygons2d.size()-1;
|
size_t numholes = polygons2d.size()-1;
|
||||||
PRINTB("seeding %i holes",numholes);
|
PRINTDB("seeding %i holes",numholes);
|
||||||
std::list<CDTPoint> list_of_seeds;
|
std::list<CDTPoint> list_of_seeds;
|
||||||
for (size_t i=1;i<polygons2d.size();i++) {
|
for (size_t i=1;i<polygons2d.size();i++) {
|
||||||
std::vector<CGAL_Point_2> &pgon = polygons2d[i];
|
std::vector<CGAL_Point_2> &pgon = polygons2d[i];
|
||||||
|
@ -654,19 +656,18 @@ bool tessellate_3d_face_with_holes( std::vector<CGAL_Polygon_3> &polygons, std::
|
||||||
}
|
}
|
||||||
std::list<CDTPoint>::iterator li = list_of_seeds.begin();
|
std::list<CDTPoint>::iterator li = list_of_seeds.begin();
|
||||||
for (;li!=list_of_seeds.end();li++) {
|
for (;li!=list_of_seeds.end();li++) {
|
||||||
//PRINTB("seed %s",*li);
|
|
||||||
double x = CGAL::to_double( li->x() );
|
double x = CGAL::to_double( li->x() );
|
||||||
double y = CGAL::to_double( li->y() );
|
double y = CGAL::to_double( li->y() );
|
||||||
PRINTB("seed %f,%f",x%y);
|
PRINTDB("seed %f,%f",x%y);
|
||||||
}
|
}
|
||||||
PRINT("seeding done");
|
PRINTD("seeding done");
|
||||||
|
|
||||||
PRINT( "meshing" );
|
PRINTD( "meshing" );
|
||||||
CGAL::refine_Delaunay_mesh_2_without_edge_refinement( cdt,
|
CGAL::refine_Delaunay_mesh_2_without_edge_refinement( cdt,
|
||||||
list_of_seeds.begin(), list_of_seeds.end(),
|
list_of_seeds.begin(), list_of_seeds.end(),
|
||||||
DummyCriteria<CDT>() );
|
DummyCriteria<CDT>() );
|
||||||
|
|
||||||
PRINT("meshing done");
|
PRINTD("meshing done");
|
||||||
// this fails because it calls is_simple and is_simple fails on many
|
// this fails because it calls is_simple and is_simple fails on many
|
||||||
// Nef Polyhedron faces
|
// Nef Polyhedron faces
|
||||||
//CGAL::Orientation original_orientation =
|
//CGAL::Orientation original_orientation =
|
||||||
|
@ -695,7 +696,7 @@ bool tessellate_3d_face_with_holes( std::vector<CGAL_Polygon_3> &polygons, std::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PRINTB("built %i triangles\n",triangles.size());
|
PRINTDB("built %i triangles\n",triangles.size());
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
/////// Tessellation end
|
/////// Tessellation end
|
||||||
|
@ -917,13 +918,15 @@ public:
|
||||||
#ifdef GEN_SURFACE_DEBUG
|
#ifdef GEN_SURFACE_DEBUG
|
||||||
printf("],\n");
|
printf("],\n");
|
||||||
|
|
||||||
printf("points=[");
|
dbg.str("");
|
||||||
|
dbg<<"points=[";
|
||||||
for (int vidx=0;vidx<vertices.size();vidx++) {
|
for (int vidx=0;vidx<vertices.size();vidx++) {
|
||||||
if (vidx > 0) printf(",");
|
if (vidx > 0) dbg<<",";
|
||||||
const Vector3d &v = vertices.getArray()[vidx];
|
const Vector3d &v = vertices.getArray()[vidx];
|
||||||
printf("[%g,%g,%g]", v[0], v[1], v[2]);
|
dbg<<format("[%g,%g,%g]") % v[0] % v[1] % v[2];
|
||||||
}
|
}
|
||||||
printf("]);\n");
|
dbg<<"]);";
|
||||||
|
PRINTDB("%s",dbg.str());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -997,7 +1000,7 @@ void ZRemover::visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet )
|
||||||
log << " <!-- ZRemover Halffacet visit end -->\n";
|
log << " <!-- ZRemover Halffacet visit end -->\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
static CGAL_Nef_polyhedron *createNefPolyhedronFromPolySet(const PolySet &ps)
|
CGAL_Nef_polyhedron *createNefPolyhedronFromPolySet(const PolySet &ps)
|
||||||
{
|
{
|
||||||
assert(ps.getDimension() == 3);
|
assert(ps.getDimension() == 3);
|
||||||
if (ps.isEmpty()) return new CGAL_Nef_polyhedron();
|
if (ps.isEmpty()) return new CGAL_Nef_polyhedron();
|
||||||
|
@ -1025,16 +1028,19 @@ static CGAL_Nef_polyhedron *createNefPolyhedronFromPolySet(const PolySet &ps)
|
||||||
PRINTB("CGAL error in CGAL_Nef_polyhedron3(): %s", e.what());
|
PRINTB("CGAL error in CGAL_Nef_polyhedron3(): %s", e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (plane_error) try {
|
if (plane_error) {
|
||||||
|
try {
|
||||||
PolySet ps2(3);
|
PolySet ps2(3);
|
||||||
CGAL_Polyhedron P;
|
CGAL_Polyhedron P;
|
||||||
PolysetUtils::tessellate_faces(ps, ps2);
|
PolysetUtils::tessellate_faces(ps, ps2);
|
||||||
bool err = createPolyhedronFromPolySet(ps2,P);
|
bool err = createPolyhedronFromPolySet(ps2,P);
|
||||||
if (!err) N = new CGAL_Nef_polyhedron3(P);
|
if (!err) N = new CGAL_Nef_polyhedron3(P);
|
||||||
}
|
}
|
||||||
catch (const CGAL::Assertion_exception &e) {
|
catch (const CGAL::Failure_exception &e) {
|
||||||
PRINTB("Alternate construction failed. CGAL error in CGAL_Nef_polyhedron3(): %s", e.what());
|
PRINTB("Alternate construction failed. CGAL error in CGAL_Nef_polyhedron3(): %s", e.what());
|
||||||
|
N = new CGAL_Nef_polyhedron3();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
CGAL::set_error_behaviour(old_behaviour);
|
CGAL::set_error_behaviour(old_behaviour);
|
||||||
return new CGAL_Nef_polyhedron(N);
|
return new CGAL_Nef_polyhedron(N);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ namespace CGALUtils {
|
||||||
CGAL_Iso_cuboid_3 boundingBox(const CGAL_Nef_polyhedron3 &N);
|
CGAL_Iso_cuboid_3 boundingBox(const CGAL_Nef_polyhedron3 &N);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
CGAL_Nef_polyhedron *createNefPolyhedronFromPolySet(const PolySet &ps);
|
||||||
CGAL_Nef_polyhedron *createNefPolyhedronFromGeometry(const class Geometry &geom);
|
CGAL_Nef_polyhedron *createNefPolyhedronFromGeometry(const class Geometry &geom);
|
||||||
bool createPolySetFromPolyhedron(const CGAL_Polyhedron &p, PolySet &ps);
|
bool createPolySetFromPolyhedron(const CGAL_Polyhedron &p, PolySet &ps);
|
||||||
bool createPolySetFromNefPolyhedron3(const CGAL_Nef_polyhedron3 &N, PolySet &ps);
|
bool createPolySetFromNefPolyhedron3(const CGAL_Nef_polyhedron3 &N, PolySet &ps);
|
||||||
|
|
354
src/import.cc
354
src/import.cc
|
@ -106,6 +106,7 @@ AbstractNode *ImportModule::instantiate(const Context *ctx, const ModuleInstanti
|
||||||
if (ext == ".stl") actualtype = TYPE_STL;
|
if (ext == ".stl") actualtype = TYPE_STL;
|
||||||
else if (ext == ".off") actualtype = TYPE_OFF;
|
else if (ext == ".off") actualtype = TYPE_OFF;
|
||||||
else if (ext == ".dxf") actualtype = TYPE_DXF;
|
else if (ext == ".dxf") actualtype = TYPE_DXF;
|
||||||
|
else if (ext == ".obj") actualtype = TYPE_OBJ;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImportNode *node = new ImportNode(inst, actualtype);
|
ImportNode *node = new ImportNode(inst, actualtype);
|
||||||
|
@ -171,7 +172,7 @@ void uint32_byte_swap( uint32_t &x )
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_stl_facet( std::ifstream &f, stl_facet &facet )
|
void read_stl_facet( std::istream &f, stl_facet &facet )
|
||||||
{
|
{
|
||||||
f.read( (char*)facet.data8, STL_FACET_NUMBYTES );
|
f.read( (char*)facet.data8, STL_FACET_NUMBYTES );
|
||||||
#ifdef BOOST_BIG_ENDIAN
|
#ifdef BOOST_BIG_ENDIAN
|
||||||
|
@ -182,118 +183,260 @@ void read_stl_facet( std::ifstream &f, stl_facet &facet )
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// translate the polyset so it's center is at 0,0,0
|
||||||
|
void center_polyset( PolySet &p )
|
||||||
|
{
|
||||||
|
BoundingBox bb = p.getBoundingBox();
|
||||||
|
Vector3d t = -bb.min();
|
||||||
|
t -= (bb.max()-bb.min()) / 2;
|
||||||
|
p.translate( t );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create PolySet from GeomView's OFF format. return true on error,
|
||||||
|
false on success. This is an alternative back-up to CGAL's OFF loader.
|
||||||
|
CGAL's loader doesn't work on some OFF files, like those from the
|
||||||
|
Antiprism program that have single-vertex color faces.
|
||||||
|
Faces with <3 points, and colors, are completely ignored.
|
||||||
|
On error, the PolySet may be left in a partially-built state. */
|
||||||
|
bool createPolySetFromOFF( std::istream &in, PolySet &ps )
|
||||||
|
{
|
||||||
|
bool err = false;
|
||||||
|
if (!in.good()) return true;
|
||||||
|
std::vector<Vector3d> vertlist;
|
||||||
|
std::string line;
|
||||||
|
size_t numvertices, numfaces, numfaceverts, vertindex;
|
||||||
|
double x,y,z;
|
||||||
|
if (!std::getline(in, line)) return true;
|
||||||
|
if (line.find("OFF")==std::string::npos) return true;
|
||||||
|
if (!std::getline(in, line)) return true;
|
||||||
|
if (!(std::istringstream(line) >> numvertices >> numfaces)) return true;
|
||||||
|
if (numvertices==0 || numfaces==0) return true;
|
||||||
|
for (size_t i=0;i<numvertices;i++) {
|
||||||
|
if (!(std::getline(in,line))) return true;
|
||||||
|
if (!(std::istringstream(line) >> x >> y >> z)) return true;
|
||||||
|
vertlist.push_back( Vector3d(x,y,z) );
|
||||||
|
}
|
||||||
|
for (size_t i=0;i<numfaces;i++) {
|
||||||
|
if (!std::getline(in,line)) return true;
|
||||||
|
std::istringstream ss(line);
|
||||||
|
if (!(ss >> numfaceverts)) return true;
|
||||||
|
// face with single vertex might be a weird color thing. skip.
|
||||||
|
if (numfaceverts<3) continue;
|
||||||
|
ps.append_poly();
|
||||||
|
for (size_t j=0;j<numfaceverts;j++) {
|
||||||
|
if (!(ss >> vertindex)) return true;
|
||||||
|
Vector3d v = vertlist[vertindex%vertlist.size()];
|
||||||
|
ps.append_vertex( v.x(), v.y(), v.z() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ps.polygons.size()==0) return true;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* create PolySet from Wavefront(TM) OBJ format stream. return true on error,
|
||||||
|
false on success. Error during read can result in a mal-formed PolySet.
|
||||||
|
This code only reads simple vertices and faces, everything else is
|
||||||
|
ignored. Colors, Normals, and Textures are completely ignored. Face
|
||||||
|
point indexes with '/' textures will be read, but the textures are
|
||||||
|
ignored.
|
||||||
|
*/
|
||||||
|
bool createPolySetFromOBJ( std::istream &in, PolySet &ps )
|
||||||
|
{
|
||||||
|
PRINTD("OBJ import");
|
||||||
|
bool err = false;
|
||||||
|
if (!in.good()) return true;
|
||||||
|
std::vector<Vector3d> vertlist;
|
||||||
|
std::string line,keyword,tmpline,faceindex;
|
||||||
|
int vertindex;
|
||||||
|
size_t pos;
|
||||||
|
double x,y,z;
|
||||||
|
while (std::getline(in, line)) {
|
||||||
|
// deal with the 'continued' line backslash feature of OBJ
|
||||||
|
while ((pos=line.find("\\"))!=std::string::npos) {
|
||||||
|
PRINTDB("line with backslash continuation: %s",line);
|
||||||
|
line = line.substr(0,pos==0 ? 0 : pos-1);
|
||||||
|
if (std::getline(in, tmpline)) {
|
||||||
|
PRINTDB(" adding tmpline %s",tmpline);
|
||||||
|
line += tmpline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PRINTDB("line, full read: %s",line);
|
||||||
|
std::istringstream ss(line);
|
||||||
|
bool ok = (ss >> keyword);
|
||||||
|
if (ok && keyword == "v") {
|
||||||
|
if (!(ss >> x >> y >> z)) { return true; }
|
||||||
|
Vector3d v( x, y, z );
|
||||||
|
vertlist.push_back( v );
|
||||||
|
PRINTDB("vertex: %s",v.transpose());
|
||||||
|
}
|
||||||
|
else if (ok && keyword == "f") { // face
|
||||||
|
ps.append_poly();
|
||||||
|
while (ss >> faceindex) {
|
||||||
|
PRINTDB("face (vindexes) %s",faceindex);
|
||||||
|
if ((pos=faceindex.find("/"))!=std::string::npos) {
|
||||||
|
PRINTD(" vindex with /");
|
||||||
|
std::istringstream ss2(faceindex.substr(0,pos));
|
||||||
|
if (!(ss2 >> vertindex)) return true;
|
||||||
|
} else {
|
||||||
|
std::istringstream ss2(faceindex);
|
||||||
|
if (!(ss2 >> vertindex)) return true;
|
||||||
|
}
|
||||||
|
PRINTDB("vertindex %s",vertindex);
|
||||||
|
if (vertindex<0) {
|
||||||
|
PRINTD("<0, relative index");
|
||||||
|
vertindex = vertlist.size()+vertindex;
|
||||||
|
} else {
|
||||||
|
PRINTD(">0, absolute index (1based)");
|
||||||
|
vertindex--;
|
||||||
|
}
|
||||||
|
Vector3d v = vertlist[vertindex%vertlist.size()];
|
||||||
|
ps.append_vertex( v.x(), v.y(), v.z() );
|
||||||
|
}
|
||||||
|
if (ps.polygons.back().size()<3) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ps.polygons.size()==0) return true;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create PolySet from STL format stream. return true on error, false on
|
||||||
|
success. stream should be positioned at the end of file before passing
|
||||||
|
to this function. */
|
||||||
|
bool createPolySetFromSTL( std::istream &f, PolySet &p )
|
||||||
|
{
|
||||||
|
bool err = false;
|
||||||
|
boost::regex ex_sfe("solid|facet|endloop");
|
||||||
|
boost::regex ex_outer("outer loop");
|
||||||
|
boost::regex ex_vertex("vertex");
|
||||||
|
boost::regex ex_vertices("\\s*vertex\\s+([^\\s]+)\\s+([^\\s]+)\\s+([^\\s]+)");
|
||||||
|
|
||||||
|
bool binary = false;
|
||||||
|
std::streampos file_size = f.tellg();
|
||||||
|
if (file_size==0) {
|
||||||
|
PRINT("WARNING: Import file has size of 0");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
f.seekg(80);
|
||||||
|
if (!f.eof()) {
|
||||||
|
uint32_t facenum = 0;
|
||||||
|
f.read((char *)&facenum, sizeof(uint32_t));
|
||||||
|
#ifdef BOOST_BIG_ENDIAN
|
||||||
|
uint32_byte_swap( facenum );
|
||||||
|
#endif
|
||||||
|
if (file_size == static_cast<std::streamoff>(80 + 4 + 50*facenum)) {
|
||||||
|
binary = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.seekg(0);
|
||||||
|
|
||||||
|
char data[5];
|
||||||
|
f.read(data, 5);
|
||||||
|
if (!binary && !f.eof() && !memcmp(data, "solid", 5)) {
|
||||||
|
int i = 0;
|
||||||
|
double vdata[3][3];
|
||||||
|
std::string line;
|
||||||
|
std::getline(f, line);
|
||||||
|
while (!f.eof()) {
|
||||||
|
|
||||||
|
std::getline(f, line);
|
||||||
|
boost::trim(line);
|
||||||
|
if (boost::regex_search(line, ex_sfe)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (boost::regex_search(line, ex_outer)) {
|
||||||
|
i = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
boost::smatch results;
|
||||||
|
if (boost::regex_search(line, results, ex_vertices)) {
|
||||||
|
try {
|
||||||
|
for (int v=0;v<3;v++) {
|
||||||
|
vdata[i][v] = boost::lexical_cast<double>(results[v+1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const boost::bad_lexical_cast &blc) {
|
||||||
|
PRINTB("WARNING: Can't parse vertex line '%s'.", line);
|
||||||
|
i = 10;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (++i == 3) {
|
||||||
|
p.append_poly();
|
||||||
|
p.append_vertex(vdata[0][0], vdata[0][1], vdata[0][2]);
|
||||||
|
p.append_vertex(vdata[1][0], vdata[1][1], vdata[1][2]);
|
||||||
|
p.append_vertex(vdata[2][0], vdata[2][1], vdata[2][2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
f.ignore(80-5+4);
|
||||||
|
while (1) {
|
||||||
|
stl_facet facet;
|
||||||
|
read_stl_facet( f, facet );
|
||||||
|
if (f.eof()) break;
|
||||||
|
p.append_poly();
|
||||||
|
p.append_vertex(facet.data.x1, facet.data.y1, facet.data.z1);
|
||||||
|
p.append_vertex(facet.data.x2, facet.data.y2, facet.data.z2);
|
||||||
|
p.append_vertex(facet.data.x3, facet.data.y3, facet.data.z3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p.polygons.size()==0) err = true;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Will return an empty geometry if the import failed, but not NULL
|
Create a new Geometry from the data in the file at this->filename.
|
||||||
|
Will return an empty geometry if the import failed, but not NULL.
|
||||||
|
The file will be closed before this function returns.
|
||||||
|
The caller is responsible for freeing the new Geometry memory.
|
||||||
*/
|
*/
|
||||||
Geometry *ImportNode::createGeometry() const
|
Geometry *ImportNode::createGeometry() const
|
||||||
{
|
{
|
||||||
Geometry *g = NULL;
|
Geometry *g = NULL;
|
||||||
|
bool err = false;
|
||||||
|
PolySet *p = NULL;
|
||||||
|
|
||||||
|
if (this->type & (TYPE_STL|TYPE_OFF|TYPE_OBJ)) {
|
||||||
|
p = new PolySet(3);
|
||||||
|
handle_dep((std::string)this->filename);
|
||||||
|
}
|
||||||
|
|
||||||
switch (this->type) {
|
switch (this->type) {
|
||||||
case TYPE_STL: {
|
case TYPE_STL: {
|
||||||
PolySet *p = new PolySet(3);
|
|
||||||
g = p;
|
|
||||||
|
|
||||||
handle_dep((std::string)this->filename);
|
|
||||||
// Open file and position at the end
|
// Open file and position at the end
|
||||||
std::ifstream f(this->filename.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
|
std::ifstream f(this->filename.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
|
||||||
if (!f.good()) {
|
if (!(err=f.bad())) err = createPolySetFromSTL( f, *p );
|
||||||
PRINTB("WARNING: Can't open import file '%s'.", this->filename);
|
else PRINTB("WARNING: Can't open import file '%s'.", this->filename);
|
||||||
return g;
|
f.close();
|
||||||
}
|
|
||||||
|
|
||||||
boost::regex ex_sfe("solid|facet|endloop");
|
|
||||||
boost::regex ex_outer("outer loop");
|
|
||||||
boost::regex ex_vertex("vertex");
|
|
||||||
boost::regex ex_vertices("\\s*vertex\\s+([^\\s]+)\\s+([^\\s]+)\\s+([^\\s]+)");
|
|
||||||
|
|
||||||
bool binary = false;
|
|
||||||
std::streampos file_size = f.tellg();
|
|
||||||
f.seekg(80);
|
|
||||||
if (!f.eof()) {
|
|
||||||
uint32_t facenum = 0;
|
|
||||||
f.read((char *)&facenum, sizeof(uint32_t));
|
|
||||||
#ifdef BOOST_BIG_ENDIAN
|
|
||||||
uint32_byte_swap( facenum );
|
|
||||||
#endif
|
|
||||||
if (file_size == static_cast<std::streamoff>(80 + 4 + 50*facenum)) {
|
|
||||||
binary = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.seekg(0);
|
|
||||||
|
|
||||||
char data[5];
|
|
||||||
f.read(data, 5);
|
|
||||||
if (!binary && !f.eof() && !memcmp(data, "solid", 5)) {
|
|
||||||
int i = 0;
|
|
||||||
double vdata[3][3];
|
|
||||||
std::string line;
|
|
||||||
std::getline(f, line);
|
|
||||||
while (!f.eof()) {
|
|
||||||
|
|
||||||
std::getline(f, line);
|
|
||||||
boost::trim(line);
|
|
||||||
if (boost::regex_search(line, ex_sfe)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (boost::regex_search(line, ex_outer)) {
|
|
||||||
i = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
boost::smatch results;
|
|
||||||
if (boost::regex_search(line, results, ex_vertices)) {
|
|
||||||
try {
|
|
||||||
for (int v=0;v<3;v++) {
|
|
||||||
vdata[i][v] = boost::lexical_cast<double>(results[v+1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (const boost::bad_lexical_cast &blc) {
|
|
||||||
PRINTB("WARNING: Can't parse vertex line '%s'.", line);
|
|
||||||
i = 10;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (++i == 3) {
|
|
||||||
p->append_poly();
|
|
||||||
p->append_vertex(vdata[0][0], vdata[0][1], vdata[0][2]);
|
|
||||||
p->append_vertex(vdata[1][0], vdata[1][1], vdata[1][2]);
|
|
||||||
p->append_vertex(vdata[2][0], vdata[2][1], vdata[2][2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
f.ignore(80-5+4);
|
|
||||||
while (1) {
|
|
||||||
stl_facet facet;
|
|
||||||
read_stl_facet( f, facet );
|
|
||||||
if (f.eof()) break;
|
|
||||||
p->append_poly();
|
|
||||||
p->append_vertex(facet.data.x1, facet.data.y1, facet.data.z1);
|
|
||||||
p->append_vertex(facet.data.x2, facet.data.y2, facet.data.z2);
|
|
||||||
p->append_vertex(facet.data.x3, facet.data.y3, facet.data.z3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TYPE_OFF: {
|
case TYPE_OFF: {
|
||||||
PolySet *p = new PolySet(3);
|
bool try_polyset_read = true;
|
||||||
g = p;
|
#ifdef ENABLE_CGAL // we try CGAL read first, if it fails, we use polyset read
|
||||||
#ifdef ENABLE_CGAL
|
|
||||||
CGAL_Polyhedron poly;
|
|
||||||
std::ifstream file(this->filename.c_str(), std::ios::in | std::ios::binary);
|
std::ifstream file(this->filename.c_str(), std::ios::in | std::ios::binary);
|
||||||
if (!file.good()) {
|
if (!(err=file.bad())) {
|
||||||
PRINTB("WARNING: Can't open import file '%s'.", this->filename);
|
CGAL_Polyhedron poly;
|
||||||
|
file >> poly;
|
||||||
|
if (poly.size_of_vertices()==0) {
|
||||||
|
PRINTDB("CGAL import of %s failed. Attempting PolySet import.", filename);
|
||||||
|
} else {
|
||||||
|
err = createPolySetFromPolyhedron(poly, *p);
|
||||||
|
if (!err) try_polyset_read = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
file >> poly;
|
PRINTB("WARNING: Can't open import file '%s'.", this->filename);
|
||||||
file.close();
|
}
|
||||||
|
file.close();
|
||||||
bool err = createPolySetFromPolyhedron(poly, *p);
|
#endif // ENABLE_CGAL
|
||||||
|
if (try_polyset_read) {
|
||||||
|
std::ifstream file(this->filename.c_str(), std::ios::in | std::ios::binary);
|
||||||
|
if (!(err=file.bad())) err = createPolySetFromOFF( file, *p );
|
||||||
|
else PRINTB("WARNING: Can't open import file '%s'.", this->filename);
|
||||||
|
file.close();
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
PRINT("WARNING: OFF import requires CGAL.");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TYPE_DXF: {
|
case TYPE_DXF: {
|
||||||
|
@ -301,11 +444,30 @@ Geometry *ImportNode::createGeometry() const
|
||||||
g = dd.toPolygon2d();
|
g = dd.toPolygon2d();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case TYPE_OBJ: {
|
||||||
|
std::ifstream file(this->filename.c_str(), std::ios::in | std::ios::binary);
|
||||||
|
if (!(err=file.bad())) err = createPolySetFromOBJ( file, *p );
|
||||||
|
else PRINTB("WARNING: Can't open import file '%s'.", this->filename);
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
PRINTB("ERROR: Unsupported file format while trying to import file '%s'", this->filename);
|
PRINTB("ERROR: Unsupported file format while trying to import file '%s'", this->filename);
|
||||||
g = new PolySet(0);
|
g = new PolySet(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this->type & (TYPE_STL|TYPE_OFF|TYPE_OBJ)) {
|
||||||
|
if (err) {
|
||||||
|
PRINTB("WARNING: Import of %s failed",this->filename);
|
||||||
|
p->polygons.clear();
|
||||||
|
} else if (this->center) {
|
||||||
|
center_polyset(*p);
|
||||||
|
}
|
||||||
|
if (OpenSCAD::debug!="")
|
||||||
|
PRINTDB("imported polyset:\n %s \n-----.", p->dump());
|
||||||
|
g = p;
|
||||||
|
}
|
||||||
|
|
||||||
if (g) g->setConvexity(this->convexity);
|
if (g) g->setConvexity(this->convexity);
|
||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,8 @@ enum import_type_e {
|
||||||
TYPE_UNKNOWN,
|
TYPE_UNKNOWN,
|
||||||
TYPE_STL,
|
TYPE_STL,
|
||||||
TYPE_OFF,
|
TYPE_OFF,
|
||||||
TYPE_DXF
|
TYPE_DXF,
|
||||||
|
TYPE_OBJ
|
||||||
};
|
};
|
||||||
|
|
||||||
class ImportNode : public LeafNode
|
class ImportNode : public LeafNode
|
||||||
|
|
|
@ -493,7 +493,7 @@ MainWindow::openFile(const QString &new_filename)
|
||||||
{
|
{
|
||||||
QString actual_filename = new_filename;
|
QString actual_filename = new_filename;
|
||||||
QFileInfo fi(new_filename);
|
QFileInfo fi(new_filename);
|
||||||
if (fi.suffix().toLower().contains(QRegExp("^(stl|off|dxf)$"))) {
|
if (fi.suffix().toLower().contains(QRegExp("^(stl|off|dxf|obj)$"))) {
|
||||||
actual_filename = QString();
|
actual_filename = QString();
|
||||||
}
|
}
|
||||||
#ifdef ENABLE_MDI
|
#ifdef ENABLE_MDI
|
||||||
|
|
|
@ -199,8 +199,8 @@ namespace PolysetUtils {
|
||||||
triangles.push_back( pgon );
|
triangles.push_back( pgon );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (const CGAL::Assertion_exception &e) {
|
} catch (const CGAL::Failure_exception &e) {
|
||||||
PRINTB("CGAL error in dxftess triangulate_polygon: %s", e.what());
|
PRINTB("CGAL error while triangulating polygon: %s", e.what());
|
||||||
err = true;
|
err = true;
|
||||||
}
|
}
|
||||||
CGAL::set_error_behaviour(old_behaviour);
|
CGAL::set_error_behaviour(old_behaviour);
|
||||||
|
|
|
@ -22,7 +22,6 @@ void PRINT(const std::string &msg);
|
||||||
void PRINT_NOCACHE(const std::string &msg);
|
void PRINT_NOCACHE(const std::string &msg);
|
||||||
#define PRINTB_NOCACHE(_fmt, _arg) do { PRINT_NOCACHE(str(boost::format(_fmt) % _arg)); } while (0)
|
#define PRINTB_NOCACHE(_fmt, _arg) do { PRINT_NOCACHE(str(boost::format(_fmt) % _arg)); } while (0)
|
||||||
|
|
||||||
|
|
||||||
void PRINT_CONTEXT(const class Context *ctx, const class Module *mod, const class ModuleInstantiation *inst);
|
void PRINT_CONTEXT(const class Context *ctx, const class Module *mod, const class ModuleInstantiation *inst);
|
||||||
|
|
||||||
std::string two_digit_exp_format( std::string doublestr );
|
std::string two_digit_exp_format( std::string doublestr );
|
||||||
|
|
|
@ -842,6 +842,7 @@ list(APPEND CGALPNGTEST_FILES ${FEATURES_FILES} ${SCAD_DXF_FILES} ${EXAMPLE_FILE
|
||||||
list(APPEND CGALPNGTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/include-tests.scad
|
list(APPEND CGALPNGTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/include-tests.scad
|
||||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/use-tests.scad
|
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/use-tests.scad
|
||||||
${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/transform-nan-inf-tests.scad
|
${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/transform-nan-inf-tests.scad
|
||||||
|
${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/unreadable_by_cgal_off.scad
|
||||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles-test.scad
|
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles-test.scad
|
||||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles_dir/localfiles-compatibility-test.scad
|
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles_dir/localfiles-compatibility-test.scad
|
||||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/rotate-empty-bbox.scad
|
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/rotate-empty-bbox.scad
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 5.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
Loading…
Reference in New Issue