Files
create/src/Mod/Import/App/dxf/ImpExpDxf.h
2025-06-25 07:41:03 +02:00

436 lines
17 KiB
C++

/***************************************************************************
* Copyright (c) 2015 Yorik van Havre (yorik@uncreated.net) *
* *
* 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 <gp_Pnt.hxx>
#include <App/Document.h>
#include <TopoDS_Shape.hxx>
#include <Mod/Part/App/TopoShape.h>
#include <Mod/Part/App/PartFeature.h>
#include "dxf.h"
class BRepAdaptor_Curve;
namespace Import
{
class ImportExport ImpExpDxfRead: public CDxfRead
{
public:
ImpExpDxfRead(const std::string& filepath, App::Document* pcDoc);
ImpExpDxfRead(const ImpExpDxfRead&) = delete;
ImpExpDxfRead(ImpExpDxfRead&&) = delete;
void operator=(const ImpExpDxfRead&) = delete;
void operator=(ImpExpDxfRead&&) = delete;
~ImpExpDxfRead() override
{
Py_XDECREF(DraftModule);
}
Py::Object getStatsAsPyObject();
bool ReadEntitiesSection() override;
// CDxfRead's virtual functions
bool OnReadBlock(const std::string& name, int flags) override;
void OnReadLine(const Base::Vector3d& start, const Base::Vector3d& end, bool hidden) override;
void OnReadPoint(const Base::Vector3d& start) override;
void OnReadText(const Base::Vector3d& point,
double height,
const std::string& text,
double rotation) override;
void OnReadArc(const Base::Vector3d& start,
const Base::Vector3d& end,
const Base::Vector3d& center,
bool dir,
bool hidden) override;
void OnReadCircle(const Base::Vector3d& start,
const Base::Vector3d& center,
bool dir,
bool hidden) override;
void OnReadEllipse(const Base::Vector3d& center,
double major_radius,
double minor_radius,
double rotation,
double start_angle,
double end_angle,
bool dir) override;
void OnReadSpline(struct SplineData& sd) override;
void OnReadInsert(const Base::Vector3d& point,
const Base::Vector3d& scale,
const std::string& name,
double rotation) override;
// Expand a block reference; this should only happen when the collector draws to the document
// rather than saving things The transform should include the OCS Orientation transform for the
// insertion.
void ExpandInsert(const std::string& name,
const Base::Matrix4D& transform,
const Base::Vector3d& point,
double rotation,
const Base::Vector3d& scale);
void OnReadDimension(const Base::Vector3d& start,
const Base::Vector3d& end,
const Base::Vector3d& point,
double rotation) override;
void OnReadPolyline(std::list<VertexInfo>& /*vertices*/, int flags) override;
std::string Deformat(const char* text); // Removes DXF formatting from texts
std::string getOptionSource()
{
return m_optionSource;
}
void setOptionSource(const std::string& sourceName)
{
m_optionSource = sourceName;
}
void setOptions();
private:
bool shouldSkipEntity() const
{
// This entity is in paper space, and the user setting says to ignore it.
return !m_importPaperSpaceEntities && m_entityAttributes.m_paperSpace;
}
static gp_Pnt makePoint(const Base::Vector3d& point3d)
{
return {point3d.x, point3d.y, point3d.z};
}
void MoveToLayer(App::DocumentObject* object) const;
// Combine all the shapes in the given shapes collection into a single shape, and AddObject that
// to the drawing. unref's all the shapes in the collection, possibly freeing them.
void CombineShapes(std::list<TopoDS_Shape>& shapes, const char* nameBase) const;
PyObject* DraftModule = nullptr;
protected:
PyObject* getDraftModule()
{
if (DraftModule == nullptr) {
static int times = 0;
DraftModule = PyImport_ImportModule("Draft");
if (DraftModule == nullptr && times++ == 0) {
ImportError("Unable to locate \"Draft\" module");
}
}
return DraftModule;
}
CDxfRead::Layer*
MakeLayer(const std::string& name, ColorIndex_t color, std::string&& lineType) override;
// Overrides for layer management so we can record the layer objects in the FreeCAD drawing that
// are associated with the layers in the DXF.
class Layer: public CDxfRead::Layer
{
public:
Layer(const std::string& name,
ColorIndex_t color,
std::string&& lineType,
PyObject* drawingLayer);
Layer(const Layer&) = delete;
Layer(Layer&&) = delete;
void operator=(const Layer&) = delete;
void operator=(Layer&&) = delete;
~Layer() override;
// The View object for the layer or Py_None (e.g. if no gui)
PyObject* const DraftLayerView;
std::vector<App::DocumentObject*> Contents;
void FinishLayer() const;
App::PropertyLinkListHidden* GroupContents;
};
using FeaturePythonBuilder =
std::function<App::FeaturePython*(const Base::Matrix4D& transform)>;
// Block management
class Block
{
public:
struct Insert
{
const Base::Vector3d Point;
const Base::Vector3d Scale;
const std::string Name;
const double Rotation;
// NOLINTNEXTLINE(readability/nolint)
// NOLINTNEXTLINE(modernize-pass-by-value) Pass by value adds unwarranted complexity
Insert(const std::string& Name,
const Base::Vector3d& Point,
double Rotation,
const Base::Vector3d& Scale)
: Point(Point)
, Scale(Scale)
, Name(Name)
, Rotation(Rotation)
{}
};
// NOLINTNEXTLINE(readability/nolint)
// NOLINTNEXTLINE(modernize-pass-by-value) Pass by value adds unwarranted complexity
Block(const std::string& name, int flags)
: Name(name)
, Flags(flags)
{}
const std::string Name;
const int Flags;
std::map<CDxfRead::CommonEntityAttributes, std::list<TopoDS_Shape>> Shapes;
std::map<CDxfRead::CommonEntityAttributes, std::list<FeaturePythonBuilder>>
FeatureBuildersList;
std::map<CDxfRead::CommonEntityAttributes, std::list<Insert>> Inserts;
};
private:
std::map<std::string, Block> Blocks;
App::Document* document;
std::string m_optionSource;
protected:
friend class DrawingEntityCollector;
void IncrementCreatedObjectCount()
{
m_stats.totalEntitiesCreated++;
}
virtual void ApplyGuiStyles(Part::Feature* /*object*/) const
{}
virtual void ApplyGuiStyles(App::FeaturePython* /*object*/) const
{}
// Gathering of created entities
class EntityCollector
{
public:
explicit EntityCollector(ImpExpDxfRead& reader)
: Reader(reader)
, previousCollector(reader.Collector)
{
Reader.Collector = this;
}
EntityCollector(const EntityCollector&) = delete;
EntityCollector(EntityCollector&&) = delete;
void operator=(const EntityCollector&) = delete;
void operator=(EntityCollector&&) = delete;
virtual ~EntityCollector()
{
if (Reader.Collector == this) {
Reader.Collector = previousCollector;
}
}
// Called by OnReadXxxx functions to add Part objects
virtual void AddObject(const TopoDS_Shape& shape, const char* nameBase) = 0;
// Called by OnReadXxxx functions to add FeaturePython (draft) objects.
// Because we can't readily copy Draft objects, this method instead takes a builder which,
// when called, creates and returns the object.
virtual void AddObject(FeaturePythonBuilder shapeBuilder) = 0;
// Called by OnReadInsert to either remember in a nested block or expand the block into the
// drawing
virtual void AddInsert(const Base::Vector3d& point,
const Base::Vector3d& scale,
const std::string& name,
double rotation) = 0;
protected:
ImpExpDxfRead& Reader;
private:
EntityCollector* const previousCollector;
};
class DrawingEntityCollector: public EntityCollector
{
// This collector places all objects into the drawing
public:
explicit DrawingEntityCollector(ImpExpDxfRead& reader)
: EntityCollector(reader)
{}
void AddObject(const TopoDS_Shape& shape, const char* nameBase) override;
void AddObject(FeaturePythonBuilder shapeBuilder) override;
void AddInsert(const Base::Vector3d& point,
const Base::Vector3d& scale,
const std::string& name,
double rotation) override
{
Reader.ExpandInsert(name, Reader.OCSOrientationTransform, point, rotation, scale);
}
};
class ShapeSavingEntityCollector: public DrawingEntityCollector
{
// This places draft objects into the drawing but stashes away Shapes.
public:
ShapeSavingEntityCollector(
ImpExpDxfRead& reader,
std::map<CDxfRead::CommonEntityAttributes, std::list<TopoDS_Shape>>& shapesList)
: DrawingEntityCollector(reader)
, ShapesList(shapesList)
{}
void AddObject(const TopoDS_Shape& shape, const char* /*nameBase*/) override
{
ShapesList[Reader.m_entityAttributes].push_back(shape);
}
private:
std::map<CDxfRead::CommonEntityAttributes, std::list<TopoDS_Shape>>& ShapesList;
};
#ifdef LATER
class PolylineEntityCollector: public CombiningDrawingEntityCollector
{
// This places draft objects into the drawing but stashes away Shapes.
public:
explicit PolylineEntityCollector(CDxfRead& reader)
: CombiningDrawingEntityCollector(reader)
, previousMmergeOption(reader.m_mergeOption)
{
// TODO: We also have to temporarily shift from DraftObjects to some other mode so the
// pieces of the polyline some through as shapes and not Draft objects, or maybe the
// polyline builder should not call OnArcRead and OnLineRead to do their dirty work.
}
~PolylineEntityCollector();
void AddObject(Part::TopoShape* shape) override;
void AddObject(App::FeaturePython* shape) override;
private:
const EntityCollector* previousEntityCollector;
const eEntityMergeType_t previousMmergeOption;
};
#endif
class BlockDefinitionCollector: public EntityCollector
{
// Collect all the entities plus their entityAttrubutes into given collections.
public:
BlockDefinitionCollector(
ImpExpDxfRead& reader,
std::map<CDxfRead::CommonEntityAttributes, std::list<TopoDS_Shape>>& shapesList,
std::map<CDxfRead::CommonEntityAttributes, std::list<FeaturePythonBuilder>>&
featureBuildersList,
std::map<CDxfRead::CommonEntityAttributes, std::list<Block::Insert>>& insertsList)
: EntityCollector(reader)
, ShapesList(shapesList)
, FeatureBuildersList(featureBuildersList)
, InsertsList(insertsList)
{}
// TODO: We will want AddAttributeDefinition as well.
void AddObject(const TopoDS_Shape& shape, const char* /*nameBase*/) override
{
ShapesList[Reader.m_entityAttributes].push_back(shape);
}
void AddObject(FeaturePythonBuilder shapeBuilder) override
{
FeatureBuildersList[Reader.m_entityAttributes].push_back(shapeBuilder);
}
void AddInsert(const Base::Vector3d& point,
const Base::Vector3d& scale,
const std::string& name,
double rotation) override
{
InsertsList[Reader.m_entityAttributes].emplace_back(
Block::Insert(name, point, rotation, scale));
}
private:
std::map<CDxfRead::CommonEntityAttributes, std::list<TopoDS_Shape>>& ShapesList;
std::map<CDxfRead::CommonEntityAttributes, std::list<FeaturePythonBuilder>>&
FeatureBuildersList;
std::map<CDxfRead::CommonEntityAttributes, std::list<Block::Insert>>& InsertsList;
};
private:
EntityCollector* Collector = nullptr;
};
class ImportExport ImpExpDxfWrite: public CDxfWrite
{
public:
explicit ImpExpDxfWrite(std::string filepath);
ImpExpDxfWrite(const ImpExpDxfWrite&) = delete;
ImpExpDxfWrite(const ImpExpDxfWrite&&) = delete;
ImpExpDxfWrite& operator=(const ImpExpDxfWrite&) = delete;
ImpExpDxfWrite& operator=(const ImpExpDxfWrite&&) = delete;
~ImpExpDxfWrite();
void exportShape(TopoDS_Shape input);
std::string getOptionSource()
{
return m_optionSource;
}
void setOptionSource(const std::string& s)
{
m_optionSource = s;
}
void setOptions();
void exportText(const char* text,
Base::Vector3d position1,
Base::Vector3d position2,
double size,
int just);
void exportLinearDim(Base::Vector3d textLocn,
Base::Vector3d lineLocn,
Base::Vector3d extLine1Start,
Base::Vector3d extLine2Start,
char* dimText,
int type);
void exportAngularDim(Base::Vector3d textLocn,
Base::Vector3d lineLocn,
Base::Vector3d extLine1End,
Base::Vector3d extLine2End,
Base::Vector3d apexPoint,
char* dimText);
void exportRadialDim(Base::Vector3d centerPoint,
Base::Vector3d textLocn,
Base::Vector3d arcPoint,
char* dimText);
void exportDiametricDim(Base::Vector3d textLocn,
Base::Vector3d arcPoint1,
Base::Vector3d arcPoint2,
char* dimText);
static bool gp_PntEqual(gp_Pnt p1, gp_Pnt p2);
static bool gp_PntCompare(gp_Pnt p1, gp_Pnt p2);
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); // LWPolyline not supported in R12?
void exportPolyline(BRepAdaptor_Curve& c);
// std::string m_optionSource;
double optionMaxLength;
bool optionPolyLine;
bool optionExpPoints;
};
} // namespace Import
#endif // IMPEXPDXF_H