Streamline scaling for DXF import

Eliminate m_measurement_inch to clean up logic for priority of MEASUREMENT and INSUNITS.
Save the actual scaling factor rather than the scaling enum so a switch statement is not executed for each call to mm()
Add to CDxfRead the work to handle dxfScaling option, ImpExpDxfRead just has to set it up now.
Get the scaling factor from a lookup table rather than a switch statement
Display a message explaining what the scaling factor is and where it comes from
Remove large amount of Lint.
This commit is contained in:
Kevin Martin
2023-12-14 07:02:04 -05:00
committed by Yorik van Havre
parent 51e4561fd7
commit c2fb684ff7
7 changed files with 969 additions and 864 deletions

View File

@@ -78,10 +78,12 @@ using BRepAdaptor_HCurve = BRepAdaptor_Curve;
//******************************************************************************
// reading
ImpExpDxfRead::ImpExpDxfRead(std::string filepath, App::Document* pcDoc)
: CDxfRead(filepath.c_str())
ImpExpDxfRead::ImpExpDxfRead(const std::string& filepath, App::Document* pcDoc)
: CDxfRead(filepath)
, document(pcDoc)
, optionGroupLayers(false)
, optionImportAnnotations(true)
{
document = pcDoc;
setOptionSource("User parameter:BaseApp/Preferences/Mod/Draft");
setOptions();
}
@@ -92,22 +94,17 @@ void ImpExpDxfRead::setOptions()
App::GetApplication().GetParameterGroupByPath(getOptionSource().c_str());
optionGroupLayers = hGrp->GetBool("groupLayers", false);
optionImportAnnotations = hGrp->GetBool("dxftext", false);
optionScaling = hGrp->GetFloat("dxfScaling", 1.0);
SetAdditionalScaling(hGrp->GetFloat("dxfScaling", 1.0));
}
gp_Pnt ImpExpDxfRead::makePoint(const double point3d[3]) const
void ImpExpDxfRead::OnReadLine(const Base::Vector3d& start,
const Base::Vector3d& end,
bool /*hidden*/)
{
if (optionScaling != 1.0) {
return {point3d[0] * optionScaling, point3d[1] * optionScaling, point3d[2] * optionScaling};
}
return {point3d[0], point3d[1], point3d[2]};
}
void ImpExpDxfRead::OnReadLine(const double* s, const double* e, bool /*hidden*/)
{
gp_Pnt p0 = makePoint(s);
gp_Pnt p1 = makePoint(e);
gp_Pnt p0 = makePoint(start);
gp_Pnt p1 = makePoint(end);
if (p0.IsEqual(p1, 0.00000001)) {
// TODO: Really?? What about the people designing integrated circuits?
return;
}
BRepBuilderAPI_MakeEdge makeEdge(p0, p1);
@@ -116,27 +113,27 @@ void ImpExpDxfRead::OnReadLine(const double* s, const double* e, bool /*hidden*/
}
void ImpExpDxfRead::OnReadPoint(const double* s)
void ImpExpDxfRead::OnReadPoint(const Base::Vector3d& start)
{
BRepBuilderAPI_MakeVertex makeVertex(makePoint(s));
BRepBuilderAPI_MakeVertex makeVertex(makePoint(start));
TopoDS_Vertex vertex = makeVertex.Vertex();
AddObject(new Part::TopoShape(vertex));
}
void ImpExpDxfRead::OnReadArc(const double* s,
const double* e,
const double* c,
void ImpExpDxfRead::OnReadArc(const Base::Vector3d& start,
const Base::Vector3d& end,
const Base::Vector3d& center,
bool dir,
bool /*hidden*/)
{
gp_Pnt p0 = makePoint(s);
gp_Pnt p1 = makePoint(e);
gp_Pnt p0 = makePoint(start);
gp_Pnt p1 = makePoint(end);
gp_Dir up(0, 0, 1);
if (!dir) {
up = -up;
}
gp_Pnt pc = makePoint(c);
gp_Pnt pc = makePoint(center);
gp_Circ circle(gp_Ax2(pc, up), p0.Distance(pc));
if (circle.Radius() > 0) {
BRepBuilderAPI_MakeEdge makeEdge(circle, p0, p1);
@@ -149,14 +146,17 @@ void ImpExpDxfRead::OnReadArc(const double* s,
}
void ImpExpDxfRead::OnReadCircle(const double* s, const double* c, bool dir, bool /*hidden*/)
void ImpExpDxfRead::OnReadCircle(const Base::Vector3d& start,
const Base::Vector3d& center,
bool dir,
bool /*hidden*/)
{
gp_Pnt p0 = makePoint(s);
gp_Pnt p0 = makePoint(start);
gp_Dir up(0, 0, 1);
if (!dir) {
up = -up;
}
gp_Pnt pc = makePoint(c);
gp_Pnt pc = makePoint(center);
gp_Circ circle(gp_Ax2(pc, up), p0.Distance(pc));
if (circle.Radius() > 0) {
BRepBuilderAPI_MakeEdge makeEdge(circle);
@@ -180,18 +180,18 @@ Handle(Geom_BSplineCurve) getSplineFromPolesAndKnots(struct SplineData& sd)
// handle the poles
TColgp_Array1OfPnt occpoles(1, sd.control_points);
int index = 1;
for (auto x : sd.controlx) {
occpoles(index++).SetX(x);
for (auto coordinate : sd.controlx) {
occpoles(index++).SetX(coordinate);
}
index = 1;
for (auto y : sd.controly) {
occpoles(index++).SetY(y);
for (auto coordinate : sd.controly) {
occpoles(index++).SetY(coordinate);
}
index = 1;
for (auto z : sd.controlz) {
occpoles(index++).SetZ(z);
for (auto coordinate : sd.controlz) {
occpoles(index++).SetZ(coordinate);
}
// handle knots and mults
@@ -202,10 +202,9 @@ Handle(Geom_BSplineCurve) getSplineFromPolesAndKnots(struct SplineData& sd)
TColStd_Array1OfInteger occmults(1, numKnots);
TColStd_Array1OfReal occknots(1, numKnots);
index = 1;
for (auto k : unique) {
size_t m = std::count(sd.knot.begin(), sd.knot.end(), k);
occknots(index) = k;
occmults(index) = m;
for (auto knot : unique) {
occknots(index) = knot;
occmults(index) = (int)std::count(sd.knot.begin(), sd.knot.end(), knot);
index++;
}
@@ -213,8 +212,8 @@ Handle(Geom_BSplineCurve) getSplineFromPolesAndKnots(struct SplineData& sd)
TColStd_Array1OfReal occweights(1, sd.control_points);
if (sd.weight.size() == std::size_t(sd.control_points)) {
index = 1;
for (auto w : sd.weight) {
occweights(index++) = w;
for (auto weight : sd.weight) {
occweights(index++) = weight;
}
}
else {
@@ -240,18 +239,18 @@ Handle(Geom_BSplineCurve) getInterpolationSpline(struct SplineData& sd)
// handle the poles
Handle(TColgp_HArray1OfPnt) fitpoints = new TColgp_HArray1OfPnt(1, sd.fit_points);
int index = 1;
for (auto x : sd.fitx) {
fitpoints->ChangeValue(index++).SetX(x);
for (auto coordinate : sd.fitx) {
fitpoints->ChangeValue(index++).SetX(coordinate);
}
index = 1;
for (auto y : sd.fity) {
fitpoints->ChangeValue(index++).SetY(y);
for (auto coordinate : sd.fity) {
fitpoints->ChangeValue(index++).SetY(coordinate);
}
index = 1;
for (auto z : sd.fitz) {
fitpoints->ChangeValue(index++).SetZ(z);
for (auto coordinate : sd.fitz) {
fitpoints->ChangeValue(index++).SetZ(coordinate);
}
Standard_Boolean periodic = sd.flag == 2;
@@ -288,21 +287,22 @@ void ImpExpDxfRead::OnReadSpline(struct SplineData& sd)
}
}
void ImpExpDxfRead::OnReadEllipse(const double* c,
// NOLINTBEGIN(bugprone-easily-swappable-parameters)
void ImpExpDxfRead::OnReadEllipse(const Base::Vector3d& center,
double major_radius,
double minor_radius,
double rotation,
double /*start_angle*/,
double /*end_angle*/,
bool dir)
// NOLINTEND(bugprone-easily-swappable-parameters)
{
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);
gp_Pnt pc = makePoint(center);
gp_Elips ellipse(gp_Ax2(pc, up), major_radius, minor_radius);
ellipse.Rotate(gp_Ax1(pc, up), rotation);
if (ellipse.MinorRadius() > 0) {
BRepBuilderAPI_MakeEdge makeEdge(ellipse);
@@ -315,34 +315,34 @@ void ImpExpDxfRead::OnReadEllipse(const double* c,
}
void ImpExpDxfRead::OnReadText(const double* point,
void ImpExpDxfRead::OnReadText(const Base::Vector3d& point,
const double height,
const char* text,
const std::string& text,
const double rotation)
{
// Note that our parameters do not contain all the information needed to properly orient the
// text. As a result the text will always appear on the XY plane
if (optionImportAnnotations) {
if (LayerName().substr(0, 6) != "BLOCKS") {
if (LayerName().rfind("BLOCKS", 0) != 0) {
PyObject* draftModule = nullptr;
Base::Vector3d insertionPoint(point[0], point[1], point[2]);
insertionPoint *= optionScaling;
Base::Rotation rot(Base::Vector3d(0, 0, 1), rotation);
PyObject* placement = new Base::PlacementPy(Base::Placement(insertionPoint, rot));
PyObject* placement = new Base::PlacementPy(Base::Placement(point, rot));
draftModule = PyImport_ImportModule("Draft");
if (draftModule != nullptr) {
// returns a wrapped App::FeaturePython
auto builtText = static_cast<App::FeaturePythonPyT<App::DocumentObjectPy>*>(
PyObject_CallMethod(draftModule,
"make_text",
"sOif",
text,
placement,
0,
height));
auto builtText = dynamic_cast<App::FeaturePythonPyT<App::DocumentObjectPy>*>(
// NOLINTNEXTLINE(readability/nolint)
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
(Base::PyObjectBase*)PyObject_CallMethod(draftModule,
"make_text",
"sOif",
text.c_str(),
placement,
0,
height));
if (builtText != nullptr) {
ApplyGuiStyles(
static_cast<App::FeaturePython*>(builtText->getDocumentObjectPtr()));
dynamic_cast<App::FeaturePython*>(builtText->getDocumentObjectPtr()));
}
}
// We own all the return values so we must release them.
@@ -356,9 +356,9 @@ void ImpExpDxfRead::OnReadText(const double* point,
}
void ImpExpDxfRead::OnReadInsert(const double* point,
const double* scale,
const char* name,
void ImpExpDxfRead::OnReadInsert(const Base::Vector3d& point,
const Base::Vector3d& scale,
const std::string& name,
double rotation)
{
// std::cout << "Inserting block " << name << " rotation " << rotation << " pos " << point[0] <<
@@ -367,32 +367,26 @@ void ImpExpDxfRead::OnReadInsert(const double* point,
std::string prefix = "BLOCKS ";
prefix += name;
prefix += " ";
auto checkScale = [=](double v) {
return v != 0.0 ? v : 1.0;
auto checkScale = [=](double scale) {
return scale != 0.0 ? scale : 1.0;
};
for (std::map<std::string, std::vector<Part::TopoShape*>>::const_iterator i = layers.begin();
i != layers.end();
++i) {
std::string k = i->first;
if (k.substr(0, prefix.size()) == prefix) {
for (const auto& layer : layers) {
if (layer.first.substr(0, prefix.size()) == prefix) {
BRep_Builder builder;
TopoDS_Compound comp;
builder.MakeCompound(comp);
std::vector<Part::TopoShape*> v = i->second;
for (std::vector<Part::TopoShape*>::const_iterator j = v.begin(); j != v.end(); ++j) {
const TopoDS_Shape& sh = (*j)->getShape();
for (const auto& shape : layer.second) {
const TopoDS_Shape& sh = shape->getShape();
if (!sh.IsNull()) {
builder.Add(comp, sh);
}
}
if (!comp.IsNull()) {
Part::TopoShape* pcomp = new Part::TopoShape(comp);
auto pcomp = new Part::TopoShape(comp);
Base::Matrix4D mat;
mat.scale(checkScale(scale[0]), checkScale(scale[1]), checkScale(scale[2]));
mat.rotZ(rotation);
mat.move(point[0] * optionScaling,
point[1] * optionScaling,
point[2] * optionScaling);
mat.move(point[0], point[1], point[2]);
pcomp->transformShape(mat, true);
AddObject(pcomp);
}
@@ -401,35 +395,36 @@ void ImpExpDxfRead::OnReadInsert(const double* point,
}
void ImpExpDxfRead::OnReadDimension(const double* s,
const double* e,
const double* point,
void ImpExpDxfRead::OnReadDimension(const Base::Vector3d& start,
const Base::Vector3d& end,
const Base::Vector3d& point,
double /*rotation*/)
{
if (optionImportAnnotations) {
PyObject* draftModule = nullptr;
PyObject* start = new Base::VectorPy(Base::Vector3d(s[0], s[1], s[2]) * optionScaling);
PyObject* end = new Base::VectorPy(Base::Vector3d(e[0], e[1], e[2]) * optionScaling);
PyObject* lineLocation =
new Base::VectorPy(Base::Vector3d(point[0], point[1], point[2]) * optionScaling);
PyObject* startPy = new Base::VectorPy(start);
PyObject* endPy = new Base::VectorPy(end);
PyObject* lineLocationPy = new Base::VectorPy(point);
draftModule = PyImport_ImportModule("Draft");
if (draftModule != nullptr) {
// returns a wrapped App::FeaturePython
auto builtDim = static_cast<App::FeaturePythonPyT<App::DocumentObjectPy>*>(
PyObject_CallMethod(draftModule,
"make_linear_dimension",
"OOO",
start,
end,
lineLocation));
auto builtDim = dynamic_cast<App::FeaturePythonPyT<App::DocumentObjectPy>*>(
// NOLINTNEXTLINE(readability/nolint)
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
(Base::PyObjectBase*)PyObject_CallMethod(draftModule,
"make_linear_dimension",
"OOO",
startPy,
endPy,
lineLocationPy));
if (builtDim != nullptr) {
ApplyGuiStyles(static_cast<App::FeaturePython*>(builtDim->getDocumentObjectPtr()));
ApplyGuiStyles(dynamic_cast<App::FeaturePython*>(builtDim->getDocumentObjectPtr()));
}
}
// We own all the return values so we must release them.
Py_DECREF(start);
Py_DECREF(end);
Py_DECREF(lineLocation);
Py_DECREF(startPy);
Py_DECREF(endPy);
Py_DECREF(lineLocationPy);
Py_XDECREF(draftModule);
}
}
@@ -438,15 +433,16 @@ void ImpExpDxfRead::OnReadDimension(const double* s,
void ImpExpDxfRead::AddObject(Part::TopoShape* shape)
{
std::vector<Part::TopoShape*> vec;
if (layers.count(LayerName())) {
vec = layers[LayerName()];
std::string destinationLayerName(LayerName());
if (layers.count(destinationLayerName) != 0) {
vec = layers[destinationLayerName];
}
vec.push_back(shape);
layers[LayerName()] = vec;
layers[destinationLayerName] = vec;
if (!optionGroupLayers) {
if (LayerName().substr(0, 6) != "BLOCKS") {
Part::Feature* pcFeature =
static_cast<Part::Feature*>(document->addObject("Part::Feature", "Shape"));
if (destinationLayerName.rfind("BLOCKS", 0) != 0) {
auto pcFeature =
dynamic_cast<Part::Feature*>(document->addObject("Part::Feature", "Shape"));
pcFeature->Shape.setValue(shape->getShape());
ApplyGuiStyles(pcFeature);
}
@@ -461,33 +457,31 @@ std::string ImpExpDxfRead::Deformat(const char* text)
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 < strlen(text); i++) {
if (text[i] == '\\') {
char ch = text[i];
if (ch == '\\') {
escape = true;
}
else if (escape) {
if (longescape) {
if (text[i] == ';') {
if (ch == ';') {
escape = false;
longescape = false;
}
}
else if ((ch == 'H') || (ch == 'h') || (ch == 'Q') || (ch == 'q') || (ch == 'W')
|| (ch == 'w') || (ch == 'F') || (ch == 'f') || (ch == 'A') || (ch == 'a')
|| (ch == 'C') || (ch == 'c') || (ch == 'T') || (ch == 't')) {
longescape = true;
}
else {
if ((text[i] == 'H') || (text[i] == 'h') || (text[i] == 'Q') || (text[i] == 'q')
|| (text[i] == 'W') || (text[i] == 'w') || (text[i] == 'F') || (text[i] == 'f')
|| (text[i] == 'A') || (text[i] == 'a') || (text[i] == 'C') || (text[i] == 'c')
|| (text[i] == 'T') || (text[i] == 't')) {
longescape = true;
}
else {
if ((text[i] == 'P') || (text[i] == 'p')) {
ss << "\n";
}
escape = false;
if ((ch == 'P') || (ch == 'p')) {
ss << "\n";
}
escape = false;
}
}
else if ((text[i] != '{') && (text[i] != '}')) {
ss << text[i];
else if ((ch != '{') && (ch != '}')) {
ss << ch;
}
}
return ss.str();
@@ -497,28 +491,23 @@ std::string ImpExpDxfRead::Deformat(const char* text)
void ImpExpDxfRead::AddGraphics() const
{
if (optionGroupLayers) {
for (std::map<std::string, std::vector<Part::TopoShape*>>::const_iterator i =
layers.begin();
i != layers.end();
++i) {
for (const auto& layer : layers) {
BRep_Builder builder;
TopoDS_Compound comp;
builder.MakeCompound(comp);
std::string k = i->first;
std::string k = layer.first;
if (k == "0") { // FreeCAD doesn't like an object name being '0'...
k = "LAYER_0";
}
std::vector<Part::TopoShape*> v = i->second;
if (k.substr(0, 6) != "BLOCKS") {
for (std::vector<Part::TopoShape*>::const_iterator j = v.begin(); j != v.end();
++j) {
const TopoDS_Shape& sh = (*j)->getShape();
if (k.rfind("BLOCKS", 0) != 0) {
for (const auto& shape : layer.second) {
const TopoDS_Shape& sh = shape->getShape();
if (!sh.IsNull()) {
builder.Add(comp, sh);
}
}
if (!comp.IsNull()) {
Part::Feature* pcFeature = static_cast<Part::Feature*>(
auto pcFeature = dynamic_cast<Part::Feature*>(
document->addObject("Part::Feature", k.c_str()));
pcFeature->Shape.setValue(comp);
}
@@ -530,7 +519,7 @@ void ImpExpDxfRead::AddGraphics() const
//******************************************************************************
// writing
void gPntToTuple(double* result, gp_Pnt& p)
void gPntToTuple(double result[3], gp_Pnt& p)
{
result[0] = p.X();
result[1] = p.Y();
@@ -574,9 +563,9 @@ void ImpExpDxfWrite::exportShape(const TopoDS_Shape input)
if (adapt.GetType() == GeomAbs_Circle) {
double f = adapt.FirstParameter();
double l = adapt.LastParameter();
gp_Pnt s = adapt.Value(f);
gp_Pnt start = adapt.Value(f);
gp_Pnt e = adapt.Value(l);
if (fabs(l - f) > 1.0 && s.SquareDistance(e) < 0.001) {
if (fabs(l - f) > 1.0 && start.SquareDistance(e) < 0.001) {
exportCircle(adapt);
}
else {
@@ -586,9 +575,9 @@ void ImpExpDxfWrite::exportShape(const TopoDS_Shape input)
else if (adapt.GetType() == GeomAbs_Ellipse) {
double f = adapt.FirstParameter();
double l = adapt.LastParameter();
gp_Pnt s = adapt.Value(f);
gp_Pnt start = adapt.Value(f);
gp_Pnt e = adapt.Value(l);
if (fabs(l - f) > 1.0 && s.SquareDistance(e) < 0.001) {
if (fabs(l - f) > 1.0 && start.SquareDistance(e) < 0.001) {
if (m_polyOverride) {
if (m_version >= 14) {
exportLWPoly(adapt);

View File

@@ -39,19 +39,25 @@ namespace Import
class ImportExport ImpExpDxfRead: public CDxfRead
{
public:
ImpExpDxfRead(std::string filepath, App::Document* pcDoc);
ImpExpDxfRead(const std::string& filepath, App::Document* pcDoc);
// CDxfRead's virtual functions
void OnReadLine(const double* s, const double* e, bool hidden) override;
void OnReadPoint(const double* s) override;
void OnReadText(const double* point,
const double height,
const char* text,
const double rotation) override;
void
OnReadArc(const double* s, const double* e, const double* c, bool dir, bool hidden) override;
void OnReadCircle(const double* s, const double* c, bool dir, bool hidden) override;
void OnReadEllipse(const double* c,
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,
@@ -59,13 +65,13 @@ public:
double end_angle,
bool dir) override;
void OnReadSpline(struct SplineData& sd) override;
void OnReadInsert(const double* point,
const double* scale,
const char* name,
void OnReadInsert(const Base::Vector3d& point,
const Base::Vector3d& scale,
const std::string& name,
double rotation) override;
void OnReadDimension(const double* s,
const double* e,
const double* point,
void OnReadDimension(const Base::Vector3d& start,
const Base::Vector3d& end,
const Base::Vector3d& point,
double rotation) override;
void AddGraphics() const override;
@@ -77,24 +83,26 @@ public:
{
return m_optionSource;
}
void setOptionSource(std::string s)
void setOptionSource(const std::string& sourceName)
{
m_optionSource = s;
m_optionSource = sourceName;
}
void setOptions();
private:
gp_Pnt makePoint(const double point3d[3]) const;
static gp_Pnt makePoint(const Base::Vector3d& point3d)
{
return {point3d.x, point3d.y, point3d.z};
}
protected:
virtual void ApplyGuiStyles(Part::Feature*)
virtual void ApplyGuiStyles(Part::Feature* /*object*/)
{}
virtual void ApplyGuiStyles(App::FeaturePython*)
virtual void ApplyGuiStyles(App::FeaturePython* /*object*/)
{}
App::Document* document;
bool optionGroupLayers;
bool optionImportAnnotations;
double optionScaling;
std::map<std::string, std::vector<Part::TopoShape*>> layers;
std::string m_optionSource;
};
@@ -103,9 +111,13 @@ 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(const TopoDS_Shape input);
void exportShape(TopoDS_Shape input);
std::string getOptionSource()
{
return m_optionSource;
@@ -129,8 +141,8 @@ public:
int type);
void exportAngularDim(Base::Vector3d textLocn,
Base::Vector3d lineLocn,
Base::Vector3d extLine1Start,
Base::Vector3d extLine2Start,
Base::Vector3d extLine1End,
Base::Vector3d extLine2End,
Base::Vector3d apexPoint,
char* dimText);
void exportRadialDim(Base::Vector3d centerPoint,

File diff suppressed because it is too large Load Diff

View File

@@ -3,8 +3,8 @@
// This program is released under the BSD license. See the file COPYING for details.
// modified 2018 wandererfan
#ifndef _dxf_h_
#define _dxf_h_
#ifndef Included_dxf_h_
#define Included_dxf_h_
#ifdef _MSC_VER
#pragma warning(disable : 4251)
@@ -26,39 +26,93 @@
#include <App/Color.h>
#include <Mod/Import/ImportGlobal.h>
// For some reason Cpplint complains about some of the categories used by Clang-tidy
// However, cpplint also does not seem to use NOLINTE BEGIN and NOLINT END so we must use
// NOLINT NEXT LINE on each occurrence. [spaces added to avoid being seen by lint]
using ColorIndex_t = int; // DXF color index
typedef int ColorIndex_t; // DXF color index
typedef enum
// The C++ version we use does not support designated initiailzers, so we have a class to set this
// up
class DxfUnits
{
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;
public:
using eDxfUnits_t = 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,
kMaxUnit
};
private:
// NOLINTNEXTLINE(readability/nolint)
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
DxfUnits()
{
// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers)
m_factors[eInches] = 25.4;
m_factors[eFeet] = 25.4 * 12;
m_factors[eMiles] = 1609344.0;
m_factors[eMillimeters] = 1.0;
m_factors[eCentimeters] = 10.0;
m_factors[eMeters] = 1000.0;
m_factors[eKilometers] = 1000000.0;
m_factors[eMicroinches] = 25.4 / 1000.0;
m_factors[eMils] = 25.4 / 1000.0;
m_factors[eYards] = 3 * 12 * 25.4;
m_factors[eAngstroms] = 0.0000001;
m_factors[eNanometers] = 0.000001;
m_factors[eMicrons] = 0.001;
m_factors[eDecimeters] = 100.0;
m_factors[eDekameters] = 10000.0;
m_factors[eHectometers] = 100000.0;
m_factors[eGigameters] = 1000000000000.0;
m_factors[eAstronomicalUnits] = 149597870690000.0;
m_factors[eLightYears] = 9454254955500000000.0;
m_factors[eParsecs] = 30856774879000000000.0;
// NOLINTEND(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers)
}
public:
static double Factor(eDxfUnits_t enumValue)
{
// NOLINTNEXTLINE(readability/nolint)
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
return Instance.m_factors[enumValue];
}
static bool IsValid(eDxfUnits_t enumValue)
{
return enumValue > eUnspecified && enumValue <= eParsecs;
}
private:
static const DxfUnits Instance;
// NOLINTNEXTLINE(readability/nolint)
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
double m_factors[kMaxUnit];
};
// spline data for reading
struct SplineData
{
double norm[3] = {0, 0, 0};
Base::Vector3d norm;
int degree = 0;
int knots = 0;
int control_points = 0;
@@ -119,8 +173,45 @@ struct LWPolyDataOut
std::vector<double> Bulge;
point3D Extr;
};
typedef enum
{
using eDXFGroupCode_t = enum {
eObjectType = 0,
ePrimaryText = 1,
eName = 2,
eExtraText = 3,
eLinetypeName = 6,
eTextStyleName = 7,
eLayerName = 8,
eVariableName = 9,
ePrimaryPoint = 10,
ePoint2 = 11,
ePoint3 = 12,
ePoint4 = 13,
ePoint5 = 14,
eFloat1 = 40,
eFloat2 = 41,
eFloat3 = 42,
eFloat4 = 43,
eAngleDegrees1 = 50,
eAngleDegrees2 = 51,
eColor = 62,
eCoordinateSpace = 67,
eInteger1 = 70,
eInteger2 = 71,
eInteger3 = 72,
eInteger4 = 73,
eInteger5 = 74,
eUCSOrigin = 110,
eUCSXDirection = 111,
eUCSYDirection = 112,
eExtrusionDirection = 210,
// The following apply to points and directions in text DXF files to identify the three
// coordinates
eXOffset = 0,
eYOffset = 10,
eZOffset = 20
};
using eDXFVersion_t = enum {
RUnknown,
ROlder,
R10,
@@ -134,7 +225,20 @@ typedef enum
R2013,
R2018,
RNewer,
} eDXFVersion_t;
};
using eDimensionType_t = enum {
eLinear = 0, // Rotated, Horizontal, or Vertical
eAligned = 1,
eAngular = 2,
eDiameter = 3,
eRadius = 4,
eAngular3Point = 5,
eOrdinate = 6,
eTypeMask = 0xF,
eOnlyBlockReference = 32,
eOrdianetIsXType = 64,
eUserTextLocation = 128
};
//********************
class ImportExport CDxfWrite
@@ -148,38 +252,45 @@ private:
std::ostringstream* m_ssLayer;
protected:
void putLine(const Base::Vector3d s,
const Base::Vector3d e,
static Base::Vector3d toVector3d(const double* coordinatesXYZ)
{
// NOLINTNEXTLINE(readability/nolint)
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
return Base::Vector3d(coordinatesXYZ[0], coordinatesXYZ[1], coordinatesXYZ[2]);
}
void putLine(const Base::Vector3d& start,
const Base::Vector3d& end,
std::ostringstream* outStream,
const std::string handle,
const std::string ownerHandle);
const std::string& handle,
const std::string& ownerHandle);
void putText(const char* text,
const Base::Vector3d location1,
const Base::Vector3d location2,
const double height,
const int horizJust,
const Base::Vector3d& location1,
const Base::Vector3d& location2,
double height,
int horizJust,
std::ostringstream* outStream,
const std::string handle,
const std::string ownerHandle);
void putArrow(Base::Vector3d arrowPos,
Base::Vector3d barb1Pos,
Base::Vector3d barb2Pos,
const std::string& handle,
const std::string& ownerHandle);
void putArrow(Base::Vector3d& arrowPos,
Base::Vector3d& barb1Pos,
Base::Vector3d& barb2Pos,
std::ostringstream* outStream,
const std::string handle,
const std::string ownerHandle);
const std::string& handle,
const std::string& ownerHandle);
//! copy boiler plate file
std::string getPlateFile(std::string fileSpec);
void setDataDir(std::string s)
void setDataDir(const std::string& dirName)
{
m_dataDir = s;
m_dataDir = dirName;
}
std::string getHandle();
std::string getEntityHandle();
std::string getLayerHandle();
std::string getBlockHandle();
std::string getBlkRecordHandle();
// NOLINTBEGIN(cppcoreguidelines-non-private-member-variables-in-classes)
std::string m_optionSource;
int m_version;
int m_handle;
@@ -199,15 +310,20 @@ protected:
std::vector<std::string> m_layerList;
std::vector<std::string> m_blockList;
std::vector<std::string> m_blkRecordList;
// NOLINTEND(cppcoreguidelines-non-private-member-variables-in-classes)
public:
explicit CDxfWrite(const char* filepath);
CDxfWrite(const CDxfWrite&) = delete;
CDxfWrite(const CDxfWrite&&) = delete;
CDxfWrite& operator=(const CDxfWrite&) = delete;
CDxfWrite& operator=(const CDxfWrite&&) = delete;
~CDxfWrite();
void init();
void endRun();
bool Failed()
bool Failed() const
{
return m_fail;
}
@@ -217,37 +333,39 @@ public:
{
return m_layerName;
}
void setLayerName(std::string s);
void setVersion(int v)
void setLayerName(std::string name);
void setVersion(int version)
{
m_version = v;
m_version = version;
}
void setPolyOverride(bool b)
void setPolyOverride(bool setting)
{
m_polyOverride = b;
m_polyOverride = setting;
}
void addBlockName(std::string s, std::string blkRecordHandle);
void addBlockName(const std::string& name, const std::string& blkRecordHandle);
void writeLine(const double* s, const double* e);
void writeLine(const double* start, const double* end);
void writePoint(const double*);
void writeArc(const double* s, const double* e, const double* c, bool dir);
void writeEllipse(const double* c,
void writeArc(const double* start, const double* end, const double* center, bool dir);
void writeEllipse(const double* center,
double major_radius,
double minor_radius,
double rotation,
double start_angle,
double end_angle,
bool endIsCW);
void writeCircle(const double* c, double radius);
void writeCircle(const double* center, double radius);
void writeSpline(const SplineDataOut& sd);
void writeLWPolyLine(const LWPolyDataOut& pd);
void writePolyline(const LWPolyDataOut& pd);
// NOLINTNEXTLINE(readability/nolint)
// NOLINTNEXTLINE(readability-identifier-length)
void writeVertex(double x, double y, double z);
void writeText(const char* text,
const double* location1,
const double* location2,
const double height,
const int horizJust);
double height,
int horizJust);
void writeLinearDim(const double* textMidPoint,
const double* lineDefPoint,
const double* extLine1,
@@ -312,36 +430,50 @@ class ImportExport CDxfRead
{
private:
// Low-level reader members
std::ifstream* m_ifs;
int m_record_type = 0;
char m_record_data[1024] = "";
std::ifstream* m_ifs; // TODO: gsl::owner<ifstream>
eDXFGroupCode_t m_record_type = eObjectType;
std::string m_record_data;
bool m_not_eof = true;
int m_line = 0;
bool m_repeat_last_record = false;
// file-level options/properties
eDxfUnits_t m_eUnits = eMillimeters;
bool m_measurement_inch = false;
// The scaling from DXF units to millimetres.
// This does not include the dxfScaling option
// This has the value 0.0 if no units have been specified.
// If it is still 0 after reading the HEADER section, it iw set to comething sensible.
double m_unitScalingFactor = 0.0;
protected:
// An additional scaling factor which can be modified before readDXF is called, and will be
// incorporated into m_unitScalingFactor.
void SetAdditionalScaling(double scaling)
{
m_additionalScaling = scaling <= 0.0 ? 1.0 : scaling;
}
private:
double m_additionalScaling = 1.0;
// The following provide a state when reading any entity: If m_block_name is not empty the
// entity is in a BLOCK being defined, and LayerName() will return "BLOCKS xxxx" where xxxx is
// the block name. Otherwise m_layer_name will be the layer name from the entity records
// (default to "0") and LayerName() will return "ENTITIES xxxx" where xxxx is the layer name.
// This is clunky but it is a non-private interface and so difficult to change.
char m_layer_name[1024] = "0";
char m_block_name[1024] = "";
std::string m_layer_name;
std::string m_block_name;
// Error-handling control
bool m_ignore_errors = true;
bool m_fail = false;
std::map<std::string, ColorIndex_t>
m_layer_ColorIndex_map; // Mapping from layer name -> layer color index
// Mapping from layer name -> layer color index
std::map<std::string, ColorIndex_t> m_layer_ColorIndex_map;
const ColorIndex_t ColorBylayer = 256;
const ColorIndex_t ColorByBlock = 0;
// Readers for various parts of the DXF file.
bool ReadSection();
// Section readers (sections are identified by the type-2 (name) record they start with and each
// has its own reader function
bool ReadHeaderSection();
@@ -351,6 +483,12 @@ private:
bool ReadIgnoredSection();
// The Header section consists of multipel variables, only a few of which we give special
// handling.
bool ReadVariable();
bool ReadVersion();
bool ReadDWGCodePage();
// The Tables section consists of several tables (again identified by their type-2 record asfter
// th 0-TABLE record) each with its own reader
bool ReadLayerTable();
@@ -359,7 +497,6 @@ private:
// inline-defined to.
bool ReadIgnoredTable();
bool ReadUnits();
bool ReadLayer();
bool ReadEntity(); // Identify entity type and read it
@@ -373,134 +510,181 @@ private:
bool ReadSpline();
bool ReadLwPolyLine();
bool ReadPolyLine();
typedef struct
struct VertexInfo
{
double location[3];
double bulge;
} VertexInfo;
Base::Vector3d location;
double bulge = 0;
};
bool OnReadPolyline(std::list<VertexInfo>&, int flags);
void OnReadArc(double start_angle,
double end_angle,
double radius,
const double* c,
const Base::Vector3d& center,
double z_extrusion_dir,
bool hidden);
void OnReadCircle(const double* c, double radius, bool hidden);
void OnReadEllipse(const double* c,
const double* m,
void OnReadCircle(const Base::Vector3d& center, double radius, bool hidden);
void OnReadEllipse(const Base::Vector3d& center,
const Base::Vector3d& majorAxisEnd,
double ratio,
double start_angle,
double end_angle);
bool ReadInsert();
bool ReadDimension();
bool ReadUnknownEntity();
// Helper for reading common attributes for entities
void InitializeAttributes();
void InitializeCommonEntityAttributes();
void Setup3DVectorAttribute(int x_record_type, double destination[3]);
void SetupScaledDoubleAttribute(int record_type, double& destination);
void SetupScaledDoubleIntoList(int record_type, std::list<double>& destination);
void Setup3DCoordinatesIntoLists(int x_record_type,
void Setup3DVectorAttribute(eDXFGroupCode_t x_record_type, Base::Vector3d& destination);
void SetupScaledDoubleAttribute(eDXFGroupCode_t record_type, double& destination);
void SetupScaledDoubleIntoList(eDXFGroupCode_t record_type, std::list<double>& destination);
void Setup3DCoordinatesIntoLists(eDXFGroupCode_t x_record_type,
std::list<double>& x_destination,
std::list<double>& y_destination,
std::list<double>& z_destination);
void SetupStringAttribute(int record_type, char* destination);
void SetupStringAttribute(int record_type, std::string& destination);
void SetupStringAttribute(eDXFGroupCode_t record_type, std::string& destination);
std::map<int, std::pair<void (*)(CDxfRead*, void*), void*>> m_coordinate_attributes;
static void ProcessScaledDouble(CDxfRead* object, void* target);
static void ProcessScaledDoubleIntoList(CDxfRead* object, void* target);
static void ProcessString(CDxfRead* object, void* target);
static void ProcessStdString(CDxfRead* object, void* target);
// For all types T where strean >> x and x = 0 works
template<typename T>
void SetupValueAttribute(int record_type, T& target);
void SetupValueAttribute(eDXFGroupCode_t record_type, T& destination);
// TODO: Once all compilers used for FreeCAD support class-level template specializations,
// SetupValueAttribute could have specializations and replace SetupStringAttribute etc.
// The template specialization is required to handle the (char *) case, which would
// otherwise try to read the actual pointer from the stream, or... what?
// The specialization would also handle the default value when it cannot be zero.
template<typename T>
static void ProcessValue(CDxfRead* object, void* target);
static void ProcessValue(CDxfRead* object, void* target)
{
ParseValue<T>(object, target);
}
template<typename T>
static bool ParseValue(CDxfRead* object, void* target);
bool ProcessAttribute();
void ProcessAllAttributes();
bool ReadBlockInfo();
bool ReadVersion();
bool ReadDWGCodePage();
bool ResolveEncoding();
bool get_next_record();
void repeat_last_record();
bool (CDxfRead::*stringToUTF8)(std::string&) const = &CDxfRead::UTF8ToUTF8;
protected:
// common entity properties. Some properties are accumulated local to the reader method and
// passed to the ReadXxxx virtual method. Others are collected here as private values and also
// passed to ReadXxxx. Finally some of the attributes are accessed using references to
// public/protected fields or methods (such as LayerName()). Altogether a bit of a mishmash.
// NOLINTBEGIN(cppcoreguidelines-non-private-member-variables-in-classes)
ColorIndex_t m_ColorIndex = 0;
char m_LineType[1024] = "";
std::string m_LineType;
eDXFVersion_t m_version = RUnknown; // Version from $ACADVER variable in DXF
const char* (CDxfRead::*stringToUTF8)(const char*) const = &CDxfRead::UTF8ToUTF8;
// Although this is called "ImportWarning" it is just a wrapper to write a warning eithout any
// NOLINTEND(cppcoreguidelines-non-private-member-variables-in-classes)
// Although this is called "ImportError" it is just a wrapper to write a warning eithout any
// additional information such as a line number and as such, may be split into a basic
// message-writer and something that adds a line number.
//
// The "Developer" methods stick a line break into the output window.
// The "User" methods show up in the notification popup window.
// "Critical" causes a popup messagebox
// "Warnings" show up in yellow in the output window and with a warning icon in the notification
// popup "Error" show up in red in the output window and with an error icon in the notification
// popup "Notification" show up in black in the output window and an information icon in the
// notification popup "Log" goes to a log somewhere and not to the screen/user at all
template<typename... args>
void ImportError(const char* format, args... argValues) const
void ImportError(const char* format, args&&... argValues) const
{
Base::ConsoleSingleton::Instance().Warning(format, argValues...);
Base::ConsoleSingleton::Instance().Warning(format, std::forward<args>(argValues)...);
}
void UnsupportedFeature(const char* format, ...);
template<typename... args>
void ImportObservation(const char* format, args&&... argValues) const
{
Base::ConsoleSingleton::Instance().Message(format, std::forward<args>(argValues)...);
}
template<typename... args>
void UnsupportedFeature(const char* format, args&&... argValues);
private:
std::map<std::string, std::pair<int, int>> m_unsupportedFeaturesNoted;
const std::string* m_CodePage =
nullptr; // Code Page name from $DWGCODEPAGE or null if none/not read yet
std::string m_CodePage; // Code Page name from $DWGCODEPAGE or null if none/not read yet
// The following was going to be python's canonical name for the encoding, but this is (a) not
// easily found and (b) does not speed up finding the encoding object.
const std::string* m_encoding =
nullptr; // A name for the encoding implied by m_version and m_CodePage
const char* UTF8ToUTF8(const char* encoded) const;
const char* GeneralToUTF8(const char* encoded) const;
std::string m_encoding; // A name for the encoding implied by m_version and m_CodePage
bool UTF8ToUTF8(std::string& encoded) const;
bool GeneralToUTF8(std::string& encoded) const;
// Compare with specific object name for eObjectType records
bool IsObjectName(const char* testName) const
{
return m_record_data == testName;
}
// Compare with specific variable name for eVariableName records
bool IsVariableName(const char* testName) const
{
return m_record_data == testName;
}
public:
explicit CDxfRead(const char* filepath); // this opens the file
virtual ~CDxfRead(); // this closes the file
explicit CDxfRead(const std::string& filepath); // this opens the file
CDxfRead(const CDxfRead&) = delete;
CDxfRead(const CDxfRead&&) = delete;
CDxfRead& operator=(const CDxfRead&) = delete;
CDxfRead& operator=(const CDxfRead&&) = delete;
virtual ~CDxfRead(); // this closes the file
bool Failed()
bool Failed() const
{
return m_fail;
}
void DoRead(
const bool ignore_errors = false); // this reads the file and calls the following functions
void
DoRead(bool ignore_errors = false); // this reads the file and calls the following functions
double mm(double value) const;
private:
double mm(double value) const
{
if (m_unitScalingFactor == 0.0) {
// No scaling factor has been specified.
// TODO: Resolve this once we know the HEADER is complete
return value;
}
return m_unitScalingFactor * value;
}
public:
bool IgnoreErrors() const
{
return (m_ignore_errors);
}
virtual void OnReadLine(const double* /*s*/, const double* /*e*/, bool /*hidden*/)
virtual void
OnReadLine(const Base::Vector3d& /*start*/, const Base::Vector3d& /*end*/, bool /*hidden*/)
{}
virtual void OnReadPoint(const double* /*s*/)
virtual void OnReadPoint(const Base::Vector3d& /*start*/)
{}
virtual void OnReadText(const double* /*point*/,
virtual void OnReadText(const Base::Vector3d& /*point*/,
const double /*height*/,
const char* /*text*/,
const std::string& /*text*/,
const double /*rotation*/)
{}
virtual void OnReadArc(const double* /*s*/,
const double* /*e*/,
const double* /*c*/,
virtual void OnReadArc(const Base::Vector3d& /*start*/,
const Base::Vector3d& /*end*/,
const Base::Vector3d& /*center*/,
bool /*dir*/,
bool /*hidden*/)
{}
virtual void
OnReadCircle(const double* /*s*/, const double* /*c*/, bool /*dir*/, bool /*hidden*/)
virtual void OnReadCircle(const Base::Vector3d& /*start*/,
const Base::Vector3d& /*center*/,
bool /*dir*/,
bool /*hidden*/)
{}
virtual void OnReadEllipse(const double* /*c*/,
virtual void OnReadEllipse(const Base::Vector3d& /*center*/,
double /*major_radius*/,
double /*minor_radius*/,
double /*rotation*/,
@@ -510,14 +694,14 @@ public:
{}
virtual void OnReadSpline(struct SplineData& /*sd*/)
{}
virtual void OnReadInsert(const double* /*point*/,
const double* /*scale*/,
const char* /*name*/,
virtual void OnReadInsert(const Base::Vector3d& /*point*/,
const Base::Vector3d& /*scale*/,
const std::string& /*name*/,
double /*rotation*/)
{}
virtual void OnReadDimension(const double* /*s*/,
const double* /*e*/,
const double* /*point*/,
virtual void OnReadDimension(const Base::Vector3d& /*start*/,
const Base::Vector3d& /*end*/,
const Base::Vector3d& /*point*/,
double /*rotation*/)
{}
virtual void AddGraphics() const

View File

@@ -40,8 +40,10 @@ public:
ImpExpDxfReadGui(std::string filepath, App::Document* pcDoc);
protected:
void ApplyGuiStyles(Part::Feature*);
void ApplyGuiStyles(App::FeaturePython*);
void ApplyGuiStyles(Part::Feature* object) override;
void ApplyGuiStyles(App::FeaturePython* object) override;
private:
Gui::Document* GuiDocument;
};
} // namespace ImportGui

View File

@@ -7,25 +7,31 @@
AreaDxfRead::AreaDxfRead(CArea* area, const char* filepath):CDxfRead(filepath), m_area(area){}
void AreaDxfRead::StartCurveIfNecessary(const double* s)
void AreaDxfRead::StartCurveIfNecessary(const Base::Vector3d& startPoint) const
{
Point ps(s);
if((m_area->m_curves.size() == 0) || (m_area->m_curves.back().m_vertices.size() == 0) || (m_area->m_curves.back().m_vertices.back().m_p != ps))
Point ps(startPoint.x, startPoint.y);
if(m_area->m_curves.empty() || m_area->m_curves.back().m_vertices.empty() || m_area->m_curves.back().m_vertices.back().m_p != ps)
{
// start a new curve
m_area->m_curves.emplace_back();
m_area->m_curves.back().m_vertices.push_back(ps);
m_area->m_curves.back().m_vertices.emplace_back(ps);
}
}
void AreaDxfRead::OnReadLine(const double* s, const double* e, bool /*hidden*/)
void AreaDxfRead::OnReadLine(const Base::Vector3d& start, const Base::Vector3d& end, bool /*hidden*/)
{
StartCurveIfNecessary(s);
m_area->m_curves.back().m_vertices.push_back(Point(e));
StartCurveIfNecessary(start);
m_area->m_curves.back().m_vertices.emplace_back(Point(end.x, end.y));
}
void AreaDxfRead::OnReadArc(const double* s, const double* e, const double* c, bool dir, bool /*hidden*/)
void AreaDxfRead::OnReadArc(const Base::Vector3d& start,
const Base::Vector3d& end,
const Base::Vector3d& center,
bool dir,
bool /*hidden*/)
{
StartCurveIfNecessary(s);
m_area->m_curves.back().m_vertices.emplace_back(dir?1:0, Point(e), Point(c));
StartCurveIfNecessary(start);
m_area->m_curves.back().m_vertices.emplace_back(dir ? 1 : 0,
Point(end.x, end.y),
Point(center.x, center.y));
}

View File

@@ -11,13 +11,13 @@ class CArea;
class CCurve;
class AreaDxfRead : public CDxfRead{
void StartCurveIfNecessary(const double* s);
void StartCurveIfNecessary(const Base::Vector3d& startPoint) const;
public:
CArea* m_area;
AreaDxfRead(CArea* area, const char* filepath);
// AreaDxfRead's virtual functions
void OnReadLine(const double* s, const double* e, bool /*hidden*/) override;
void OnReadArc(const double* s, const double* e, const double* c, bool dir, bool /*hidden*/) override;
void OnReadLine(const Base::Vector3d& start, const Base::Vector3d& end, bool /*hidden*/) override;
void OnReadArc(const Base::Vector3d& start, const Base::Vector3d& end, const Base::Vector3d& center, bool dir, bool /*hidden*/) override;
};