diff --git a/src/Mod/Import/App/AppImportPy.cpp b/src/Mod/Import/App/AppImportPy.cpp index 0ee60c56b6..508edf87e7 100644 --- a/src/Mod/Import/App/AppImportPy.cpp +++ b/src/Mod/Import/App/AppImportPy.cpp @@ -66,6 +66,10 @@ #include #include #include +#include +#include + +#include "ImpExpDxf.h" namespace Import { class Module : public Py::ExtensionModule @@ -85,7 +89,13 @@ public: add_varargs_method("export",&Module::exporter, "export(list,string) -- Export a list of objects into a single file." ); - initialize("This module is the Import module."); // register with Python + add_varargs_method("readDXF",&Module::readDXF, + "readDXF(filename,[document,ignore_errors]): Imports a DXF file into the given document. ignore_errors is True by default." + ); + add_varargs_method("writeDXFShape",&Module::writeDXFShape, + "writeDXFShape(shape,filename): Exports a Shape to a DXF file." + ); + initialize("This module is the Import module."); // register with Python } virtual ~Module() {} @@ -313,6 +323,74 @@ private: return Py::None(); } + + Py::Object readDXF(const Py::Tuple& args) + { + char* Name; + const char* DocName=0; + bool IgnoreErrors=true; + if (!PyArg_ParseTuple(args.ptr(), "et|sb","utf-8",&Name,&DocName,&IgnoreErrors)) + throw Py::Exception(); + + std::string EncodedName = std::string(Name); + PyMem_Free(Name); + + Base::FileInfo file(EncodedName.c_str()); + if (!file.exists()) + throw Py::RuntimeError("File doesn't exist"); + + App::Document *pcDoc; + if (DocName) + pcDoc = App::GetApplication().getDocument(DocName); + else + pcDoc = App::GetApplication().getActiveDocument(); + if (!pcDoc) + pcDoc = App::GetApplication().newDocument(DocName); + + try { + // read the DXF file + ImpExpDxfRead dxf_file(EncodedName,pcDoc); + //dxf_file.setOptionSource("myoptionpath"); + //dxf_file.setOptions(); + dxf_file.DoRead(IgnoreErrors); + pcDoc->recompute(); + } + catch (const Base::Exception& e) { + throw Py::RuntimeError(e.what()); + } + return Py::None(); + } + + Py::Object writeDXFShape(const Py::Tuple& args) + { + PyObject *shapeObj; + char* name; + if (!PyArg_ParseTuple(args.ptr(), "Oet", &shapeObj, "utf-8",&name)) { + throw Py::Exception("expected (Page,path"); + } + + std::string filePath = std::string(name); + std::string layerName = "none"; + PyMem_Free(name); + try { + ImpExpDxfWrite writer(filePath); + //writer.setOptionSource("myoptionpath"); + //writer.setOptions(); + writer.setLayerName(layerName); + if (PyObject_TypeCheck(shapeObj, &(Part::TopoShapePy::Type))) { + Part::TopoShape* obj = static_cast(shapeObj)->getTopoShapePtr(); + TopoDS_Shape shape = obj->getShape(); + writer.exportShape(shape); + } + } + catch (const Base::Exception& e) { + throw Py::RuntimeError(e.what()); + } + + return Py::None(); + } + + }; /* static PyObject * importAssembly(PyObject *self, PyObject *args) diff --git a/src/Mod/Import/App/CMakeLists.txt b/src/Mod/Import/App/CMakeLists.txt index 85b5b4370e..1e88146fa5 100644 --- a/src/Mod/Import/App/CMakeLists.txt +++ b/src/Mod/Import/App/CMakeLists.txt @@ -37,6 +37,10 @@ SET(Import_SRCS StepShapePyImp.cpp PreCompiled.cpp PreCompiled.h + ImpExpDxf.cpp + ImpExpDxf.h + dxf.cpp + dxf.h ) SET(SCL_Resources diff --git a/src/Mod/Import/App/ImpExpDxf.cpp b/src/Mod/Import/App/ImpExpDxf.cpp new file mode 100644 index 0000000000..18c8c24db6 --- /dev/null +++ b/src/Mod/Import/App/ImpExpDxf.cpp @@ -0,0 +1,593 @@ +/*************************************************************************** + * Copyright (c) Yorik van Havre (yorik@uncreated.net) 2015 * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" + +#ifndef _PreComp_ +#endif + +#include "ImpExpDxf.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Import; + + +//****************************************************************************** +// reading +ImpExpDxfRead::ImpExpDxfRead(std::string filepath, App::Document *pcDoc) : CDxfRead(filepath.c_str()) +{ + document = pcDoc; + setOptionSource("User parameter:BaseApp/Preferences/Mod/Draft"); + setOptions(); +// ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Draft"); +// optionGroupLayers = hGrp->GetBool("groupLayers",false); +// optionImportAnnotations = hGrp->GetBool("dxftext",false); +// optionScaling = hGrp->GetFloat("dxfScaling",1.0); +} + +void ImpExpDxfRead::setOptions(void) +{ + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(getOptionSource().c_str()); + optionGroupLayers = hGrp->GetBool("groupLayers",false); + optionImportAnnotations = hGrp->GetBool("dxftext",false); + optionScaling = hGrp->GetFloat("dxfScaling",1.0); +} + +gp_Pnt ImpExpDxfRead::makePoint(const double* p) +{ + double sp1(p[0]); + double sp2(p[1]); + double sp3(p[2]); + if (optionScaling != 1.0) { + sp1 = sp1 * optionScaling; + sp2 = sp2 * optionScaling; + sp3 = sp3 * optionScaling; + } + return gp_Pnt(sp1,sp2,sp3); +} + +void ImpExpDxfRead::OnReadLine(const double* s, const double* e, bool /*hidden*/) +{ + gp_Pnt p0 = makePoint(s); + gp_Pnt p1 = makePoint(e); + if (p0.IsEqual(p1,0.00000001)) + return; + BRepBuilderAPI_MakeEdge makeEdge(p0, p1); + TopoDS_Edge edge = makeEdge.Edge(); + AddObject(new Part::TopoShape(edge)); +} + + +void ImpExpDxfRead::OnReadPoint(const double* s) +{ + BRepBuilderAPI_MakeVertex makeVertex(makePoint(s)); + TopoDS_Vertex vertex = makeVertex.Vertex(); + AddObject(new Part::TopoShape(vertex)); +} + + +void ImpExpDxfRead::OnReadArc(const double* s, const double* e, const double* c, bool dir, bool /*hidden*/) +{ + gp_Pnt p0 = makePoint(s); + gp_Pnt p1 = makePoint(e); + gp_Dir up(0, 0, 1); + if (!dir) + up = -up; + gp_Pnt pc = makePoint(c); + gp_Circ circle(gp_Ax2(pc, up), p0.Distance(pc)); + BRepBuilderAPI_MakeEdge makeEdge(circle, p0, p1); + TopoDS_Edge edge = makeEdge.Edge(); + AddObject(new Part::TopoShape(edge)); +} + + +void ImpExpDxfRead::OnReadCircle(const double* s, const double* c, bool dir, bool /*hidden*/) +{ + gp_Pnt p0 = makePoint(s); + gp_Dir up(0, 0, 1); + if (!dir) + up = -up; + gp_Pnt pc = makePoint(c); + gp_Circ circle(gp_Ax2(pc, up), p0.Distance(pc)); + BRepBuilderAPI_MakeEdge makeEdge(circle); + TopoDS_Edge edge = makeEdge.Edge(); + AddObject(new Part::TopoShape(edge)); +} + + +void ImpExpDxfRead::OnReadSpline(struct SplineData& /*sd*/) +{ + // not yet implemented +} + + +void ImpExpDxfRead::OnReadEllipse(const double* c, double major_radius, double minor_radius, double rotation, double /*start_angle*/, double /*end_angle*/, bool dir) +{ + gp_Dir up(0, 0, 1); + if(!dir) + up = -up; + gp_Pnt pc = makePoint(c); + gp_Elips ellipse(gp_Ax2(pc, up), major_radius * optionScaling, minor_radius * optionScaling); + ellipse.Rotate(gp_Ax1(pc,up),rotation); + BRepBuilderAPI_MakeEdge makeEdge(ellipse); + TopoDS_Edge edge = makeEdge.Edge(); + AddObject(new Part::TopoShape(edge)); +} + + +void ImpExpDxfRead::OnReadText(const double *point, const double /*height*/, const char* text) +{ + if (optionImportAnnotations) { + Base::Vector3d pt(point[0] * optionScaling, point[1] * optionScaling, point[2] * optionScaling); + if(LayerName().substr(0, 6) != "BLOCKS") { + App::Annotation *pcFeature = (App::Annotation *)document->addObject("App::Annotation", "Text"); + pcFeature->LabelText.setValue(Deformat(text)); + pcFeature->Position.setValue(pt); + } + //else std::cout << "skipped text in block: " << LayerName() << std::endl; + } +} + + +void ImpExpDxfRead::OnReadInsert(const double* point, const double* scale, const char* name, double rotation) +{ + //std::cout << "Inserting block " << name << " rotation " << rotation << " pos " << point[0] << "," << point[1] << "," << point[2] << " scale " << scale[0] << "," << scale[1] << "," << scale[2] << std::endl; + std::string prefix = "BLOCKS "; + prefix += name; + prefix += " "; + for(std::map > ::const_iterator i = layers.begin(); i != layers.end(); ++i) { + std::string k = i->first; + if(k.substr(0, prefix.size()) == prefix) { + BRep_Builder builder; + TopoDS_Compound comp; + builder.MakeCompound(comp); + std::vector v = i->second; + for(std::vector::const_iterator j = v.begin(); j != v.end(); ++j) { + const TopoDS_Shape& sh = (*j)->getShape(); + if (!sh.IsNull()) + builder.Add(comp, sh); + } + if (!comp.IsNull()) { + Part::TopoShape* pcomp = new Part::TopoShape(comp); + Base::Matrix4D mat; + mat.scale(scale[0],scale[1],scale[2]); + mat.rotZ(rotation); + mat.move(point[0]*optionScaling,point[1]*optionScaling,point[2]*optionScaling); + pcomp->transformShape(mat,true); + AddObject(pcomp); + } + } + } +} + + +void ImpExpDxfRead::OnReadDimension(const double* s, const double* e, const double* point, double /*rotation*/) +{ + if (optionImportAnnotations) { + Base::Interpreter().runString("import Draft"); + Base::Interpreter().runStringArg("p1=FreeCAD.Vector(%f,%f,%f)",s[0]*optionScaling,s[1]*optionScaling,s[2]*optionScaling); + Base::Interpreter().runStringArg("p2=FreeCAD.Vector(%f,%f,%f)",e[0]*optionScaling,e[1]*optionScaling,e[2]*optionScaling); + Base::Interpreter().runStringArg("p3=FreeCAD.Vector(%f,%f,%f)",point[0]*optionScaling,point[1]*optionScaling,point[2]*optionScaling); + Base::Interpreter().runString("Draft.makeDimension(p1,p2,p3)"); + } +} + + +void ImpExpDxfRead::AddObject(Part::TopoShape *shape) +{ + //std::cout << "layer:" << LayerName() << std::endl; + std::vector vec; + if (layers.count(LayerName())) + vec = layers[LayerName()]; + vec.push_back(shape); + layers[LayerName()] = vec; + if (!optionGroupLayers) { + if(LayerName().substr(0, 6) != "BLOCKS") { + Part::Feature *pcFeature = (Part::Feature *)document->addObject("Part::Feature", "Shape"); + pcFeature->Shape.setValue(shape->getShape()); + } + } +} + + +std::string ImpExpDxfRead::Deformat(const char* text) +{ + // this function removes DXF formatting from texts + std::stringstream ss; + bool escape = false; // turned on when finding an escape character + bool longescape = false; // turned on for certain escape codes that expect additional chars + for(unsigned int i = 0; i > ::const_iterator i = layers.begin(); i != layers.end(); ++i) { + BRep_Builder builder; + TopoDS_Compound comp; + builder.MakeCompound(comp); + std::string k = i->first; + if (k == "0") // FreeCAD doesn't like an object name being '0'... + k = "LAYER_0"; + std::vector v = i->second; + if(k.substr(0, 6) != "BLOCKS") { + for(std::vector::const_iterator j = v.begin(); j != v.end(); ++j) { + const TopoDS_Shape& sh = (*j)->getShape(); + if (!sh.IsNull()) + builder.Add(comp, sh); + } + if (!comp.IsNull()) { + Part::Feature *pcFeature = (Part::Feature *)document->addObject("Part::Feature", k.c_str()); + pcFeature->Shape.setValue(comp); + } + } + } + } +} + +//****************************************************************************** +// writing + +void gPntToTuple(double* result, gp_Pnt& p) +{ + result[0] = p.X(); + result[1] = p.Y(); + result[2] = p.Z(); +} + +point3D gPntTopoint3D(gp_Pnt& p) +{ + point3D result; + result.x = p.X(); + result.y = p.Y(); + result.z = p.Z(); + return result; +} + +ImpExpDxfWrite::ImpExpDxfWrite(std::string filepath) : + CDxfWrite(filepath.c_str()), + m_layerName("none") +{ + setOptionSource("User parameter:BaseApp/Preferences/Mod/Draft"); + setOptions(); +} + +void ImpExpDxfWrite::setOptions(void) +{ + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Draft"); + optionMaxLength = hGrp->GetFloat("maxsegmentlength",5.0); + optionPolyLine = hGrp->GetBool("DiscretizeEllipses",true); +} + +void ImpExpDxfWrite::exportShape(const TopoDS_Shape input) +{ + //export Edges + TopExp_Explorer edges(input, TopAbs_EDGE); + for (int i = 1 ; edges.More(); edges.Next(),i++) { + const TopoDS_Edge& edge = TopoDS::Edge(edges.Current()); + BRepAdaptor_Curve adapt(edge); + if (adapt.GetType() == GeomAbs_Circle) { + double f = adapt.FirstParameter(); + double l = adapt.LastParameter(); + gp_Pnt s = adapt.Value(f); + gp_Pnt e = adapt.Value(l); + if (fabs(l-f) > 1.0 && s.SquareDistance(e) < 0.001) { + exportCircle(adapt); + } else { + exportArc(adapt); + } + } else if (adapt.GetType() == GeomAbs_Ellipse) { + double f = adapt.FirstParameter(); + double l = adapt.LastParameter(); + gp_Pnt s = adapt.Value(f); + gp_Pnt e = adapt.Value(l); + if (fabs(l-f) > 1.0 && s.SquareDistance(e) < 0.001) { + exportEllipse(adapt); + } else { + exportEllipseArc(adapt); + } + + } else if (adapt.GetType() == GeomAbs_BSplineCurve) { + if (optionPolyLine) { + exportLWPoly(adapt); + } else { + exportBSpline(adapt); + } + } else if (adapt.GetType() == GeomAbs_BezierCurve) { + exportBCurve(adapt); + } else if (adapt.GetType() == GeomAbs_Line) { + exportLine(adapt); + } else { + Base::Console().Warning("ImpExpDxf - unknown curve type: %d\n",adapt.GetType()); + } + } + + //export Vertices +// TopExp_Explorer verts(input, TopAbs_VERTEX); +// for (int i = 1 ; verts.More(); verts.Next(),i++) { +// const TopoDS_Vertex& v = TopoDS::Vertex(verts.Current()); + +// } +} + +void ImpExpDxfWrite::exportCircle(BRepAdaptor_Curve c) +{ + gp_Circ circ = c.Circle(); + gp_Pnt p = circ.Location(); + double center[3] = {0,0,0}; + gPntToTuple(center, p); + + double radius = circ.Radius(); + + WriteCircle(center, radius, getLayerName().c_str()); +} + +void ImpExpDxfWrite::exportEllipse(BRepAdaptor_Curve c) +{ + gp_Elips ellp = c.Ellipse(); + gp_Pnt p = ellp.Location(); + double center[3] = {0,0,0}; + gPntToTuple(center, p); + + double major = ellp.MajorRadius(); + double minor = ellp.MinorRadius(); + + gp_Dir xaxis = ellp.XAxis().Direction(); //direction of major axis + //rotation appears to be the clockwise(?) angle between major & +Y?? + double rotation = xaxis.AngleWithRef(gp_Dir(0, 1, 0), gp_Dir(0, 0, 1)); + + //2*M_PI = 6.28319 is invalid(doesn't display in LibreCAD), but 2PI = 6.28318 is valid! + //WriteEllipse(center, major, minor, rotation, 0.0, 2 * M_PI, true, getLayerName().c_str() ); + WriteEllipse(center, major, minor, rotation, 0.0, 6.28318, true, getLayerName().c_str() ); +} + +void ImpExpDxfWrite::exportArc(BRepAdaptor_Curve c) +{ + gp_Circ circ = c.Circle(); + gp_Pnt p = circ.Location(); + double center[3] = {0,0,0}; + gPntToTuple(center, p); + + double f = c.FirstParameter(); + double l = c.LastParameter(); + gp_Pnt s = c.Value(f); + double start[3]; + gPntToTuple(start, s); + gp_Pnt m = c.Value((l+f)/2.0); + gp_Pnt e = c.Value(l); + double end[3] = {0,0,0}; + gPntToTuple(end, e); + + gp_Vec v1(m,s); + gp_Vec v2(m,e); + gp_Vec v3(0,0,1); + double a = v3.DotCross(v1,v2); + + bool dir = (a < 0) ? true: false; + WriteArc(start, end, center, dir, getLayerName().c_str() ); +} + +void ImpExpDxfWrite::exportEllipseArc(BRepAdaptor_Curve c) +{ + gp_Elips ellp = c.Ellipse(); + gp_Pnt p = ellp.Location(); + double center[3] = {0,0,0}; + gPntToTuple(center, p); + + double major = ellp.MajorRadius(); + double minor = ellp.MinorRadius(); + + gp_Dir xaxis = ellp.XAxis().Direction(); //direction of major axis + //rotation appears to be the clockwise angle between major & +Y?? + double rotation = xaxis.AngleWithRef(gp_Dir(0, 1, 0), gp_Dir(0, 0, 1)); + + double f = c.FirstParameter(); + double l = c.LastParameter(); + gp_Pnt s = c.Value(f); + gp_Pnt m = c.Value((l+f)/2.0); + gp_Pnt e = c.Value(l); + + gp_Vec v1(m,s); + gp_Vec v2(m,e); + gp_Vec v3(0,0,1); + double a = v3.DotCross(v1,v2); + + double startAngle = fmod(f,2.0*M_PI); + double endAngle = fmod(l,2.0*M_PI); + bool dir = (a < 0) ? true: false; + + WriteEllipse(center, major, minor, rotation, startAngle, endAngle, dir, getLayerName().c_str() ); +} + +void ImpExpDxfWrite::exportBSpline(BRepAdaptor_Curve c) +{ + SplineDataOut sd; + Handle(Geom_BSplineCurve) spline; + double f,l; + gp_Pnt s,ePt; + + Standard_Real tol3D = 0.001; + Standard_Integer maxDegree = 3, maxSegment = 100; + Handle(BRepAdaptor_HCurve) hCurve = new BRepAdaptor_HCurve(c); + Approx_Curve3d approx(hCurve, tol3D, GeomAbs_C0, maxSegment, maxDegree); + if (approx.IsDone() && approx.HasResult()) { + spline = approx.Curve(); + } else { + if (approx.HasResult()) { //result, but not within tolerance + spline = approx.Curve(); + Base::Console().Message("DxfWrite::exportBSpline - result not within tolerance\n"); + } else { + f = c.FirstParameter(); + l = c.LastParameter(); + s = c.Value(f); + ePt = c.Value(l); + Base::Console().Message("DxfWrite::exportBSpline - no result- from:(%.3f,%.3f) to:(%.3f,%.3f) poles: %d\n", + s.X(),s.Y(),ePt.X(),ePt.Y(),spline->NbPoles()); + TColgp_Array1OfPnt controlPoints(0,1); + controlPoints.SetValue(0,s); + controlPoints.SetValue(1,ePt); + spline = GeomAPI_PointsToBSpline(controlPoints,1).Curve(); + } + } + //WF? norm of surface containing curve?? + sd.norm.x = 0.0; + sd.norm.y = 0.0; + sd.norm.z = 1.0; + + sd.flag = spline->IsClosed(); + sd.flag += spline->IsPeriodic()*2; + sd.flag += spline->IsRational()*4; + + sd.degree = spline->Degree(); + sd.control_points = spline->NbPoles(); + sd.knots = spline->NbKnots(); + gp_Pnt p; + spline->D0(spline->FirstParameter(),p); + sd.starttan = gPntTopoint3D(p); + spline->D0(spline->LastParameter(),p); + sd.endtan = gPntTopoint3D(p); + + TColStd_Array1OfReal knotsequence(1,sd.knots); + spline->KnotSequence(knotsequence); + for (int i = knotsequence.Lower() ; i <= knotsequence.Upper(); i++) { + sd.knot.push_back(knotsequence(i)); + } + TColgp_Array1OfPnt poles(1,spline->NbPoles()); + spline->Poles(poles); + for (int i = poles.Lower(); i <= poles.Upper(); i++) { + sd.control.push_back(gPntTopoint3D(poles(i))); + } + //OCC doesn't have separate lists for control points and fit points. + + WriteSpline(sd,getLayerName().c_str()); +} + +void ImpExpDxfWrite::exportBCurve(BRepAdaptor_Curve c) +{ + (void) c; + Base::Console().Message("BCurve dxf export not yet supported\n"); +} + +void ImpExpDxfWrite::exportLine(BRepAdaptor_Curve c) +{ + double f = c.FirstParameter(); + double l = c.LastParameter(); + gp_Pnt s = c.Value(f); + double start[3] = {0,0,0}; + gPntToTuple(start, s); + gp_Pnt e = c.Value(l); + double end[3] = {0,0,0}; + gPntToTuple(end, e); + WriteLine(start, end, getLayerName().c_str()); +} + +void ImpExpDxfWrite::exportLWPoly(BRepAdaptor_Curve c) +{ + LWPolyDataOut pd; + pd.Flag = c.IsClosed(); + pd.Elev = 0.0; + pd.Thick = 0.0; + pd.Extr.x = 0.0; + pd.Extr.y = 0.0; + pd.Extr.z = 1.0; + + GCPnts_UniformAbscissa discretizer; + discretizer.Initialize (c, optionMaxLength); + std::vector points; + if (discretizer.IsDone () && discretizer.NbPoints () > 0) { + int nbPoints = discretizer.NbPoints (); + for (int i=1; i<=nbPoints; i++) { + gp_Pnt p = c.Value (discretizer.Parameter (i)); + pd.Verts.push_back(gPntTopoint3D(p)); + } + WriteLWPolyLine(pd,getLayerName().c_str()); + } +} + + diff --git a/src/Mod/Import/App/ImpExpDxf.h b/src/Mod/Import/App/ImpExpDxf.h new file mode 100644 index 0000000000..8261aacd32 --- /dev/null +++ b/src/Mod/Import/App/ImpExpDxf.h @@ -0,0 +1,101 @@ +/*************************************************************************** + * Copyright (c) Yorik van Havre (yorik@uncreated.net) 2015 * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef IMPEXPDXF_H +#define IMPEXPDXF_H + +#include "dxf.h" +#include +#include +#include + +class BRepAdaptor_Curve; + +namespace Import +{ + class ImportExport ImpExpDxfRead : public CDxfRead + { + public: + ImpExpDxfRead(std::string filepath, App::Document *pcDoc); + + // CDxfRead's virtual functions + void OnReadLine(const double* s, const double* e, bool hidden); + void OnReadPoint(const double* s); + void OnReadText(const double* point, const double height, const char* text); + void OnReadArc(const double* s, const double* e, const double* c, bool dir, bool hidden); + void OnReadCircle(const double* s, const double* c, bool dir, bool hidden); + void OnReadEllipse(const double* c, double major_radius, double minor_radius, double rotation, double start_angle, double end_angle, bool dir); + void OnReadSpline(struct SplineData& sd); + void OnReadInsert(const double* point, const double* scale, const char* name, double rotation); + void OnReadDimension(const double* s, const double* e, const double* point, double rotation); + void AddGraphics() const; + + // FreeCAD-specific functions + void AddObject(Part::TopoShape *shape); //Called by OnRead functions to add Part objects + std::string Deformat(const char* text); // Removes DXF formatting from texts + + std::string getOptionSource() { return m_optionSource; } + void setOptionSource(std::string s) { m_optionSource = s; } + void setOptions(void); + + private: + gp_Pnt makePoint(const double* p); + + protected: + App::Document *document; + bool optionGroupLayers; + bool optionImportAnnotations; + double optionScaling; + std::map > layers; + std::string m_optionSource; + }; + + class ImportExport ImpExpDxfWrite : public CDxfWrite + { + public: + ImpExpDxfWrite(std::string filepath); + + void exportShape(const TopoDS_Shape input); + std::string getLayerName() { return m_layerName; } + void setLayerName(std::string s) { m_layerName = s; } + std::string getOptionSource() { return m_optionSource; } + void setOptionSource(std::string s) { m_optionSource = s; } + void setOptions(void); + + protected: + void exportCircle(BRepAdaptor_Curve c); + void exportEllipse(BRepAdaptor_Curve c); + void exportArc(BRepAdaptor_Curve c); + void exportEllipseArc(BRepAdaptor_Curve c); + void exportBSpline(BRepAdaptor_Curve c); + void exportBCurve(BRepAdaptor_Curve c); + void exportLine(BRepAdaptor_Curve c); + void exportLWPoly(BRepAdaptor_Curve c); + std::string m_layerName; + std::string m_optionSource; + double optionMaxLength; + bool optionPolyLine; + }; + +} + +#endif // IMPEXPDXF_H diff --git a/src/Mod/Import/App/dxf.cpp b/src/Mod/Import/App/dxf.cpp new file mode 100644 index 0000000000..85efc9af22 --- /dev/null +++ b/src/Mod/Import/App/dxf.cpp @@ -0,0 +1,1973 @@ +// dxf.cpp +// Copyright (c) 2009, Dan Heeks +// This program is released under the BSD license. See the file COPYING for details. +// modified 2018 wandererfan + +#include "dxf.h" + +using namespace std; +static const double Pi = 3.14159265358979323846264338327950288419716939937511; + +CDxfWrite::CDxfWrite(const char* filepath) +{ + // start the file + m_fail = false; +#ifdef __WXMSW__ + m_ofs = new ofstream(filepath, ios::out); +#else + m_ofs = new ofstream(filepath, ios::out); +#endif + if(!(*m_ofs)){ + m_fail = true; + return; + } + m_ofs->imbue(std::locale("C")); + + // start + (*m_ofs) << 0 << endl; + (*m_ofs) << "SECTION" << endl; + (*m_ofs) << 2 << endl; + (*m_ofs) << "ENTITIES" << endl; +} + +CDxfWrite::~CDxfWrite() +{ + // end + (*m_ofs) << 0 << endl; + (*m_ofs) << "ENDSEC" << endl; + (*m_ofs) << 0 << endl; + (*m_ofs) << "EOF"; + + delete m_ofs; +} + +void CDxfWrite::WriteLine(const double* s, const double* e, const char* layer_name) +{ + (*m_ofs) << 0 << endl; + (*m_ofs) << "LINE" << endl; + (*m_ofs) << 8 << endl; // Group code for layer name + (*m_ofs) << layer_name << endl; // Layer number + (*m_ofs) << 10 << endl; // Start point of line + (*m_ofs) << s[0] << endl; // X in WCS coordinates + (*m_ofs) << 20 << endl; + (*m_ofs) << s[1] << endl; // Y in WCS coordinates + (*m_ofs) << 30 << endl; + (*m_ofs) << s[2] << endl; // Z in WCS coordinates + (*m_ofs) << 11 << endl; // End point of line + (*m_ofs) << e[0] << endl; // X in WCS coordinates + (*m_ofs) << 21 << endl; + (*m_ofs) << e[1] << endl; // Y in WCS coordinates + (*m_ofs) << 31 << endl; + (*m_ofs) << e[2] << endl; // Z in WCS coordinates +} + +//*************************** +//WriteLWPolyLine +//added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project +void CDxfWrite::WriteLWPolyLine(LWPolyDataOut pd, const char* layer_name) +{ + (*m_ofs) << 0 << endl; + (*m_ofs) << "LWPOLYLINE" << endl; + (*m_ofs) << 8 << endl; // Group code for layer name + (*m_ofs) << layer_name << endl; // Layer name + (*m_ofs) << 100 << endl; + (*m_ofs) << "AcDbPolyline" << endl; + (*m_ofs) << 90 << endl; + (*m_ofs) << pd.nVert << endl; // number of vertices + (*m_ofs) << 70 << endl; + (*m_ofs) << pd.Flag << endl; + (*m_ofs) << 43 << endl; + (*m_ofs) << pd.Width << endl; //Constant width opt + (*m_ofs) << 38 << endl; + (*m_ofs) << pd.Elev << endl; // Elevation + (*m_ofs) << 39 << endl; + (*m_ofs) << pd.Thick << endl; // Thickness + for (auto& p: pd.Verts) { + (*m_ofs) << 10 << endl; // Vertices + (*m_ofs) << p.x << endl; + (*m_ofs) << 20 << endl; + (*m_ofs) << p.y << endl; + } + for (auto& s: pd.StartWidth) { + (*m_ofs) << 40 << endl; + (*m_ofs) << s << endl; // Start Width + } + for (auto& e: pd.EndWidth) { + (*m_ofs) << 41 << endl; + (*m_ofs) << e << endl; // End Width + } + for (auto& b: pd.Bulge) { // Bulge + (*m_ofs) << 42 << endl; + (*m_ofs) << b << endl; + } + (*m_ofs) << 210 << endl; //Extrusion dir + (*m_ofs) << pd.Extr.x << endl; + (*m_ofs) << 220 << endl; + (*m_ofs) << pd.Extr.y << endl; + (*m_ofs) << 230 << endl; + (*m_ofs) << pd.Extr.z << endl; +} +void CDxfWrite::WritePoint(const double* s, const char* layer_name) +{ + (*m_ofs) << 0 << endl; + (*m_ofs) << "POINT" << endl; + (*m_ofs) << 8 << endl; // Group code for layer name + (*m_ofs) << layer_name << endl; // Layer number + (*m_ofs) << 10 << endl; // Start point of line + (*m_ofs) << s[0] << endl; // X in WCS coordinates + (*m_ofs) << 20 << endl; + (*m_ofs) << s[1] << endl; // Y in WCS coordinates + (*m_ofs) << 30 << endl; + (*m_ofs) << s[2] << endl; // Z in WCS coordinates +} + +void CDxfWrite::WriteArc(const double* s, const double* e, const double* c, bool dir, const char* layer_name) +{ + double ax = s[0] - c[0]; + double ay = s[1] - c[1]; + double bx = e[0] - c[0]; + double by = e[1] - c[1]; + + double start_angle = atan2(ay, ax) * 180/Pi; + double end_angle = atan2(by, bx) * 180/Pi; + double radius = sqrt(ax*ax + ay*ay); + if(!dir){ + double temp = start_angle; + start_angle = end_angle; + end_angle = temp; + } + (*m_ofs) << 0 << endl; + (*m_ofs) << "ARC" << endl; + (*m_ofs) << 8 << endl; // Group code for layer name + (*m_ofs) << layer_name << endl; // Layer number + (*m_ofs) << 10 << endl; // Centre X + (*m_ofs) << c[0] << endl; // X in WCS coordinates + (*m_ofs) << 20 << endl; + (*m_ofs) << c[1] << endl; // Y in WCS coordinates + (*m_ofs) << 30 << endl; + (*m_ofs) << c[2] << endl; // Z in WCS coordinates + (*m_ofs) << 40 << endl; // + (*m_ofs) << radius << endl; // Radius + (*m_ofs) << 50 << endl; + (*m_ofs) << start_angle << endl; // Start angle + (*m_ofs) << 51 << endl; + (*m_ofs) << end_angle << endl; // End angle +} + +void CDxfWrite::WriteCircle(const double* c, double radius, const char* layer_name) +{ + (*m_ofs) << 0 << endl; + (*m_ofs) << "CIRCLE" << endl; + (*m_ofs) << 8 << endl; // Group code for layer name + (*m_ofs) << layer_name << endl; // Layer number + (*m_ofs) << 10 << endl; // Centre X + (*m_ofs) << c[0] << endl; // X in WCS coordinates + (*m_ofs) << 20 << endl; + (*m_ofs) << c[1] << endl; // Y in WCS coordinates + (*m_ofs) << 30 << endl; + (*m_ofs) << c[2] << endl; // Z in WCS coordinates + (*m_ofs) << 40 << endl; // + (*m_ofs) << radius << endl; // Radius +} + +void CDxfWrite::WriteEllipse(const double* c, double major_radius, double minor_radius, double rotation, double start_angle, double end_angle, bool dir, const char* layer_name ) +{ + double m[3]; + m[2]=0; + m[0] = major_radius * sin(rotation); + m[1] = major_radius * cos(rotation); + + double ratio = minor_radius/major_radius; + + if(!dir){ + double temp = start_angle; + start_angle = end_angle; + end_angle = temp; + } + (*m_ofs) << 0 << endl; + (*m_ofs) << "ELLIPSE" << endl; + (*m_ofs) << 8 << endl; // Group code for layer name + (*m_ofs) << layer_name << endl; // Layer number + (*m_ofs) << 10 << endl; // Centre X + (*m_ofs) << c[0] << endl; // X in WCS coordinates + (*m_ofs) << 20 << endl; + (*m_ofs) << c[1] << endl; // Y in WCS coordinates + (*m_ofs) << 30 << endl; + (*m_ofs) << c[2] << endl; // Z in WCS coordinates + (*m_ofs) << 40 << endl; // + (*m_ofs) << ratio << endl; // Ratio + (*m_ofs) << 11 << endl; // + (*m_ofs) << m[0] << endl; // Major X + (*m_ofs) << 21 << endl; + (*m_ofs) << m[1] << endl; // Major Y + (*m_ofs) << 31 << endl; + (*m_ofs) << m[2] << endl; // Major Z + (*m_ofs) << 41 << endl; + (*m_ofs) << start_angle << endl; // Start angle + (*m_ofs) << 42 << endl; + (*m_ofs) << end_angle << endl; // End angle +} + +//*************************** +//WriteSpline +//added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project +void CDxfWrite::WriteSpline(SplineDataOut sd, const char* layer_name) +{ + (*m_ofs) << 0 << endl; + (*m_ofs) << "SPLINE" << endl; + (*m_ofs) << 8 << endl; // Group code for layer name + (*m_ofs) << layer_name << endl; // Layer number + (*m_ofs) << 100 << endl; + (*m_ofs) << "AcDbEntity" << endl; + (*m_ofs) << 100 << endl; + (*m_ofs) << "AcDbSpline" << endl; //normal 210,220,230 + (*m_ofs) << 70 << endl; + (*m_ofs) << sd.flag << endl; //flags + (*m_ofs) << 71 << endl; + (*m_ofs) << sd.degree << endl; + (*m_ofs) << 72 << endl; + (*m_ofs) << sd.knots << endl; + (*m_ofs) << 73 << endl; + (*m_ofs) << sd.control_points << endl; + (*m_ofs) << 74 << endl; + (*m_ofs) << 0 << endl; + + (*m_ofs) << 12 << endl; + (*m_ofs) << sd.starttan.x << endl; + (*m_ofs) << 22 << endl; + (*m_ofs) << sd.starttan.y << endl; + (*m_ofs) << 32 << endl; + (*m_ofs) << sd.starttan.z << endl; + (*m_ofs) << 13 << endl; + (*m_ofs) << sd.endtan.x << endl; + (*m_ofs) << 23 << endl; + (*m_ofs) << sd.endtan.y << endl; + (*m_ofs) << 33 << endl; + (*m_ofs) << sd.endtan.z << endl; + + for (auto& k: sd.knot) { + (*m_ofs) << 40 << endl; + (*m_ofs) << k << endl; + } + + for (auto& w : sd.weight) { + (*m_ofs) << 41 << endl; + (*m_ofs) << w << endl; + } + + for (auto& c: sd.control) { + (*m_ofs) << 10 << endl; + (*m_ofs) << c.x << endl; // X in WCS coordinates + (*m_ofs) << 20 << endl; + (*m_ofs) << c.y << endl; // Y in WCS coordinates + (*m_ofs) << 30 << endl; + (*m_ofs) << c.z << endl; // Z in WCS coordinates + } + for (auto& f: sd.fit) { + (*m_ofs) << 11 << endl; + (*m_ofs) << f.x << endl; // X in WCS coordinates + (*m_ofs) << 21 << endl; + (*m_ofs) << f.y << endl; // Y in WCS coordinates + (*m_ofs) << 31 << endl; + (*m_ofs) << f.z << endl; // Z in WCS coordinates + } +} + + + +CDxfRead::CDxfRead(const char* filepath) +{ + // start the file + memset( m_unused_line, '\0', sizeof(m_unused_line) ); + m_fail = false; + m_aci = 0; + m_eUnits = eMillimeters; + m_measurement_inch = false; + strcpy(m_layer_name, "0"); // Default layer name + m_ignore_errors = true; + + m_ifs = new ifstream(filepath); + if(!(*m_ifs)){ + m_fail = true; + printf("DXF file didn't load\n"); + return; + } + m_ifs->imbue(std::locale("C")); + +} + +CDxfRead::~CDxfRead() +{ + delete m_ifs; +} + +double CDxfRead::mm( double value ) const +{ + if(m_measurement_inch) + { + value *= 0.0393700787401575; + } + + switch(m_eUnits) + { + case eUnspecified: return(value * 1.0); // We don't know any better. + case eInches: return(value * 25.4); + case eFeet: return(value * 25.4 * 12); + case eMiles: return(value * 1609344.0); + case eMillimeters: return(value * 1.0); + case eCentimeters: return(value * 10.0); + case eMeters: return(value * 1000.0); + case eKilometers: return(value * 1000000.0); + case eMicroinches: return(value * 25.4 / 1000.0); + case eMils: return(value * 25.4 / 1000.0); + case eYards: return(value * 3 * 12 * 25.4); + case eAngstroms: return(value * 0.0000001); + case eNanometers: return(value * 0.000001); + case eMicrons: return(value * 0.001); + case eDecimeters: return(value * 100.0); + case eDekameters: return(value * 10000.0); + case eHectometers: return(value * 100000.0); + case eGigameters: return(value * 1000000000000.0); + case eAstronomicalUnits: return(value * 149597870690000.0); + case eLightYears: return(value * 9454254955500000000.0); + case eParsecs: return(value * 30856774879000000000.0); + default: return(value * 1.0); // We don't know any better. + } // End switch +} // End mm() method + + +bool CDxfRead::ReadLine() +{ + double s[3] = {0, 0, 0}; + double e[3] = {0, 0, 0}; + bool hidden = false; + + while(!((*m_ifs).eof())) + { + get_line(); + int n; + + if(sscanf(m_str, "%d", &n) != 1) + { + printf("CDxfRead::ReadLine() Failed to read integer from '%s'\n", m_str ); + return false; + } + + std::istringstream ss; + ss.imbue(std::locale("C")); + switch(n){ + case 0: + // next item found, so finish with line + DerefACI(); + OnReadLine(s, e, hidden); + hidden = false; + return true; + + case 8: // Layer name follows + get_line(); + strcpy(m_layer_name, m_str); + break; + + case 6: // line style name follows + get_line(); + if(m_str[0] == 'h' || m_str[0] == 'H')hidden = true; + break; + + case 10: + // start x + get_line(); + ss.str(m_str); ss >> s[0]; s[0] = mm(s[0]); if(ss.fail()) return false; + break; + case 20: + // start y + get_line(); + ss.str(m_str); ss >> s[1]; s[1] = mm(s[1]); if(ss.fail()) return false; + break; + case 30: + // start z + get_line(); + ss.str(m_str); ss >> s[2]; s[2] = mm(s[2]); if(ss.fail()) return false; + break; + case 11: + // end x + get_line(); + ss.str(m_str); ss >> e[0]; e[0] = mm(e[0]); if(ss.fail()) return false; + break; + case 21: + // end y + get_line(); + ss.str(m_str); ss >> e[1]; e[1] = mm(e[1]); if(ss.fail()) return false; + break; + case 31: + // end z + get_line(); + ss.str(m_str); ss >> e[2]; e[2] = mm(e[2]); if(ss.fail()) return false; + break; + case 62: + // color index + get_line(); + ss.str(m_str); ss >> m_aci; if(ss.fail()) return false; + break; + + case 100: + case 39: + case 210: + case 220: + case 230: + // skip the next line + get_line(); + break; + default: + // skip the next line + get_line(); + break; + } + } + + try { + DerefACI(); + OnReadLine(s, e, false); + } + catch(...) + { + if (! IgnoreErrors()) throw; // Re-throw the exception. + } + + return false; +} + +bool CDxfRead::ReadPoint() +{ + double s[3] = {0, 0, 0}; + + while(!((*m_ifs).eof())) + { + get_line(); + int n; + + if(sscanf(m_str, "%d", &n) != 1) + { + printf("CDxfRead::ReadPoint() Failed to read integer from '%s'\n", m_str ); + return false; + } + + std::istringstream ss; + ss.imbue(std::locale("C")); + switch(n){ + case 0: + // next item found, so finish with line + DerefACI(); + OnReadPoint(s); + return true; + + case 8: // Layer name follows + get_line(); + strcpy(m_layer_name, m_str); + break; + + case 10: + // start x + get_line(); + ss.str(m_str); ss >> s[0]; s[0] = mm(s[0]); if(ss.fail()) return false; + break; + case 20: + // start y + get_line(); + ss.str(m_str); ss >> s[1]; s[1] = mm(s[1]); if(ss.fail()) return false; + break; + case 30: + // start z + get_line(); + ss.str(m_str); ss >> s[2]; s[2] = mm(s[2]); if(ss.fail()) return false; + break; + + case 62: + // color index + get_line(); + ss.str(m_str); ss >> m_aci; if(ss.fail()) return false; + break; + + case 100: + case 39: + case 210: + case 220: + case 230: + // skip the next line + get_line(); + break; + default: + // skip the next line + get_line(); + break; + } + + } + + try { + DerefACI(); + OnReadPoint(s); + } + catch(...) + { + if (! IgnoreErrors()) throw; // Re-throw the exception. + } + + return false; +} + +bool CDxfRead::ReadArc() +{ + double start_angle = 0.0;// in degrees + double end_angle = 0.0; + double radius = 0.0; + double c[3]; // centre + double z_extrusion_dir = 1.0; + bool hidden = false; + + while(!((*m_ifs).eof())) + { + get_line(); + int n; + if(sscanf(m_str, "%d", &n) != 1) + { + printf("CDxfRead::ReadArc() Failed to read integer from '%s'\n", m_str); + return false; + } + + std::istringstream ss; + ss.imbue(std::locale("C")); + switch(n){ + case 0: + // next item found, so finish with arc + DerefACI(); + OnReadArc(start_angle, end_angle, radius, c,z_extrusion_dir, hidden); + hidden = false; + return true; + + case 8: // Layer name follows + get_line(); + strcpy(m_layer_name, m_str); + break; + + case 6: // line style name follows + get_line(); + if(m_str[0] == 'h' || m_str[0] == 'H')hidden = true; + break; + + case 10: + // centre x + get_line(); + ss.str(m_str); ss >> c[0]; c[0] = mm(c[0]); if(ss.fail()) return false; + break; + case 20: + // centre y + get_line(); + ss.str(m_str); ss >> c[1]; c[1] = mm(c[1]); if(ss.fail()) return false; + break; + case 30: + // centre z + get_line(); + ss.str(m_str); ss >> c[2]; c[2] = mm(c[2]); if(ss.fail()) return false; + break; + case 40: + // radius + get_line(); + ss.str(m_str); ss >> radius; radius = mm(radius); if(ss.fail()) return false; + break; + case 50: + // start angle + get_line(); + ss.str(m_str); ss >> start_angle; if(ss.fail()) return false; + break; + case 51: + // end angle + get_line(); + ss.str(m_str); ss >> end_angle; if(ss.fail()) return false; + break; + case 62: + // color index + get_line(); + ss.str(m_str); ss >> m_aci; if(ss.fail()) return false; + break; + + + + case 100: + case 39: + case 210: + case 220: + // skip the next line + get_line(); + break; + case 230: + //Z extrusion direction for arc + get_line(); + ss.str(m_str); ss >> z_extrusion_dir; if(ss.fail()) return false; + break; + + default: + // skip the next line + get_line(); + break; + } + } + DerefACI(); + OnReadArc(start_angle, end_angle, radius, c, z_extrusion_dir, false); + return false; +} + +bool CDxfRead::ReadSpline() +{ + struct SplineData sd; + sd.norm[0] = 0; + sd.norm[1] = 0; + sd.norm[2] = 1; + sd.degree = 0; + sd.knots = 0; + sd.flag = 0; + sd.control_points = 0; + sd.fit_points = 0; + + double temp_double; + + while(!((*m_ifs).eof())) + { + get_line(); + int n; + if(sscanf(m_str, "%d", &n) != 1) + { + printf("CDxfRead::ReadSpline() Failed to read integer from '%s'\n", m_str); + return false; + } + std::istringstream ss; + ss.imbue(std::locale("C")); + switch(n){ + case 0: + // next item found, so finish with Spline + DerefACI(); + OnReadSpline(sd); + return true; + case 8: // Layer name follows + get_line(); + strcpy(m_layer_name, m_str); + break; + case 62: + // color index + get_line(); + ss.str(m_str); ss >> m_aci; if(ss.fail()) return false; + break; + case 210: + // normal x + get_line(); + ss.str(m_str); ss >> sd.norm[0]; if(ss.fail()) return false; + break; + case 220: + // normal y + get_line(); + ss.str(m_str); ss >> sd.norm[1]; if(ss.fail()) return false; + break; + case 230: + // normal z + get_line(); + ss.str(m_str); ss >> sd.norm[2]; if(ss.fail()) return false; + break; + case 70: + // flag + get_line(); + ss.str(m_str); ss >> sd.flag; if(ss.fail()) return false; + break; + case 71: + // degree + get_line(); + ss.str(m_str); ss >> sd.degree; if(ss.fail()) return false; + break; + case 72: + // knots + get_line(); + ss.str(m_str); ss >> sd.knots; if(ss.fail()) return false; + break; + case 73: + // control points + get_line(); + ss.str(m_str); ss >> sd.control_points; if(ss.fail()) return false; + break; + case 74: + // fit points + get_line(); + ss.str(m_str); ss >> sd.fit_points; if(ss.fail()) return false; + break; + case 12: + // starttan x + get_line(); + ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false; + sd.starttanx.push_back(temp_double); + break; + case 22: + // starttan y + get_line(); + ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false; + sd.starttany.push_back(temp_double); + break; + case 32: + // starttan z + get_line(); + ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false; + sd.starttanz.push_back(temp_double); + break; + case 13: + // endtan x + get_line(); + ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false; + sd.endtanx.push_back(temp_double); + break; + case 23: + // endtan y + get_line(); + ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false; + sd.endtany.push_back(temp_double); + break; + case 33: + // endtan z + get_line(); + ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false; + sd.endtanz.push_back(temp_double); + break; + case 40: + // knot + get_line(); + ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false; + sd.knot.push_back(temp_double); + break; + case 41: + // weight + get_line(); + ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false; + sd.weight.push_back(temp_double); + break; + case 10: + // control x + get_line(); + ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false; + sd.controlx.push_back(temp_double); + break; + case 20: + // control y + get_line(); + ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false; + sd.controly.push_back(temp_double); + break; + case 30: + // control z + get_line(); + ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false; + sd.controlz.push_back(temp_double); + break; + case 11: + // fit x + get_line(); + ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false; + sd.fitx.push_back(temp_double); + break; + case 21: + // fit y + get_line(); + ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false; + sd.fity.push_back(temp_double); + break; + case 31: + // fit z + get_line(); + ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false; + sd.fitz.push_back(temp_double); + break; + case 42: + case 43: + case 44: + // skip the next line + get_line(); + break; + default: + // skip the next line + get_line(); + break; + } + } + DerefACI(); + OnReadSpline(sd); + return false; +} + + +bool CDxfRead::ReadCircle() +{ + double radius = 0.0; + double c[3]; // centre + bool hidden = false; + + while(!((*m_ifs).eof())) + { + get_line(); + int n; + if(sscanf(m_str, "%d", &n) != 1) + { + printf("CDxfRead::ReadCircle() Failed to read integer from '%s'\n", m_str); + return false; + } + std::istringstream ss; + ss.imbue(std::locale("C")); + switch(n){ + case 0: + // next item found, so finish with Circle + DerefACI(); + OnReadCircle(c, radius, hidden); + hidden = false; + return true; + + case 6: // line style name follows + get_line(); + if(m_str[0] == 'h' || m_str[0] == 'H')hidden = true; + break; + + case 8: // Layer name follows + get_line(); + strcpy(m_layer_name, m_str); + break; + + case 10: + // centre x + get_line(); + ss.str(m_str); ss >> c[0]; c[0] = mm(c[0]); if(ss.fail()) return false; + break; + case 20: + // centre y + get_line(); + ss.str(m_str); ss >> c[1]; c[1] = mm(c[1]); if(ss.fail()) return false; + break; + case 30: + // centre z + get_line(); + ss.str(m_str); ss >> c[2]; c[2] = mm(c[2]); if(ss.fail()) return false; + break; + case 40: + // radius + get_line(); + ss.str(m_str); ss >> radius; radius = mm(radius); if(ss.fail()) return false; + break; + case 62: + // color index + get_line(); + ss.str(m_str); ss >> m_aci; if(ss.fail()) return false; + break; + + case 100: + case 39: + case 210: + case 220: + case 230: + // skip the next line + get_line(); + break; + default: + // skip the next line + get_line(); + break; + } + } + DerefACI(); + OnReadCircle(c, radius, false); + return false; +} + + +bool CDxfRead::ReadText() +{ + double c[3]; // coordinate + double height = 0.03082; + + memset( c, 0, sizeof(c) ); + + while(!((*m_ifs).eof())) + { + get_line(); + int n; + if(sscanf(m_str, "%d", &n) != 1) + { + printf("CDxfRead::ReadText() Failed to read integer from '%s'\n", m_str); + return false; + } + std::istringstream ss; + ss.imbue(std::locale("C")); + switch(n){ + case 0: + return false; + case 8: // Layer name follows + get_line(); + strcpy(m_layer_name, m_str); + break; + + case 10: + // centre x + get_line(); + ss.str(m_str); ss >> c[0]; c[0] = mm(c[0]); if(ss.fail()) return false; + break; + case 20: + // centre y + get_line(); + ss.str(m_str); ss >> c[1]; c[1] = mm(c[1]); if(ss.fail()) return false; + break; + case 30: + // centre z + get_line(); + ss.str(m_str); ss >> c[2]; c[2] = mm(c[2]); if(ss.fail()) return false; + break; + case 40: + // text height + get_line(); + ss.str(m_str); ss >> height; height = mm(height); if(ss.fail()) return false; + break; + case 1: + // text + get_line(); + DerefACI(); + OnReadText(c, height * 25.4 / 72.0, m_str); + return(true); + + case 62: + // color index + get_line(); + ss.str(m_str); ss >> m_aci; if(ss.fail()) return false; + break; + + case 100: + case 39: + case 210: + case 220: + case 230: + // skip the next line + get_line(); + break; + default: + // skip the next line + get_line(); + break; + } + } + + return false; +} + + +bool CDxfRead::ReadEllipse() +{ + double c[3]; // centre + double m[3]; //major axis point + double ratio=0; //ratio of major to minor axis + double start=0; //start of arc + double end=0; // end of arc + + while(!((*m_ifs).eof())) + { + get_line(); + int n; + if(sscanf(m_str, "%d", &n) != 1) + { + printf("CDxfRead::ReadEllipse() Failed to read integer from '%s'\n", m_str); + return false; + } + std::istringstream ss; + ss.imbue(std::locale("C")); + switch(n){ + case 0: + // next item found, so finish with Ellipse + DerefACI(); + OnReadEllipse(c, m, ratio, start, end); + return true; + case 8: // Layer name follows + get_line(); + strcpy(m_layer_name, m_str); + break; + + case 10: + // centre x + get_line(); + ss.str(m_str); ss >> c[0]; c[0] = mm(c[0]); if(ss.fail()) return false; + break; + case 20: + // centre y + get_line(); + ss.str(m_str); ss >> c[1]; c[1] = mm(c[1]); if(ss.fail()) return false; + break; + case 30: + // centre z + get_line(); + ss.str(m_str); ss >> c[2]; c[2] = mm(c[2]); if(ss.fail()) return false; + break; + case 11: + // major x + get_line(); + ss.str(m_str); ss >> m[0]; m[0] = mm(m[0]); if(ss.fail()) return false; + break; + case 21: + // major y + get_line(); + ss.str(m_str); ss >> m[1]; m[1] = mm(m[1]); if(ss.fail()) return false; + break; + case 31: + // major z + get_line(); + ss.str(m_str); ss >> m[2]; m[2] = mm(m[2]); if(ss.fail()) return false; + break; + case 40: + // ratio + get_line(); + ss.str(m_str); ss >> ratio; if(ss.fail()) return false; + break; + case 41: + // start + get_line(); + ss.str(m_str); ss >> start; if(ss.fail()) return false; + break; + case 42: + // end + get_line(); + ss.str(m_str); ss >> end; if(ss.fail()) return false; + break; + case 62: + // color index + get_line(); + ss.str(m_str); ss >> m_aci; if(ss.fail()) return false; + break; + case 100: + case 210: + case 220: + case 230: + // skip the next line + get_line(); + break; + default: + // skip the next line + get_line(); + break; + } + } + DerefACI(); + OnReadEllipse(c, m, ratio, start, end); + return false; +} + + +static bool poly_prev_found = false; +static double poly_prev_x; +static double poly_prev_y; +static double poly_prev_z; +static double poly_prev_bulge_found; +static double poly_prev_bulge; +static bool poly_first_found = false; +static double poly_first_x; +static double poly_first_y; +static double poly_first_z; + +static void AddPolyLinePoint(CDxfRead* dxf_read, double x, double y, double z, bool bulge_found, double bulge) +{ + + try { + if(poly_prev_found) + { + bool arc_done = false; + if(poly_prev_bulge_found) + { + double cot = 0.5 * ((1.0 / poly_prev_bulge) - poly_prev_bulge); + double cx = ((poly_prev_x + x) - ((y - poly_prev_y) * cot)) / 2.0; + double cy = ((poly_prev_y + y) + ((x - poly_prev_x) * cot)) / 2.0; + double ps[3] = {poly_prev_x, poly_prev_y, poly_prev_z}; + double pe[3] = {x, y, z}; + double pc[3] = {cx, cy, (poly_prev_z + z)/2.0}; + dxf_read->OnReadArc(ps, pe, pc, poly_prev_bulge >= 0, false); + arc_done = true; + } + + if(!arc_done) + { + double s[3] = {poly_prev_x, poly_prev_y, poly_prev_z}; + double e[3] = {x, y, z}; + dxf_read->OnReadLine(s, e, false); + } + } + + poly_prev_found = true; + poly_prev_x = x; + poly_prev_y = y; + poly_prev_z = z; + if(!poly_first_found) + { + poly_first_x = x; + poly_first_y = y; + poly_first_z = z; + poly_first_found = true; + } + poly_prev_bulge_found = bulge_found; + poly_prev_bulge = bulge; + } + catch(...) + { + if (! dxf_read->IgnoreErrors()) throw; // Re-throw it. + } +} + +static void PolyLineStart() +{ + poly_prev_found = false; + poly_first_found = false; +} + +bool CDxfRead::ReadLwPolyLine() +{ + PolyLineStart(); + + bool x_found = false; + bool y_found = false; + double x = 0.0; + double y = 0.0; + double z = 0.0; + bool bulge_found = false; + double bulge = 0.0; + bool closed = false; + int flags; + bool next_item_found = false; + + while(!((*m_ifs).eof()) && !next_item_found) + { + get_line(); + int n; + if(sscanf(m_str, "%d", &n) != 1) + { + printf("CDxfRead::ReadLwPolyLine() Failed to read integer from '%s'\n", m_str); + return false; + } + std::istringstream ss; + ss.imbue(std::locale("C")); + switch(n){ + case 0: + // next item found + + DerefACI(); + if(x_found && y_found){ + // add point + AddPolyLinePoint(this, x, y, z, bulge_found, bulge); + bulge_found = false; + x_found = false; + y_found = false; + } + next_item_found = true; + break; + case 8: // Layer name follows + get_line(); + strcpy(m_layer_name, m_str); + break; + case 10: + // x + get_line(); + if(x_found && y_found){ + // add point + AddPolyLinePoint(this, x, y, z, bulge_found, bulge); + bulge_found = false; + x_found = false; + y_found = false; + } + ss.str(m_str); ss >> x; x = mm(x); if(ss.fail()) return false; + x_found = true; + break; + case 20: + // y + get_line(); + ss.str(m_str); ss >> y; y = mm(y); if(ss.fail()) return false; + y_found = true; + break; + case 38: + // elevation + get_line(); + ss.str(m_str); ss >> z; z = mm(z); if(ss.fail()) return false; + break; + case 42: + // bulge + get_line(); + ss.str(m_str); ss >> bulge; if(ss.fail()) return false; + bulge_found = true; + break; + case 70: + // flags + get_line(); + if(sscanf(m_str, "%d", &flags) != 1)return false; + closed = ((flags & 1) != 0); + break; + case 62: + // color index + get_line(); + ss.str(m_str); ss >> m_aci; if(ss.fail()) return false; + break; + default: + // skip the next line + get_line(); + break; + } + } + + if(next_item_found) + { + if(closed && poly_first_found) + { + // repeat the first point + DerefACI(); + AddPolyLinePoint(this, poly_first_x, poly_first_y, poly_first_z, false, 0.0); + } + return true; + } + + return false; +} + + +bool CDxfRead::ReadVertex(double *pVertex, bool *bulge_found, double *bulge) +{ + bool x_found = false; + bool y_found = false; + + double x = 0.0; + double y = 0.0; + double z = 0.0; + *bulge = 0.0; + *bulge_found = false; + + pVertex[0] = 0.0; + pVertex[1] = 0.0; + pVertex[2] = 0.0; + + while(!(*m_ifs).eof()) { + get_line(); + int n; + if(sscanf(m_str, "%d", &n) != 1) { + printf("CDxfRead::ReadVertex() Failed to read integer from '%s'\n", m_str); + return false; + } + std::istringstream ss; + ss.imbue(std::locale("C")); + switch(n){ + case 0: + DerefACI(); + put_line(m_str); // read one line too many. put it back. + return(x_found && y_found); + break; + + case 8: // Layer name follows + get_line(); + strcpy(m_layer_name, m_str); + break; + + case 10: + // x + get_line(); + ss.str(m_str); ss >> x; pVertex[0] = mm(x); if(ss.fail()) return false; + x_found = true; + break; + case 20: + // y + get_line(); + ss.str(m_str); ss >> y; pVertex[1] = mm(y); if(ss.fail()) return false; + y_found = true; + break; + case 30: + // z + get_line(); + ss.str(m_str); ss >> z; pVertex[2] = mm(z); if(ss.fail()) return false; + break; + + case 42: + get_line(); + *bulge_found = true; + ss.str(m_str); ss >> *bulge; if(ss.fail()) return false; + break; + case 62: + // color index + get_line(); + ss.str(m_str); ss >> m_aci; if(ss.fail()) return false; + break; + + default: + // skip the next line + get_line(); + break; + } + } + + return false; +} + + + +bool CDxfRead::ReadPolyLine() +{ + PolyLineStart(); + + bool closed = false; + int flags; + bool first_vertex_section_found = false; + double first_vertex[3] = {0,0,0}; + bool bulge_found; + double bulge; + + while(!(*m_ifs).eof()) + { + get_line(); + int n; + if(sscanf(m_str, "%d", &n) != 1) + { + printf("CDxfRead::ReadPolyLine() Failed to read integer from '%s'\n", m_str); + return false; + } + std::istringstream ss; + ss.imbue(std::locale("C")); + switch(n){ + case 0: + // next item found + DerefACI(); + get_line(); + if (! strcmp(m_str,"VERTEX")) + { + double vertex[3]; + if (CDxfRead::ReadVertex(vertex, &bulge_found, &bulge)) + { + if(!first_vertex_section_found) { + first_vertex_section_found = true; + memcpy(first_vertex, vertex, 3*sizeof(double)); + } + AddPolyLinePoint(this, vertex[0], vertex[1], vertex[2], bulge_found, bulge); + break; + } + } + if (! strcmp(m_str,"SEQEND")) + { + if(closed && first_vertex_section_found) { + AddPolyLinePoint(this, first_vertex[0], first_vertex[1], first_vertex[2], 0, 0); + } + first_vertex_section_found = false; + PolyLineStart(); + return(true); + } + break; + case 70: + // flags + get_line(); + if(sscanf(m_str, "%d", &flags) != 1)return false; + closed = ((flags & 1) != 0); + break; + case 62: + // color index + get_line(); + ss.str(m_str); ss >> m_aci; if(ss.fail()) return false; + break; + default: + // skip the next line + get_line(); + break; + } + } + + return false; +} + +void CDxfRead::OnReadArc(double start_angle, double end_angle, double radius, const double* c, double z_extrusion_dir, bool hidden){ + double s[3], e[3], temp[3] ; + if (z_extrusion_dir==1.0) + { + temp[0] =c[0]; + temp[1] =c[1]; + temp[2] =c[2]; + s[0] = c[0] + radius * cos(start_angle * Pi/180); + s[1] = c[1] + radius * sin(start_angle * Pi/180); + s[2] = c[2]; + e[0] = c[0] + radius * cos(end_angle * Pi/180); + e[1] = c[1] + radius * sin(end_angle * Pi/180); + e[2] = c[2]; + } + else + { + temp[0] =-c[0]; + temp[1] =c[1]; + temp[2] =c[2]; + + e[0] = -(c[0] + radius * cos(start_angle * Pi/180)); + e[1] = (c[1] + radius * sin(start_angle * Pi/180)); + e[2] = c[2]; + s[0] = -(c[0] + radius * cos(end_angle * Pi/180)); + s[1] = (c[1] + radius * sin(end_angle * Pi/180)); + s[2] = c[2]; + + } + OnReadArc(s, e, temp, true, hidden); +} + +void CDxfRead::OnReadCircle(const double* c, double radius, bool hidden){ + double s[3]; + double start_angle = 0; + s[0] = c[0] + radius * cos(start_angle * Pi/180); + s[1] = c[1] + radius * sin(start_angle * Pi/180); + s[2] = c[2]; + + OnReadCircle(s, c, false, hidden); //false to change direction because otherwise the arc length is zero +} + +void CDxfRead::OnReadEllipse(const double* c, const double* m, double ratio, double start_angle, double end_angle){ + double major_radius = sqrt(m[0]*m[0] + m[1]*m[1] + m[2]*m[2]); + double minor_radius = major_radius * ratio; + + //Since we only support 2d stuff, we can calculate the rotation from the major axis x and y value only, + //since z is zero, major_radius is the vector length + + double rotation = atan2(m[1]/major_radius,m[0]/major_radius); + + + OnReadEllipse(c, major_radius, minor_radius, rotation, start_angle, end_angle, true); +} + + +bool CDxfRead::ReadInsert() +{ + double c[3]; // coordinate + double s[3]; // scale + double rot = 0.0; // rotation + char name[1024]; + s[0] = 1.0; + s[1] = 1.0; + s[2] = 1.0; + + while(!((*m_ifs).eof())) + { + get_line(); + int n; + if(sscanf(m_str, "%d", &n) != 1) + { + printf("CDxfRead::ReadInsert() Failed to read integer from '%s'\n", m_str); + return false; + } + std::istringstream ss; + ss.imbue(std::locale("C")); + switch(n){ + case 0: + // next item found + DerefACI(); + OnReadInsert(c, s, name, rot * Pi/180); + return(true); + case 8: + // Layer name follows + get_line(); + strcpy(m_layer_name, m_str); + break; + case 10: + // coord x + get_line(); + ss.str(m_str); ss >> c[0]; c[0] = mm(c[0]); if(ss.fail()) return false; + break; + case 20: + // coord y + get_line(); + ss.str(m_str); ss >> c[1]; c[1] = mm(c[1]); if(ss.fail()) return false; + break; + case 30: + // coord z + get_line(); + ss.str(m_str); ss >> c[2]; c[2] = mm(c[2]); if(ss.fail()) return false; + break; + case 41: + // scale x + get_line(); + ss.str(m_str); ss >> s[0]; if(ss.fail()) return false; + break; + case 42: + // scale y + get_line(); + ss.str(m_str); ss >> s[1]; if(ss.fail()) return false; + break; + case 43: + // scale z + get_line(); + ss.str(m_str); ss >> s[2]; if(ss.fail()) return false; + break; + case 50: + // rotation + get_line(); + ss.str(m_str); ss >> rot; if(ss.fail()) return false; + break; + case 2: + // block name + get_line(); + strcpy(name, m_str); + break; + case 62: + // color index + get_line(); + ss.str(m_str); ss >> m_aci; if(ss.fail()) return false; + break; + case 100: + case 39: + case 210: + case 220: + case 230: + // skip the next line + get_line(); + break; + default: + // skip the next line + get_line(); + break; + } + } + return false; +} + + +bool CDxfRead::ReadDimension() +{ + double s[3]; // startpoint + double e[3]; // endpoint + double p[3]; // dimpoint + double rot = -1.0; // rotation + + while(!((*m_ifs).eof())) + { + get_line(); + int n; + if(sscanf(m_str, "%d", &n) != 1) + { + printf("CDxfRead::ReadInsert() Failed to read integer from '%s'\n", m_str); + return false; + } + std::istringstream ss; + ss.imbue(std::locale("C")); + switch(n){ + case 0: + // next item found + DerefACI(); + OnReadDimension(s, e, p, rot * Pi/180); + return(true); + case 8: + // Layer name follows + get_line(); + strcpy(m_layer_name, m_str); + break; + case 13: + // start x + get_line(); + ss.str(m_str); ss >> s[0]; s[0] = mm(s[0]); if(ss.fail()) return false; + break; + case 23: + // start y + get_line(); + ss.str(m_str); ss >> s[1]; s[1] = mm(s[1]); if(ss.fail()) return false; + break; + case 33: + // start z + get_line(); + ss.str(m_str); ss >> s[2]; s[2] = mm(s[2]); if(ss.fail()) return false; + break; + case 14: + // end x + get_line(); + ss.str(m_str); ss >> e[0]; e[0] = mm(e[0]); if(ss.fail()) return false; + break; + case 24: + // end y + get_line(); + ss.str(m_str); ss >> e[1]; e[1] = mm(e[1]); if(ss.fail()) return false; + break; + case 34: + // end z + get_line(); + ss.str(m_str); ss >> e[2]; e[2] = mm(e[2]); if(ss.fail()) return false; + break; + case 10: + // dimline x + get_line(); + ss.str(m_str); ss >> p[0]; p[0] = mm(p[0]); if(ss.fail()) return false; + break; + case 20: + // dimline y + get_line(); + ss.str(m_str); ss >> p[1]; p[1] = mm(p[1]); if(ss.fail()) return false; + break; + case 30: + // dimline z + get_line(); + ss.str(m_str); ss >> p[2]; p[2] = mm(p[2]); if(ss.fail()) return false; + break; + case 50: + // rotation + get_line(); + ss.str(m_str); ss >> rot; if(ss.fail()) return false; + break; + case 62: + // color index + get_line(); + ss.str(m_str); ss >> m_aci; if(ss.fail()) return false; + break; + case 100: + case 39: + case 210: + case 220: + case 230: + // skip the next line + get_line(); + break; + default: + // skip the next line + get_line(); + break; + } + } + return false; +} + + +bool CDxfRead::ReadBlockInfo() +{ + while(!((*m_ifs).eof())) + { + get_line(); + int n; + if(sscanf(m_str, "%d", &n) != 1) + { + printf("CDxfRead::ReadBlockInfo() Failed to read integer from '%s'\n", m_str); + return false; + } + std::istringstream ss; + ss.imbue(std::locale("C")); + switch(n){ + case 2: + // block name + get_line(); + strcpy(m_block_name, m_str); + return true; + case 3: + // block name too??? + get_line(); + strcpy(m_block_name, m_str); + return true; + default: + // skip the next line + get_line(); + break; + } + } + return false; +} + + +void CDxfRead::get_line() +{ + if (m_unused_line[0] != '\0') + { + strcpy(m_str, m_unused_line); + memset( m_unused_line, '\0', sizeof(m_unused_line)); + return; + } + + m_ifs->getline(m_str, 1024); + + char str[1024]; + size_t len = strlen(m_str); + int j = 0; + bool non_white_found = false; + for(size_t i = 0; i 0) + { + result.append(m_section_name); + result.append(" "); + } + + if (strlen(m_block_name) > 0) + { + result.append(m_block_name); + result.append(" "); + } + + if (strlen(m_layer_name) > 0) + { + result.append(m_layer_name); + } + + return(result); +} diff --git a/src/Mod/Import/App/dxf.h b/src/Mod/Import/App/dxf.h new file mode 100644 index 0000000000..7d8597e7a4 --- /dev/null +++ b/src/Mod/Import/App/dxf.h @@ -0,0 +1,209 @@ +// dxf.h +// Copyright (c) 2009, Dan Heeks +// This program is released under the BSD license. See the file COPYING for details. +// modified 2018 wandererfan + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//Following is required to be defined on Ubuntu with OCC 6.3.1 +#ifndef HAVE_IOSTREAM +#define HAVE_IOSTREAM +#endif + +typedef int Aci_t; // AutoCAD color index + +typedef enum +{ + eUnspecified = 0, // Unspecified (No units) + eInches, + eFeet, + eMiles, + eMillimeters, + eCentimeters, + eMeters, + eKilometers, + eMicroinches, + eMils, + eYards, + eAngstroms, + eNanometers, + eMicrons, + eDecimeters, + eDekameters, + eHectometers, + eGigameters, + eAstronomicalUnits, + eLightYears, + eParsecs +} eDxfUnits_t; + + +//spline data for reading +struct SplineData +{ + double norm[3]; + int degree; + int knots; + int control_points; + int fit_points; + int flag; + std::list starttanx; + std::list starttany; + std::list starttanz; + std::list endtanx; + std::list endtany; + std::list endtanz; + std::list knot; + std::list weight; + std::list controlx; + std::list controly; + std::list controlz; + std::list fitx; + std::list fity; + std::list fitz; +}; + +//*************************** +//data structures for writing +//added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project +struct point3D +{ + double x; + double y; + double z; +}; + +struct SplineDataOut +{ + point3D norm; + int degree; + int knots; + int control_points; + int fit_points; + int flag; + point3D starttan; + point3D endtan; + std::vector knot; + std::vector weight; + std::vector control; + std::vector fit; +}; + +struct LWPolyDataOut +{ + double nVert; + int Flag; + double Width; + double Elev; + double Thick; + std::vector Verts; + std::vector StartWidth; + std::vector EndWidth; + std::vector Bulge; + point3D Extr; +}; +//******************** + +class CDxfWrite{ +private: + std::ofstream* m_ofs; + bool m_fail; + +public: + CDxfWrite(const char* filepath); + ~CDxfWrite(); + + bool Failed(){return m_fail;} + + void WriteLine(const double* s, const double* e, const char* layer_name ); + void WritePoint(const double*, const char*); + void WriteArc(const double* s, const double* e, const double* c, bool dir, const char* layer_name ); + void WriteEllipse(const double* c, double major_radius, double minor_radius, double rotation, double start_angle, double end_angle, bool dir, const char* layer_name ); + void WriteCircle(const double* c, double radius, const char* layer_name ); + void WriteSpline(SplineDataOut sd, const char* layer_name); + void WriteLWPolyLine(LWPolyDataOut pd, const char* layer_name); + +}; + +// derive a class from this and implement it's virtual functions +class CDxfRead{ +private: + std::ifstream* m_ifs; + + bool m_fail; + char m_str[1024]; + char m_unused_line[1024]; + eDxfUnits_t m_eUnits; + bool m_measurement_inch; + char m_layer_name[1024]; + char m_section_name[1024]; + char m_block_name[1024]; + bool m_ignore_errors; + + + typedef std::map< std::string,Aci_t > LayerAciMap_t; + LayerAciMap_t m_layer_aci; // layer names -> layer color aci map + + bool ReadUnits(); + bool ReadLayer(); + bool ReadLine(); + bool ReadText(); + bool ReadArc(); + bool ReadCircle(); + bool ReadEllipse(); + bool ReadPoint(); + bool ReadSpline(); + bool ReadLwPolyLine(); + bool ReadPolyLine(); + bool ReadVertex(double *pVertex, bool *bulge_found, double *bulge); + void OnReadArc(double start_angle, double end_angle, double radius, const double* c, double z_extrusion_dir, bool hidden); + void OnReadCircle(const double* c, double radius, bool hidden); + void OnReadEllipse(const double* c, const double* m, double ratio, double start_angle, double end_angle); + bool ReadInsert(); + bool ReadDimension(); + bool ReadBlockInfo(); + + void get_line(); + void put_line(const char *value); + void DerefACI(); + +protected: + Aci_t m_aci; // manifest color name or 256 for layer color + +public: + CDxfRead(const char* filepath); // this opens the file + ~CDxfRead(); // this closes the file + + bool Failed(){return m_fail;} + void DoRead(const bool ignore_errors = false); // this reads the file and calls the following functions + + double mm( double value ) const; + + bool IgnoreErrors() const { return(m_ignore_errors); } + + virtual void OnReadLine(const double* /*s*/, const double* /*e*/, bool /*hidden*/){} + virtual void OnReadPoint(const double* /*s*/){} + virtual void OnReadText(const double* /*point*/, const double /*height*/, const char* /*text*/){} + virtual void OnReadArc(const double* /*s*/, const double* /*e*/, const double* /*c*/, bool /*dir*/, bool /*hidden*/){} + virtual void OnReadCircle(const double* /*s*/, const double* /*c*/, bool /*dir*/, bool /*hidden*/){} + virtual void OnReadEllipse(const double* /*c*/, double /*major_radius*/, double /*minor_radius*/, double /*rotation*/, double /*start_angle*/, double /*end_angle*/, bool /*dir*/){} + virtual void OnReadSpline(struct SplineData& /*sd*/){} + virtual void OnReadInsert(const double* /*point*/, const double* /*scale*/, const char* /*name*/, double /*rotation*/){} + virtual void OnReadDimension(const double* /*s*/, const double* /*e*/, const double* /*point*/, double /*rotation*/){} + virtual void AddGraphics() const { } + + std::string LayerName() const; + +};