From e3d42e82a6e0d849d265227a7129580db5184c8d Mon Sep 17 00:00:00 2001 From: wandererfan Date: Sun, 3 Dec 2023 17:27:35 -0500 Subject: [PATCH] [Import]Flatten sketch before dxf export. --- src/Mod/Import/App/AppImportPy.cpp | 37 +++++-- src/Mod/Import/App/CMakeLists.txt | 2 + src/Mod/Import/App/SketchExportHelper.cpp | 115 ++++++++++++++++++++++ src/Mod/Import/App/SketchExportHelper.h | 46 +++++++++ src/Mod/Import/App/dxf/dxf.cpp | 12 ++- 5 files changed, 199 insertions(+), 13 deletions(-) create mode 100644 src/Mod/Import/App/SketchExportHelper.cpp create mode 100644 src/Mod/Import/App/SketchExportHelper.h diff --git a/src/Mod/Import/App/AppImportPy.cpp b/src/Mod/Import/App/AppImportPy.cpp index 797f916871..ab99106577 100644 --- a/src/Mod/Import/App/AppImportPy.cpp +++ b/src/Mod/Import/App/AppImportPy.cpp @@ -51,6 +51,7 @@ #endif #include "dxf/ImpExpDxf.h" +#include "SketchExportHelper.h" #include #include #include @@ -427,8 +428,10 @@ private: return Py::None(); } + Py::Object writeDXFShape(const Py::Tuple& args) { + Base::Console().Message("Imp:writeDXFShape()\n"); PyObject* shapeObj = nullptr; char* fname = nullptr; std::string filePath; @@ -592,11 +595,19 @@ private: PyObject* item = (*it).ptr(); App::DocumentObject* obj = static_cast(item)->getDocumentObjectPtr(); - Part::Feature* part = static_cast(obj); - layerName = part->getNameInDocument(); + layerName = obj->getNameInDocument(); writer.setLayerName(layerName); - const TopoDS_Shape& shape = part->Shape.getValue(); - writer.exportShape(shape); + TopoDS_Shape shapeToExport; + if (SketchExportHelper::isSketch(obj)) { + // project sketch along sketch Z via hlrProjector to get geometry on XY plane + shapeToExport = SketchExportHelper::getFlatSketchXY(obj); + } else { + // do we know that obj is a Part::Feature? is this checked somewhere before this? + // this should be a located shape?? + Part::Feature* part = static_cast(obj); + shapeToExport = part->Shape.getValue(); + } + writer.exportShape(shapeToExport); } } writer.endRun(); @@ -620,6 +631,8 @@ private: filePath = std::string(fname); layerName = "none"; PyMem_Free(fname); + App::DocumentObject* obj = static_cast(docObj)->getDocumentObjectPtr(); + Base::Console().Message("Imp:writeDXFObject - docObj: %s\n", obj->getNameInDocument()); if ((versionParm == 12) || (versionParm == 14)) { versionOverride = true; @@ -644,11 +657,19 @@ private: writer.init(); App::DocumentObject* obj = static_cast(docObj)->getDocumentObjectPtr(); - Part::Feature* part = static_cast(obj); - layerName = part->getNameInDocument(); + layerName = obj->getNameInDocument(); writer.setLayerName(layerName); - const TopoDS_Shape& shape = part->Shape.getValue(); - writer.exportShape(shape); + TopoDS_Shape shapeToExport; + if (SketchExportHelper::isSketch(obj)) { + // project sketch along sketch Z via hlrProjector to get geometry on XY plane + shapeToExport = SketchExportHelper::getFlatSketchXY(obj); + } else { + // TODO: do we know that obj is a Part::Feature? is this checked somewhere before this? + // TODO: this should be a located shape?? + Part::Feature* part = static_cast(obj); + shapeToExport = part->Shape.getValue(); + } + writer.exportShape(shapeToExport); writer.endRun(); return Py::None(); } diff --git a/src/Mod/Import/App/CMakeLists.txt b/src/Mod/Import/App/CMakeLists.txt index 47777c79bb..fff72a3683 100644 --- a/src/Mod/Import/App/CMakeLists.txt +++ b/src/Mod/Import/App/CMakeLists.txt @@ -50,6 +50,8 @@ SET(Import_SRCS WriterIges.h WriterStep.cpp WriterStep.h + SketchExportHelper.cpp + SketchExportHelper.h dxf/ImpExpDxf.cpp dxf/ImpExpDxf.h dxf/dxf.cpp diff --git a/src/Mod/Import/App/SketchExportHelper.cpp b/src/Mod/Import/App/SketchExportHelper.cpp new file mode 100644 index 0000000000..95e22d08a5 --- /dev/null +++ b/src/Mod/Import/App/SketchExportHelper.cpp @@ -0,0 +1,115 @@ +/*************************************************************************** + * Copyright (c) 2024 WandererFan * + * * + * 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 * + * * + ***************************************************************************/ + +//! a class to assist with exporting sketches to dxf + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +#include +#include +#include +#include +#include +#endif + +#include +#include +#include + +#include + +#include "SketchExportHelper.h" + +using namespace Import; + +//! project a shape so that it is represented as a flat shape on the XY plane. Z coordinate information +//! is lost in this process, so it should only be used for flat objects like sketches. +//! Note: this only returns hard and outline edges. Seam, smooth, isoparametric and hidden lines are not returned. +TopoDS_Shape SketchExportHelper::projectShape(const TopoDS_Shape& inShape, const gp_Ax2& projectionCS) +{ + Handle(HLRBRep_Algo) brep_hlr = new HLRBRep_Algo(); + brep_hlr->Add(inShape); + HLRAlgo_Projector projector(projectionCS); + brep_hlr->Projector(projector); + brep_hlr->Update(); + brep_hlr->Hide(); + HLRBRep_HLRToShape hlrToShape(brep_hlr); + BRep_Builder builder; + TopoDS_Compound comp; + builder.MakeCompound(comp); + if (!hlrToShape.VCompound().IsNull()) { + builder.Add(comp, hlrToShape.VCompound()); + } + if (!hlrToShape.OutLineVCompound().IsNull()) { + builder.Add(comp, hlrToShape.OutLineVCompound()); + } + return comp; + } + + +//! true if obj is a sketch + bool SketchExportHelper::isSketch(App::DocumentObject* obj) + { + // TODO:: the check for an object being a sketch should be done as in the commented + // if statement below. To do this, we need to include Mod/Sketcher/SketchObject.h, + // but that makes Import dependent on Eigen libraries which we don't use. As a + // workaround we will inspect the object's class name. + // if (obj->isDerivedFrom(Sketcher::SketchObject::getClassTypeId())) { + std::string objTypeName = obj->getTypeId().getName(); + std::string sketcherToken("Sketcher"); + return objTypeName.find(sketcherToken) != std::string::npos; + } + + +//! return a version of a sketch's geometry mapped to the OXYZ coordinate system +//! preferred by dxf + TopoDS_Shape SketchExportHelper::getFlatSketchXY(App::DocumentObject* obj) + { + // since we can't reference Sketcher module here, we will cast obj to + // a Part::Feature instead + auto sketch = dynamic_cast(obj); + if ( !sketch || !isSketch(obj)){ + return {}; + } + + auto plm = sketch->Placement.getValue(); + Base::Rotation rot = plm.getRotation(); + + //get the sketch normal + Base::Vector3d stdZ{0.0, 0.0, 1.0}; + Base::Vector3d sketchNormal; + rot.multVec(stdZ, sketchNormal); + Base::Vector3d stdX{1.0, 0.0, 0.0}; + Base::Vector3d sketchX; + rot.multVec(stdX, sketchX); + + //get the sketch origin + Base::Vector3d position = plm.getPosition(); + gp_Ax2 projectionCS(gp_Pnt(position.x, position.y, position.z), + gp_Dir(sketchNormal.x, sketchNormal.y, sketchNormal.z), + gp_Dir(sketchX.x, sketchX.y, sketchX.z)); + const TopoDS_Shape& shape = sketch->Shape.getValue(); + return projectShape(shape, projectionCS); + } + diff --git a/src/Mod/Import/App/SketchExportHelper.h b/src/Mod/Import/App/SketchExportHelper.h new file mode 100644 index 0000000000..80f52223cc --- /dev/null +++ b/src/Mod/Import/App/SketchExportHelper.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (c) 2024 WandererFan * + * * + * 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 * + * * + ***************************************************************************/ + +//! a class to assist with exporting sketches to dxf + +#include + +#include +#include + +namespace App +{ +class DocumentObject; +} + +namespace Import +{ + +class ImportExport SketchExportHelper +{ +public: + static TopoDS_Shape projectShape(const TopoDS_Shape& inShape, const gp_Ax2& projectionCS); + static bool isSketch(App::DocumentObject* obj); + static TopoDS_Shape getFlatSketchXY(App::DocumentObject* obj); +}; + +} diff --git a/src/Mod/Import/App/dxf/dxf.cpp b/src/Mod/Import/App/dxf/dxf.cpp index 7aab753225..1f57076e53 100644 --- a/src/Mod/Import/App/dxf/dxf.cpp +++ b/src/Mod/Import/App/dxf/dxf.cpp @@ -656,7 +656,7 @@ void CDxfWrite::writePolyline(const LWPolyDataOut& pd) (*m_ssEntity) << " 20" << endl; (*m_ssEntity) << p.y << endl; (*m_ssEntity) << " 30" << endl; - (*m_ssEntity) << "0.0" << endl; + (*m_ssEntity) << p.z << endl; } (*m_ssEntity) << " 0" << endl; (*m_ssEntity) << "SEQEND" << endl; @@ -692,7 +692,10 @@ void CDxfWrite::writePoint(const double* point) (*m_ssEntity) << point[2] << endl; // Z in WCS coordinates } +//! arc from 3 points - start, end, center. dir true if arc is AntiClockwise. unspecified assumption is that +//! points are on XY plane in coord system OXYZ. void CDxfWrite::writeArc(const double* start, const double* end, const double* center, bool dir) + { double ax = start[0] - center[0]; double ay = start[1] - center[1]; @@ -766,8 +769,8 @@ void CDxfWrite::writeCircle(const double* center, double radius) (*m_ssEntity) << center[0] << endl; // X in WCS coordinates (*m_ssEntity) << " 20" << endl; (*m_ssEntity) << center[1] << endl; // Y in WCS coordinates - // (*m_ssEntity) << " 30" << endl; - // (*m_ssEntity) << center[2] << endl; // Z in WCS coordinates + (*m_ssEntity) << " 30" << endl; + (*m_ssEntity) << center[2] << endl; // Z in WCS coordinates (*m_ssEntity) << " 40" << endl; // (*m_ssEntity) << radius << endl; // Radius } @@ -817,8 +820,7 @@ void CDxfWrite::writeEllipse(const double* center, (*m_ssEntity) << " 31" << endl; (*m_ssEntity) << m.z << endl; // Major Z (*m_ssEntity) << " 40" << endl; // - (*m_ssEntity) << ratio - << endl; // Ratio + (*m_ssEntity) << ratio << endl; // Ratio // (*m_ssEntity) << "210" << endl; //extrusion dir?? // (*m_ssEntity) << "0" << endl; // (*m_ssEntity) << "220" << endl;