From 31c5fd73f2f9dd026fc527cd384ec07211327a36 Mon Sep 17 00:00:00 2001 From: Hugues Delorme Date: Mon, 20 Nov 2023 18:51:41 +0100 Subject: [PATCH 01/10] IO_Dxf: syncronize with latest FreeCad + better MTEXT support Relates to GitHub #240 --- src/base/string_conv.h | 15 + src/io_dxf/dxf.cpp | 3367 +++++++++++++++++++++--------------- src/io_dxf/dxf.h | 335 ++-- src/io_dxf/io_dxf.cpp | 125 +- src/io_off/io_off_reader.h | 1 - 5 files changed, 2365 insertions(+), 1478 deletions(-) diff --git a/src/base/string_conv.h b/src/base/string_conv.h index 166ccb67..4570ee52 100644 --- a/src/base/string_conv.h +++ b/src/base/string_conv.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -136,6 +137,13 @@ template<> struct StringConv } }; +// std::string_view -> NCollection_Utf8String +template<> struct StringConv { + static auto to(std::string_view str) { + return NCollection_Utf8String(str.data(), static_cast(str.size())); + } +}; + // -- // -- Handle(TCollection_HAsciiString) -> X // -- @@ -180,6 +188,13 @@ template<> struct StringConv { } }; +// std::string -> NCollection_Utf8String +template<> struct StringConv { + static auto to(const std::string& str) { + return NCollection_Utf8String(str.c_str(), static_cast(str.size())); + } +}; + // -- // -- TCollection_AsciiString -> X // -- diff --git a/src/io_dxf/dxf.cpp b/src/io_dxf/dxf.cpp index 730be108..edcf93c6 100644 --- a/src/io_dxf/dxf.cpp +++ b/src/io_dxf/dxf.cpp @@ -3,15 +3,18 @@ // This program is released under the BSD license. See the file COPYING for details. // modified 2018 wandererfan -// MAYO: file initially taken from FreeCad/src/Mod/Import/App/dxf.cpp -- commit #1ac35d2 +// MAYO: file taken from FreeCad/src/Mod/Import/App/dxf.cpp -- commit #55292e9 #if defined(_MSC_VER) && !defined(_USE_MATH_DEFINES) //required by windows for M_PI definition # define _USE_MATH_DEFINES #endif +#include +#include #include #include +#include #include "../base/filepath.h" #include "dxf.h" @@ -19,10 +22,52 @@ namespace { template -void safe_strcpy(char (&dst)[N1], const char (&src)[N2]) { +void safe_strcpy(char (&dst)[N1], const char (&src)[N2]) +{ strncpy(dst, src, std::min(N1, N2)); } +class ScopedCLocale { +public: + ScopedCLocale(int category) + : m_category(category), + m_savedLocale(std::setlocale(category, nullptr)) + { + std::setlocale(category, "C"); + } + + ~ScopedCLocale() + { + std::setlocale(m_category, m_savedLocale); + } + +private: + int m_category = 0; + const char* m_savedLocale = nullptr; +}; + +double stringToDouble(const std::string& line) +{ + try { + return std::stod(line); + } catch (...) { + throw std::runtime_error("Failed to fetch double value from line:\n" + line); + } + + return 0.; +} + +int stringToInt(const std::string& line) +{ + try { + return std::stoi(line); + } catch (...) { + throw std::runtime_error("Failed to fetch int value from line:\n" + line); + } + + return 0; +} + } // namespace Base::Vector3d toVector3d(const double* a) @@ -34,27 +79,27 @@ Base::Vector3d toVector3d(const double* a) return result; } -CDxfWrite::CDxfWrite(const char* filepath) : -m_ofs(filepath, std::ios::out), -//TODO: these should probably be parameters in config file -//handles: -//boilerplate 0 - A00 -//used by dxf.cpp A01 - FFFE -//ACAD HANDSEED FFFF - -m_handle(0xA00), //room for 2560 handles in boilerplate files -//m_entityHandle(0x300), //don't need special ranges for handles -//m_layerHandle(0x30), -//m_blockHandle(0x210), -//m_blkRecordHandle(0x110), -m_polyOverride(false), -m_layerName("none") +CDxfWrite::CDxfWrite(const char* filepath) + : m_ofs(filepath, std::ios::out), + //TODO: these should probably be parameters in config file + //handles: + //boilerplate 0 - A00 + //used by dxf.cpp A01 - FFFE + //ACAD HANDSEED FFFF + + m_handle(0xA00), //room for 2560 handles in boilerplate files + //m_entityHandle(0x300), //don't need special ranges for handles + //m_layerHandle(0x30), + //m_blockHandle(0x210), + //m_blkRecordHandle(0x110), + m_polyOverride(false), + m_layerName("none") { // start the file m_fail = false; m_version = 12; - if(!m_ofs) + if (!m_ofs) m_fail = true; else m_ofs.imbue(std::locale::classic()); @@ -64,7 +109,7 @@ CDxfWrite::~CDxfWrite() { } -void CDxfWrite::init(void) +void CDxfWrite::init() { writeHeaderSection(); makeBlockRecordTableHead(); @@ -72,7 +117,7 @@ void CDxfWrite::init(void) } //! assemble pieces into output file -void CDxfWrite::endRun(void) +void CDxfWrite::endRun() { makeLayerTable(); makeBlockRecordTableBody(); @@ -90,7 +135,7 @@ void CDxfWrite::endRun(void) //*************************** //writeHeaderSection //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::writeHeaderSection(void) +void CDxfWrite::writeHeaderSection() { std::stringstream ss; #if 0 @@ -117,7 +162,7 @@ void CDxfWrite::writeHeaderSection(void) //*************************** //writeClassesSection //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::writeClassesSection(void) +void CDxfWrite::writeClassesSection() { if (m_version < 14) { return; @@ -133,7 +178,7 @@ void CDxfWrite::writeClassesSection(void) //*************************** //writeTablesSection //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::writeTablesSection(void) +void CDxfWrite::writeTablesSection() { //static tables section head end content std::stringstream ss; @@ -162,7 +207,7 @@ void CDxfWrite::writeTablesSection(void) //*************************** //makeLayerTable //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::makeLayerTable(void) +void CDxfWrite::makeLayerTable() { std::string tablehash = getLayerHandle(); m_ssLayer << " 0" << std::endl; @@ -230,63 +275,63 @@ void CDxfWrite::makeLayerTable(void) //*************************** //makeBlockRecordTableHead //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::makeBlockRecordTableHead(void) +void CDxfWrite::makeBlockRecordTableHead() { if (m_version < 14) { return; } - std::string tablehash = getBlkRecordHandle(); - m_saveBlockRecordTableHandle = tablehash; - m_ssBlkRecord << " 0" << std::endl; - m_ssBlkRecord << "TABLE" << std::endl; - m_ssBlkRecord << " 2" << std::endl; - m_ssBlkRecord << "BLOCK_RECORD" << std::endl; - m_ssBlkRecord << " 5" << std::endl; - m_ssBlkRecord << tablehash << std::endl; - m_ssBlkRecord << "330" << std::endl; - m_ssBlkRecord << "0" << std::endl; - m_ssBlkRecord << "100" << std::endl; - m_ssBlkRecord << "AcDbSymbolTable" << std::endl; - m_ssBlkRecord << " 70" << std::endl; - m_ssBlkRecord << (m_blockList.size() + 5) << std::endl; - - m_saveModelSpaceHandle = getBlkRecordHandle(); - m_ssBlkRecord << " 0" << std::endl; - m_ssBlkRecord << "BLOCK_RECORD" << std::endl; - m_ssBlkRecord << " 5" << std::endl; - m_ssBlkRecord << m_saveModelSpaceHandle << std::endl; - m_ssBlkRecord << "330" << std::endl; - m_ssBlkRecord << tablehash << std::endl; - m_ssBlkRecord << "100" << std::endl; - m_ssBlkRecord << "AcDbSymbolTableRecord" << std::endl; - m_ssBlkRecord << "100" << std::endl; - m_ssBlkRecord << "AcDbBlockTableRecord" << std::endl; - m_ssBlkRecord << " 2" << std::endl; - m_ssBlkRecord << "*MODEL_SPACE" << std::endl; -// m_ssBlkRecord << " 1" << std::endl; -// m_ssBlkRecord << " " << std::endl; - - m_savePaperSpaceHandle = getBlkRecordHandle(); - m_ssBlkRecord << " 0" << std::endl; - m_ssBlkRecord << "BLOCK_RECORD" << std::endl; - m_ssBlkRecord << " 5" << std::endl; - m_ssBlkRecord << m_savePaperSpaceHandle << std::endl; - m_ssBlkRecord << "330" << std::endl; - m_ssBlkRecord << tablehash << std::endl; - m_ssBlkRecord << "100" << std::endl; - m_ssBlkRecord << "AcDbSymbolTableRecord" << std::endl; - m_ssBlkRecord << "100" << std::endl; - m_ssBlkRecord << "AcDbBlockTableRecord" << std::endl; - m_ssBlkRecord << " 2" << std::endl; - m_ssBlkRecord << "*PAPER_SPACE" << std::endl; -// m_ssBlkRecord << " 1" << std::endl; -// m_ssBlkRecord << " " << std::endl; + std::string tablehash = getBlkRecordHandle(); + m_saveBlockRecordTableHandle = tablehash; + m_ssBlkRecord << " 0" << std::endl; + m_ssBlkRecord << "TABLE" << std::endl; + m_ssBlkRecord << " 2" << std::endl; + m_ssBlkRecord << "BLOCK_RECORD" << std::endl; + m_ssBlkRecord << " 5" << std::endl; + m_ssBlkRecord << tablehash << std::endl; + m_ssBlkRecord << "330" << std::endl; + m_ssBlkRecord << "0" << std::endl; + m_ssBlkRecord << "100" << std::endl; + m_ssBlkRecord << "AcDbSymbolTable" << std::endl; + m_ssBlkRecord << " 70" << std::endl; + m_ssBlkRecord << (m_blockList.size() + 5) << std::endl; + + m_saveModelSpaceHandle = getBlkRecordHandle(); + m_ssBlkRecord << " 0" << std::endl; + m_ssBlkRecord << "BLOCK_RECORD" << std::endl; + m_ssBlkRecord << " 5" << std::endl; + m_ssBlkRecord << m_saveModelSpaceHandle << std::endl; + m_ssBlkRecord << "330" << std::endl; + m_ssBlkRecord << tablehash << std::endl; + m_ssBlkRecord << "100" << std::endl; + m_ssBlkRecord << "AcDbSymbolTableRecord" << std::endl; + m_ssBlkRecord << "100" << std::endl; + m_ssBlkRecord << "AcDbBlockTableRecord" << std::endl; + m_ssBlkRecord << " 2" << std::endl; + m_ssBlkRecord << "*MODEL_SPACE" << std::endl; + // m_ssBlkRecord << " 1" << std::endl; + // m_ssBlkRecord << " " << std::endl; + + m_savePaperSpaceHandle = getBlkRecordHandle(); + m_ssBlkRecord << " 0" << std::endl; + m_ssBlkRecord << "BLOCK_RECORD" << std::endl; + m_ssBlkRecord << " 5" << std::endl; + m_ssBlkRecord << m_savePaperSpaceHandle << std::endl; + m_ssBlkRecord << "330" << std::endl; + m_ssBlkRecord << tablehash << std::endl; + m_ssBlkRecord << "100" << std::endl; + m_ssBlkRecord << "AcDbSymbolTableRecord" << std::endl; + m_ssBlkRecord << "100" << std::endl; + m_ssBlkRecord << "AcDbBlockTableRecord" << std::endl; + m_ssBlkRecord << " 2" << std::endl; + m_ssBlkRecord << "*PAPER_SPACE" << std::endl; + // m_ssBlkRecord << " 1" << std::endl; + // m_ssBlkRecord << " " << std::endl; } - + //*************************** //makeBlockRecordTableBody //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::makeBlockRecordTableBody(void) +void CDxfWrite::makeBlockRecordTableBody() { if (m_version < 14) { return; @@ -306,8 +351,8 @@ void CDxfWrite::makeBlockRecordTableBody(void) m_ssBlkRecord << "AcDbBlockTableRecord" << std::endl; m_ssBlkRecord << " 2" << std::endl; m_ssBlkRecord << b << std::endl; -// m_ssBlkRecord << " 70" << std::endl; -// m_ssBlkRecord << " 0" << std::endl; + // m_ssBlkRecord << " 70" << std::endl; + // m_ssBlkRecord << " 0" << std::endl; iBlkRecord++; } } @@ -315,7 +360,7 @@ void CDxfWrite::makeBlockRecordTableBody(void) //*************************** //makeBlockSectionHead //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::makeBlockSectionHead(void) +void CDxfWrite::makeBlockSectionHead() { m_ssBlock << " 0" << std::endl; m_ssBlock << "SECTION" << std::endl; @@ -432,8 +477,7 @@ std::string CDxfWrite::getPlateFile(const std::string& fileSpec) std::string line; std::ifstream inFile (fpath); - while (!inFile.eof()) - { + while (!inFile.eof()) { std::getline(inFile,line); if (!inFile.eof()) { outString << line << '\n'; @@ -443,7 +487,7 @@ std::string CDxfWrite::getPlateFile(const std::string& fileSpec) return outString.str(); } -std::string CDxfWrite::getHandle(void) +std::string CDxfWrite::getHandle() { m_handle++; std::stringstream ss; @@ -452,24 +496,44 @@ std::string CDxfWrite::getHandle(void) return ss.str(); } -std::string CDxfWrite::getEntityHandle(void) +std::string CDxfWrite::getEntityHandle() { return getHandle(); + // m_entityHandle++; + // std::stringstream ss; + // ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2); + // ss << m_entityHandle; + // return ss.str(); } -std::string CDxfWrite::getLayerHandle(void) +std::string CDxfWrite::getLayerHandle() { return getHandle(); + // m_layerHandle++; + // std::stringstream ss; + // ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2); + // ss << m_layerHandle; + // return ss.str(); } -std::string CDxfWrite::getBlockHandle(void) +std::string CDxfWrite::getBlockHandle() { return getHandle(); + // m_blockHandle++; + // std::stringstream ss; + // ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2); + // ss << m_blockHandle; + // return ss.str(); } -std::string CDxfWrite::getBlkRecordHandle(void) +std::string CDxfWrite::getBlkRecordHandle() { return getHandle(); + // m_blkRecordHandle++; + // std::stringstream ss; + // ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2); + // ss << m_blkRecordHandle; + // return ss.str(); } void CDxfWrite::addBlockName(std::string b, std::string h) @@ -480,8 +544,8 @@ void CDxfWrite::addBlockName(std::string b, std::string h) void CDxfWrite::setLayerName(std::string s) { - m_layerName = s; - m_layerList.push_back(s); + m_layerName = s; + m_layerList.push_back(s); } void CDxfWrite::writeLine(const double* s, const double* e) @@ -489,9 +553,11 @@ void CDxfWrite::writeLine(const double* s, const double* e) putLine(toVector3d(s),toVector3d(e),m_ssEntity, getEntityHandle(), m_saveModelSpaceHandle); } -void CDxfWrite::putLine(const Base::Vector3d& s, const Base::Vector3d& e, - std::ostringstream& outStream, const std::string& handle, - const std::string& ownerHandle) +void CDxfWrite::putLine(const Base::Vector3d& s, + const Base::Vector3d& e, + std::ostringstream& outStream, + const std::string& handle, + const std::string& ownerHandle) { outStream << " 0" << std::endl; outStream << "LINE" << std::endl; @@ -551,11 +617,11 @@ void CDxfWrite::writeLWPolyLine(const LWPolyDataOut &pd) m_ssEntity << pd.Flag << std::endl; m_ssEntity << " 43" << std::endl; m_ssEntity << "0" << std::endl; //Constant width opt -// m_ssEntity << pd.Width << std::endl; //Constant width opt -// m_ssEntity << " 38" << std::endl; -// m_ssEntity << pd.Elev << std::endl; // Elevation -// m_ssEntity << " 39" << std::endl; -// m_ssEntity << pd.Thick << std::endl; // Thickness + // m_ssEntity << pd.Width << std::endl; //Constant width opt + // m_ssEntity << " 38" << std::endl; + // m_ssEntity << pd.Elev << std::endl; // Elevation + // m_ssEntity << " 39" << std::endl; + // m_ssEntity << pd.Thick << std::endl; // Thickness for (auto& p: pd.Verts) { m_ssEntity << " 10" << std::endl; // Vertices m_ssEntity << p.x << std::endl; @@ -574,12 +640,12 @@ void CDxfWrite::writeLWPolyLine(const LWPolyDataOut &pd) m_ssEntity << " 42" << std::endl; m_ssEntity << b << std::endl; } -// m_ssEntity << "210" << std::endl; //Extrusion dir -// m_ssEntity << pd.Extr.x << std::endl; -// m_ssEntity << "220" << std::endl; -// m_ssEntity << pd.Extr.y << std::endl; -// m_ssEntity << "230" << std::endl; -// m_ssEntity << pd.Extr.z << std::endl; + // m_ssEntity << "210" << std::endl; //Extrusion dir + // m_ssEntity << pd.Extr.x << std::endl; + // m_ssEntity << "220" << std::endl; + // m_ssEntity << pd.Extr.y << std::endl; + // m_ssEntity << "230" << std::endl; + // m_ssEntity << pd.Extr.z << std::endl; } //*************************** @@ -671,7 +737,7 @@ void CDxfWrite::writeArc(const double* s, const double* e, const double* c, bool double start_angle = atan2(ay, ax) * 180/M_PI; double end_angle = atan2(by, bx) * 180/M_PI; double radius = sqrt(ax*ax + ay*ay); - if(!dir){ + if (!dir){ double temp = start_angle; start_angle = end_angle; end_angle = temp; @@ -688,9 +754,9 @@ void CDxfWrite::writeArc(const double* s, const double* e, const double* c, bool } m_ssEntity << " 8" << std::endl; // Group code for layer name m_ssEntity << getLayerName() << std::endl; // Layer number -// m_ssEntity << " 62" << std::endl; -// m_ssEntity << " 0" << std::endl; - if (m_version > 12) { + // m_ssEntity << " 62" << std::endl; + // m_ssEntity << " 0" << std::endl; + if (m_version > 12) { m_ssEntity << "100" << std::endl; m_ssEntity << "AcDbCircle" << std::endl; } @@ -727,7 +793,7 @@ void CDxfWrite::writeCircle(const double* c, double radius) } m_ssEntity << " 8" << std::endl; // Group code for layer name m_ssEntity << getLayerName() << std::endl; // Layer number - if (m_version > 12) { + if (m_version > 12) { m_ssEntity << "100" << std::endl; m_ssEntity << "AcDbCircle" << std::endl; } @@ -735,14 +801,18 @@ void CDxfWrite::writeCircle(const double* c, double radius) m_ssEntity << c[0] << std::endl; // X in WCS coordinates m_ssEntity << " 20" << std::endl; m_ssEntity << c[1] << std::endl; // Y in WCS coordinates -// m_ssEntity << " 30" << std::endl; -// m_ssEntity << c[2] << std::endl; // Z in WCS coordinates + // m_ssEntity << " 30" << std::endl; + // m_ssEntity << c[2] << std::endl; // Z in WCS coordinates m_ssEntity << " 40" << std::endl; // m_ssEntity << radius << std::endl; // Radius } -void CDxfWrite::writeEllipse(const double* c, double major_radius, double minor_radius, - double rotation, double start_angle, double end_angle, +void CDxfWrite::writeEllipse(const double* c, + double major_radius, + double minor_radius, + double rotation, + double start_angle, + double end_angle, bool endIsCW) { double m[3]; @@ -752,7 +822,7 @@ void CDxfWrite::writeEllipse(const double* c, double major_radius, double minor_ double ratio = minor_radius/major_radius; - if(!endIsCW){ //end is NOT CW from start + if (!endIsCW){ //end is NOT CW from start double temp = start_angle; start_angle = end_angle; end_angle = temp; @@ -769,7 +839,7 @@ void CDxfWrite::writeEllipse(const double* c, double major_radius, double minor_ } m_ssEntity << " 8" << std::endl; // Group code for layer name m_ssEntity << getLayerName() << std::endl; // Layer number - if (m_version > 12) { + if (m_version > 12) { m_ssEntity << "100" << std::endl; m_ssEntity << "AcDbEllipse" << std::endl; } @@ -787,12 +857,12 @@ void CDxfWrite::writeEllipse(const double* c, double major_radius, double minor_ m_ssEntity << m[2] << std::endl; // Major Z m_ssEntity << " 40" << std::endl; // m_ssEntity << ratio << std::endl; // Ratio -// m_ssEntity << "210" << std::endl; //extrusion dir?? -// m_ssEntity << "0" << std::endl; -// m_ssEntity << "220" << std::endl; -// m_ssEntity << "0" << std::endl; -// m_ssEntity << "230" << std::endl; -// m_ssEntity << "1" << std::endl; + // m_ssEntity << "210" << std::endl; //extrusion dir?? + // m_ssEntity << "0" << std::endl; + // m_ssEntity << "220" << std::endl; + // m_ssEntity << "0" << std::endl; + // m_ssEntity << "230" << std::endl; + // m_ssEntity << "1" << std::endl; m_ssEntity << " 41" << std::endl; m_ssEntity << start_angle << std::endl; // Start angle (radians [0..2pi]) m_ssEntity << " 42" << std::endl; @@ -838,18 +908,18 @@ void CDxfWrite::writeSpline(const SplineDataOut &sd) m_ssEntity << " 74" << std::endl; m_ssEntity << 0 << std::endl; -// m_ssEntity << " 12" << std::endl; -// m_ssEntity << sd.starttan.x << std::endl; -// m_ssEntity << " 22" << std::endl; -// m_ssEntity << sd.starttan.y << std::endl; -// m_ssEntity << " 32" << std::endl; -// m_ssEntity << sd.starttan.z << std::endl; -// m_ssEntity << " 13" << std::endl; -// m_ssEntity << sd.endtan.x << std::endl; -// m_ssEntity << " 23" << std::endl; -// m_ssEntity << sd.endtan.y << std::endl; -// m_ssEntity << " 33" << std::endl; -// m_ssEntity << sd.endtan.z << std::endl; + // m_ssEntity << " 12" << std::endl; + // m_ssEntity << sd.starttan.x << std::endl; + // m_ssEntity << " 22" << std::endl; + // m_ssEntity << sd.starttan.y << std::endl; + // m_ssEntity << " 32" << std::endl; + // m_ssEntity << sd.starttan.z << std::endl; + // m_ssEntity << " 13" << std::endl; + // m_ssEntity << sd.endtan.x << std::endl; + // m_ssEntity << " 23" << std::endl; + // m_ssEntity << sd.endtan.y << std::endl; + // m_ssEntity << " 33" << std::endl; + // m_ssEntity << sd.endtan.z << std::endl; for (auto& k: sd.knot) { m_ssEntity << " 40" << std::endl; @@ -910,21 +980,33 @@ void CDxfWrite::writeVertex(double x, double y, double z) m_ssEntity << 0 << std::endl; } -void CDxfWrite::writeText(const char* text, const double* location1, const double* location2, - const double height, const int horizJust) +void CDxfWrite::writeText(const char* text, + const double* location1, + const double* location2, + const double height, + const int horizJust) { - putText(text, toVector3d(location1), toVector3d(location2), - height, horizJust, - m_ssEntity, getEntityHandle(), m_saveModelSpaceHandle); + putText(text, + toVector3d(location1), + toVector3d(location2), + height, + horizJust, + m_ssEntity, + getEntityHandle(), + m_saveModelSpaceHandle); } //*************************** //putText //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::putText(const char* text, const Base::Vector3d& location1, const Base::Vector3d& location2, - const double height, const int horizJust, - std::ostringstream& outStream, const std::string& handle, - const std::string& ownerHandle) +void CDxfWrite::putText(const char* text, + const Base::Vector3d& location1, + const Base::Vector3d& location2, + const double height, + const int horizJust, + std::ostringstream& outStream, + const std::string& handle, + const std::string& ownerHandle) { (void) location2; @@ -944,8 +1026,8 @@ void CDxfWrite::putText(const char* text, const Base::Vector3d& location1, const outStream << "100" << std::endl; outStream << "AcDbText" << std::endl; } -// outStream << " 39" << std::endl; -// outStream << 0 << std::endl; //thickness + // outStream << " 39" << std::endl; + // outStream << 0 << std::endl; //thickness outStream << " 10" << std::endl; //first alignment point outStream << location1.x << std::endl; outStream << " 20" << std::endl; @@ -956,33 +1038,33 @@ void CDxfWrite::putText(const char* text, const Base::Vector3d& location1, const outStream << height << std::endl; outStream << " 1" << std::endl; outStream << text << std::endl; -// outStream << " 50" << std::endl; -// outStream << 0 << std::endl; //rotation -// outStream << " 41" << std::endl; -// outStream << 1 << std::endl; -// outStream << " 51" << std::endl; -// outStream << 0 << std::endl; + // outStream << " 50" << std::endl; + // outStream << 0 << std::endl; //rotation + // outStream << " 41" << std::endl; + // outStream << 1 << std::endl; + // outStream << " 51" << std::endl; + // outStream << 0 << std::endl; outStream << " 7" << std::endl; outStream << "STANDARD" << std::endl; //style -// outStream << " 71" << std::endl; //default -// outStream << "0" << std::endl; + // outStream << " 71" << std::endl; //default + // outStream << "0" << std::endl; outStream << " 72" << std::endl; outStream << horizJust << std::endl; -//// outStream << " 73" << std::endl; -//// outStream << "0" << std::endl; + //// outStream << " 73" << std::endl; + //// outStream << "0" << std::endl; outStream << " 11" << std::endl; //second alignment point outStream << location2.x << std::endl; outStream << " 21" << std::endl; outStream << location2.y << std::endl; outStream << " 31" << std::endl; outStream << location2.z << std::endl; -// outStream << "210" << std::endl; -// outStream << "0" << std::endl; -// outStream << "220" << std::endl; -// outStream << "0" << std::endl; -// outStream << "230" << std::endl; -// outStream << "1" << std::endl; + // outStream << "210" << std::endl; + // outStream << "0" << std::endl; + // outStream << "220" << std::endl; + // outStream << "0" << std::endl; + // outStream << "230" << std::endl; + // outStream << "1" << std::endl; if (m_version > 12) { outStream << "100" << std::endl; outStream << "AcDbText" << std::endl; @@ -990,8 +1072,11 @@ void CDxfWrite::putText(const char* text, const Base::Vector3d& location1, const } -void CDxfWrite::putArrow(const Base::Vector3d& arrowPos, const Base::Vector3d& barb1Pos, const Base::Vector3d& barb2Pos, - std::ostringstream& outStream, const std::string& handle, +void CDxfWrite::putArrow(const Base::Vector3d& arrowPos, + const Base::Vector3d& barb1Pos, + const Base::Vector3d& barb2Pos, + std::ostringstream& outStream, + const std::string& handle, const std::string& ownerHandle) { outStream << " 0" << std::endl; @@ -1044,9 +1129,12 @@ void CDxfWrite::putArrow(const Base::Vector3d& arrowPos, const Base::Vector3d& b #define ALIGNED 0 #define HORIZONTAL 1 #define VERTICAL 2 -void CDxfWrite::writeLinearDim(const double* textMidPoint, const double* lineDefPoint, - const double* extLine1, const double* extLine2, - const char* dimText, int type) +void CDxfWrite::writeLinearDim(const double* textMidPoint, + const double* lineDefPoint, + const double* extLine1, + const double* extLine2, + const char* dimText, + int type) { m_ssEntity << " 0" << std::endl; m_ssEntity << "DIMENSION" << std::endl; @@ -1083,17 +1171,17 @@ void CDxfWrite::writeLinearDim(const double* textMidPoint, const double* lineDef m_ssEntity << 1 << std::endl; // dimType1 = Aligned } if ( (type == HORIZONTAL) || - (type == VERTICAL) ) { + (type == VERTICAL) ) { m_ssEntity << " 70" << std::endl; m_ssEntity << 32 << std::endl; // dimType0 = Aligned + 32 (bit for unique block)? } -// m_ssEntity << " 71" << std::endl; // not R12 -// m_ssEntity << 1 << std::endl; // attachPoint ??1 = topleft + // m_ssEntity << " 71" << std::endl; // not R12 + // m_ssEntity << 1 << std::endl; // attachPoint ??1 = topleft m_ssEntity << " 1" << std::endl; m_ssEntity << dimText << std::endl; m_ssEntity << " 3" << std::endl; m_ssEntity << "STANDARD" << std::endl; //style -//linear dims + //linear dims if (m_version > 12) { m_ssEntity << "100" << std::endl; m_ssEntity << "AcDbAlignedDimension" << std::endl; @@ -1115,27 +1203,27 @@ void CDxfWrite::writeLinearDim(const double* textMidPoint, const double* lineDef m_ssEntity << " 50" << std::endl; m_ssEntity << "90" << std::endl; } - if ( (type == HORIZONTAL) || - (type == VERTICAL) ) { + if ( (type == HORIZONTAL) || (type == VERTICAL) ) { m_ssEntity << "100" << std::endl; m_ssEntity << "AcDbRotatedDimension" << std::endl; } } writeDimBlockPreamble(); - writeLinearDimBlock(textMidPoint,lineDefPoint, - extLine1, extLine2, - dimText, type); + writeLinearDimBlock(textMidPoint, lineDefPoint, extLine1, extLine2, dimText, type); writeBlockTrailer(); } //*************************** //writeAngularDim //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::writeAngularDim(const double* textMidPoint, const double* lineDefPoint, - const double* startExt1, const double* endExt1, - const double* startExt2, const double* endExt2, - const char* dimText) +void CDxfWrite::writeAngularDim(const double* textMidPoint, + const double* lineDefPoint, + const double* startExt1, + const double* endExt1, + const double* startExt2, + const double* endExt2, + const char* dimText) { m_ssEntity << " 0" << std::endl; m_ssEntity << "DIMENSION" << std::endl; @@ -1172,14 +1260,14 @@ void CDxfWrite::writeAngularDim(const double* textMidPoint, const double* lineDe m_ssEntity << " 70" << std::endl; m_ssEntity << 2 << std::endl; // dimType 2 = Angular 5 = Angular 3 point - // +32 for block?? (not R12) -// m_ssEntity << " 71" << std::endl; // not R12? not required? -// m_ssEntity << 5 << std::endl; // attachPoint 5 = middle + // +32 for block?? (not R12) + // m_ssEntity << " 71" << std::endl; // not R12? not required? + // m_ssEntity << 5 << std::endl; // attachPoint 5 = middle m_ssEntity << " 1" << std::endl; m_ssEntity << dimText << std::endl; m_ssEntity << " 3" << std::endl; m_ssEntity << "STANDARD" << std::endl; //style -//angular dims + //angular dims if (m_version > 12) { m_ssEntity << "100" << std::endl; m_ssEntity << "AcDb2LineAngularDimension" << std::endl; @@ -1212,9 +1300,12 @@ void CDxfWrite::writeAngularDim(const double* textMidPoint, const double* lineDe m_ssEntity << " 36" << std::endl; m_ssEntity << lineDefPoint[2] << std::endl; writeDimBlockPreamble(); - writeAngularDimBlock(textMidPoint, lineDefPoint, - startExt1, endExt1, - startExt2, endExt2, + writeAngularDimBlock(textMidPoint, + lineDefPoint, + startExt1, + endExt1, + startExt2, + endExt2, dimText); writeBlockTrailer(); } @@ -1222,9 +1313,10 @@ void CDxfWrite::writeAngularDim(const double* textMidPoint, const double* lineDe //*************************** //writeRadialDim //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::writeRadialDim(const double* centerPoint, const double* textMidPoint, - const double* arcPoint, - const char* dimText) +void CDxfWrite::writeRadialDim(const double* centerPoint, + const double* textMidPoint, + const double* arcPoint, + const char* dimText) { m_ssEntity << " 0" << std::endl; m_ssEntity << "DIMENSION" << std::endl; @@ -1258,13 +1350,13 @@ void CDxfWrite::writeRadialDim(const double* centerPoint, const double* textMidP m_ssEntity << textMidPoint[2] << std::endl; m_ssEntity << " 70" << std::endl; m_ssEntity << 4 << std::endl; // dimType 4 = Radius -// m_ssEntity << " 71" << std::endl; // not R12 -// m_ssEntity << 1 << std::endl; // attachPoint 5 = middle center + // m_ssEntity << " 71" << std::endl; // not R12 + // m_ssEntity << 1 << std::endl; // attachPoint 5 = middle center m_ssEntity << " 1" << std::endl; m_ssEntity << dimText << std::endl; m_ssEntity << " 3" << std::endl; m_ssEntity << "STANDARD" << std::endl; //style -//radial dims + //radial dims if (m_version > 12) { m_ssEntity << "100" << std::endl; m_ssEntity << "AcDbRadialDimension" << std::endl; @@ -1286,9 +1378,10 @@ void CDxfWrite::writeRadialDim(const double* centerPoint, const double* textMidP //*************************** //writeDiametricDim //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::writeDiametricDim(const double* textMidPoint, - const double* arcPoint1, const double* arcPoint2, - const char* dimText) +void CDxfWrite::writeDiametricDim(const double* textMidPoint, + const double* arcPoint1, + const double* arcPoint2, + const char* dimText) { m_ssEntity << " 0" << std::endl; m_ssEntity << "DIMENSION" << std::endl; @@ -1322,13 +1415,13 @@ void CDxfWrite::writeDiametricDim(const double* textMidPoint, m_ssEntity << textMidPoint[2] << std::endl; m_ssEntity << " 70" << std::endl; m_ssEntity << 3 << std::endl; // dimType 3 = Diameter -// m_ssEntity << " 71" << std::endl; // not R12 -// m_ssEntity << 5 << std::endl; // attachPoint 5 = middle center + // m_ssEntity << " 71" << std::endl; // not R12 + // m_ssEntity << 5 << std::endl; // attachPoint 5 = middle center m_ssEntity << " 1" << std::endl; m_ssEntity << dimText << std::endl; m_ssEntity << " 3" << std::endl; m_ssEntity << "STANDARD" << std::endl; //style -//diametric dims + //diametric dims if (m_version > 12) { m_ssEntity << "100" << std::endl; m_ssEntity << "AcDbDiametricDimension" << std::endl; @@ -1350,7 +1443,7 @@ void CDxfWrite::writeDiametricDim(const double* textMidPoint, //*************************** //writeDimBlockPreamble //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::writeDimBlockPreamble(void) +void CDxfWrite::writeDimBlockPreamble() { if (m_version > 12) { std::string blockName("*"); @@ -1395,7 +1488,7 @@ void CDxfWrite::writeDimBlockPreamble(void) //*************************** //writeBlockTrailer //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::writeBlockTrailer(void) +void CDxfWrite::writeBlockTrailer() { m_ssBlock << " 0" << std::endl; m_ssBlock << "ENDBLK" << std::endl; @@ -1407,8 +1500,8 @@ void CDxfWrite::writeBlockTrailer(void) m_ssBlock << "100" << std::endl; m_ssBlock << "AcDbEntity" << std::endl; } -// m_ssBlock << " 67" << std::endl; -// m_ssBlock << "1" << std::endl; + // m_ssBlock << " 67" << std::endl; + // m_ssBlock << "1" << std::endl; m_ssBlock << " 8" << std::endl; m_ssBlock << getLayerName() << std::endl; if (m_version > 12) { @@ -1420,9 +1513,12 @@ void CDxfWrite::writeBlockTrailer(void) //*************************** //writeLinearDimBlock //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::writeLinearDimBlock(const double* textMidPoint, const double* dimLine, - const double* e1Start, const double* e2Start, - const char* dimText, int type) +void CDxfWrite::writeLinearDimBlock(const double* textMidPoint, + const double* dimLine, + const double* e1Start, + const double* e2Start, + const char* dimText, + int type) { Base::Vector3d e1S(e1Start[0],e1Start[1],e1Start[2]); Base::Vector3d e2S(e2Start[0],e2Start[1],e2Start[2]); @@ -1436,7 +1532,8 @@ void CDxfWrite::writeLinearDimBlock(const double* textMidPoint, const double* di angle = angle * 180.0 / M_PI; if (type == ALIGNED) { //NOP - } else if (type == HORIZONTAL) { + } + else if (type == HORIZONTAL) { double x = e1Start[0]; double y = dimLine[1]; e1E = Base::Vector3d(x, y, 0.0); @@ -1451,7 +1548,8 @@ void CDxfWrite::writeLinearDimBlock(const double* textMidPoint, const double* di para = Base::Vector3d(-1, 0, 0); //left } angle = 0; - } else if (type == VERTICAL) { + } + else if (type == VERTICAL) { double x = dimLine[0]; double y = e1Start[1]; e1E = Base::Vector3d(x, y, 0.0); @@ -1471,44 +1569,45 @@ void CDxfWrite::writeLinearDimBlock(const double* textMidPoint, const double* di double arrowLen = 5.0; //magic number double arrowWidth = arrowLen/6.0/2.0; //magic number calc! - putLine(e2S, e2E, - m_ssBlock, getBlockHandle(), - m_saveBlkRecordHandle); + putLine(e2S, e2E, m_ssBlock, getBlockHandle(), m_saveBlkRecordHandle); - putLine(e1S, e1E, - m_ssBlock, getBlockHandle(), - m_saveBlkRecordHandle); + putLine(e1S, e1E, m_ssBlock, getBlockHandle(), m_saveBlkRecordHandle); - putLine(e1E, e2E, - m_ssBlock, getBlockHandle(), - m_saveBlkRecordHandle); + putLine(e1E, e2E, m_ssBlock, getBlockHandle(), m_saveBlkRecordHandle); - putText(dimText,toVector3d(textMidPoint), toVector3d(dimLine),3.5,1, - m_ssBlock,getBlockHandle(),m_saveBlkRecordHandle); + putText(dimText, + toVector3d(textMidPoint), + toVector3d(dimLine), + 3.5, + 1, + m_ssBlock, + getBlockHandle(), + m_saveBlkRecordHandle); perp.Normalize(); para.Normalize(); Base::Vector3d arrowStart = e1E; Base::Vector3d barb1 = arrowStart + perp*arrowWidth - para*arrowLen; Base::Vector3d barb2 = arrowStart - perp*arrowWidth - para*arrowLen; - putArrow(arrowStart, barb1, barb2, - m_ssBlock,getBlockHandle(),m_saveBlkRecordHandle); + putArrow(arrowStart, barb1, barb2, m_ssBlock, getBlockHandle(), m_saveBlkRecordHandle); arrowStart = e2E; barb1 = arrowStart + perp*arrowWidth + para*arrowLen; barb2 = arrowStart - perp*arrowWidth + para*arrowLen; - putArrow(arrowStart, barb1, barb2, - m_ssBlock,getBlockHandle(),m_saveBlkRecordHandle); + putArrow(arrowStart, barb1, barb2, m_ssBlock, getBlockHandle(), m_saveBlkRecordHandle); } //*************************** //writeAngularDimBlock //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::writeAngularDimBlock(const double* textMidPoint, const double* lineDefPoint, - const double* startExt1, const double* endExt1, - const double* startExt2, const double* endExt2, - const char* dimText) +void CDxfWrite::writeAngularDimBlock(const double* textMidPoint, + const double* lineDefPoint, + const double* startExt1, + const double* endExt1, + const double* startExt2, + const double* endExt2, + const char* dimText) { Base::Vector3d e1S(startExt1[0],startExt1[1],startExt1[2]); //apex Base::Vector3d e2S(startExt2[0],startExt2[1],startExt2[2]); @@ -1522,10 +1621,10 @@ void CDxfWrite::writeAngularDimBlock(const double* textMidPoint, const double* l double span = fabs(endAngle - startAngle); double offset = span * 0.10; if (startAngle < 0) { - startAngle += 2.0 * M_PI; + startAngle += 2.0 * M_PI; } if (endAngle < 0) { - endAngle += 2.0 * M_PI; + endAngle += 2.0 * M_PI; } Base::Vector3d startOff(cos(startAngle + offset),sin(startAngle + offset),0.0); Base::Vector3d endOff(cos(endAngle - offset),sin(endAngle - offset),0.0); @@ -1547,8 +1646,8 @@ void CDxfWrite::writeAngularDimBlock(const double* textMidPoint, const double* l } m_ssBlock << " 8" << std::endl; m_ssBlock << "0" << std::endl; -// m_ssBlock << " 62" << std::endl; -// m_ssBlock << " 0" << std::endl; + // m_ssBlock << " 62" << std::endl; + // m_ssBlock << " 0" << std::endl; if (m_version > 12) { m_ssBlock << "100" << std::endl; m_ssBlock << "AcDbCircle" << std::endl; @@ -1570,8 +1669,14 @@ void CDxfWrite::writeAngularDimBlock(const double* textMidPoint, const double* l m_ssBlock << " 51" << std::endl; m_ssBlock << endAngle << std::endl; //end angle - putText(dimText,toVector3d(textMidPoint), toVector3d(textMidPoint),3.5,1, - m_ssBlock,getBlockHandle(),m_saveBlkRecordHandle); + putText(dimText, + toVector3d(textMidPoint), + toVector3d(textMidPoint), + 3.5, + 1, + m_ssBlock, + getBlockHandle(), + m_saveBlkRecordHandle); e1.Normalize(); e2.Normalize(); @@ -1591,28 +1696,36 @@ void CDxfWrite::writeAngularDimBlock(const double* textMidPoint, const double* l Base::Vector3d barb1 = arrow1Start + perp1*arrowWidth - tanP1*arrowLen; Base::Vector3d barb2 = arrow1Start - perp1*arrowWidth - tanP1*arrowLen; - putArrow(arrow1Start, barb1, barb2, - m_ssBlock,getBlockHandle(),m_saveBlkRecordHandle); + putArrow(arrow1Start, barb1, barb2, m_ssBlock, getBlockHandle(), m_saveBlkRecordHandle); barb1 = arrow2Start + perp2*arrowWidth - tanP2*arrowLen; barb2 = arrow2Start - perp2*arrowWidth - tanP2*arrowLen; - putArrow(arrow2Start, barb1, barb2, - m_ssBlock,getBlockHandle(),m_saveBlkRecordHandle); + putArrow(arrow2Start, barb1, barb2, m_ssBlock, getBlockHandle(), m_saveBlkRecordHandle); } //*************************** //writeRadialDimBlock //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::writeRadialDimBlock(const double* centerPoint, const double* textMidPoint, - const double* arcPoint, const char* dimText) +void CDxfWrite::writeRadialDimBlock(const double* centerPoint, + const double* textMidPoint, + const double* arcPoint, + const char* dimText) { - putLine(toVector3d(centerPoint), toVector3d(arcPoint), - m_ssBlock, getBlockHandle(), + putLine(toVector3d(centerPoint), + toVector3d(arcPoint), + m_ssBlock, + getBlockHandle(), m_saveBlkRecordHandle); - putText(dimText,toVector3d(textMidPoint), toVector3d(textMidPoint),3.5,1, - m_ssBlock,getBlockHandle(),m_saveBlkRecordHandle); + putText(dimText, + toVector3d(textMidPoint), + toVector3d(textMidPoint), + 3.5, + 1, + m_ssBlock, + getBlockHandle(), + m_saveBlkRecordHandle); Base::Vector3d c(centerPoint[0],centerPoint[1],centerPoint[2]); Base::Vector3d a(arcPoint[0],arcPoint[1],arcPoint[2]); @@ -1625,23 +1738,31 @@ void CDxfWrite::writeRadialDimBlock(const double* centerPoint, const double* tex Base::Vector3d barb1 = arrowStart + perp*arrowWidth - para*arrowLen; Base::Vector3d barb2 = arrowStart - perp*arrowWidth - para*arrowLen; - putArrow(arrowStart, barb1, barb2, - m_ssBlock,getBlockHandle(),m_saveBlkRecordHandle); + putArrow(arrowStart, barb1, barb2, m_ssBlock, getBlockHandle(), m_saveBlkRecordHandle); } //*************************** //writeDiametricDimBlock //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::writeDiametricDimBlock(const double* textMidPoint, - const double* arcPoint1, const double* arcPoint2, - const char* dimText) +void CDxfWrite::writeDiametricDimBlock(const double* textMidPoint, + const double* arcPoint1, + const double* arcPoint2, + const char* dimText) { - putLine(toVector3d(arcPoint1), toVector3d(arcPoint2), - m_ssBlock, getBlockHandle(), + putLine(toVector3d(arcPoint1), + toVector3d(arcPoint2), + m_ssBlock, + getBlockHandle(), m_saveBlkRecordHandle); - putText(dimText,toVector3d(textMidPoint), toVector3d(textMidPoint),3.5,1, - m_ssBlock,getBlockHandle(),m_saveBlkRecordHandle); + putText(dimText, + toVector3d(textMidPoint), + toVector3d(textMidPoint), + 3.5, + 1, + m_ssBlock, + getBlockHandle(), + m_saveBlkRecordHandle); Base::Vector3d a1(arcPoint1[0],arcPoint1[1],arcPoint1[2]); Base::Vector3d a2(arcPoint2[0],arcPoint2[1],arcPoint2[2]); @@ -1654,21 +1775,18 @@ void CDxfWrite::writeDiametricDimBlock(const double* textMidPoint, Base::Vector3d barb1 = arrowStart + perp*arrowWidth + para*arrowLen; Base::Vector3d barb2 = arrowStart - perp*arrowWidth + para*arrowLen; - putArrow(arrowStart, barb1, barb2, - m_ssBlock,getBlockHandle(),m_saveBlkRecordHandle); + putArrow(arrowStart, barb1, barb2, m_ssBlock, getBlockHandle(), m_saveBlkRecordHandle); arrowStart = a2; barb1 = arrowStart + perp*arrowWidth - para*arrowLen; barb2 = arrowStart - perp*arrowWidth - para*arrowLen; - putArrow(arrowStart, barb1, barb2, - m_ssBlock,getBlockHandle(),m_saveBlkRecordHandle); - + putArrow(arrowStart, barb1, barb2, m_ssBlock, getBlockHandle(), m_saveBlkRecordHandle); } //*************************** //writeBlocksSection //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::writeBlocksSection(void) +void CDxfWrite::writeBlocksSection() { if (m_version < 14) { std::stringstream ss; @@ -1687,7 +1805,7 @@ void CDxfWrite::writeBlocksSection(void) //*************************** //writeEntitiesSection //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::writeEntitiesSection(void) +void CDxfWrite::writeEntitiesSection() { std::stringstream ss; ss << "entities" << m_version << ".rub"; @@ -1705,7 +1823,7 @@ void CDxfWrite::writeEntitiesSection(void) //*************************** //writeObjectsSection //added by Wandererfan 2018 (wandererfan@gmail.com) for FreeCAD project -void CDxfWrite::writeObjectsSection(void) +void CDxfWrite::writeObjectsSection() { if (m_version < 14) { return; @@ -1723,7 +1841,7 @@ CDxfRead::CDxfRead(const char* filepath) memset( m_str, '\0', sizeof(m_str) ); memset( m_unused_line, '\0', sizeof(m_unused_line) ); m_fail = false; - m_aci = 0; + m_ColorIndex = 0; m_eUnits = eMillimeters; m_measurement_inch = false; safe_strcpy(m_layer_name, "0"); // Default layer name @@ -1731,6 +1849,10 @@ CDxfRead::CDxfRead(const char* filepath) memset( m_block_name, '\0', sizeof(m_block_name) ); m_ignore_errors = true; + m_version = RUnknown; + //m_CodePage = nullptr; + //m_encoding = nullptr; + if (!m_ifs) m_fail = true; else @@ -1739,39 +1861,66 @@ CDxfRead::CDxfRead(const char* filepath) CDxfRead::~CDxfRead() { + //delete m_CodePage; + //delete m_encoding; } double CDxfRead::mm( double value ) const { - if(m_measurement_inch) - { + // re #6461 + // this if handles situation of malformed DXF file where + // MEASUREMENT specifies English units, but + // INSUNITS specifies millimeters or is not specified + //(millimeters is our default) + if (m_measurement_inch && (m_eUnits == eMillimeters)) { value *= 25.4; } - switch(m_eUnits) - { - case eUnspecified: return(value); // 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); - 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); // We don't know any better. + 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 @@ -1782,95 +1931,130 @@ bool CDxfRead::ReadLine() double e[3] = {0, 0, 0}; bool hidden = false; - while(!m_ifs.eof()) - { + while (!m_ifs.eof()) { get_line(); int n; - if(sscanf(m_str, "%d", &n) != 1) - { + if (sscanf(m_str, "%d", &n) != 1) { this->ReportError_readInteger("DXF::ReadLine()"); 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(); - safe_strcpy(m_layer_name, m_str); - break; + ss.imbue(std::locale::classic()); + switch (n){ + case 0: + // next item found, so finish with line + ResolveColorIndex(); + OnReadLine(s, e, 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(); + safe_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 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; + 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_ColorIndex; + 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(); + ResolveColorIndex(); OnReadLine(s, e, false); } - catch(...) - { - if (! IgnoreErrors()) throw; // Re-throw the exception. + catch (...) { + if (!IgnoreErrors()) { + throw; // Re-throw the exception. + } } return false; @@ -1880,76 +2064,93 @@ bool CDxfRead::ReadPoint() { double s[3] = {0, 0, 0}; - while(!m_ifs.eof()) - { + while (!m_ifs.eof()) { get_line(); int n; - if(sscanf(m_str, "%d", &n) != 1) - { + if (sscanf(m_str, "%d", &n) != 1) { this->ReportError_readInteger("DXF::ReadPoint()"); 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(); - safe_strcpy(m_layer_name, m_str); - break; + ss.imbue(std::locale::classic()); + switch (n){ + case 0: + // next item found, so finish with line + ResolveColorIndex(); + OnReadPoint(s); + return true; - 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 8: // Layer name follows + get_line(); + safe_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 100: - case 39: - case 210: - case 220: - case 230: - // skip the next line - get_line(); - break; - default: - // skip the next line - get_line(); - 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_ColorIndex; + 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(); + ResolveColorIndex(); OnReadPoint(s); } - catch(...) - { - if (! IgnoreErrors()) throw; // Re-throw the exception. + catch (...) { + if (!IgnoreErrors()) { + throw; // Re-throw the exception. + } } return false; @@ -1964,94 +2165,129 @@ bool CDxfRead::ReadArc() double z_extrusion_dir = 1.0; bool hidden = false; - while(!m_ifs.eof()) - { + while (!m_ifs.eof()) { get_line(); int n; - if(sscanf(m_str, "%d", &n) != 1) - { + if (sscanf(m_str, "%d", &n) != 1) { this->ReportError_readInteger("DXF::ReadArc()"); 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(); - safe_strcpy(m_layer_name, m_str); - break; + ss.imbue(std::locale::classic()); + switch (n){ + case 0: + // next item found, so finish with arc + ResolveColorIndex(); + OnReadArc(start_angle, end_angle, radius, c,z_extrusion_dir, 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(); + safe_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 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 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_ColorIndex; + 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; + 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; + default: + // skip the next line + get_line(); + break; } } - DerefACI(); + ResolveColorIndex(); OnReadArc(start_angle, end_angle, radius, c, z_extrusion_dir, false); return false; } @@ -2070,340 +2306,475 @@ bool CDxfRead::ReadSpline() double temp_double; - while(!m_ifs.eof()) - { + while (!m_ifs.eof()) { get_line(); int n; - if(sscanf(m_str, "%d", &n) != 1) - { + if (sscanf(m_str, "%d", &n) != 1) { this->ReportError_readInteger("DXF::ReadSpline()"); 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(); - safe_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] = {0,0,0}; // centre - bool hidden = false; - - while(!m_ifs.eof()) - { - get_line(); - int n; - if(sscanf(m_str, "%d", &n) != 1) - { + ss.imbue(std::locale::classic()); + switch (n){ + case 0: + // next item found, so finish with Spline + ResolveColorIndex(); + OnReadSpline(sd); + return true; + case 8: // Layer name follows + get_line(); + safe_strcpy(m_layer_name, m_str); + break; + case 62: + // color index + get_line(); + ss.str(m_str); + ss >> m_ColorIndex; + 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; + } + } + ResolveColorIndex(); + OnReadSpline(sd); + return false; +} + + +bool CDxfRead::ReadCircle() +{ + double radius = 0.0; + double c[3] = {0,0,0}; // centre + bool hidden = false; + + while (!m_ifs.eof()) { + get_line(); + int n; + if (sscanf(m_str, "%d", &n) != 1) { this->ReportError_readInteger("DXF::ReadCircle()"); 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; + ss.imbue(std::locale::classic()); + switch (n){ + case 0: + // next item found, so finish with Circle + ResolveColorIndex(); + OnReadCircle(c, radius, hidden); + hidden = false; + return true; - case 8: // Layer name follows - get_line(); - safe_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 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; + case 8: // Layer name follows + get_line(); + safe_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_ColorIndex; + 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(); + ResolveColorIndex(); OnReadCircle(c, radius, false); return false; } - -bool CDxfRead::ReadText() +void CDxfRead::ReadText() { - double c[3]; // coordinate - double height = 0.03082; - double rotation = 0.; // degrees - char text[1024] = {}; + ScopedCLocale _(LC_NUMERIC); - memset( c, 0, sizeof(c) ); - - while(!m_ifs.eof()) - { + DxfText text; + while (!m_ifs.eof()) { get_line(); - int n; - if(sscanf(m_str, "%d", &n) != 1) - { - this->ReportError_readInteger("DXF::ReadText()"); - return false; - } - std::istringstream ss; - ss.imbue(std::locale("C")); - switch(n){ - case 0: - DerefACI(); - OnReadText(c, height * 25.4 / 72.0, rotation, text); - return(true); - - case 8: // Layer name follows - get_line(); - safe_strcpy(m_layer_name, m_str); - break; + const int n = stringToInt(m_str); + switch (n) { + case 0: + ResolveColorIndex(); + { + size_t pos = text.str.find("\\P", 0); + while (pos != std::string::npos) { + text.str.replace(pos, 2, "\n"); + pos = text.str.find("\\P", pos + 1); + } - 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(); - safe_strcpy(text, m_str); - break; + text.str = this->toUtf8(text.str); + OnReadText(text); + } + return; + case 8: // Layer name follows + get_line(); + safe_strcpy(m_layer_name, m_str); + break; - case 50: - // text rotation - get_line(); - ss.str(m_str); ss >> rotation; if(ss.fail()) return false; - break; + case 10: + // centre x + get_line(); + text.point[0] = mm(stringToDouble(m_str)); + break; + case 20: + // centre y + get_line(); + text.point[1] = mm(stringToDouble(m_str)); + break; + case 30: + // centre z + get_line(); + text.point[2] = mm(stringToDouble(m_str)); + break; + case 40: + // text height + get_line(); + text.height = mm(stringToDouble(m_str)) * 25.4 / 72.0; + break; + case 50: + // text rotation + get_line(); + text.rotation = stringToDouble(m_str); + break; + case 3: + // Additional text that goes before the type 1 text + // Note that if breaking the text into type-3 records splits a UFT-8 encoding we do + // the decoding after splicing the lines together. I'm not sure if this actually + // occurs, but handling the text this way will treat this condition properly. + get_line(); + text.str.append(m_str); + break; + case 1: + // final text + get_line(); + text.str.append(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; + case 62: + // color index + get_line(); + m_ColorIndex = stringToInt(m_str); + break; + + case 71: { + // attachment point + get_line(); + const int ap = stringToInt(m_str); + if (ap >= 1 && ap <= 9) { + text.attachPoint = static_cast(ap); + } } - } + break; - return false; + case 100: + case 39: + case 210: + case 220: + case 230: + default: + // skip the next line + get_line(); + break; + } + } } @@ -2415,92 +2786,136 @@ bool CDxfRead::ReadEllipse() double start=0; //start of arc double end=0; // end of arc - while(!m_ifs.eof()) - { + while (!m_ifs.eof()) { get_line(); int n; - if(sscanf(m_str, "%d", &n) != 1) - { + if (sscanf(m_str, "%d", &n) != 1) { this->ReportError_readInteger("DXF::ReadEllipse()"); 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(); - safe_strcpy(m_layer_name, m_str); - break; + ss.imbue(std::locale::classic()); + switch (n){ + case 0: + // next item found, so finish with Ellipse + ResolveColorIndex(); + OnReadEllipse(c, m, ratio, start, end); + return true; + case 8: // Layer name follows + get_line(); + safe_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; + 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_ColorIndex; + 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(); + ResolveColorIndex(); OnReadEllipse(c, m, ratio, start, end); return false; } @@ -2517,15 +2932,14 @@ 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) +static void +AddPolyLinePoint(CDxfRead* dxf_read, double x, double y, double z, bool bulge_found, double bulge) { try { - if(poly_prev_found) - { + if (poly_prev_found) { bool arc_done = false; - if(poly_prev_bulge_found) - { + 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; @@ -2536,8 +2950,7 @@ static void AddPolyLinePoint(CDxfRead* dxf_read, double x, double y, double z, b arc_done = true; } - if(!arc_done) - { + 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); @@ -2548,8 +2961,7 @@ static void AddPolyLinePoint(CDxfRead* dxf_read, double x, double y, double z, b poly_prev_x = x; poly_prev_y = y; poly_prev_z = z; - if(!poly_first_found) - { + if (!poly_first_found) { poly_first_x = x; poly_first_y = y; poly_first_z = z; @@ -2558,9 +2970,10 @@ static void AddPolyLinePoint(CDxfRead* dxf_read, double x, double y, double z, b poly_prev_bulge_found = bulge_found; poly_prev_bulge = bulge; } - catch(...) - { - if (! dxf_read->IgnoreErrors()) throw; // Re-throw it. + catch (...) { + if (!dxf_read->IgnoreErrors()) { + throw; // Re-throw it. + } } } @@ -2585,89 +2998,110 @@ bool CDxfRead::ReadLwPolyLine() int flags; bool next_item_found = false; - while(!m_ifs.eof() && !next_item_found) - { + while (!m_ifs.eof() && !next_item_found) { get_line(); int n; - if(sscanf(m_str, "%d", &n) != 1) - { + if (sscanf(m_str, "%d", &n) != 1) { this->ReportError_readInteger("DXF::ReadLwPolyLine()"); 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(); - safe_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; + ss.imbue(std::locale::classic()); + switch (n){ + case 0: + // next item found + + ResolveColorIndex(); + 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(); + safe_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_ColorIndex; + if (ss.fail()) { + return false; + } + break; + default: + // skip the next line + get_line(); + break; } } - if(next_item_found) - { - if(closed && poly_first_found) - { + if (next_item_found) { + if (closed && poly_first_found) { // repeat the first point - DerefACI(); + ResolveColorIndex(); AddPolyLinePoint(this, poly_first_x, poly_first_y, poly_first_z, false, 0.0); } return true; @@ -2692,7 +3126,7 @@ bool CDxfRead::ReadVertex(double *pVertex, bool *bulge_found, double *bulge) pVertex[1] = 0.0; pVertex[2] = 0.0; - while(!m_ifs.eof()) { + while (!m_ifs.eof()) { get_line(); int n; if(sscanf(m_str, "%d", &n) != 1) { @@ -2700,12 +3134,12 @@ bool CDxfRead::ReadVertex(double *pVertex, bool *bulge_found, double *bulge) return false; } std::istringstream ss; - ss.imbue(std::locale("C")); - switch(n){ + ss.imbue(std::locale::classic()); + switch (n){ case 0: - DerefACI(); + ResolveColorIndex(); put_line(m_str); // read one line too many. put it back. - return(x_found && y_found); + return (x_found && y_found); break; case 8: // Layer name follows @@ -2716,31 +3150,54 @@ bool CDxfRead::ReadVertex(double *pVertex, bool *bulge_found, double *bulge) case 10: // x get_line(); - ss.str(m_str); ss >> x; pVertex[0] = mm(x); if(ss.fail()) return false; + 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; + 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; + 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; + ss.str(m_str); + ss >> *bulge; + if (ss.fail()) { + return false; + } + break; + case 62: + // color index + get_line(); + ss.str(m_str); + ss >> m_ColorIndex; + 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 @@ -2753,7 +3210,6 @@ bool CDxfRead::ReadVertex(double *pVertex, bool *bulge_found, double *bulge) } - bool CDxfRead::ReadPolyLine() { PolyLineStart(); @@ -2765,115 +3221,133 @@ bool CDxfRead::ReadPolyLine() bool bulge_found; double bulge; - while(!m_ifs.eof()) - { + while (!m_ifs.eof()) { get_line(); int n; - if(sscanf(m_str, "%d", &n) != 1) - { + if (sscanf(m_str, "%d", &n) != 1) { this->ReportError_readInteger("DXF::ReadPolyLine()"); 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] = {0,0,0}; - 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; + ss.imbue(std::locale::classic()); + switch (n){ + case 0: + // next item found + ResolveColorIndex(); + get_line(); + if (!strcmp(m_str, "VERTEX")) { + double vertex[3] = {0,0,0}; + 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); + } + if (!strcmp(m_str, "SEQEND")) { + if (closed && first_vertex_section_found) { + AddPolyLinePoint(this, + first_vertex[0], + first_vertex[1], + first_vertex[2], + 0, + 0); } - 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; + 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_ColorIndex; + 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] = {0,0,0}, e[3] = {0,0,0}, temp[3] = {0,0,0}; - 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 * M_PI/180); - s[1] = c[1] + radius * sin(start_angle * M_PI/180); - s[2] = c[2]; - e[0] = c[0] + radius * cos(end_angle * M_PI/180); - e[1] = c[1] + radius * sin(end_angle * M_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 * M_PI/180)); - e[1] = (c[1] + radius * sin(start_angle * M_PI/180)); - e[2] = c[2]; - s[0] = -(c[0] + radius * cos(end_angle * M_PI/180)); - s[1] = (c[1] + radius * sin(end_angle * M_PI/180)); - s[2] = c[2]; - +void CDxfRead::OnReadArc(double start_angle, + double end_angle, + double radius, + const double* c, + double z_extrusion_dir, + bool hidden) +{ + double s[3] = {0, 0, 0}, e[3] = {0, 0, 0}, temp[3] = {0, 0, 0}; + 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 * M_PI / 180); + s[1] = c[1] + radius * sin(start_angle * M_PI / 180); + s[2] = c[2]; + e[0] = c[0] + radius * cos(end_angle * M_PI / 180); + e[1] = c[1] + radius * sin(end_angle * M_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 * M_PI/180)); + e[1] = (c[1] + radius * sin(start_angle * M_PI/180)); + e[2] = c[2]; + s[0] = -(c[0] + radius * cos(end_angle * M_PI/180)); + s[1] = (c[1] + radius * sin(end_angle * M_PI/180)); + s[2] = c[2]; } OnReadArc(s, e, temp, true, hidden); } -void CDxfRead::OnReadCircle(const double* c, double radius, bool 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 * M_PI/180); - s[1] = c[1] + radius * sin(start_angle * M_PI/180); + s[0] = c[0] + radius * cos(start_angle * M_PI / 180); + s[1] = c[1] + radius * sin(start_angle * M_PI / 180); s[2] = c[2]; - OnReadCircle(s, c, false, hidden); //false to change direction because otherwise the arc length is zero + 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]); +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 + // 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); + double rotation = atan2(m[1] / major_radius, m[0] / major_radius); OnReadEllipse(c, major_radius, minor_radius, rotation, start_angle, end_angle, true); @@ -2887,85 +3361,118 @@ bool CDxfRead::ReadInsert() double rot = 0.0; // rotation char name[1024] = {0}; - while(!m_ifs.eof()) - { + while (!m_ifs.eof()) { get_line(); int n; - if(sscanf(m_str, "%d", &n) != 1) - { + if (sscanf(m_str, "%d", &n) != 1) { this->ReportError_readInteger("DXF::ReadInsert()"); return false; } std::istringstream ss; - ss.imbue(std::locale("C")); - switch(n){ - case 0: - // next item found - DerefACI(); - OnReadInsert(c, s, name, rot * M_PI/180); - return(true); - case 8: - // Layer name follows - get_line(); - safe_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(); - safe_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; + ss.imbue(std::locale::classic()); + switch (n){ + case 0: + // next item found + ResolveColorIndex(); + OnReadInsert(c, s, name, rot * M_PI/180); + return(true); + case 8: + // Layer name follows + get_line(); + safe_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_ColorIndex; + 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; @@ -2979,95 +3486,146 @@ bool CDxfRead::ReadDimension() double p[3] = {0,0,0}; // dimpoint double rot = -1.0; // rotation - while(!m_ifs.eof()) - { + while (!m_ifs.eof()) { get_line(); int n; - if(sscanf(m_str, "%d", &n) != 1) - { + if (sscanf(m_str, "%d", &n) != 1) { this->ReportError_readInteger("DXF::ReadDimension()"); return false; } std::istringstream ss; - ss.imbue(std::locale("C")); - switch(n){ - case 0: - // next item found - DerefACI(); - OnReadDimension(s, e, p, rot * M_PI/180); - return(true); - case 8: - // Layer name follows - get_line(); - safe_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; + ss.imbue(std::locale::classic()); + switch (n){ + case 0: + // next item found + ResolveColorIndex(); + OnReadDimension(s, e, p, rot * M_PI/180); + return(true); + case 8: + // Layer name follows + get_line(); + safe_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_ColorIndex; + 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; @@ -3076,32 +3634,30 @@ bool CDxfRead::ReadDimension() bool CDxfRead::ReadBlockInfo() { - while(!m_ifs.eof()) - { + while (!m_ifs.eof()) { get_line(); int n; - if(sscanf(m_str, "%d", &n) != 1) - { + if (sscanf(m_str, "%d", &n) != 1) { this->ReportError_readInteger("DXF::ReadBlockInfo()"); return false; } std::istringstream ss; - ss.imbue(std::locale("C")); - switch(n){ - case 2: - // block name - get_line(); - safe_strcpy(m_block_name, m_str); - return true; - case 3: - // block name too??? - get_line(); - safe_strcpy(m_block_name, m_str); - return true; - default: - // skip the next line - get_line(); - break; + ss.imbue(std::locale::classic()); + switch (n){ + case 2: + // block name + get_line(); + safe_strcpy(m_block_name, m_str); + return true; + case 3: + // block name too??? + get_line(); + safe_strcpy(m_block_name, m_str); + return true; + default: + // skip the next line + get_line(); + break; } } return false; @@ -3110,25 +3666,23 @@ bool CDxfRead::ReadBlockInfo() void CDxfRead::get_line() { - if (m_unused_line[0] != '\0') - { + if (m_unused_line[0] != '\0') { safe_strcpy(m_str, m_unused_line); - memset( m_unused_line, '\0', sizeof(m_unused_line)); + memset(m_unused_line, '\0', sizeof(m_unused_line)); return; } m_ifs.getline(m_str, 1024); - ++m_lineNum; char str[1024]; size_t len = strlen(m_str); int j = 0; bool non_white_found = false; - for(size_t i = 0; iReportError_readInteger("DXF::ReadUnits()"); return(false); } @@ -3175,215 +3727,313 @@ bool CDxfRead::ReadUnits() bool CDxfRead::ReadLayer() { std::string layername; - int aci = -1; + ColorIndex_t colorIndex = -1; - while(!m_ifs.eof()) - { + while (!m_ifs.eof()) { get_line(); int n; - if(sscanf(m_str, "%d", &n) != 1) - { + if (sscanf(m_str, "%d", &n) != 1) { this->ReportError_readInteger("DXF::ReadLayer()"); return false; } std::istringstream ss; - ss.imbue(std::locale("C")); - switch(n){ - case 0: // next item found, so finish with line - if (layername.empty()) - return false; + ss.imbue(std::locale::classic()); + switch (n){ + case 0: // next item found, so finish with line + if (layername.empty()) { + this->ReportError_readInteger("DXF::ReadLayer() - no layer name"); + return false; + } + m_layer_ColorIndex_map[layername] = colorIndex; + return true; - m_layer_aci[layername] = aci; - return true; + case 2: // Layer name follows + get_line(); + layername = m_str; + break; - case 2: // Layer name follows - get_line(); - layername = m_str; - break; + case 62: + // layer color ; if negative, layer is off + get_line(); + if (sscanf(m_str, "%d", &colorIndex) != 1) { + return false; + } + break; - case 62: - // layer color ; if negative, layer is off - get_line(); - if(sscanf(m_str, "%d", &aci) != 1)return false; - break; - - case 6: // linetype name - case 70: // layer flags - case 100: - case 290: - case 370: - case 390: - // skip the next line - get_line(); - break; - default: - // skip the next line - get_line(); - break; + case 6: // linetype name + case 70: // layer flags + case 100: + case 290: + case 370: + case 390: + // skip the next line + get_line(); + break; + default: + // skip the next line + get_line(); + break; } } return false; } +bool CDxfRead::ReadVersion() +{ + static const std::vector VersionNames = { + // This table is indexed by eDXFVersion_t - (ROlder+1) + "AC1006", + "AC1009", + "AC1012", + "AC1014", + "AC1015", + "AC1018", + "AC1021", + "AC1024", + "AC1027", + "AC1032"}; + + assert(VersionNames.size() == RNewer - ROlder - 1); + get_line(); + get_line(); + std::vector::const_iterator first = VersionNames.cbegin(); + std::vector::const_iterator last = VersionNames.cend(); + std::vector::const_iterator found = std::lower_bound(first, last, m_str); + if (found == last) { + m_version = RNewer; + } + else if (*found == m_str) { + m_version = (eDXFVersion_t)(std::distance(first, found) + (ROlder + 1)); + } + else if (found == first) { + m_version = ROlder; + } + else { + m_version = RUnknown; + } + + return ResolveEncoding(); +} + +bool CDxfRead::ReadDWGCodePage() +{ + get_line(); + get_line(); + m_CodePage = m_str; + + return ResolveEncoding(); +} + +bool CDxfRead::ResolveEncoding() +{ + // + // See https://ezdxf.readthedocs.io/en/stable/dxfinternals/fileencoding.html# + // + + if (m_version >= R2007) { // Note this does not include RUnknown, but does include RLater + return this->setSourceEncoding("UTF8"); + } + else { + std::transform(m_CodePage.cbegin(), m_CodePage.cend(), m_CodePage.begin(), [](char c) { + return std::toupper(c, std::locale::classic()); + }); + // ANSI_1252 by default if $DWGCODEPAGE is not set + if (m_CodePage.empty()) + m_CodePage = "ANSI_1252"; + + return this->setSourceEncoding(m_CodePage); + } +} + +#if 0 +const char* CDxfRead::UTF8ToUTF8(const char* encoded) const +{ + return encoded; +} + +const char* CDxfRead::GeneralToUTF8(const char* encoded) const +{ + Base::PyGILStateLocker lock; + PyObject* decoded = PyUnicode_Decode(encoded, strlen(encoded), m_encoding->c_str(), "strict"); + if (decoded == nullptr) { + return nullptr; + } + Py_ssize_t len; + const char* converted = PyUnicode_AsUTF8AndSize(decoded, &len); + char* result = nullptr; + if (converted != nullptr) { + // converted only has lifetime of decoded so we must save a copy. + result = (char*)malloc(len + 1); + if (result == nullptr) { + PyErr_SetString(PyExc_MemoryError, "Out of memory"); + } + else { + memcpy(result, converted, len + 1); + } + } + Py_DECREF(decoded); + return result; +} +#endif + void CDxfRead::DoRead(const bool ignore_errors /* = false */ ) { m_ignore_errors = ignore_errors; - if(m_fail)return; + if (m_fail) { + return; + } get_line(); - while(!m_ifs.eof()) - { - m_aci = 256; - - if (!strcmp( m_str, "$INSUNITS" )){ - if (!ReadUnits())return; + while (!m_ifs.eof()) { + if (!strcmp(m_str, "$INSUNITS" )) { + if (!ReadUnits()) { + return; + } continue; } // End if - then - if (!strcmp( m_str, "$MEASUREMENT" )){ + if (!strcmp(m_str, "$MEASUREMENT" )) { get_line(); get_line(); int n = 1; - if(sscanf(m_str, "%d", &n) == 1) - { - if(n == 0)m_measurement_inch = true; + if (sscanf(m_str, "%d", &n) == 1) { + if (n == 0) { + m_measurement_inch = true; + } } continue; } // End if - then - else if(!strcmp(m_str, "0")) - { + if (!strcmp(m_str, "$ACADVER")) { + if (!ReadVersion()) { + return; + } + continue; + } // End if - then + + if (!strcmp(m_str, "$DWGCODEPAGE")) { + if (!ReadDWGCodePage()) { + return; + } + continue; + } // End if - then + + if (!strcmp(m_str, "0")) { get_line(); - if (!strcmp( m_str, "SECTION" )){ - safe_strcpy(m_section_name, ""); - get_line(); - get_line(); - if (strcmp( m_str, "ENTITIES" )) - safe_strcpy(m_section_name, m_str); - safe_strcpy(m_block_name, ""); + if (!strcmp( m_str, "SECTION" )) { + safe_strcpy(m_section_name, ""); + get_line(); + get_line(); + if (strcmp( m_str, "ENTITIES" )) { + safe_strcpy(m_section_name, m_str); + } + safe_strcpy(m_block_name, ""); - } // End if - then - else if (!strcmp( m_str, "TABLE" )){ - get_line(); - get_line(); - } + } // End if - then + else if (!strcmp( m_str, "TABLE" )) { + get_line(); + get_line(); + } - else if (!strcmp( m_str, "LAYER" )){ - if(!ReadLayer()) - { - this->ReportError("DXF::DoRead() - Failed to read layer"); - //return; Some objects or tables can have "LAYER" as name... + else if (!strcmp( m_str, "LAYER" )) { + get_line(); + get_line(); + if (!ReadLayer()) { + this->ReportError("DXF::DoRead() - Failed to read layer"); + //return; Some objects or tables can have "LAYER" as name... } - continue; - } - - else if (!strcmp( m_str, "BLOCK" )) { - if(!ReadBlockInfo()) - { - this->ReportError("DXF::DoRead() - Failed to read block info"); - return; + continue; } - continue; - } // End if - then - else if (!strcmp( m_str, "ENDSEC" )){ - safe_strcpy(m_section_name, ""); - safe_strcpy(m_block_name, ""); - } // End if - then - else if(!strcmp(m_str, "LINE")){ - if(!ReadLine()) - { - this->ReportError("DXF::DoRead() - Failed to read line"); + else if (!strcmp( m_str, "BLOCK" )) { + if (!ReadBlockInfo()) { + this->ReportError("DXF::DoRead() - Failed to read block info"); return; } continue; - } - else if(!strcmp(m_str, "ARC")){ - if(!ReadArc()) - { - this->ReportError("DXF::DoRead() - Failed to read arc"); + } // End if - then + + else if (!strcmp( m_str, "ENDSEC" )) { + safe_strcpy(m_section_name, ""); + safe_strcpy(m_block_name, ""); + } // End if - then + else if (!strcmp(m_str, "LINE")) { + if (!ReadLine()) { + this->ReportError("DXF::DoRead() - Failed to read line"); return; } continue; } - else if(!strcmp(m_str, "CIRCLE")){ - if(!ReadCircle()) - { - this->ReportError("DXF::DoRead() - Failed to read circle"); + else if (!strcmp(m_str, "ARC")) { + if (!ReadArc()) { + this->ReportError("DXF::DoRead() - Failed to read arc"); return; } continue; } - else if(!strcmp(m_str, "MTEXT")){ - if(!ReadText()) - { - this->ReportError("DXF::DoRead() - Failed to read text"); + else if (!strcmp(m_str, "CIRCLE")) { + if (!ReadCircle()) { + this->ReportError("DXF::DoRead() - Failed to read circle"); return; } continue; } - else if(!strcmp(m_str, "TEXT")){ - if(!ReadText()) - { - this->ReportError("DXF::DoRead() - Failed to read text"); + else if (!strcmp(m_str, "MTEXT") || !strcmp(m_str, "TEXT")) { + try { + ReadText(); + } catch (const std::runtime_error& err) { + this->ReportError("DXF::DoRead() - Failed to read text\nError: " + std::string(err.what())); return; } continue; } - else if(!strcmp(m_str, "ELLIPSE")){ - if(!ReadEllipse()) - { + else if (!strcmp(m_str, "ELLIPSE")) { + if (!ReadEllipse()) { this->ReportError("DXF::DoRead() - Failed to read ellipse"); return; } continue; } - else if(!strcmp(m_str, "SPLINE")){ - if(!ReadSpline()) - { + else if (!strcmp(m_str, "SPLINE")) { + if (!ReadSpline()) { this->ReportError("DXF::DoRead() - Failed to read spline"); return; } continue; } else if (!strcmp(m_str, "LWPOLYLINE")) { - if(!ReadLwPolyLine()) - { + if (!ReadLwPolyLine()) { this->ReportError("DXF::DoRead() - Failed to read LW Polyline"); return; } continue; } else if (!strcmp(m_str, "POLYLINE")) { - if(!ReadPolyLine()) - { + if (!ReadPolyLine()) { this->ReportError("DXF::DoRead() - Failed to read Polyline"); return; } continue; } else if (!strcmp(m_str, "POINT")) { - if(!ReadPoint()) - { + if (!ReadPoint()) { this->ReportError("DXF::DoRead() - Failed to read Point"); return; } continue; } else if (!strcmp(m_str, "INSERT")) { - if(!ReadInsert()) - { + if (!ReadInsert()) { this->ReportError("DXF::DoRead() - Failed to read Insert"); return; } continue; } else if (!strcmp(m_str, "DIMENSION")) { - if(!ReadDimension()) - { + if (!ReadDimension()) { this->ReportError("DXF::DoRead() - Failed to read Dimension"); return; } @@ -3397,12 +4047,12 @@ void CDxfRead::DoRead(const bool ignore_errors /* = false */ ) } -void CDxfRead::DerefACI() +void CDxfRead::ResolveColorIndex() { - if (m_aci == 256) // if color = layer color, replace by color from layer + if (m_ColorIndex == ColorBylayer) // if color = layer color, replace by color from layer { - m_aci = m_layer_aci[std::string(m_layer_name)]; + m_ColorIndex = m_layer_ColorIndex_map[std::string(m_layer_name)]; } } @@ -3429,20 +4079,17 @@ std::string CDxfRead::LayerName() const { std::string result; - if (strlen(m_section_name) > 0) - { + if (strlen(m_section_name) > 0) { result.append(m_section_name); result.append(" "); } - if (strlen(m_block_name) > 0) - { + if (strlen(m_block_name) > 0) { result.append(m_block_name); result.append(" "); } - if (strlen(m_layer_name) > 0) - { + if (strlen(m_layer_name) > 0) { result.append(m_layer_name); } diff --git a/src/io_dxf/dxf.h b/src/io_dxf/dxf.h index 9cd8b05e..f38bdacd 100644 --- a/src/io_dxf/dxf.h +++ b/src/io_dxf/dxf.h @@ -3,30 +3,27 @@ // This program is released under the BSD license. See the file COPYING for details. // modified 2018 wandererfan -// MAYO: file initially taken from FreeCad/src/Mod/Import/App/dxf.h -- commit #47d5707 +// MAYO: file taken from FreeCad/src/Mod/Import/App/dxf.h -- commit #55292e9 #pragma once #include +#include +#include +#include +#include +#include #include -#include +#include #include #include -#include #include -#include -#include -#include -#include +#include +#include #include "freecad.h" -//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 int ColorIndex_t; // DXF color index typedef enum { @@ -53,6 +50,19 @@ typedef enum eParsecs } eDxfUnits_t; +enum class AttachmentPoint { + TopLeft = 1, TopCenter, TopRight, + MiddleLeft, MiddleCenter, MiddleRight, + BottomLeft, BottomCenter, BottomRight +}; + +struct DxfText { + double point[3] = {}; + double height = 0.03082; + std::string str; + double rotation = 0.; // radians + AttachmentPoint attachPoint = AttachmentPoint::TopLeft; +}; //spline data for reading struct SplineData @@ -118,9 +128,26 @@ struct LWPolyDataOut std::vector Bulge; point3D Extr; }; +typedef enum +{ + RUnknown, + ROlder, + R10, + R11_12, + R13, + R14, + R2000, + R2004, + R2007, + R2010, + R2013, + R2018, + RNewer, +} eDXFVersion_t; //******************** -class CDxfWrite{ +class CDxfWrite +{ private: std::ofstream m_ofs; bool m_fail; @@ -130,29 +157,45 @@ class CDxfWrite{ std::ostringstream m_ssLayer; protected: - void putLine(const Base::Vector3d& s, const Base::Vector3d& e, - std::ostringstream& outStream, const std::string& handle, + void putLine(const Base::Vector3d& s, + const Base::Vector3d& e, + std::ostringstream& outStream, + 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, - std::ostringstream& outStream, const std::string& handle, + void putText(const char* text, + const Base::Vector3d& location1, + const Base::Vector3d& location2, + const double height, + const int horizJust, + std::ostringstream& outStream, + const std::string& handle, const std::string& ownerHandle); - void putArrow(const Base::Vector3d& arrowPos, const Base::Vector3d& barb1Pos, const Base::Vector3d& barb2Pos, - std::ostringstream& outStream, const std::string& handle, + void putArrow(const Base::Vector3d& arrowPos, + const Base::Vector3d& barb1Pos, + const Base::Vector3d& barb2Pos, + std::ostringstream& outStream, + const std::string& handle, const std::string& ownerHandle); //! copy boiler plate file std::string getPlateFile(const std::string& fileSpec); - void setDataDir(const std::string& s) { m_dataDir = s; } - std::string getHandle(void); - std::string getEntityHandle(void); - std::string getLayerHandle(void); - std::string getBlockHandle(void); - std::string getBlkRecordHandle(void); + void setDataDir(const std::string& s) + { + m_dataDir = s; + } + std::string getHandle(); + std::string getEntityHandle(); + std::string getLayerHandle(); + std::string getBlockHandle(); + std::string getBlkRecordHandle(); std::string m_optionSource; int m_version; int m_handle; + int m_entityHandle; + int m_layerHandle; + int m_blockHandle; + int m_blkRecordHandle; bool m_polyOverride; std::string m_saveModelSpaceHandle; @@ -170,74 +213,112 @@ class CDxfWrite{ CDxfWrite(const char* filepath); ~CDxfWrite(); - void init(void); - void endRun(void); + void init(); + void endRun(); - bool Failed(){return m_fail;} + bool Failed() + { + return m_fail; + } // void setOptions(void); // bool isVersionValid(int vers); - std::string getLayerName() { return m_layerName; } + std::string getLayerName() + { + return m_layerName; + } void setLayerName(std::string s); - void setVersion(int v) { m_version = v;} - void setPolyOverride(bool b) { m_polyOverride = b; } + void setVersion(int v) + { + m_version = v; + } + void setPolyOverride(bool b) + { + m_polyOverride = b; + } void addBlockName(std::string s, std::string blkRecordHandle); void writeLine(const double* s, const double* e); void writePoint(const double*); void writeArc(const double* s, const double* e, const double* c, bool dir); - void writeEllipse(const double* c, double major_radius, double minor_radius, - double rotation, double start_angle, double end_angle, bool endIsCW); + void writeEllipse(const double* c, + double major_radius, + double minor_radius, + double rotation, + double start_angle, + double end_angle, + bool endIsCW); void writeCircle(const double* c, double radius ); - void writeSpline(const SplineDataOut &sd); - void writeLWPolyLine(const LWPolyDataOut &pd); - void writePolyline(const LWPolyDataOut &pd); + void writeSpline(const SplineDataOut& sd); + void writeLWPolyLine(const LWPolyDataOut& pd); + void writePolyline(const LWPolyDataOut& pd); 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); - void writeLinearDim(const double* textMidPoint, const double* lineDefPoint, - const double* extLine1, const double* extLine2, - const char* dimText, int type); - void writeLinearDimBlock(const double* textMidPoint, const double* lineDefPoint, - const double* extLine1, const double* extLine2, - const char* dimText, int type); - void writeAngularDim(const double* textMidPoint, const double* lineDefPoint, - const double* startExt1, const double* endExt1, - const double* startExt2, const double* endExt2, - const char* dimText); - void writeAngularDimBlock(const double* textMidPoint, const double* lineDefPoint, - const double* startExt1, const double* endExt1, - const double* startExt2, const double* endExt2, - const char* dimText); - void writeRadialDim(const double* centerPoint, const double* textMidPoint, - const double* arcPoint, - const char* dimText); - void writeRadialDimBlock(const double* centerPoint, const double* textMidPoint, - const double* arcPoint, const char* dimText); - void writeDiametricDim(const double* textMidPoint, - const double* arcPoint1, const double* arcPoint2, - const char* dimText); - void writeDiametricDimBlock(const double* textMidPoint, - const double* arcPoint1, const double* arcPoint2, + void writeText(const char* text, + const double* location1, + const double* location2, + const double height, + const int horizJust); + void writeLinearDim(const double* textMidPoint, + const double* lineDefPoint, + const double* extLine1, + const double* extLine2, + const char* dimText, + int type); + void writeLinearDimBlock(const double* textMidPoint, + const double* lineDefPoint, + const double* extLine1, + const double* extLine2, + const char* dimText, + int type); + void writeAngularDim(const double* textMidPoint, + const double* lineDefPoint, + const double* startExt1, + const double* endExt1, + const double* startExt2, + const double* endExt2, const char* dimText); + void writeAngularDimBlock(const double* textMidPoint, + const double* lineDefPoint, + const double* startExt1, + const double* endExt1, + const double* startExt2, + const double* endExt2, + const char* dimText); + void writeRadialDim(const double* centerPoint, + const double* textMidPoint, + const double* arcPoint, + const char* dimText); + void writeRadialDimBlock(const double* centerPoint, + const double* textMidPoint, + const double* arcPoint, + const char* dimText); + void writeDiametricDim(const double* textMidPoint, + const double* arcPoint1, + const double* arcPoint2, + const char* dimText); + void writeDiametricDimBlock(const double* textMidPoint, + const double* arcPoint1, + const double* arcPoint2, + const char* dimText); void writeDimBlockPreamble(); - void writeBlockTrailer(void); - - void writeHeaderSection(void); - void writeTablesSection(void); - void writeBlocksSection(void); - void writeEntitiesSection(void); - void writeObjectsSection(void); - void writeClassesSection(void); - - void makeLayerTable(void); - void makeBlockRecordTableHead(void); - void makeBlockRecordTableBody(void); - void makeBlockSectionHead(void); + void writeBlockTrailer(); + + void writeHeaderSection(); + void writeTablesSection(); + void writeBlocksSection(); + void writeEntitiesSection(); + void writeObjectsSection(); + void writeClassesSection(); + + void makeLayerTable(); + void makeBlockRecordTableHead(); + void makeBlockRecordTableBody(); + void makeBlockSectionHead(); }; // derive a class from this and implement it's virtual functions -class CDxfRead{ +class CDxfRead +{ private: std::ifstream m_ifs; @@ -252,13 +333,14 @@ class CDxfRead{ bool m_ignore_errors; - typedef std::map< std::string,Aci_t > LayerAciMap_t; - LayerAciMap_t m_layer_aci; // layer names -> layer color aci map + std::map + m_layer_ColorIndex_map; // Mapping from layer name -> layer color index + const ColorIndex_t ColorBylayer = 256; bool ReadUnits(); bool ReadLayer(); bool ReadLine(); - bool ReadText(); + void ReadText(); bool ReadArc(); bool ReadCircle(); bool ReadEllipse(); @@ -267,48 +349,97 @@ class CDxfRead{ 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 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); + void OnReadEllipse(const double* c, + const double* m, + double ratio, + double start_angle, + double end_angle); bool ReadInsert(); bool ReadDimension(); bool ReadBlockInfo(); + bool ReadVersion(); + bool ReadDWGCodePage(); + bool ResolveEncoding(); void put_line(const char *value); - void DerefACI(); + void ResolveColorIndex(); void ReportError_readInteger(const char* context); protected: - Aci_t m_aci; // manifest color name or 256 for layer color - int m_lineNum = 0; + ColorIndex_t m_ColorIndex; + eDXFVersion_t m_version; // Version from $ACADVER variable in DXF std::streamsize gcount() const; virtual void get_line(); - virtual void ReportError(const char* /*msg*/) {} + virtual void ReportError(const std::string& /*msg*/) {} + + virtual bool setSourceEncoding(const std::string& /*codepage*/) { return true; } + virtual std::string toUtf8(const std::string& strSource) { return strSource; } + +private: + std::string m_CodePage; // Code Page name from $DWGCODEPAGE or null if none/not read yet public: CDxfRead(const char* filepath); // this opens the file virtual ~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 + 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*/, double /*rotation*/, 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 { } + 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 DxfText&) {} + 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; - }; diff --git a/src/io_dxf/io_dxf.cpp b/src/io_dxf/io_dxf.cpp index 1d7b29da..37dc2d73 100644 --- a/src/io_dxf/io_dxf.cpp +++ b/src/io_dxf/io_dxf.cpp @@ -16,6 +16,7 @@ #include "../base/property_enumeration.h" #include "../base/task_progress.h" #include "../base/string_conv.h" +#include "../base/tkernel_utils.h" #include "../base/unit_system.h" #include "aci_table.h" #include "dxf.h" @@ -26,16 +27,20 @@ #include #include #include +#include +#include #include #include #include #include #include +#include #include #include #include #include +#include #include #include @@ -74,9 +79,12 @@ class DxfReader::Internal : public CDxfRead { TaskProgress* m_progress = nullptr; std::uintmax_t m_fileSize = 0; std::uintmax_t m_fileReadSize = 0; + Resource_FormatType m_srcEncoding = Resource_ANSI; protected: void get_line() override; + bool setSourceEncoding(const std::string& codepage) override; + std::string toUtf8(const std::string& strSource) override; public: Internal(const FilePath& filepath, TaskProgress* progress = nullptr); @@ -88,7 +96,7 @@ class DxfReader::Internal : public CDxfRead { // 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, double rotation, const char* text) override; + void OnReadText(const DxfText& text) 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, double major_radius, double minor_radius, double rotation, double start_angle, double end_angle, bool dir) override; @@ -96,7 +104,7 @@ class DxfReader::Internal : public CDxfRead { void OnReadInsert(const double* point, const double* scale, const char* name, double rotation) override; void OnReadDimension(const double* s, const double* e, const double* point, double rotation) override; - void ReportError(const char* msg) override; + void ReportError(const std::string& msg) override; static Handle_Geom_BSplineCurve createSplineFromPolesAndKnots(struct SplineData& sd); static Handle_Geom_BSplineCurve createInterpolationSpline(struct SplineData& sd); @@ -153,7 +161,7 @@ TDF_LabelSequence DxfReader::transfer(DocumentPtr doc, TaskProgress* progress) Handle_XCAFDoc_ColorTool colorTool = doc->xcaf().colorTool(); Handle_XCAFDoc_LayerTool layerTool = doc->xcaf().layerTool(); std::unordered_map mapLayerNameLabel; - std::unordered_map mapAciColorLabel; + std::unordered_map mapAciColorLabel; auto fnAddRootShape = [&](const TopoDS_Shape& shape, const std::string& shapeName, TDF_Label layer) { const TDF_Label labelShape = shapeTool->NewShape(); @@ -166,7 +174,7 @@ TDF_LabelSequence DxfReader::transfer(DocumentPtr doc, TaskProgress* progress) return labelShape; }; - auto fnAddAci = [&](Aci_t aci) { + auto fnAddAci = [&](ColorIndex_t aci) { auto it = mapAciColorLabel.find(aci); if (it != mapAciColorLabel.cend()) return it->second; @@ -225,7 +233,7 @@ TDF_LabelSequence DxfReader::transfer(DocumentPtr doc, TaskProgress* progress) const TDF_Label compLabel = fnAddRootShape(comp, layerName, layerLabel); // Check if all entities have the same color bool uniqueColor = true; - const Aci_t aci = !vecEntity.empty() ? vecEntity.front().aci : -1; + const ColorIndex_t aci = !vecEntity.empty() ? vecEntity.front().aci : -1; for (const Entity& entity : vecEntity) { uniqueColor = entity.aci == aci; if (!uniqueColor) @@ -277,6 +285,76 @@ void DxfReader::Internal::get_line() m_progress->setValue(MathUtils::toPercent(m_fileReadSize, 0, m_fileSize)); } +bool DxfReader::Internal::setSourceEncoding(const std::string& codepage) +{ + std::optional encoding; + +#if OCC_VERSION_HEX >= OCC_VERSION_CHECK(7, 4, 0) + if (codepage == "UTF8") + encoding = Resource_FormatType_UTF8; + else if (codepage == "ANSI_932") // Japanese + encoding = Resource_FormatType_SJIS; + else if (codepage == "ANSI_936") // UnifiedChinese + encoding = Resource_FormatType_GB; + else if (codepage == "ANSI_949") // Korean + encoding = Resource_FormatType_EUC; +#endif + +#if OCC_VERSION_HEX >= OCC_VERSION_CHECK(7, 5, 0) + if (encoding) + ; // NOP: encoding already found above + else if (codepage == "ANSI_936") // UnifiedChinese + encoding = Resource_FormatType_GBK; + else if (codepage == "ANSI_950") // TradChinese + encoding = Resource_FormatType_Big5; + else if (codepage == "ANSI_1250") + encoding = Resource_FormatType_CP1250; + else if (codepage == "ANSI_1251") + encoding = Resource_FormatType_CP1251; + else if (codepage == "ANSI_1252") + encoding = Resource_FormatType_CP1252; + else if (codepage == "ANSI_1253") + encoding = Resource_FormatType_CP1253; + else if (codepage == "ANSI_1254") + encoding = Resource_FormatType_CP1254; + else if (codepage == "ANSI_1255") + encoding = Resource_FormatType_CP1255; + else if (codepage == "ANSI_1256") + encoding = Resource_FormatType_CP1256; + else if (codepage == "ANSI_1257") + encoding = Resource_FormatType_CP1257; + else if (codepage == "ANSI_1258") + encoding = Resource_FormatType_CP1258; +#endif + + if (encoding) { + m_srcEncoding = encoding.value(); + } + else { + m_srcEncoding = Resource_ANSI; + m_messenger->emitWarning("Codepage " + codepage + " not supported"); + } + + return true; +} + +std::string DxfReader::Internal::toUtf8(const std::string& strSource) +{ + if (m_srcEncoding == Resource_ANSI) // Resource_ANSI is a pass-through(OpenCascade) + return strSource; + +#if OCC_VERSION_HEX >= OCC_VERSION_CHECK(7, 4, 0) + if (m_srcEncoding == Resource_FormatType_UTF8) + return strSource; + + TCollection_ExtendedString extStr; + Resource_Unicode::ConvertFormatToUnicode(m_srcEncoding, strSource.c_str(), extStr); + return to_stdString(extStr); +#else + return strSource; +#endif +} + DxfReader::Internal::Internal(const FilePath& filepath, TaskProgress* progress) : CDxfRead(filepath.u8string().c_str()), m_progress(progress) @@ -302,25 +380,40 @@ void DxfReader::Internal::OnReadPoint(const double* s) this->addShape(vertex); } -void DxfReader::Internal::OnReadText(const double* point, const double height, double rotation, const char* text) +void DxfReader::Internal::OnReadText(const DxfText& text) { if (!m_params.importAnnotations) return; - const gp_Pnt pt = this->toPnt(point); + const gp_Pnt pt = this->toPnt(text.point); const std::string layerName = this->LayerName(); if (!startsWith(layerName, "BLOCKS")) { const std::string& fontName = m_params.fontNameForTextObjects; - const double fontHeight = 4 * height * m_params.scaling; + const double fontHeight = 4 * text.height * m_params.scaling; Font_BRepFont brepFont; if (brepFont.Init(fontName.c_str(), Font_FA_Regular, fontHeight)) { gp_Trsf rotTrsf; - if (rotation != 0.) - rotTrsf.SetRotation(gp_Ax1(pt, gp::DZ()), UnitSystem::radians(rotation * Quantity_Degree)); + if (!MathUtils::fuzzyIsNull(text.rotation)) + rotTrsf.SetRotation(gp_Ax1(pt, gp::DZ()), text.rotation); + + const int ap = static_cast(text.attachPoint); + Graphic3d_HorizontalTextAlignment hAttachPnt = Graphic3d_HTA_LEFT; + if (ap == 2 || ap == 5 || ap == 8) + hAttachPnt = Graphic3d_HTA_CENTER; + else if (ap == 3 || ap == 6 || ap == 9) + hAttachPnt = Graphic3d_HTA_RIGHT; + + Graphic3d_VerticalTextAlignment vAttachPnt = Graphic3d_VTA_TOP; + if (ap == 4 || ap == 5 || ap == 6) + vAttachPnt = Graphic3d_VTA_CENTER; + else if (ap == 7 || ap == 8 || ap == 9) + vAttachPnt = Graphic3d_VTA_BOTTOM; const gp_Ax3 locText(pt, gp::DZ(), gp::DX().Transformed(rotTrsf)); Font_BRepTextBuilder brepTextBuilder; - const TopoDS_Shape shapeText = brepTextBuilder.Perform(brepFont, text, locText); + const TopoDS_Shape shapeText = brepTextBuilder.Perform( + brepFont, string_conv(text.str), locText, hAttachPnt, vAttachPnt + ); this->addShape(shapeText); } else { @@ -368,7 +461,8 @@ void DxfReader::Internal::OnReadEllipse( double major_radius, double minor_radius, double rotation, double /*start_angle*/, double /*end_angle*/, - bool dir) + bool dir + ) { const gp_Dir up = dir ? gp::DZ() : -gp::DZ(); const gp_Pnt pc = this->toPnt(c); @@ -435,7 +529,8 @@ void DxfReader::Internal::OnReadInsert(const double* point, const double* scale, trsfScale.SetValues( nscale[0], 0, 0, 0, 0, nscale[1], 0, 0, - 0, 0, nscale[2], 0); + 0, 0, nscale[2], 0 + ); gp_Trsf trsfRotZ; trsfRotZ.SetRotation(gp::OZ(), rotation); gp_Trsf trsfMove; @@ -460,7 +555,7 @@ void DxfReader::Internal::OnReadDimension(const double* s, const double* e, cons } } -void DxfReader::Internal::ReportError(const char* msg) +void DxfReader::Internal::ReportError(const std::string& msg) { m_messenger->emitError(msg); } @@ -481,7 +576,7 @@ gp_Pnt DxfReader::Internal::toPnt(const double* coords) const void DxfReader::Internal::addShape(const TopoDS_Shape& shape) { - const Entity newEntity{ m_aci, shape }; + const Entity newEntity{ m_ColorIndex, shape }; const std::string layerName = this->LayerName(); auto itFound = m_layers.find(layerName); if (itFound != m_layers.end()) { diff --git a/src/io_off/io_off_reader.h b/src/io_off/io_off_reader.h index eba56187..c5e319f9 100644 --- a/src/io_off/io_off_reader.h +++ b/src/io_off/io_off_reader.h @@ -11,7 +11,6 @@ #include #include - #include namespace Mayo { From 85a3aa12f0a1fe9a991f3715fd6f812cdf58702b Mon Sep 17 00:00:00 2001 From: Hugues Delorme Date: Tue, 21 Nov 2023 12:19:28 +0100 Subject: [PATCH 02/10] IO_Dxf: handle CP850 codepage when possible --- src/io_dxf/io_dxf.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/io_dxf/io_dxf.cpp b/src/io_dxf/io_dxf.cpp index 37dc2d73..a26effc5 100644 --- a/src/io_dxf/io_dxf.cpp +++ b/src/io_dxf/io_dxf.cpp @@ -302,7 +302,7 @@ bool DxfReader::Internal::setSourceEncoding(const std::string& codepage) #if OCC_VERSION_HEX >= OCC_VERSION_CHECK(7, 5, 0) if (encoding) - ; // NOP: encoding already found above + ; // Encoding already found above else if (codepage == "ANSI_936") // UnifiedChinese encoding = Resource_FormatType_GBK; else if (codepage == "ANSI_950") // TradChinese @@ -327,6 +327,13 @@ bool DxfReader::Internal::setSourceEncoding(const std::string& codepage) encoding = Resource_FormatType_CP1258; #endif +#if OCC_VERSION_HEX >= OCC_VERSION_CHECK(7, 6, 0) + if (encoding) + ; // Encoding already found above + else if (codepage == "ANSI_850" || codepage == "DOS850") + encoding = Resource_FormatType_CP850; +#endif + if (encoding) { m_srcEncoding = encoding.value(); } From a3d1e9b0be9cb89ad129a73bbb32ab92ce1f3a64 Mon Sep 17 00:00:00 2001 From: Hugues Delorme Date: Wed, 22 Nov 2023 11:08:44 +0100 Subject: [PATCH 03/10] Base: add BRepUtils::makeEdge() helper function --- src/base/brep_utils.cpp | 9 +++++++++ src/base/brep_utils.h | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/src/base/brep_utils.cpp b/src/base/brep_utils.cpp index f5ac725e..1b2f1197 100644 --- a/src/base/brep_utils.cpp +++ b/src/base/brep_utils.cpp @@ -36,6 +36,15 @@ void BRepUtils::addShape(TopoDS_Shape* ptrTargetShape, const TopoDS_Shape& shape builder.Add(*ptrTargetShape, shape); } +TopoDS_Edge BRepUtils::makeEdge(const Handle(Poly_Polygon3D)& polygon) +{ + TopoDS_Edge edge; + BRep_Builder builder; + builder.MakeEdge(edge); + builder.UpdateEdge(edge, polygon); + return edge; +} + TopoDS_Face BRepUtils::makeFace(const Handle(Poly_Triangulation)& mesh) { TopoDS_Face face; diff --git a/src/base/brep_utils.h b/src/base/brep_utils.h index 98d6952c..76830e89 100644 --- a/src/base/brep_utils.h +++ b/src/base/brep_utils.h @@ -8,7 +8,9 @@ #include "occ_brep_mesh_parameters.h" +#include #include +#include #include #include #include @@ -26,6 +28,9 @@ struct BRepUtils { // Adds 'shape' in target shape 'ptrTargetShape' static void addShape(TopoDS_Shape* ptrTargetShape, const TopoDS_Shape& shape); + // Creates a non-geometric TopoDS_Edge wrapping 'polygon' + static TopoDS_Edge makeEdge(const Handle(Poly_Polygon3D)& polygon); + // Creates a non-geometric TopoDS_Face wrapping triangulation 'mesh' static TopoDS_Face makeFace(const Handle(Poly_Triangulation)& mesh); From fe6c38749ea1f770a84c5bb6c7382cc7ae0676b2 Mon Sep 17 00:00:00 2001 From: Hugues Delorme Date: Wed, 22 Nov 2023 11:08:57 +0100 Subject: [PATCH 04/10] IO_Dxf: reader improvements * Fix crash when aci isn't found in XCAFDoc_ColorTool * Refactor support of POLYLINE entities * Centralize handling of common group codes(8, 62) * Fix reading of layers Relates to GitHub #241 --- src/io_dxf/dxf.cpp | 375 +++++++++--------------------------------- src/io_dxf/dxf.h | 66 +++++++- src/io_dxf/io_dxf.cpp | 31 +++- 3 files changed, 172 insertions(+), 300 deletions(-) diff --git a/src/io_dxf/dxf.cpp b/src/io_dxf/dxf.cpp index edcf93c6..853c1aa0 100644 --- a/src/io_dxf/dxf.cpp +++ b/src/io_dxf/dxf.cpp @@ -19,6 +19,8 @@ #include "../base/filepath.h" #include "dxf.h" +#include + namespace { template @@ -31,7 +33,7 @@ class ScopedCLocale { public: ScopedCLocale(int category) : m_category(category), - m_savedLocale(std::setlocale(category, nullptr)) + m_savedLocale(std::setlocale(category, nullptr)) { std::setlocale(category, "C"); } @@ -68,6 +70,17 @@ int stringToInt(const std::string& line) return 0; } +unsigned stringToUnsigned(const std::string& line) +{ + try { + return std::stoul(line); + } catch (...) { + throw std::runtime_error("Failed to fetch unsigned int value from line:\n" + line); + } + + return 0; +} + } // namespace Base::Vector3d toVector3d(const double* a) @@ -138,15 +151,6 @@ void CDxfWrite::endRun() void CDxfWrite::writeHeaderSection() { std::stringstream ss; -#if 0 - ss << "FreeCAD v" - << App::Application::Config()["BuildVersionMajor"] - << "." - << App::Application::Config()["BuildVersionMinor"] - << " " - << App::Application::Config()["BuildRevision"]; -#endif - //header & version m_ofs << "999" << std::endl; m_ofs << ss.str() << std::endl; @@ -1844,7 +1848,7 @@ CDxfRead::CDxfRead(const char* filepath) m_ColorIndex = 0; m_eUnits = eMillimeters; m_measurement_inch = false; - safe_strcpy(m_layer_name, "0"); // Default layer name + m_layer_name = "0"; // Default layer name memset( m_section_name, '\0', sizeof(m_section_name) ); memset( m_block_name, '\0', sizeof(m_block_name) ); m_ignore_errors = true; @@ -1950,11 +1954,6 @@ bool CDxfRead::ReadLine() hidden = false; return true; - case 8: // Layer name follows - get_line(); - safe_strcpy(m_layer_name, m_str); - break; - case 6: // line style name follows get_line(); if (m_str[0] == 'h' || m_str[0] == 'H') { @@ -2022,16 +2021,6 @@ bool CDxfRead::ReadLine() return false; } break; - case 62: - // color index - get_line(); - ss.str(m_str); - ss >> m_ColorIndex; - if (ss.fail()) { - return false; - } - break; - case 100: case 39: case 210: @@ -2041,8 +2030,8 @@ bool CDxfRead::ReadLine() get_line(); break; default: - // skip the next line get_line(); + HandleCommonGroupCode(n); break; } } @@ -2082,11 +2071,6 @@ bool CDxfRead::ReadPoint() OnReadPoint(s); return true; - case 8: // Layer name follows - get_line(); - safe_strcpy(m_layer_name, m_str); - break; - case 10: // start x get_line(); @@ -2118,16 +2102,6 @@ bool CDxfRead::ReadPoint() } break; - case 62: - // color index - get_line(); - ss.str(m_str); - ss >> m_ColorIndex; - if (ss.fail()) { - return false; - } - break; - case 100: case 39: case 210: @@ -2137,8 +2111,8 @@ bool CDxfRead::ReadPoint() get_line(); break; default: - // skip the next line get_line(); + HandleCommonGroupCode(n); break; } } @@ -2183,11 +2157,6 @@ bool CDxfRead::ReadArc() hidden = false; return true; - case 8: // Layer name follows - get_line(); - safe_strcpy(m_layer_name, m_str); - break; - case 6: // line style name follows get_line(); if (m_str[0] == 'h' || m_str[0] == 'H') { @@ -2253,16 +2222,6 @@ bool CDxfRead::ReadArc() return false; } break; - case 62: - // color index - get_line(); - ss.str(m_str); - ss >> m_ColorIndex; - if (ss.fail()) { - return false; - } - break; - case 100: case 39: @@ -2282,8 +2241,8 @@ bool CDxfRead::ReadArc() break; default: - // skip the next line get_line(); + HandleCommonGroupCode(n); break; } } @@ -2315,25 +2274,12 @@ bool CDxfRead::ReadSpline() } std::istringstream ss; ss.imbue(std::locale::classic()); - switch (n){ + switch (n) { case 0: // next item found, so finish with Spline ResolveColorIndex(); OnReadSpline(sd); return true; - case 8: // Layer name follows - get_line(); - safe_strcpy(m_layer_name, m_str); - break; - case 62: - // color index - get_line(); - ss.str(m_str); - ss >> m_ColorIndex; - if (ss.fail()) { - return false; - } - break; case 210: // normal x get_line(); @@ -2567,8 +2513,8 @@ bool CDxfRead::ReadSpline() get_line(); break; default: - // skip the next line get_line(); + HandleCommonGroupCode(n); break; } } @@ -2608,11 +2554,6 @@ bool CDxfRead::ReadCircle() } break; - case 8: // Layer name follows - get_line(); - safe_strcpy(m_layer_name, m_str); - break; - case 10: // centre x get_line(); @@ -2653,15 +2594,6 @@ bool CDxfRead::ReadCircle() return false; } break; - case 62: - // color index - get_line(); - ss.str(m_str); - ss >> m_ColorIndex; - if (ss.fail()) { - return false; - } - break; case 100: case 39: @@ -2672,8 +2604,8 @@ bool CDxfRead::ReadCircle() get_line(); break; default: - // skip the next line get_line(); + HandleCommonGroupCode(n); break; } } @@ -2704,11 +2636,6 @@ void CDxfRead::ReadText() OnReadText(text); } return; - case 8: // Layer name follows - get_line(); - safe_strcpy(m_layer_name, m_str); - break; - case 10: // centre x get_line(); @@ -2748,12 +2675,6 @@ void CDxfRead::ReadText() text.str.append(m_str); break; - case 62: - // color index - get_line(); - m_ColorIndex = stringToInt(m_str); - break; - case 71: { // attachment point get_line(); @@ -2770,8 +2691,8 @@ void CDxfRead::ReadText() case 220: case 230: default: - // skip the next line get_line(); + HandleCommonGroupCode(n); break; } } @@ -2801,10 +2722,6 @@ bool CDxfRead::ReadEllipse() ResolveColorIndex(); OnReadEllipse(c, m, ratio, start, end); return true; - case 8: // Layer name follows - get_line(); - safe_strcpy(m_layer_name, m_str); - break; case 10: // centre x @@ -2893,15 +2810,6 @@ bool CDxfRead::ReadEllipse() return false; } break; - case 62: - // color index - get_line(); - ss.str(m_str); - ss >> m_ColorIndex; - if (ss.fail()) { - return false; - } - break; case 100: case 210: case 220: @@ -2910,8 +2818,8 @@ bool CDxfRead::ReadEllipse() get_line(); break; default: - // skip the next line get_line(); + HandleCommonGroupCode(n); break; } } @@ -2920,7 +2828,7 @@ bool CDxfRead::ReadEllipse() return false; } - +// TODO Remove this(refactoring of CDxfRead::ReadLwPolyLine() static bool poly_prev_found = false; static double poly_prev_x; static double poly_prev_y; @@ -2932,6 +2840,7 @@ static double poly_first_x; static double poly_first_y; static double poly_first_z; +// TODO Remove this(refactoring of CDxfRead::ReadLwPolyLine() static void AddPolyLinePoint(CDxfRead* dxf_read, double x, double y, double z, bool bulge_found, double bulge) { @@ -2977,12 +2886,14 @@ AddPolyLinePoint(CDxfRead* dxf_read, double x, double y, double z, bool bulge_fo } } +// TODO Remove this(refactoring of CDxfRead::ReadLwPolyLine() static void PolyLineStart() { poly_prev_found = false; poly_first_found = false; } +// TODO Reimplement this function(refactoring of CDxfRead::ReadLwPolyLine() bool CDxfRead::ReadLwPolyLine() { PolyLineStart(); @@ -3010,7 +2921,6 @@ bool CDxfRead::ReadLwPolyLine() switch (n){ case 0: // next item found - ResolveColorIndex(); if (x_found && y_found){ // add point @@ -3021,10 +2931,6 @@ bool CDxfRead::ReadLwPolyLine() } next_item_found = true; break; - case 8: // Layer name follows - get_line(); - safe_strcpy(m_layer_name, m_str); - break; case 10: // x get_line(); @@ -3082,18 +2988,9 @@ bool CDxfRead::ReadLwPolyLine() } closed = ((flags & 1) != 0); break; - case 62: - // color index - get_line(); - ss.str(m_str); - ss >> m_ColorIndex; - if (ss.fail()) { - return false; - } - break; default: - // skip the next line get_line(); + HandleCommonGroupCode(n); break; } } @@ -3110,22 +3007,10 @@ bool CDxfRead::ReadLwPolyLine() return false; } - -bool CDxfRead::ReadVertex(double *pVertex, bool *bulge_found, double *bulge) +bool CDxfRead::ReadVertex(DxfVertex* vertex) { 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; @@ -3133,75 +3018,51 @@ bool CDxfRead::ReadVertex(double *pVertex, bool *bulge_found, double *bulge) this->ReportError_readInteger("DXF::ReadVertex()"); return false; } - std::istringstream ss; - ss.imbue(std::locale::classic()); + switch (n){ case 0: ResolveColorIndex(); 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(); - safe_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; - } + vertex->point[0] = mm(stringToDouble(m_str)); x_found = true; break; case 20: // y get_line(); - ss.str(m_str); - ss >> y; - pVertex[1] = mm(y); - if (ss.fail()) { - return false; - } + vertex->point[1] = mm(stringToDouble(m_str)); y_found = true; break; case 30: // z get_line(); - ss.str(m_str); - ss >> z; - pVertex[2] = mm(z); - if (ss.fail()) { - return false; - } + vertex->point[2] = mm(stringToDouble(m_str)); break; - case 42: + case 42: { + // bulge get_line(); - *bulge_found = true; - ss.str(m_str); - ss >> *bulge; - if (ss.fail()) { - return false; - } + const int bulge = stringToInt(m_str); + if (bulge == 0) + vertex->bulge = DxfVertex::Bulge::StraightSegment; + else + vertex->bulge = DxfVertex::Bulge::SemiCircle; + } break; - case 62: - // color index + + case 70: + // flags get_line(); - ss.str(m_str); - ss >> m_ColorIndex; - if (ss.fail()) { - return false; - } + vertex->flags = stringToUnsigned(m_str); break; default: - // skip the next line get_line(); + HandleCommonGroupCode(n); break; } } @@ -3212,15 +3073,8 @@ bool CDxfRead::ReadVertex(double *pVertex, bool *bulge_found, double *bulge) 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; - + ScopedCLocale _(LC_NUMERIC); + DxfPolyline polyline; while (!m_ifs.eof()) { get_line(); int n; @@ -3228,58 +3082,32 @@ bool CDxfRead::ReadPolyLine() this->ReportError_readInteger("DXF::ReadPolyLine()"); return false; } - std::istringstream ss; - ss.imbue(std::locale::classic()); - switch (n){ + + switch (n) { case 0: // next item found ResolveColorIndex(); get_line(); if (!strcmp(m_str, "VERTEX")) { - double vertex[3] = {0,0,0}; - 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; - } + DxfVertex vertex; + if (ReadVertex(&vertex)) + polyline.vertices.push_back(vertex); } + 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); + OnReadPolyline(polyline); + 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_ColorIndex; - if (ss.fail()) { - return false; - } + polyline.flags = stringToUnsigned(m_str); break; default: - // skip the next line get_line(); + HandleCommonGroupCode(n); break; } } @@ -3376,11 +3204,6 @@ bool CDxfRead::ReadInsert() ResolveColorIndex(); OnReadInsert(c, s, name, rot * M_PI/180); return(true); - case 8: - // Layer name follows - get_line(); - safe_strcpy(m_layer_name, m_str); - break; case 10: // coord x get_line(); @@ -3452,15 +3275,6 @@ bool CDxfRead::ReadInsert() get_line(); strcpy(name, m_str); break; - case 62: - // color index - get_line(); - ss.str(m_str); - ss >> m_ColorIndex; - if (ss.fail()) { - return false; - } - break; case 100: case 39: case 210: @@ -3470,8 +3284,8 @@ bool CDxfRead::ReadInsert() get_line(); break; default: - // skip the next line get_line(); + HandleCommonGroupCode(n); break; } } @@ -3501,11 +3315,6 @@ bool CDxfRead::ReadDimension() ResolveColorIndex(); OnReadDimension(s, e, p, rot * M_PI/180); return(true); - case 8: - // Layer name follows - get_line(); - safe_strcpy(m_layer_name, m_str); - break; case 13: // start x get_line(); @@ -3605,15 +3414,6 @@ bool CDxfRead::ReadDimension() return false; } break; - case 62: - // color index - get_line(); - ss.str(m_str); - ss >> m_ColorIndex; - if (ss.fail()) { - return false; - } - break; case 100: case 39: case 210: @@ -3623,8 +3423,8 @@ bool CDxfRead::ReadDimension() get_line(); break; default: - // skip the next line get_line(); + HandleCommonGroupCode(n); break; } } @@ -3689,6 +3489,7 @@ void CDxfRead::get_line() } str[j] = 0; safe_strcpy(m_str, str); + ++m_line_nb; } void dxf_strncpy(char* dst, const char* src, size_t size) @@ -3740,7 +3541,7 @@ bool CDxfRead::ReadLayer() std::istringstream ss; ss.imbue(std::locale::classic()); - switch (n){ + switch (n) { case 0: // next item found, so finish with line if (layername.empty()) { this->ReportError_readInteger("DXF::ReadLayer() - no layer name"); @@ -3847,36 +3648,19 @@ bool CDxfRead::ResolveEncoding() } } -#if 0 -const char* CDxfRead::UTF8ToUTF8(const char* encoded) const +void CDxfRead::HandleCommonGroupCode(int n) { - return encoded; -} - -const char* CDxfRead::GeneralToUTF8(const char* encoded) const -{ - Base::PyGILStateLocker lock; - PyObject* decoded = PyUnicode_Decode(encoded, strlen(encoded), m_encoding->c_str(), "strict"); - if (decoded == nullptr) { - return nullptr; - } - Py_ssize_t len; - const char* converted = PyUnicode_AsUTF8AndSize(decoded, &len); - char* result = nullptr; - if (converted != nullptr) { - // converted only has lifetime of decoded so we must save a copy. - result = (char*)malloc(len + 1); - if (result == nullptr) { - PyErr_SetString(PyExc_MemoryError, "Out of memory"); - } - else { - memcpy(result, converted, len + 1); - } + switch (n) { + case 8: + // layer name + m_layer_name = m_str; + break; + case 62: + // color index + m_ColorIndex = stringToInt(m_str); + break; } - Py_DECREF(decoded); - return result; } -#endif void CDxfRead::DoRead(const bool ignore_errors /* = false */ ) { @@ -3888,6 +3672,8 @@ void CDxfRead::DoRead(const bool ignore_errors /* = false */ ) get_line(); while (!m_ifs.eof()) { + m_ColorIndex = ColorBylayer; // Default + if (!strcmp(m_str, "$INSUNITS" )) { if (!ReadUnits()) { return; @@ -3923,6 +3709,9 @@ void CDxfRead::DoRead(const bool ignore_errors /* = false */ ) if (!strcmp(m_str, "0")) { get_line(); + if (!strcmp(m_str, "0")) + get_line(); // Skip again + if (!strcmp( m_str, "SECTION" )) { safe_strcpy(m_section_name, ""); get_line(); @@ -3939,8 +3728,8 @@ void CDxfRead::DoRead(const bool ignore_errors /* = false */ ) } else if (!strcmp( m_str, "LAYER" )) { - get_line(); - get_line(); + //get_line(); + //get_line(); if (!ReadLayer()) { this->ReportError("DXF::DoRead() - Failed to read layer"); //return; Some objects or tables can have "LAYER" as name... @@ -4052,7 +3841,7 @@ void CDxfRead::ResolveColorIndex() if (m_ColorIndex == ColorBylayer) // if color = layer color, replace by color from layer { - m_ColorIndex = m_layer_ColorIndex_map[std::string(m_layer_name)]; + m_ColorIndex = m_layer_ColorIndex_map[m_layer_name]; } } @@ -4089,7 +3878,7 @@ std::string CDxfRead::LayerName() const result.append(" "); } - if (strlen(m_layer_name) > 0) { + if (!m_layer_name.empty()) { result.append(m_layer_name); } diff --git a/src/io_dxf/dxf.h b/src/io_dxf/dxf.h index f38bdacd..9dbbc44e 100644 --- a/src/io_dxf/dxf.h +++ b/src/io_dxf/dxf.h @@ -64,6 +64,60 @@ struct DxfText { AttachmentPoint attachPoint = AttachmentPoint::TopLeft; }; +struct DxfVertex { + enum class Bulge { StraightSegment = 0, SemiCircle = 1 }; + enum Flag { + None = 0, + ExtraVertex = 1, + CurveFitTangent = 2, + NotUsed = 4, + SplineVertex = 8, + SplineFrameControlPoint = 16, + Polyline3dVertex = 32, + Polygon3dVertex = 64, + PolyfaceMesgVertex = 128 + }; + using Flags = unsigned; + + double point[3] = {}; + Bulge bulge = Bulge::StraightSegment; + Flags flags = Flag::None; +}; + +struct DxfPolyline { + enum Flag { + None = 0, + Closed = 1, + CurveFit = 2, + SplineFit = 4, + Polyline3d = 8, + PolygonMesh3d = 16, + PolygonMeshClosedNDir = 32, + PolyfaceMesh = 64, + ContinuousLinetypePattern = 128 + }; + using Flags = unsigned; + + enum Type { + NoSmoothSurfaceFitted = 0, + QuadraticBSplineSurface = 5, + CubicBSplineSurface = 6, + BezierSurface = 8 + }; + + double elevation = 0.; + double thickness = 0.; + Flags flags = Flag::None; + double defaultStartWidth = 0.; + double defaultEndWidth = 0.; + int polygonMeshMVertexCount = 0; + int polygonMeshNVertexCount = 0; + double smoothSurfaceMDensity = 0.; + double smoothSurfaceNDensity = 0.; + double extrusionDir[3] = { 0., 0., 1. }; + std::vector vertices; +}; + //spline data for reading struct SplineData { @@ -327,11 +381,13 @@ class CDxfRead char m_unused_line[1024]; eDxfUnits_t m_eUnits; bool m_measurement_inch; - char m_layer_name[1024]; + std::string m_layer_name; char m_section_name[1024]; char m_block_name[1024]; bool m_ignore_errors; + int m_line_nb = 0; + std::map m_layer_ColorIndex_map; // Mapping from layer name -> layer color index @@ -348,7 +404,8 @@ class CDxfRead bool ReadSpline(); bool ReadLwPolyLine(); bool ReadPolyLine(); - bool ReadVertex(double *pVertex, bool *bulge_found, double *bulge); + bool ReadVertex(DxfVertex* vertex); + void OnReadArc(double start_angle, double end_angle, double radius, @@ -368,6 +425,8 @@ class CDxfRead bool ReadDWGCodePage(); bool ResolveEncoding(); + void HandleCommonGroupCode(int n); + void put_line(const char *value); void ResolveColorIndex(); @@ -407,6 +466,9 @@ class CDxfRead virtual void OnReadLine(const double* /*s*/, const double* /*e*/, bool /*hidden*/) {} + + virtual void OnReadPolyline(const DxfPolyline&) {} + virtual void OnReadPoint(const double* /*s*/) {} virtual void OnReadText(const DxfText&) {} diff --git a/src/io_dxf/io_dxf.cpp b/src/io_dxf/io_dxf.cpp index a26effc5..5eb0ad5d 100644 --- a/src/io_dxf/io_dxf.cpp +++ b/src/io_dxf/io_dxf.cpp @@ -95,6 +95,7 @@ class DxfReader::Internal : public CDxfRead { // CDxfRead's virtual functions void OnReadLine(const double* s, const double* e, bool hidden) override; + void OnReadPolyline(const DxfPolyline& polyline) override; void OnReadPoint(const double* s) override; void OnReadText(const DxfText& text) override; void OnReadArc(const double* s, const double* e, const double* c, bool dir, bool hidden) override; @@ -174,7 +175,7 @@ TDF_LabelSequence DxfReader::transfer(DocumentPtr doc, TaskProgress* progress) return labelShape; }; - auto fnAddAci = [&](ColorIndex_t aci) { + auto fnAddAci = [&](ColorIndex_t aci) -> TDF_Label { auto it = mapAciColorLabel.find(aci); if (it != mapAciColorLabel.cend()) return it->second; @@ -182,7 +183,8 @@ TDF_LabelSequence DxfReader::transfer(DocumentPtr doc, TaskProgress* progress) if (0 <= aci && CppUtils::cmpLess(aci, std::size(aciTable))) { const RGB_Color& c = aciTable[aci].second; const TDF_Label colorLabel = colorTool->AddColor( - Quantity_Color(c.r / 255., c.g / 255., c.b / 255., Quantity_TOC_RGB)); + Quantity_Color(c.r / 255., c.g / 255., c.b / 255., Quantity_TOC_RGB) + ); mapAciColorLabel.insert({ aci, colorLabel }); return colorLabel; } @@ -203,6 +205,12 @@ TDF_LabelSequence DxfReader::transfer(DocumentPtr doc, TaskProgress* progress) progress->setValue(MathUtils::toPercent(iShape, 0, shapeCount)); }; + auto fnSetShapeColor = [=](const TDF_Label& labelShape, int aci) { + const TDF_Label labelColor = fnAddAci(aci); + if (!labelColor.IsNull()) + colorTool->SetColor(labelShape, labelColor, XCAFDoc_ColorGen); + }; + if (!m_params.groupLayers) { for (const auto& [layerName, vecEntity] : m_layers) { if (startsWith(layerName, "BLOCKS")) @@ -241,13 +249,13 @@ TDF_LabelSequence DxfReader::transfer(DocumentPtr doc, TaskProgress* progress) } if (uniqueColor) { - colorTool->SetColor(compLabel, fnAddAci(aci), XCAFDoc_ColorGen); + fnSetShapeColor(compLabel, aci); } else { for (const Entity& entity : vecEntity) { if (!entity.shape.IsNull()) { const TDF_Label entityLabel = shapeTool->AddSubShape(compLabel, entity.shape); - colorTool->SetColor(entityLabel, fnAddAci(entity.aci), XCAFDoc_ColorGen); + fnSetShapeColor(entityLabel, entity.aci); } } } @@ -381,6 +389,19 @@ void DxfReader::Internal::OnReadLine(const double* s, const double* e, bool /*hi this->addShape(edge); } +void DxfReader::Internal::OnReadPolyline(const DxfPolyline& polyline) +{ + const auto& vertices = polyline.vertices; + Handle(Poly_Polygon3D) polygon = new Poly_Polygon3D( + CppUtils::safeStaticCast(vertices.size()), + false/*!hasParams*/ + ); + for (unsigned i = 0; i < vertices.size(); ++i) + polygon->ChangeNodes().ChangeValue(i + 1) = this->toPnt(vertices.at(i).point); + + this->addShape(BRepUtils::makeEdge(polygon)); +} + void DxfReader::Internal::OnReadPoint(const double* s) { const TopoDS_Vertex vertex = BRepBuilderAPI_MakeVertex(this->toPnt(s)); @@ -572,7 +593,7 @@ gp_Pnt DxfReader::Internal::toPnt(const double* coords) const double sp1(coords[0]); double sp2(coords[1]); double sp3(coords[2]); - if (m_params.scaling != 1.0) { + if (!MathUtils::fuzzyEqual(m_params.scaling, 1.)) { sp1 = sp1 * m_params.scaling; sp2 = sp2 * m_params.scaling; sp3 = sp3 * m_params.scaling; From 462c900eadbcaaec8a7c10ac77f2ece1004c3ede Mon Sep 17 00:00:00 2001 From: Hugues Delorme Date: Fri, 24 Nov 2023 14:07:19 +0100 Subject: [PATCH 05/10] Base: introduce Polygon3dBuilder helper --- src/base/mesh_utils.cpp | 108 +++++++++++++++++++++++++++++++++++----- src/base/mesh_utils.h | 107 +++++++++++++++++++++++---------------- 2 files changed, 161 insertions(+), 54 deletions(-) diff --git a/src/base/mesh_utils.cpp b/src/base/mesh_utils.cpp index 82ac14a7..0f1166d2 100644 --- a/src/base/mesh_utils.cpp +++ b/src/base/mesh_utils.cpp @@ -6,17 +6,32 @@ #include "mesh_utils.h" #include "math_utils.h" -#include + +#include #include +#include namespace Mayo { +namespace MeshUtils { + +namespace { -double MeshUtils::triangleSignedVolume(const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ& p3) +TColStd_Array1OfReal createArray1OfReal(int count) +{ + if (count > 0) + return TColStd_Array1OfReal(1 , count); + else + return TColStd_Array1OfReal(); +} + +} // namespace + +double triangleSignedVolume(const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ& p3) { return p1.Dot(p2.Crossed(p3)) / 6.0f; } -double MeshUtils::triangleArea(const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ& p3) +double triangleArea(const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ& p3) { const double ax = p2.X() - p1.X(); const double ay = p2.Y() - p1.Y(); @@ -30,7 +45,7 @@ double MeshUtils::triangleArea(const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ& return 0.5 * std::sqrt(cx*cx + cy*cy + cz*cz); } -double MeshUtils::triangulationVolume(const Handle_Poly_Triangulation& triangulation) +double triangulationVolume(const Handle_Poly_Triangulation& triangulation) { if (!triangulation) return 0; @@ -49,7 +64,7 @@ double MeshUtils::triangulationVolume(const Handle_Poly_Triangulation& triangula return std::abs(volume); } -double MeshUtils::triangulationArea(const Handle_Poly_Triangulation& triangulation) +double triangulationArea(const Handle_Poly_Triangulation& triangulation) { if (!triangulation) return 0; @@ -68,7 +83,7 @@ double MeshUtils::triangulationArea(const Handle_Poly_Triangulation& triangulati return area; } -void MeshUtils::setNode(const Handle_Poly_Triangulation& triangulation, int index, const gp_Pnt& pnt) +void setNode(const Handle_Poly_Triangulation& triangulation, int index, const gp_Pnt& pnt) { #if OCC_VERSION_HEX >= 0x070600 triangulation->SetNode(index, pnt); @@ -77,7 +92,7 @@ void MeshUtils::setNode(const Handle_Poly_Triangulation& triangulation, int inde #endif } -void MeshUtils::setTriangle(const Handle_Poly_Triangulation& triangulation, int index, const Poly_Triangle& triangle) +void setTriangle(const Handle_Poly_Triangulation& triangulation, int index, const Poly_Triangle& triangle) { #if OCC_VERSION_HEX >= 0x070600 triangulation->SetTriangle(index, triangle); @@ -86,7 +101,7 @@ void MeshUtils::setTriangle(const Handle_Poly_Triangulation& triangulation, int #endif } -void MeshUtils::setNormal(const Handle_Poly_Triangulation& triangulation, int index, const Poly_Triangulation_NormalType& n) +void setNormal(const Handle_Poly_Triangulation& triangulation, int index, const Poly_Triangulation_NormalType& n) { #if OCC_VERSION_HEX >= 0x070600 triangulation->SetNormal(index, n); @@ -98,7 +113,7 @@ void MeshUtils::setNormal(const Handle_Poly_Triangulation& triangulation, int in #endif } -void MeshUtils::setUvNode(const Handle_Poly_Triangulation& triangulation, int index, double u, double v) +void setUvNode(const Handle_Poly_Triangulation& triangulation, int index, double u, double v) { #if OCC_VERSION_HEX >= 0x070600 triangulation->SetUVNode(index, gp_Pnt2d{u, v}); @@ -107,7 +122,7 @@ void MeshUtils::setUvNode(const Handle_Poly_Triangulation& triangulation, int in #endif } -void MeshUtils::allocateNormals(const Handle_Poly_Triangulation& triangulation) +void allocateNormals(const Handle_Poly_Triangulation& triangulation) { #if OCC_VERSION_HEX >= 0x070600 triangulation->AddNormals(); @@ -117,8 +132,18 @@ void MeshUtils::allocateNormals(const Handle_Poly_Triangulation& triangulation) #endif } +const Poly_Array1OfTriangle& triangles(const Handle_Poly_Triangulation& triangulation) +{ +#if OCC_VERSION_HEX < 0x070600 + return triangulation->Triangles(); +#else + // Note: Poly_Triangulation::Triangles() was deprecated starting from OpenCascade v7.6.0 + return triangulation->InternalTriangles(); +#endif +} + // Adapted from http://cs.smith.edu/~jorourke/Code/polyorient.C -MeshUtils::Orientation MeshUtils::orientation(const AdaptorPolyline2d& polyline) +MeshUtils::Orientation orientation(const AdaptorPolyline2d& polyline) { const int pntCount = polyline.pointCount(); if (pntCount < 2) @@ -172,7 +197,7 @@ MeshUtils::Orientation MeshUtils::orientation(const AdaptorPolyline2d& polyline) } } -gp_Vec MeshUtils::directionAt(const AdaptorPolyline3d& polyline, int i) +gp_Vec directionAt(const AdaptorPolyline3d& polyline, int i) { const int pntCount = polyline.pointCount(); if (pntCount > 1) { @@ -191,4 +216,63 @@ gp_Vec MeshUtils::directionAt(const AdaptorPolyline3d& polyline, int i) return gp_Vec(); } +Polygon3dBuilder::Polygon3dBuilder(int nodeCount, ParametersOption option) +#if OCC_VERSION_HEX >= 0x070500 + : m_polygon(new Poly_Polygon3D(nodeCount, option == ParametersOption::With)), + m_ptrNodes(&m_polygon->ChangeNodes()), + m_ptrParams(option == ParametersOption::With ? &m_polygon->ChangeParameters() : nullptr) +#else + : m_nodes(1, nodeCount), + m_params(std::move(createArray1OfReal(option == ParametersOption::With ? nodeCount : 0))), + m_ptrNodes(&m_nodes), + m_ptrParams(option == ParametersOption::With ? &m_params : nullptr) +#endif +{ + assert(m_ptrNodes); + assert( + (option == ParametersOption::None && !m_ptrParams) + || (option == ParametersOption::With && m_ptrParams) + ); +} + +void Polygon3dBuilder::setNode(int i, const gp_Pnt &pnt) +{ + if (m_isFinalized) + throw std::runtime_error("Can't call setNode() on finalized Polygon3dBuilder object"); + + m_ptrNodes->ChangeValue(i) = pnt; +} + +void Polygon3dBuilder::setParameter(int i, double u) +{ + if (m_isFinalized) + throw std::runtime_error("Can't call setParameter() on finalized Polygon3dBuilder object"); + + if (m_ptrParams) + m_ptrParams->ChangeValue(i) = u; +} + +void Polygon3dBuilder::finalize() +{ + if (m_isFinalized) + return; + +#if OCC_VERSION_HEX < 0x070500 + if (m_ptrParams) + m_polygon = new Poly_Polygon3D(m_nodes, m_params); + else + m_polygon = new Poly_Polygon3D(m_nodes); +#endif + m_isFinalized = true; +} + +OccHandle Polygon3dBuilder::get() const +{ + if (!m_isFinalized) + throw std::runtime_error("Can't call get() on non finalized Polygon3dBuilder object"); + + return m_polygon; +} + +} // namespace MeshUtils } // namespace Mayo diff --git a/src/base/mesh_utils.h b/src/base/mesh_utils.h index 85aecd00..791045fc 100644 --- a/src/base/mesh_utils.h +++ b/src/base/mesh_utils.h @@ -6,6 +6,9 @@ #pragma once +#include "occ_handle.h" + +#include #include #include class gp_XYZ; @@ -13,56 +16,76 @@ class gp_XYZ; namespace Mayo { // Provides helper functions for mesh and triangle objects -struct MeshUtils { - static double triangleSignedVolume(const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ& p3); - static double triangleArea(const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ& p3); +namespace MeshUtils { + +double triangleSignedVolume(const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ& p3); +double triangleArea(const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ& p3); - static double triangulationVolume(const Handle_Poly_Triangulation& triangulation); - static double triangulationArea(const Handle_Poly_Triangulation& triangulation); +double triangulationVolume(const Handle_Poly_Triangulation& triangulation); +double triangulationArea(const Handle_Poly_Triangulation& triangulation); #if OCC_VERSION_HEX >= 0x070600 - using Poly_Triangulation_NormalType = gp_Vec3f; +using Poly_Triangulation_NormalType = gp_Vec3f; #else - using Poly_Triangulation_NormalType = gp_Vec; +using Poly_Triangulation_NormalType = gp_Vec; #endif - static void setNode(const Handle_Poly_Triangulation& triangulation, int index, const gp_Pnt& pnt); - static void setTriangle(const Handle_Poly_Triangulation& triangulation, int index, const Poly_Triangle& triangle); - static void setNormal(const Handle_Poly_Triangulation& triangulation, int index, const Poly_Triangulation_NormalType& n); - static void setUvNode(const Handle_Poly_Triangulation& triangulation, int index, double u, double v); - static void allocateNormals(const Handle_Poly_Triangulation& triangulation); +void setNode(const Handle_Poly_Triangulation& triangulation, int index, const gp_Pnt& pnt); +void setTriangle(const Handle_Poly_Triangulation& triangulation, int index, const Poly_Triangle& triangle); +void setNormal(const Handle_Poly_Triangulation& triangulation, int index, const Poly_Triangulation_NormalType& n); +void setUvNode(const Handle_Poly_Triangulation& triangulation, int index, double u, double v); +void allocateNormals(const Handle_Poly_Triangulation& triangulation); - static const Poly_Array1OfTriangle& triangles(const Handle_Poly_Triangulation& triangulation) { -#if OCC_VERSION_HEX < 0x070600 - return triangulation->Triangles(); -#else - // Note: Poly_Triangulation::Triangles() was deprecated starting from OpenCascade v7.6.0 - return triangulation->InternalTriangles(); +const Poly_Array1OfTriangle& triangles(const Handle_Poly_Triangulation& triangulation); + +enum class Orientation { + Unknown, + Clockwise, + CounterClockwise +}; + +class AdaptorPolyline2d { +public: + virtual gp_Pnt2d pointAt(int index) const = 0; + virtual int pointCount() const = 0; + virtual bool empty() const { return this->pointCount() <= 0; } +}; + +class AdaptorPolyline3d { +public: + virtual const gp_Pnt& pointAt(int i) const = 0; + virtual int pointCount() const = 0; + virtual int empty() const { return this->pointCount() <= 0; } +}; + +Orientation orientation(const AdaptorPolyline2d& polyline); +gp_Vec directionAt(const AdaptorPolyline3d& polyline, int i); + +// Provides helper to create Poly_Polygon3D objects +// Poly_Polygon3D class interface changed from OpenCascade 7.4 to 7.5 version so using this class +// directly might cause compilation errors +// Prefer Polygon3dBuilder so application code doesn't have to care about OpenCascade version +class Polygon3dBuilder { +public: + enum class ParametersOption { None, With }; + + Polygon3dBuilder(int nodeCount, ParametersOption option = ParametersOption::None); + + void setNode(int i, const gp_Pnt& pnt); + void setParameter(int i, double u); + void finalize(); + OccHandle get() const; + +private: + bool m_isFinalized = false; + OccHandle m_polygon; +#if OCC_VERSION_HEX < 0x070500 + TColgp_Array1OfPnt m_nodes; + TColStd_Array1OfReal m_params; #endif - } - - enum class Orientation { - Unknown, - Clockwise, - CounterClockwise - }; - - class AdaptorPolyline2d { - public: - virtual gp_Pnt2d pointAt(int index) const = 0; - virtual int pointCount() const = 0; - virtual bool empty() const { return this->pointCount() <= 0; } - }; - - class AdaptorPolyline3d { - public: - virtual const gp_Pnt& pointAt(int i) const = 0; - virtual int pointCount() const = 0; - virtual int empty() const { return this->pointCount() <= 0; } - }; - - static Orientation orientation(const AdaptorPolyline2d& polyline); - static gp_Vec directionAt(const AdaptorPolyline3d& polyline, int i); + TColgp_Array1OfPnt* m_ptrNodes = nullptr; + TColStd_Array1OfReal* m_ptrParams = nullptr; }; +} // namespace MeshUtils } // namespace Mayo From 92a6afd069cdcab5521ee29af8762b4e9878c3f8 Mon Sep 17 00:00:00 2001 From: Hugues Delorme Date: Fri, 24 Nov 2023 14:07:57 +0100 Subject: [PATCH 06/10] IO_Dxf: massive refactoring * Replace char[] members by std::string * Replace double* and double[3] X,Y,Z triplets with DxfCoords struct * Replace sscanf(%d) calls by internal stringToInt() * Replace std::istringstream usage by internal stringToNumeric(m_str) * Factorize X,Y,Z parsing with HandleCoordCode() function * Centralize calls to get_line() by a single call before switch(n) in each Read() function * Rewrite get_line() with C++ code based on std::string --- src/base/property_value_conversion.cpp | 20 +- src/io_dxf/dxf.cpp | 1337 ++++++++---------------- src/io_dxf/dxf.h | 192 ++-- src/io_dxf/io_dxf.cpp | 110 +- 4 files changed, 609 insertions(+), 1050 deletions(-) diff --git a/src/base/property_value_conversion.cpp b/src/base/property_value_conversion.cpp index 4e95b8d6..e44ae8c4 100644 --- a/src/base/property_value_conversion.cpp +++ b/src/base/property_value_conversion.cpp @@ -33,18 +33,18 @@ namespace { static std::string toString(double value, int prec = 6) { #if __cpp_lib_to_chars - char buff[64] = {}; - auto toCharsFormat = std::chars_format::general; - auto resToChars = std::to_chars(std::begin(buff), std::end(buff), value, toCharsFormat, prec); - if (resToChars.ec != std::errc()) - throw std::runtime_error("value_too_large"); + char buff[64] = {}; + auto toCharsFormat = std::chars_format::general; + auto resToChars = std::to_chars(std::begin(buff), std::end(buff), value, toCharsFormat, prec); + if (resToChars.ec != std::errc()) + throw std::runtime_error("value_too_large"); - return std::string(buff, resToChars.ptr - buff); + return std::string(buff, resToChars.ptr - buff); #else - std::stringstream sstr; - sstr.precision(prec); - sstr << value; - return sstr.str(); + std::stringstream sstr; + sstr.precision(prec); + sstr << value; + return sstr.str(); #endif } diff --git a/src/io_dxf/dxf.cpp b/src/io_dxf/dxf.cpp index 853c1aa0..6b6fcdc7 100644 --- a/src/io_dxf/dxf.cpp +++ b/src/io_dxf/dxf.cpp @@ -10,8 +10,12 @@ # define _USE_MATH_DEFINES #endif #include +#include #include #include +#if __cpp_lib_to_chars +# include +#endif #include #include @@ -23,12 +27,6 @@ namespace { -template -void safe_strcpy(char (&dst)[N1], const char (&src)[N2]) -{ - strncpy(dst, src, std::min(N1, N2)); -} - class ScopedCLocale { public: ScopedCLocale(int category) @@ -48,40 +46,93 @@ class ScopedCLocale { const char* m_savedLocale = nullptr; }; -double stringToDouble(const std::string& line) +} // namespace + +namespace DxfPrivate { + +template bool isStringToErrorValue(T value) { - try { - return std::stod(line); - } catch (...) { - throw std::runtime_error("Failed to fetch double value from line:\n" + line); + if constexpr(std::is_same_v) { + return value == std::numeric_limits::max(); + } + else if constexpr(std::is_same_v) { + return value == std::numeric_limits::max(); + } + else if constexpr(std::is_same_v) { + constexpr double dMax = std::numeric_limits::max(); + return std::abs(value - dMax) * 1000000000000. <= std::min(std::abs(value), std::abs(dMax)); + } + else { + return false; } - - return 0.; } -int stringToInt(const std::string& line) +template +T stringToNumeric(const std::string& line, StringToErrorMode errorMode) { +#if __cpp_lib_to_chars + T value; + auto [ptr, err] = std::from_chars(line.c_str(), line.c_str() + line.size(), value); + if (err == std::errc()) + return value; +#else try { - return std::stoi(line); + if constexpr(std::is_same_v) { + return std::stoi(line); + } + else if constexpr(std::is_same_v) { + return std::stoul(line); + } + else if constexpr(std::is_same_v) { + return std::stod(line); + } + else { + if (errorMode == StringToErrorMode::ReturnErrorValue) + return std::numeric_limits::max(); + else + throw std::runtime_error("Failed to fetch numeric value from line:\n" + line); + } } catch (...) { - throw std::runtime_error("Failed to fetch int value from line:\n" + line); +#endif + + if (errorMode == StringToErrorMode::ReturnErrorValue) { + return std::numeric_limits::max(); + } + else { + std::string strTypeName = "?"; + if constexpr(std::is_same_v) + strTypeName = "int"; + else if constexpr(std::is_same_v) + strTypeName = "unsigned"; + else if constexpr(std::is_same_v) + strTypeName = "double"; + + throw std::runtime_error("Failed to fetch " + strTypeName + " value from line:\n" + line); } - return 0; +#ifndef __cpp_lib_to_chars + } +#endif } -unsigned stringToUnsigned(const std::string& line) +int stringToInt(const std::string& line, StringToErrorMode errorMode) { - try { - return std::stoul(line); - } catch (...) { - throw std::runtime_error("Failed to fetch unsigned int value from line:\n" + line); - } + return stringToNumeric(line, errorMode); +} - return 0; +unsigned stringToUnsigned(const std::string& line, StringToErrorMode errorMode) +{ + return stringToNumeric(line, errorMode); } -} // namespace +double stringToDouble(const std::string& line, StringToErrorMode errorMode) +{ + return stringToNumeric(line, errorMode); +} + +} // namespace DxfPrivate + +using namespace DxfPrivate; Base::Vector3d toVector3d(const double* a) { @@ -1842,20 +1893,14 @@ CDxfRead::CDxfRead(const char* filepath) : m_ifs(filepath) { // start the file - memset( m_str, '\0', sizeof(m_str) ); - memset( m_unused_line, '\0', sizeof(m_unused_line) ); m_fail = false; m_ColorIndex = 0; m_eUnits = eMillimeters; m_measurement_inch = false; m_layer_name = "0"; // Default layer name - memset( m_section_name, '\0', sizeof(m_section_name) ); - memset( m_block_name, '\0', sizeof(m_block_name) ); m_ignore_errors = true; m_version = RUnknown; - //m_CodePage = nullptr; - //m_encoding = nullptr; if (!m_ifs) m_fail = true; @@ -1865,11 +1910,9 @@ CDxfRead::CDxfRead(const char* filepath) CDxfRead::~CDxfRead() { - //delete m_CodePage; - //delete m_encoding; } -double CDxfRead::mm( double value ) const +double CDxfRead::mm(double value) const { // re #6461 // this if handles situation of malformed DXF file where @@ -1931,95 +1974,42 @@ double CDxfRead::mm( double value ) const bool CDxfRead::ReadLine() { - double s[3] = {0, 0, 0}; - double e[3] = {0, 0, 0}; + DxfCoords s = {}; + DxfCoords e = {}; bool hidden = false; while (!m_ifs.eof()) { get_line(); - int n; - - if (sscanf(m_str, "%d", &n) != 1) { - this->ReportError_readInteger("DXF::ReadLine()"); - return false; - } - - std::istringstream ss; - ss.imbue(std::locale::classic()); - switch (n){ - case 0: + const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + if (n == 0) { // next item found, so finish with line ResolveColorIndex(); OnReadLine(s, e, hidden); - hidden = false; return true; + } + else if (isStringToErrorValue(n)) { + this->ReportError_readInteger("DXF::ReadLine()"); + return false; + } + get_line(); + switch (n) { case 6: // line style name follows - get_line(); - if (m_str[0] == 'h' || m_str[0] == 'H') { + if (!m_str.empty() && (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; - } + // start coords + HandleCoordCode(n, &s); 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; - } + // end coords + HandleCoordCode<11, 21, 31>(n, &e); break; case 100: case 39: @@ -2027,10 +2017,8 @@ bool CDxfRead::ReadLine() case 220: case 230: // skip the next line - get_line(); break; default: - get_line(); HandleCommonGroupCode(n); break; } @@ -2051,55 +2039,29 @@ bool CDxfRead::ReadLine() bool CDxfRead::ReadPoint() { - double s[3] = {0, 0, 0}; + DxfCoords s = {}; while (!m_ifs.eof()) { get_line(); - int n; - - if (sscanf(m_str, "%d", &n) != 1) { - this->ReportError_readInteger("DXF::ReadPoint()"); - return false; - } - - std::istringstream ss; - ss.imbue(std::locale::classic()); - switch (n){ - case 0: + const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + if (n == 0) { // next item found, so finish with line ResolveColorIndex(); OnReadPoint(s); return true; + } + else if (isStringToErrorValue(n)) { + this->ReportError_readInteger("DXF::ReadPoint()"); + return false; + } + get_line(); + switch (n){ 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; - } + // start coords + HandleCoordCode(n, &s); break; case 100: @@ -2108,10 +2070,8 @@ bool CDxfRead::ReadPoint() case 220: case 230: // skip the next line - get_line(); break; default: - get_line(); HandleCommonGroupCode(n); break; } @@ -2135,92 +2095,50 @@ bool CDxfRead::ReadArc() double start_angle = 0.0;// in degrees double end_angle = 0.0; double radius = 0.0; - double c[3] = {0,0,0}; // centre + DxfCoords c = {}; // 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) { - this->ReportError_readInteger("DXF::ReadArc()"); - return false; - } - - std::istringstream ss; - ss.imbue(std::locale::classic()); - switch (n){ - case 0: + const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + if (n == 0) { // next item found, so finish with arc ResolveColorIndex(); - OnReadArc(start_angle, end_angle, radius, c,z_extrusion_dir, hidden); + OnReadArc(start_angle, end_angle, radius, c, z_extrusion_dir, hidden); hidden = false; return true; + } + else if (isStringToErrorValue(n)) { + this->ReportError_readInteger("DXF::ReadArc()"); + return false; + } + get_line(); + switch (n){ case 6: // line style name follows - get_line(); - if (m_str[0] == 'h' || m_str[0] == 'H') { + if (!m_str.empty() && (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; - } + // centre coords + HandleCoordCode(n, &c); break; case 40: // radius - get_line(); - ss.str(m_str); - ss >> radius; - radius = mm(radius); - if (ss.fail()) { - return false; - } + radius = mm(stringToDouble(m_str)); break; case 50: // start angle - get_line(); - ss.str(m_str); - ss >> start_angle; - if (ss.fail()) { - return false; - } + start_angle = mm(stringToDouble(m_str)); break; case 51: // end angle - get_line(); - ss.str(m_str); - ss >> end_angle; - if (ss.fail()) { - return false; - } + end_angle = mm(stringToDouble(m_str)); break; case 100: @@ -2228,24 +2146,18 @@ bool CDxfRead::ReadArc() 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; - } + z_extrusion_dir = mm(stringToDouble(m_str)); break; default: - get_line(); HandleCommonGroupCode(n); break; } } + ResolveColorIndex(); OnReadArc(start_angle, end_angle, radius, c, z_extrusion_dir, false); return false; @@ -2254,270 +2166,122 @@ bool CDxfRead::ReadArc() bool CDxfRead::ReadSpline() { struct SplineData sd; - sd.norm[0] = 0; - sd.norm[1] = 0; - sd.norm[2] = 1; + sd.norm = {0., 0., 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) { - this->ReportError_readInteger("DXF::ReadSpline()"); - return false; - } - std::istringstream ss; - ss.imbue(std::locale::classic()); - switch (n) { - case 0: + const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + if (n == 0) { // next item found, so finish with Spline ResolveColorIndex(); OnReadSpline(sd); return true; + } + else if (isStringToErrorValue(n)) { + this->ReportError_readInteger("DXF::ReadSpline()"); + return false; + } + + get_line(); + switch (n) { 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; - } + // normal coords + HandleCoordCode<210, 220, 230>(n, &sd.norm); break; case 70: // flag - get_line(); - ss.str(m_str); - ss >> sd.flag; - if (ss.fail()) { - return false; - } + sd.flag = stringToInt(m_str); break; case 71: // degree - get_line(); - ss.str(m_str); - ss >> sd.degree; - if (ss.fail()) { - return false; - } + sd.degree = stringToInt(m_str); break; case 72: // knots - get_line(); - ss.str(m_str); - ss >> sd.knots; - if (ss.fail()) { - return false; - } + sd.knots = stringToInt(m_str); break; case 73: // control points - get_line(); - ss.str(m_str); - ss >> sd.control_points; - if (ss.fail()) { - return false; - } + sd.control_points = stringToInt(m_str); break; case 74: // fit points - get_line(); - ss.str(m_str); - ss >> sd.fit_points; - if (ss.fail()) { - return false; - } + sd.fit_points = stringToInt(m_str); 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); + sd.starttanx.push_back(mm(stringToDouble(m_str))); 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); + sd.starttany.push_back(mm(stringToDouble(m_str))); 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); + sd.starttanz.push_back(mm(stringToDouble(m_str))); 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); + sd.endtanx.push_back(mm(stringToDouble(m_str))); 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); + sd.endtany.push_back(mm(stringToDouble(m_str))); 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); + sd.endtanz.push_back(mm(stringToDouble(m_str))); 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); + sd.knot.push_back(mm(stringToDouble(m_str))); 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); + sd.weight.push_back(mm(stringToDouble(m_str))); 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); + sd.controlx.push_back(mm(stringToDouble(m_str))); 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); + sd.controly.push_back(mm(stringToDouble(m_str))); 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); + sd.controlz.push_back(mm(stringToDouble(m_str))); 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); + sd.fitx.push_back(mm(stringToDouble(m_str))); 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); + sd.fity.push_back(mm(stringToDouble(m_str))); 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); + sd.fitz.push_back(mm(stringToDouble(m_str))); break; case 42: case 43: case 44: // skip the next line - get_line(); break; default: - get_line(); HandleCommonGroupCode(n); break; } } + ResolveColorIndex(); OnReadSpline(sd); return false; @@ -2527,72 +2291,39 @@ bool CDxfRead::ReadSpline() bool CDxfRead::ReadCircle() { double radius = 0.0; - double c[3] = {0,0,0}; // centre + DxfCoords c = {}; // centre bool hidden = false; while (!m_ifs.eof()) { get_line(); - int n; - if (sscanf(m_str, "%d", &n) != 1) { - this->ReportError_readInteger("DXF::ReadCircle()"); - return false; - } - std::istringstream ss; - ss.imbue(std::locale::classic()); - switch (n){ - case 0: + const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + if (n == 0) { // next item found, so finish with Circle ResolveColorIndex(); OnReadCircle(c, radius, hidden); - hidden = false; return true; + } + else if (isStringToErrorValue(n)) { + this->ReportError_readInteger("DXF::ReadCircle()"); + return false; + } + get_line(); + switch (n){ case 6: // line style name follows - get_line(); - if (m_str[0] == 'h' || m_str[0] == 'H') { + if (!m_str.empty() && (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; - } + // centre coords + HandleCoordCode(n, &c); break; case 40: // radius - get_line(); - ss.str(m_str); - ss >> radius; - radius = mm(radius); - if (ss.fail()) { - return false; - } + radius = mm(stringToDouble(m_str)); break; case 100: @@ -2601,14 +2332,13 @@ bool CDxfRead::ReadCircle() case 220: case 230: // skip the next line - get_line(); break; default: - get_line(); HandleCommonGroupCode(n); break; } } + ResolveColorIndex(); OnReadCircle(c, radius, false); return false; @@ -2616,49 +2346,38 @@ bool CDxfRead::ReadCircle() void CDxfRead::ReadText() { - ScopedCLocale _(LC_NUMERIC); - DxfText text; while (!m_ifs.eof()) { get_line(); const int n = stringToInt(m_str); - switch (n) { - case 0: + if (n == 0) { ResolveColorIndex(); - { - size_t pos = text.str.find("\\P", 0); - while (pos != std::string::npos) { - text.str.replace(pos, 2, "\n"); - pos = text.str.find("\\P", pos + 1); - } - - text.str = this->toUtf8(text.str); - OnReadText(text); + // Replace \P by \n + size_t pos = text.str.find("\\P", 0); + while (pos != std::string::npos) { + text.str.replace(pos, 2, "\n"); + pos = text.str.find("\\P", pos + 1); } + + text.str = this->toUtf8(text.str); + OnReadText(text); return; + } + + get_line(); + switch (n) { case 10: - // centre x - get_line(); - text.point[0] = mm(stringToDouble(m_str)); - break; case 20: - // centre y - get_line(); - text.point[1] = mm(stringToDouble(m_str)); - break; case 30: - // centre z - get_line(); - text.point[2] = mm(stringToDouble(m_str)); + // centre coords + HandleCoordCode(n, &text.point); break; case 40: // text height - get_line(); text.height = mm(stringToDouble(m_str)) * 25.4 / 72.0; break; case 50: // text rotation - get_line(); text.rotation = stringToDouble(m_str); break; case 3: @@ -2666,18 +2385,15 @@ void CDxfRead::ReadText() // Note that if breaking the text into type-3 records splits a UFT-8 encoding we do // the decoding after splicing the lines together. I'm not sure if this actually // occurs, but handling the text this way will treat this condition properly. - get_line(); text.str.append(m_str); break; case 1: // final text - get_line(); text.str.append(m_str); break; case 71: { // attachment point - get_line(); const int ap = stringToInt(m_str); if (ap >= 1 && ap <= 9) { text.attachPoint = static_cast(ap); @@ -2691,7 +2407,6 @@ void CDxfRead::ReadText() case 220: case 230: default: - get_line(); HandleCommonGroupCode(n); break; } @@ -2701,128 +2416,64 @@ void CDxfRead::ReadText() bool CDxfRead::ReadEllipse() { - double c[3] = {0,0,0}; // centre - double m[3] = {0,0,0}; //major axis point - double ratio=0; //ratio of major to minor axis - double start=0; //start of arc - double end=0; // end of arc + DxfCoords c = {}; // centre + DxfCoords m = {}; //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) { - this->ReportError_readInteger("DXF::ReadEllipse()"); - return false; - } - std::istringstream ss; - ss.imbue(std::locale::classic()); - switch (n){ - case 0: + const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + if (n == 0) { // next item found, so finish with Ellipse ResolveColorIndex(); OnReadEllipse(c, m, ratio, start, end); return true; + } + else if (isStringToErrorValue(n)) { + this->ReportError_readInteger("DXF::ReadEllipse()"); + return false; + } + get_line(); + switch (n) { 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; - } + // centre coords + HandleCoordCode(n, &c); 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; - } + // major coords + HandleCoordCode<11, 21, 31>(n, &m); break; case 40: // ratio - get_line(); - ss.str(m_str); - ss >> ratio; - if (ss.fail()) { - return false; - } + ratio = stringToDouble(m_str); break; case 41: // start - get_line(); - ss.str(m_str); - ss >> start; - if (ss.fail()) { - return false; - } + start = stringToDouble(m_str); break; case 42: // end - get_line(); - ss.str(m_str); - ss >> end; - if (ss.fail()) { - return false; - } + end = stringToDouble(m_str); break; case 100: case 210: case 220: case 230: // skip the next line - get_line(); break; default: - get_line(); HandleCommonGroupCode(n); break; } } + ResolveColorIndex(); OnReadEllipse(c, m, ratio, start, end); return false; @@ -2852,16 +2503,16 @@ AddPolyLinePoint(CDxfRead* dxf_read, double x, double y, double z, bool bulge_fo 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}; + const DxfCoords ps = {poly_prev_x, poly_prev_y, poly_prev_z}; + const DxfCoords pe = {x, y, z}; + const DxfCoords pc = {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}; + const DxfCoords s = {poly_prev_x, poly_prev_y, poly_prev_z}; + const DxfCoords e = {x, y, z}; dxf_read->OnReadLine(s, e, false); } } @@ -2911,11 +2562,12 @@ bool CDxfRead::ReadLwPolyLine() while (!m_ifs.eof() && !next_item_found) { get_line(); - int n; - if (sscanf(m_str, "%d", &n) != 1) { + const int n = stringToInt(m_str); + if (isStringToErrorValue(n)) { this->ReportError_readInteger("DXF::ReadLwPolyLine()"); return false; } + std::istringstream ss; ss.imbue(std::locale::classic()); switch (n){ @@ -2983,9 +2635,7 @@ bool CDxfRead::ReadLwPolyLine() case 70: // flags get_line(); - if (sscanf(m_str, "%d", &flags) != 1) { - return false; - } + flags = stringToInt(m_str); closed = ((flags & 1) != 0); break; default: @@ -3013,39 +2663,29 @@ bool CDxfRead::ReadVertex(DxfVertex* vertex) bool y_found = false; while (!m_ifs.eof()) { get_line(); - int n; - if(sscanf(m_str, "%d", &n) != 1) { + const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + if (n == 0) { + ResolveColorIndex(); + put_line(m_str); // read one line too many. put it back. + return x_found && y_found; + } + else if (isStringToErrorValue(n)) { this->ReportError_readInteger("DXF::ReadVertex()"); return false; } + get_line(); switch (n){ - case 0: - ResolveColorIndex(); - put_line(m_str); // read one line too many. put it back. - return (x_found && y_found); - break; case 10: - // x - get_line(); - vertex->point[0] = mm(stringToDouble(m_str)); - x_found = true; - break; case 20: - // y - get_line(); - vertex->point[1] = mm(stringToDouble(m_str)); - y_found = true; - break; case 30: - // z - get_line(); - vertex->point[2] = mm(stringToDouble(m_str)); + // coords + x_found = x_found || n == 10; + y_found = y_found || n == 20; + HandleCoordCode(n, &vertex->point); break; - case 42: { // bulge - get_line(); const int bulge = stringToInt(m_str); if (bulge == 0) vertex->bulge = DxfVertex::Bulge::StraightSegment; @@ -3053,15 +2693,11 @@ bool CDxfRead::ReadVertex(DxfVertex* vertex) vertex->bulge = DxfVertex::Bulge::SemiCircle; } break; - case 70: // flags - get_line(); vertex->flags = stringToUnsigned(m_str); break; - default: - get_line(); HandleCommonGroupCode(n); break; } @@ -3073,28 +2709,27 @@ bool CDxfRead::ReadVertex(DxfVertex* vertex) bool CDxfRead::ReadPolyLine() { - ScopedCLocale _(LC_NUMERIC); DxfPolyline polyline; while (!m_ifs.eof()) { get_line(); - int n; - if (sscanf(m_str, "%d", &n) != 1) { + const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + if (isStringToErrorValue(n)) { this->ReportError_readInteger("DXF::ReadPolyLine()"); return false; } + get_line(); switch (n) { case 0: // next item found ResolveColorIndex(); - get_line(); - if (!strcmp(m_str, "VERTEX")) { + if (m_str == "VERTEX") { DxfVertex vertex; if (ReadVertex(&vertex)) - polyline.vertices.push_back(vertex); + polyline.vertices.push_back(std::move(vertex)); } - if (!strcmp(m_str, "SEQEND")) { + if (m_str == "SEQEND") { OnReadPolyline(polyline); return true; } @@ -3102,11 +2737,9 @@ bool CDxfRead::ReadPolyLine() break; case 70: // flags - get_line(); polyline.flags = stringToUnsigned(m_str); break; default: - get_line(); HandleCommonGroupCode(n); break; } @@ -3118,162 +2751,117 @@ bool CDxfRead::ReadPolyLine() void CDxfRead::OnReadArc(double start_angle, double end_angle, double radius, - const double* c, + const DxfCoords& c, double z_extrusion_dir, bool hidden) { - double s[3] = {0, 0, 0}, e[3] = {0, 0, 0}, temp[3] = {0, 0, 0}; + DxfCoords s = {}; + DxfCoords e = {}; + DxfCoords temp = {}; 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 * M_PI / 180); - s[1] = c[1] + radius * sin(start_angle * M_PI / 180); - s[2] = c[2]; - e[0] = c[0] + radius * cos(end_angle * M_PI / 180); - e[1] = c[1] + radius * sin(end_angle * M_PI / 180); - e[2] = c[2]; + temp.x = c.x; + temp.y = c.y; + temp.z = c.z; + s.x = c.x + radius * cos(start_angle * M_PI / 180); + s.y = c.y + radius * sin(start_angle * M_PI / 180); + s.z = c.z; + e.x = c.x + radius * cos(end_angle * M_PI / 180); + e.y = c.y + radius * sin(end_angle * M_PI / 180); + e.z = c.z; } else { - temp[0] =-c[0]; - temp[1] =c[1]; - temp[2] =c[2]; + temp.x = -c.x; + temp.y = c.y; + temp.z = c.z; - e[0] = -(c[0] + radius * cos(start_angle * M_PI/180)); - e[1] = (c[1] + radius * sin(start_angle * M_PI/180)); - e[2] = c[2]; - s[0] = -(c[0] + radius * cos(end_angle * M_PI/180)); - s[1] = (c[1] + radius * sin(end_angle * M_PI/180)); - s[2] = c[2]; + e.x = -(c.x + radius * cos(start_angle * M_PI/180)); + e.y = (c.y + radius * sin(start_angle * M_PI/180)); + e.z = c.z; + s.x = -(c.x + radius * cos(end_angle * M_PI/180)); + s.y = (c.y + radius * sin(end_angle * M_PI/180)); + s.z = c.z; } + OnReadArc(s, e, temp, true, hidden); } -void CDxfRead::OnReadCircle(const double* c, double radius, bool hidden) +void CDxfRead::OnReadCircle(const DxfCoords& c, double radius, bool hidden) { - double s[3]; - double start_angle = 0; - s[0] = c[0] + radius * cos(start_angle * M_PI / 180); - s[1] = c[1] + radius * sin(start_angle * M_PI / 180); - s[2] = c[2]; + constexpr double start_angle = 0; + const DxfCoords s = { + c.x + radius * cos(start_angle * M_PI / 180), + c.y + radius * sin(start_angle * M_PI / 180), + c.z + }; - OnReadCircle(s, - c, - false, - hidden); // false to change direction because otherwise the arc length is zero + const bool dir = false; // 'false' to change direction because otherwise the arc length is zero + OnReadCircle(s, c, dir, hidden); } -void CDxfRead::OnReadEllipse(const double* c, - const double* m, +void CDxfRead::OnReadEllipse(const DxfCoords& c, + const DxfCoords& 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; + const double major_radius = sqrt(m.x * m.x + m.y * m.y + m.z * m.z); + const 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); - - + const double rotation = atan2(m.y / major_radius, m.x / major_radius); OnReadEllipse(c, major_radius, minor_radius, rotation, start_angle, end_angle, true); } - bool CDxfRead::ReadInsert() { - double c[3] = {0,0,0}; // coordinate - double s[3] = {1,1,1}; // scale + DxfCoords c = {}; // coordinate + DxfScale s = {1., 1., 1.}; // scale double rot = 0.0; // rotation - char name[1024] = {0}; + std::string name; while (!m_ifs.eof()) { get_line(); - int n; - if (sscanf(m_str, "%d", &n) != 1) { + const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + if (n == 0) { + // next item found + ResolveColorIndex(); + OnReadInsert(c, s, name, rot * M_PI/180); + return true; + } + else if (isStringToErrorValue(n)) { this->ReportError_readInteger("DXF::ReadInsert()"); return false; } - std::istringstream ss; - ss.imbue(std::locale::classic()); + + get_line(); switch (n){ - case 0: - // next item found - ResolveColorIndex(); - OnReadInsert(c, s, name, rot * M_PI/180); - return(true); 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; - } + // 3d coords + HandleCoordCode(n, &c); break; case 41: // scale x - get_line(); - ss.str(m_str); - ss >> s[0]; - if (ss.fail()) { - return false; - } + s.x = stringToDouble(m_str); break; case 42: // scale y - get_line(); - ss.str(m_str); - ss >> s[1]; - if (ss.fail()) { - return false; - } + s.y = stringToDouble(m_str); break; case 43: // scale z - get_line(); - ss.str(m_str); - ss >> s[2]; - if (ss.fail()) { - return false; - } + s.z = stringToDouble(m_str); break; case 50: // rotation - get_line(); - ss.str(m_str); - ss >> rot; - if (ss.fail()) { - return false; - } + rot = stringToDouble(m_str); break; case 2: // block name - get_line(); - strcpy(name, m_str); + name = m_str; break; case 100: case 39: @@ -3281,138 +2869,60 @@ bool CDxfRead::ReadInsert() case 220: case 230: // skip the next line - get_line(); break; default: - get_line(); HandleCommonGroupCode(n); break; } } + return false; } - bool CDxfRead::ReadDimension() { - double s[3] = {0,0,0}; // startpoint - double e[3] = {0,0,0}; // endpoint - double p[3] = {0,0,0}; // dimpoint + DxfCoords s = {}; // startpoint + DxfCoords e = {}; // endpoint + DxfCoords p = {}; // dimpoint double rot = -1.0; // rotation while (!m_ifs.eof()) { get_line(); - int n; - if (sscanf(m_str, "%d", &n) != 1) { + const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + if (n == 0) { + // next item found + ResolveColorIndex(); + OnReadDimension(s, e, p, rot * M_PI/180); + return true; + } + else if (isStringToErrorValue(n)) { this->ReportError_readInteger("DXF::ReadDimension()"); return false; } - std::istringstream ss; - ss.imbue(std::locale::classic()); + + get_line(); switch (n){ - case 0: - // next item found - ResolveColorIndex(); - OnReadDimension(s, e, p, rot * M_PI/180); - return(true); 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; - } + // start coords + HandleCoordCode<13, 23, 33>(n, &s); 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; - } + // end coords + HandleCoordCode<14, 24, 34>(n, &e); 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; - } + // dimline coords + HandleCoordCode<10, 20, 30>(n, &p); break; case 50: // rotation - get_line(); - ss.str(m_str); - ss >> rot; - if (ss.fail()) { - return false; - } + rot = stringToDouble(m_str); break; case 100: case 39: @@ -3420,14 +2930,13 @@ bool CDxfRead::ReadDimension() case 220: case 230: // skip the next line - get_line(); break; default: - get_line(); HandleCommonGroupCode(n); break; } } + return false; } @@ -3436,95 +2945,75 @@ bool CDxfRead::ReadBlockInfo() { while (!m_ifs.eof()) { get_line(); - int n; - if (sscanf(m_str, "%d", &n) != 1) { + const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + if (isStringToErrorValue(n)) { this->ReportError_readInteger("DXF::ReadBlockInfo()"); return false; } - std::istringstream ss; - ss.imbue(std::locale::classic()); + + get_line(); switch (n){ case 2: // block name - get_line(); - safe_strcpy(m_block_name, m_str); + m_block_name = m_str; return true; case 3: // block name too??? - get_line(); - safe_strcpy(m_block_name, m_str); + 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') { - safe_strcpy(m_str, m_unused_line); - memset(m_unused_line, '\0', sizeof(m_unused_line)); + if (!m_unused_line.empty()) { + m_str = m_unused_line; + m_unused_line.clear(); 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 < len; i++) { - if (non_white_found || (m_str[i] != ' ' && m_str[i] != '\t')) { - if (m_str[i] != '\r') { - str[j] = m_str[i]; - j++; - } - non_white_found = true; - } - } - str[j] = 0; - safe_strcpy(m_str, str); + std::getline(m_ifs, m_str); + m_gcount = m_str.size(); ++m_line_nb; -} -void dxf_strncpy(char* dst, const char* src, size_t size) -{ - size_t ret = strlen(src); + // Erase leading whitespace characters + auto itNonSpace = m_str.begin(); + while (itNonSpace != m_str.end()) { + if (!std::isspace(*itNonSpace)) + break; - if (size) { - size_t len = (ret >= size) ? size - 1 : ret; - memcpy(dst, src, len); - dst[len] = '\0'; + ++itNonSpace; } + + m_str.erase(m_str.begin(), itNonSpace); } -void CDxfRead::put_line(const char *value) +void CDxfRead::put_line(const std::string& value) { - dxf_strncpy( m_unused_line, value, sizeof(m_unused_line) ); + m_unused_line = value; } - bool CDxfRead::ReadUnits() { get_line(); // Skip to next line. get_line(); // Skip to next line. - int n = 0; - if (sscanf(m_str, "%d", &n) == 1) { - m_eUnits = eDxfUnits_t( n ); - return(true); - } // End if - then + const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + if (!isStringToErrorValue(n)) { + m_eUnits = static_cast(n); + return true; + } else { this->ReportError_readInteger("DXF::ReadUnits()"); - return(false); + return false; } } - bool CDxfRead::ReadLayer() { std::string layername; @@ -3532,37 +3021,30 @@ bool CDxfRead::ReadLayer() while (!m_ifs.eof()) { get_line(); - int n; - - if (sscanf(m_str, "%d", &n) != 1) { - this->ReportError_readInteger("DXF::ReadLayer()"); - return false; - } - - std::istringstream ss; - ss.imbue(std::locale::classic()); - switch (n) { - case 0: // next item found, so finish with line + const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + if (n == 0) { if (layername.empty()) { this->ReportError_readInteger("DXF::ReadLayer() - no layer name"); return false; } + m_layer_ColorIndex_map[layername] = colorIndex; return true; + } + else if (isStringToErrorValue(n)) { + this->ReportError_readInteger("DXF::ReadLayer()"); + return false; + } + get_line(); + switch (n) { case 2: // Layer name follows - get_line(); layername = m_str; break; - case 62: // layer color ; if negative, layer is off - get_line(); - if (sscanf(m_str, "%d", &colorIndex) != 1) { - return false; - } + colorIndex = stringToInt(m_str); break; - case 6: // linetype name case 70: // layer flags case 100: @@ -3570,11 +3052,9 @@ bool CDxfRead::ReadLayer() case 370: case 390: // skip the next line - get_line(); break; default: // skip the next line - get_line(); break; } } @@ -3584,17 +3064,18 @@ bool CDxfRead::ReadLayer() bool CDxfRead::ReadVersion() { static const std::vector VersionNames = { - // This table is indexed by eDXFVersion_t - (ROlder+1) - "AC1006", - "AC1009", - "AC1012", - "AC1014", - "AC1015", - "AC1018", - "AC1021", - "AC1024", - "AC1027", - "AC1032"}; + // This table is indexed by eDXFVersion_t - (ROlder+1) + "AC1006", + "AC1009", + "AC1012", + "AC1014", + "AC1015", + "AC1018", + "AC1021", + "AC1024", + "AC1027", + "AC1032" + }; assert(VersionNames.size() == RNewer - ROlder - 1); get_line(); @@ -3662,72 +3143,72 @@ void CDxfRead::HandleCommonGroupCode(int n) } } -void CDxfRead::DoRead(const bool ignore_errors /* = false */ ) +void CDxfRead::DoRead(bool ignore_errors) { m_ignore_errors = ignore_errors; + m_gcount = 0; if (m_fail) { return; } get_line(); + ScopedCLocale _(LC_NUMERIC); while (!m_ifs.eof()) { m_ColorIndex = ColorBylayer; // Default - if (!strcmp(m_str, "$INSUNITS" )) { + if (m_str == "$INSUNITS") { if (!ReadUnits()) { return; } continue; } // End if - then - if (!strcmp(m_str, "$MEASUREMENT" )) { + if (m_str == "$MEASUREMENT") { get_line(); get_line(); - int n = 1; - if (sscanf(m_str, "%d", &n) == 1) { - if (n == 0) { - m_measurement_inch = true; - } - } + const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + if (n == 0) + m_measurement_inch = true; + continue; } // End if - then - if (!strcmp(m_str, "$ACADVER")) { + if (m_str == "$ACADVER") { if (!ReadVersion()) { return; } continue; } // End if - then - if (!strcmp(m_str, "$DWGCODEPAGE")) { + if (m_str == "$DWGCODEPAGE") { if (!ReadDWGCodePage()) { return; } continue; } // End if - then - if (!strcmp(m_str, "0")) { + if (m_str == "0") { get_line(); - if (!strcmp(m_str, "0")) + if (m_str == "0") get_line(); // Skip again - if (!strcmp( m_str, "SECTION" )) { - safe_strcpy(m_section_name, ""); + if (m_str == "SECTION") { + m_section_name.clear(); get_line(); get_line(); - if (strcmp( m_str, "ENTITIES" )) { - safe_strcpy(m_section_name, m_str); + if (m_str != "ENTITIES") { + m_section_name = m_str; } - safe_strcpy(m_block_name, ""); + m_block_name.clear(); } // End if - then - else if (!strcmp( m_str, "TABLE" )) { + else if (m_str == "TABLE") { get_line(); get_line(); } - else if (!strcmp( m_str, "LAYER" )) { + else if (m_str == "LAYER" ) { //get_line(); //get_line(); if (!ReadLayer()) { @@ -3737,40 +3218,40 @@ void CDxfRead::DoRead(const bool ignore_errors /* = false */ ) continue; } - else if (!strcmp( m_str, "BLOCK" )) { + else if (m_str == "BLOCK" ) { if (!ReadBlockInfo()) { - this->ReportError("DXF::DoRead() - Failed to read block info"); + this->ReportError("DXF::DoRead()f - Failed to read block info"); return; } continue; } // End if - then - else if (!strcmp( m_str, "ENDSEC" )) { - safe_strcpy(m_section_name, ""); - safe_strcpy(m_block_name, ""); + else if (m_str == "ENDSEC" ) { + m_section_name.clear(); + m_block_name.clear(); } // End if - then - else if (!strcmp(m_str, "LINE")) { + else if (m_str == "LINE") { if (!ReadLine()) { this->ReportError("DXF::DoRead() - Failed to read line"); return; } continue; } - else if (!strcmp(m_str, "ARC")) { + else if (m_str == "ARC") { if (!ReadArc()) { this->ReportError("DXF::DoRead() - Failed to read arc"); return; } continue; } - else if (!strcmp(m_str, "CIRCLE")) { + else if (m_str == "CIRCLE") { if (!ReadCircle()) { this->ReportError("DXF::DoRead() - Failed to read circle"); return; } continue; } - else if (!strcmp(m_str, "MTEXT") || !strcmp(m_str, "TEXT")) { + else if (m_str == "MTEXT" || m_str == "TEXT") { try { ReadText(); } catch (const std::runtime_error& err) { @@ -3779,49 +3260,49 @@ void CDxfRead::DoRead(const bool ignore_errors /* = false */ ) } continue; } - else if (!strcmp(m_str, "ELLIPSE")) { + else if (m_str == "ELLIPSE") { if (!ReadEllipse()) { this->ReportError("DXF::DoRead() - Failed to read ellipse"); return; } continue; } - else if (!strcmp(m_str, "SPLINE")) { + else if (m_str == "SPLINE") { if (!ReadSpline()) { this->ReportError("DXF::DoRead() - Failed to read spline"); return; } continue; } - else if (!strcmp(m_str, "LWPOLYLINE")) { + else if (m_str == "LWPOLYLINE") { if (!ReadLwPolyLine()) { this->ReportError("DXF::DoRead() - Failed to read LW Polyline"); return; } continue; } - else if (!strcmp(m_str, "POLYLINE")) { + else if (m_str == "POLYLINE") { if (!ReadPolyLine()) { this->ReportError("DXF::DoRead() - Failed to read Polyline"); return; } continue; } - else if (!strcmp(m_str, "POINT")) { + else if (m_str == "POINT") { if (!ReadPoint()) { this->ReportError("DXF::DoRead() - Failed to read Point"); return; } continue; } - else if (!strcmp(m_str, "INSERT")) { + else if (m_str == "INSERT") { if (!ReadInsert()) { this->ReportError("DXF::DoRead() - Failed to read Insert"); return; } continue; } - else if (!strcmp(m_str, "DIMENSION")) { + else if (m_str == "DIMENSION") { if (!ReadDimension()) { this->ReportError("DXF::DoRead() - Failed to read Dimension"); return; @@ -3832,17 +3313,15 @@ void CDxfRead::DoRead(const bool ignore_errors /* = false */ ) get_line(); } + AddGraphics(); } void CDxfRead::ResolveColorIndex() { - if (m_ColorIndex == ColorBylayer) // if color = layer color, replace by color from layer - { m_ColorIndex = m_layer_ColorIndex_map[m_layer_name]; - } } void CDxfRead::ReportError_readInteger(const char* context) @@ -3861,19 +3340,21 @@ void CDxfRead::ReportError_readInteger(const char* context) std::streamsize CDxfRead::gcount() const { - return m_ifs.gcount(); + // std::getline() doesn't affect std::istream::gcount + //return m_ifs.gcount(); + return m_gcount; } std::string CDxfRead::LayerName() const { std::string result; - if (strlen(m_section_name) > 0) { + if (!m_section_name.empty()) { result.append(m_section_name); result.append(" "); } - if (strlen(m_block_name) > 0) { + if (!m_block_name.empty()) { result.append(m_block_name); result.append(" "); } @@ -3882,5 +3363,5 @@ std::string CDxfRead::LayerName() const result.append(m_layer_name); } - return(result); + return result; } diff --git a/src/io_dxf/dxf.h b/src/io_dxf/dxf.h index 9dbbc44e..7361672e 100644 --- a/src/io_dxf/dxf.h +++ b/src/io_dxf/dxf.h @@ -56,8 +56,20 @@ enum class AttachmentPoint { BottomLeft, BottomCenter, BottomRight }; +struct DxfCoords { + double x; + double y; + double z; +}; + +struct DxfScale { + double x; + double y; + double z; +}; + struct DxfText { - double point[3] = {}; + DxfCoords point = {}; double height = 0.03082; std::string str; double rotation = 0.; // radians @@ -79,7 +91,7 @@ struct DxfVertex { }; using Flags = unsigned; - double point[3] = {}; + DxfCoords point = {}; Bulge bulge = Bulge::StraightSegment; Flags flags = Flag::None; }; @@ -121,7 +133,7 @@ struct DxfPolyline { //spline data for reading struct SplineData { - double norm[3]; + DxfCoords norm; int degree; int knots; int control_points; @@ -370,6 +382,27 @@ class CDxfWrite void makeBlockSectionHead(); }; +namespace DxfPrivate { + +enum class StringToErrorMode { Throw = 0x1, ReturnErrorValue = 0x2 }; + +double stringToDouble( + const std::string& line, + StringToErrorMode errorMode = StringToErrorMode::Throw +); + +int stringToInt( + const std::string& line, + StringToErrorMode errorMode = StringToErrorMode::Throw +); + +unsigned stringToUnsigned( + const std::string& line, + StringToErrorMode errorMode = StringToErrorMode::Throw +); + +} // namespace DxfPrivate + // derive a class from this and implement it's virtual functions class CDxfRead { @@ -377,20 +410,21 @@ class CDxfRead std::ifstream m_ifs; bool m_fail; - char m_str[1024]; - char m_unused_line[1024]; + std::string m_str; + std::string m_unused_line; eDxfUnits_t m_eUnits; bool m_measurement_inch; std::string m_layer_name; - char m_section_name[1024]; - char m_block_name[1024]; + std::string m_section_name; + std::string m_block_name; bool m_ignore_errors; + std::streamsize m_gcount = 0; int m_line_nb = 0; - std::map - m_layer_ColorIndex_map; // Mapping from layer name -> layer color index + // Mapping from layer name -> layer color index + std::map m_layer_ColorIndex_map; const ColorIndex_t ColorBylayer = 256; bool ReadUnits(); @@ -406,18 +440,22 @@ class CDxfRead bool ReadPolyLine(); bool ReadVertex(DxfVertex* vertex); - 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); + void OnReadArc( + double start_angle, + double end_angle, + double radius, + const DxfCoords& c, + double z_extrusion_dir, + bool hidden + ); + void OnReadCircle(const DxfCoords& c, double radius, bool hidden); + void OnReadEllipse( + const DxfCoords& c, + const DxfCoords& m, + double ratio, + double start_angle, + double end_angle + ); bool ReadInsert(); bool ReadDimension(); bool ReadBlockInfo(); @@ -425,9 +463,25 @@ class CDxfRead bool ReadDWGCodePage(); bool ResolveEncoding(); + template + void HandleCoordCode(int n, DxfCoords* coords) + { + switch (n) { + case XCode: + coords->x = mm(DxfPrivate::stringToDouble(m_str)); + break; + case YCode: + coords->y = mm(DxfPrivate::stringToDouble(m_str)); + break; + case ZCode: + coords->z = mm(DxfPrivate::stringToDouble(m_str)); + break; + } + } + void HandleCommonGroupCode(int n); - void put_line(const char *value); + void put_line(const std::string& value); void ResolveColorIndex(); void ReportError_readInteger(const char* context); @@ -450,58 +504,54 @@ class CDxfRead CDxfRead(const char* filepath); // this opens the file virtual ~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 + bool IgnoreErrors() const { return m_ignore_errors; } + bool Failed() const { return m_fail; } - double mm( double value ) const; + double mm(double value) const; - bool IgnoreErrors() const - { - return(m_ignore_errors); - } + void DoRead(bool ignore_errors = false); // this reads the file and calls the following functions + + virtual void OnReadLine(const DxfCoords& s, const DxfCoords& e, bool hidden) = 0; + + virtual void OnReadPolyline(const DxfPolyline&) = 0; + + virtual void OnReadPoint(const DxfCoords& s) = 0; + + virtual void OnReadText(const DxfText&) = 0; + + virtual void OnReadArc( + const DxfCoords& s, const DxfCoords& e, const DxfCoords& c, bool dir, bool hidden + ) = 0; + + virtual void OnReadCircle(const DxfCoords& s, const DxfCoords& c, bool dir, bool hidden) = 0; + + virtual void OnReadEllipse( + const DxfCoords& c, + double major_radius, + double minor_radius, + double rotation, + double start_angle, + double end_angle, + bool dir + ) = 0; + + virtual void OnReadSpline(struct SplineData& sd) = 0; + + virtual void OnReadInsert( + const DxfCoords& point, + const DxfScale& scale, + const std::string& name, + double rotation + ) = 0; + + virtual void OnReadDimension( + const DxfCoords& s, + const DxfCoords& e, + const DxfCoords& point, + double rotation + ) = 0; - virtual void OnReadLine(const double* /*s*/, const double* /*e*/, bool /*hidden*/) - {} - - virtual void OnReadPolyline(const DxfPolyline&) {} - - virtual void OnReadPoint(const double* /*s*/) - {} - virtual void OnReadText(const DxfText&) {} - 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 - {} + virtual void AddGraphics() const = 0; std::string LayerName() const; }; diff --git a/src/io_dxf/io_dxf.cpp b/src/io_dxf/io_dxf.cpp index 5eb0ad5d..23741eb2 100644 --- a/src/io_dxf/io_dxf.cpp +++ b/src/io_dxf/io_dxf.cpp @@ -11,6 +11,7 @@ #include "../base/document.h" #include "../base/filepath.h" #include "../base/math_utils.h" +#include "../base/mesh_utils.h" #include "../base/messenger.h" #include "../base/property_builtins.h" #include "../base/property_enumeration.h" @@ -27,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +46,8 @@ #include #include +#include + namespace Mayo { namespace IO { @@ -94,23 +98,24 @@ class DxfReader::Internal : public CDxfRead { const auto& layers() const { return m_layers; } // CDxfRead's virtual functions - void OnReadLine(const double* s, const double* e, bool hidden) override; + void OnReadLine(const DxfCoords& s, const DxfCoords& e, bool hidden) override; void OnReadPolyline(const DxfPolyline& polyline) override; - void OnReadPoint(const double* s) override; + void OnReadPoint(const DxfCoords& s) override; void OnReadText(const DxfText& text) 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, double major_radius, double minor_radius, double rotation, double start_angle, double end_angle, bool dir) override; + void OnReadArc(const DxfCoords& s, const DxfCoords& e, const DxfCoords& c, bool dir, bool hidden) override; + void OnReadCircle(const DxfCoords& s, const DxfCoords& c, bool dir, bool hidden) override; + void OnReadEllipse(const DxfCoords& c, 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 double* point, const double* scale, const char* name, double rotation) override; - void OnReadDimension(const double* s, const double* e, const double* point, double rotation) override; + void OnReadInsert(const DxfCoords& point, const DxfScale& scale, const std::string& name, double rotation) override; + void OnReadDimension(const DxfCoords& s, const DxfCoords& e, const DxfCoords& point, double rotation) override; void ReportError(const std::string& msg) override; + void AddGraphics() const override; static Handle_Geom_BSplineCurve createSplineFromPolesAndKnots(struct SplineData& sd); static Handle_Geom_BSplineCurve createInterpolationSpline(struct SplineData& sd); - gp_Pnt toPnt(const double* coords) const; + gp_Pnt toPnt(const DxfCoords& coords) const; void addShape(const TopoDS_Shape& shape); }; @@ -378,7 +383,7 @@ DxfReader::Internal::Internal(const FilePath& filepath, TaskProgress* progress) m_fileSize = filepathFileSize(filepath); } -void DxfReader::Internal::OnReadLine(const double* s, const double* e, bool /*hidden*/) +void DxfReader::Internal::OnReadLine(const DxfCoords& s, const DxfCoords& e, bool /*hidden*/) { const gp_Pnt p0 = this->toPnt(s); const gp_Pnt p1 = this->toPnt(e); @@ -392,17 +397,16 @@ void DxfReader::Internal::OnReadLine(const double* s, const double* e, bool /*hi void DxfReader::Internal::OnReadPolyline(const DxfPolyline& polyline) { const auto& vertices = polyline.vertices; - Handle(Poly_Polygon3D) polygon = new Poly_Polygon3D( - CppUtils::safeStaticCast(vertices.size()), - false/*!hasParams*/ - ); + const int nodeCount = CppUtils::safeStaticCast(vertices.size()); + MeshUtils::Polygon3dBuilder polygonBuilder(nodeCount); for (unsigned i = 0; i < vertices.size(); ++i) - polygon->ChangeNodes().ChangeValue(i + 1) = this->toPnt(vertices.at(i).point); + polygonBuilder.setNode(i + 1, this->toPnt(vertices.at(i).point)); - this->addShape(BRepUtils::makeEdge(polygon)); + polygonBuilder.finalize(); + this->addShape(BRepUtils::makeEdge(polygonBuilder.get())); } -void DxfReader::Internal::OnReadPoint(const double* s) +void DxfReader::Internal::OnReadPoint(const DxfCoords& s) { const TopoDS_Vertex vertex = BRepBuilderAPI_MakeVertex(this->toPnt(s)); this->addShape(vertex); @@ -451,7 +455,7 @@ void DxfReader::Internal::OnReadText(const DxfText& text) } // Excerpted from FreeCad/src/Mod/Import/App/ImpExpDxf -void DxfReader::Internal::OnReadArc(const double* s, const double* e, const double* c, bool dir, bool /*hidden*/) +void DxfReader::Internal::OnReadArc(const DxfCoords& s, const DxfCoords& e, const DxfCoords& c, bool dir, bool /*hidden*/) { const gp_Pnt p0 = this->toPnt(s); const gp_Pnt p1 = this->toPnt(e); @@ -468,7 +472,7 @@ void DxfReader::Internal::OnReadArc(const double* s, const double* e, const doub } // Excerpted from FreeCad/src/Mod/Import/App/ImpExpDxf -void DxfReader::Internal::OnReadCircle(const double* s, const double* c, bool dir, bool /*hidden*/) +void DxfReader::Internal::OnReadCircle(const DxfCoords& s, const DxfCoords& c, bool dir, bool /*hidden*/) { const gp_Pnt p0 = this->toPnt(s); const gp_Dir up = dir ? gp::DZ() : -gp::DZ(); @@ -485,7 +489,7 @@ void DxfReader::Internal::OnReadCircle(const double* s, const double* c, bool di // Excerpted from FreeCad/src/Mod/Import/App/ImpExpDxf void DxfReader::Internal::OnReadEllipse( - const double* c, + const DxfCoords& c, double major_radius, double minor_radius, double rotation, double /*start_angle*/, double /*end_angle*/, @@ -534,15 +538,16 @@ void DxfReader::Internal::OnReadSpline(SplineData& sd) } // Excerpted from FreeCad/src/Mod/Import/App/ImpExpDxf -void DxfReader::Internal::OnReadInsert(const double* point, const double* scale, const char* name, double rotation) +void DxfReader::Internal::OnReadInsert( + const DxfCoords& point, const DxfScale& scale, const std::string& 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; const std::string prefix = std::string("BLOCKS ") + name + " "; for (const auto& [k, vecEntity] : m_layers) { if (!startsWith(k, prefix)) continue; // Skip - TopoDS_Compound comp = BRepUtils::makeEmptyCompound(); + TopoDS_Shape comp = BRepUtils::makeEmptyCompound(); for (const DxfReader::Entity& entity : vecEntity) { if (!entity.shape.IsNull()) BRepUtils::addShape(&comp, entity.shape); @@ -551,33 +556,51 @@ void DxfReader::Internal::OnReadInsert(const double* point, const double* scale, if (comp.IsNull()) continue; // Skip - auto nonNull = [](double v) { return !MathUtils::fuzzyIsNull(v) ? v : 1.; }; - const double nscale[] = { nonNull(scale[0]), nonNull(scale[1]), nonNull(scale[2]) }; - gp_Trsf trsfScale; - trsfScale.SetValues( - nscale[0], 0, 0, 0, - 0, nscale[1], 0, 0, - 0, 0, nscale[2], 0 - ); + if (!MathUtils::fuzzyEqual(scale.x, scale.y) || !MathUtils::fuzzyEqual(scale.x, scale.y)) { + m_messenger->emitWarning( + fmt::format("OnReadInsert('{}') - non-uniform scales aren't supported({}, {}, {})", + name, scale.x, scale.y, scale.z + ) + ); + } + + auto fnNonNull = [](double v) { return !MathUtils::fuzzyIsNull(v) ? v : 1.; }; + const double avgScale = std::abs(fnNonNull((scale.x + scale.y + scale.z) / 3.)); + if (!MathUtils::fuzzyEqual(avgScale, 1.)) { + gp_Trsf trsf; + trsf.SetScaleFactor(avgScale); + BRepBuilderAPI_Transform brepTrsf(comp, trsf); + if (brepTrsf.IsDone()) { + comp = brepTrsf.Shape(); + } + else { + m_messenger->emitWarning( + fmt::format("OnReadInsert('{}') - scaling failed({}, {}, {})", name, scale.x, scale.y, scale.z) + ); + } + } + gp_Trsf trsfRotZ; - trsfRotZ.SetRotation(gp::OZ(), rotation); + if (!MathUtils::fuzzyIsNull(rotation)) + trsfRotZ.SetRotation(gp::OZ(), rotation); + gp_Trsf trsfMove; trsfMove.SetTranslation(this->toPnt(point).XYZ()); - const gp_Trsf trsf = trsfScale * trsfRotZ * trsfMove; - comp.Location(trsf); + + comp.Location(trsfRotZ * trsfMove); this->addShape(comp); } } -void DxfReader::Internal::OnReadDimension(const double* s, const double* e, const double* point, double rotation) +void DxfReader::Internal::OnReadDimension(const DxfCoords& s, const DxfCoords& e, const DxfCoords& point, double rotation) { if (m_params.importAnnotations) { // TODO std::stringstream sstr; sstr << "DxfReader::OnReadDimension() - Not yet implemented" << std::endl - << " s: " << s[0] << ", " << s[1] << ", " << s[2] << std::endl - << " e: " << e[0] << ", " << e[1] << ", " << e[2] << std::endl - << " point: " << point[0] << ", " << point[1] << ", " << point[2] << std::endl + << " s: " << s.x << ", " << s.y << ", " << s.z << std::endl + << " e: " << e.x << ", " << e.y << ", " << e.z << std::endl + << " point: " << point.x << ", " << point.y << ", " << point.z << std::endl << " rotation: " << rotation << std::endl; m_messenger->emitWarning(sstr.str()); } @@ -588,11 +611,16 @@ void DxfReader::Internal::ReportError(const std::string& msg) m_messenger->emitError(msg); } -gp_Pnt DxfReader::Internal::toPnt(const double* coords) const +void DxfReader::Internal::AddGraphics() const +{ + // Nothing +} + +gp_Pnt DxfReader::Internal::toPnt(const DxfCoords& coords) const { - double sp1(coords[0]); - double sp2(coords[1]); - double sp3(coords[2]); + double sp1(coords.x); + double sp2(coords.y); + double sp3(coords.z); if (!MathUtils::fuzzyEqual(m_params.scaling, 1.)) { sp1 = sp1 * m_params.scaling; sp2 = sp2 * m_params.scaling; From 9bf4c707beb8b2fa2400f0232473645dadf036d6 Mon Sep 17 00:00:00 2001 From: Hugues Delorme Date: Wed, 29 Nov 2023 15:53:54 +0100 Subject: [PATCH 07/10] IO_Dxf: fix handling of closed POLYLINEs in DxfReader::Internal --- src/io_dxf/io_dxf.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/io_dxf/io_dxf.cpp b/src/io_dxf/io_dxf.cpp index 23741eb2..f4b2dd0a 100644 --- a/src/io_dxf/io_dxf.cpp +++ b/src/io_dxf/io_dxf.cpp @@ -397,11 +397,15 @@ void DxfReader::Internal::OnReadLine(const DxfCoords& s, const DxfCoords& e, boo void DxfReader::Internal::OnReadPolyline(const DxfPolyline& polyline) { const auto& vertices = polyline.vertices; - const int nodeCount = CppUtils::safeStaticCast(vertices.size()); + const bool isPolylineClosed = polyline.flags & DxfPolyline::Flag::Closed; + const int nodeCount = CppUtils::safeStaticCast(vertices.size() + (isPolylineClosed ? 1 : 0)); MeshUtils::Polygon3dBuilder polygonBuilder(nodeCount); for (unsigned i = 0; i < vertices.size(); ++i) polygonBuilder.setNode(i + 1, this->toPnt(vertices.at(i).point)); + if (isPolylineClosed) + polygonBuilder.setNode(nodeCount, this->toPnt(vertices.at(0).point)); + polygonBuilder.finalize(); this->addShape(BRepUtils::makeEdge(polygonBuilder.get())); } From 472d5011e569f7d19116707edab1f2f37d2b8772 Mon Sep 17 00:00:00 2001 From: Hugues Delorme Date: Tue, 5 Dec 2023 19:07:30 +0100 Subject: [PATCH 08/10] IO_Dxf: improvements with format support * Support SOLID and STYLE * Distinct handling of MTEXT and TEXT * Rewrite CDxfRead::ReadInsert() with new Dxf_INSERT struct Relates to GitHub #241 --- src/io_dxf/dxf.cpp | 419 +++++++++++++++++++++++++++++++++--------- src/io_dxf/dxf.h | 201 +++++++++++++++++--- src/io_dxf/io_dxf.cpp | 215 +++++++++++++++++----- 3 files changed, 675 insertions(+), 160 deletions(-) diff --git a/src/io_dxf/dxf.cpp b/src/io_dxf/dxf.cpp index 6b6fcdc7..7eee415f 100644 --- a/src/io_dxf/dxf.cpp +++ b/src/io_dxf/dxf.cpp @@ -1971,6 +1971,14 @@ double CDxfRead::mm(double value) const } // End switch } // End mm() method +const Dxf_STYLE* CDxfRead::findStyle(const std::string& name) const +{ + if (name.empty()) + return nullptr; + + auto itFound = m_mapStyle.find(name); + return itFound != m_mapStyle.cend() ? &itFound->second : nullptr; +} bool CDxfRead::ReadLine() { @@ -1999,15 +2007,11 @@ bool CDxfRead::ReadLine() hidden = true; } break; - case 10: - case 20: - case 30: + case 10: case 20: case 30: // start coords HandleCoordCode(n, &s); break; - case 11: - case 21: - case 31: + case 11: case 21: case 31: // end coords HandleCoordCode<11, 21, 31>(n, &e); break; @@ -2315,9 +2319,7 @@ bool CDxfRead::ReadCircle() hidden = true; } break; - case 10: - case 20: - case 30: + case 10: case 20: case 30: // centre coords HandleCoordCode(n, &c); break; @@ -2344,12 +2346,16 @@ bool CDxfRead::ReadCircle() return false; } -void CDxfRead::ReadText() +void CDxfRead::ReadMText() { - DxfText text; + Dxf_MTEXT text; + bool withinAcadColumnInfo = false; + bool withinAcadColumns = false; + bool withinAcadDefinedHeight = false; + while (!m_ifs.eof()) { get_line(); - const int n = stringToInt(m_str); + const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); if (n == 0) { ResolveColorIndex(); // Replace \P by \n @@ -2360,25 +2366,105 @@ void CDxfRead::ReadText() } text.str = this->toUtf8(text.str); - OnReadText(text); + OnReadMText(text); return; } get_line(); + + auto fnMatchExtensionBegin = [=](std::string_view extName, bool& tag) { + if (!tag && m_str == extName) { + tag = true; + return true; + } + return false; + }; + + auto fnMatchExtensionEnd = [=](std::string_view extName, bool& tag) { + if (tag && m_str == extName) { + tag = false; + return true; + } + return false; + }; + + if (fnMatchExtensionBegin("ACAD_MTEXT_COLUMN_INFO_BEGIN", withinAcadColumnInfo)) { + text.acadHasColumnInfo = true; + continue; // Skip + } + + if (fnMatchExtensionEnd("ACAD_MTEXT_COLUMN_INFO_END", withinAcadColumnInfo)) + continue; // Skip + + if (fnMatchExtensionBegin("ACAD_MTEXT_COLUMNS_BEGIN", withinAcadColumns)) + continue; // Skip + + if (fnMatchExtensionEnd("ACAD_MTEXT_COLUMNS_END", withinAcadColumns)) + continue; // Skip + + if (fnMatchExtensionBegin("ACAD_MTEXT_DEFINED_HEIGHT_BEGIN", withinAcadDefinedHeight)) { + text.acadHasDefinedHeight = true; + continue; // Skip + } + + if (fnMatchExtensionEnd("ACAD_MTEXT_DEFINED_HEIGHT_END", withinAcadDefinedHeight)) + continue; // Skip + + if (withinAcadColumnInfo) { + // 1040/1070 extended data code was found at beginning of current iteration + const int xn = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + get_line(); // Skip 1040/1070 line + get_line(); // Get value line of extended data code + switch (xn) { + case 75: { // 1070 + const int t = stringToInt(m_str); + if (0 <= t && t <= 2) + text.acadColumnInfo_Type = static_cast(t); + } + break; + case 76: // 1070 + text.acadColumnInfo_Count = stringToInt(m_str); + break; + case 78: // 1070 + text.acadColumnInfo_FlowReversed = stringToInt(m_str) != 0; + break; + case 79: // 1070 + text.acadColumnInfo_AutoHeight = stringToInt(m_str) != 0; + break; + case 48: // 1040 + text.acadColumnInfo_Width = mm(stringToDouble(m_str)); + break; + case 49: // 1040 + text.acadColumnInfo_GutterWidth = mm(stringToDouble(m_str)); + break; + } // endswitch + + continue; // Skip + } + + if (withinAcadDefinedHeight) { + // 1040/1070 extended data code was found at beginning of current iteration + const int xn = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + get_line(); // Skip 1040/1070 line + get_line(); // Get value line of extended data code + if (xn == 46) + text.acadDefinedHeight = mm(stringToDouble(m_str)); + + continue; // Skip + } + switch (n) { - case 10: - case 20: - case 30: + case 10: case 20: case 30: // centre coords - HandleCoordCode(n, &text.point); + HandleCoordCode(n, &text.insertionPoint); break; case 40: // text height - text.height = mm(stringToDouble(m_str)) * 25.4 / 72.0; + text.height = mm(stringToDouble(m_str)); break; case 50: // text rotation - text.rotation = stringToDouble(m_str); + text.rotationAngle = stringToDouble(m_str); break; case 3: // Additional text that goes before the type 1 text @@ -2395,17 +2481,21 @@ void CDxfRead::ReadText() case 71: { // attachment point const int ap = stringToInt(m_str); - if (ap >= 1 && ap <= 9) { - text.attachPoint = static_cast(ap); - } + if (ap >= 1 && ap <= 9) + text.attachmentPoint = static_cast(ap); } break; - case 100: - case 39: - case 210: - case 220: - case 230: + case 11: case 21: case 31: + // X-axis direction vector + HandleCoordCode<11, 21, 31>(n, &text.xAxisDirectionVector); + break; + + case 210: case 220: case 230: + // extrusion direction + HandleCoordCode<210, 220, 230>(n, &text.extrusionDirection); + break; + default: HandleCommonGroupCode(n); break; @@ -2413,6 +2503,67 @@ void CDxfRead::ReadText() } } +void CDxfRead::ReadText() +{ + Dxf_TEXT text; + + while (!m_ifs.eof()) { + get_line(); + const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + if (n == 0) { + ResolveColorIndex(); + OnReadText(text); + return; + } + + get_line(); + + switch (n) { + case 10: case 20: case 30: + HandleCoordCode(n, &text.firstAlignmentPoint); + break; + case 40: + text.height = mm(stringToDouble(m_str)); + break; + case 1: + text.str = this->toUtf8(m_str); + break; + case 50: + text.rotationAngle = stringToDouble(m_str); + break; + case 41: + text.relativeXScaleFactorWidth = stringToDouble(m_str); + break; + case 51: + text.obliqueAngle = stringToDouble(m_str); + break; + case 7: + text.styleName = m_str; + break; + case 72: { + const int hjust = stringToInt(m_str); + if (hjust >= 0 && hjust <= 5) + text.horizontalJustification = static_cast(hjust); + } + break; + case 11: case 21: case 31: + HandleCoordCode<11, 21, 31>(n, &text.secondAlignmentPoint); + break; + case 210: case 220: case 230: + HandleCoordCode<210, 220, 230>(n, &text.extrusionDirection); + break; + case 73: { + const int vjust = stringToInt(m_str); + if (vjust >= 0 && vjust <= 3) + text.verticalJustification = static_cast(vjust); + } + break; + default: + HandleCommonGroupCode(n); + break; + } + } +} bool CDxfRead::ReadEllipse() { @@ -2438,15 +2589,11 @@ bool CDxfRead::ReadEllipse() get_line(); switch (n) { - case 10: - case 20: - case 30: + case 10: case 20: case 30: // centre coords HandleCoordCode(n, &c); break; - case 11: - case 21: - case 31: + case 11: case 21: case 31: // major coords HandleCoordCode<11, 21, 31>(n, &m); break; @@ -2657,7 +2804,7 @@ bool CDxfRead::ReadLwPolyLine() return false; } -bool CDxfRead::ReadVertex(DxfVertex* vertex) +bool CDxfRead::ReadVertex(Dxf_VERTEX* vertex) { bool x_found = false; bool y_found = false; @@ -2676,9 +2823,7 @@ bool CDxfRead::ReadVertex(DxfVertex* vertex) get_line(); switch (n){ - case 10: - case 20: - case 30: + case 10: case 20: case 30: // coords x_found = x_found || n == 10; y_found = y_found || n == 20; @@ -2688,9 +2833,9 @@ bool CDxfRead::ReadVertex(DxfVertex* vertex) // bulge const int bulge = stringToInt(m_str); if (bulge == 0) - vertex->bulge = DxfVertex::Bulge::StraightSegment; + vertex->bulge = Dxf_VERTEX::Bulge::StraightSegment; else - vertex->bulge = DxfVertex::Bulge::SemiCircle; + vertex->bulge = Dxf_VERTEX::Bulge::SemiCircle; } break; case 70: @@ -2706,10 +2851,56 @@ bool CDxfRead::ReadVertex(DxfVertex* vertex) return false; } +bool CDxfRead::ReadSolid() +{ + Dxf_SOLID solid; + + while (!m_ifs.eof()) { + get_line(); + const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + if (n == 0) { + ResolveColorIndex(); + OnReadSolid(solid); + return true; + } + else if (isStringToErrorValue(n)) { + this->ReportError_readInteger("DXF::ReadSolid()"); + return false; + } + + get_line(); + switch (n) { + case 10: case 20: case 30: + HandleCoordCode<10, 20, 30>(n, &solid.corner1); + break; + case 11: case 21: case 31: + HandleCoordCode<11, 21, 31>(n, &solid.corner2); + break; + case 12: case 22: case 32: + HandleCoordCode<12, 22, 32>(n, &solid.corner3); + break; + case 13: case 23: case 33: + HandleCoordCode<13, 23, 33>(n, &solid.corner4); + solid.hasCorner4 = true; + break; + case 39: + solid.thickness = stringToDouble(m_str); + break; + case 210: case 220: case 230: + HandleCoordCode<210, 220, 230>(n, &solid.extrusionDirection); + break; + default: + HandleCommonGroupCode(n); + break; + } + } + + return false; +} bool CDxfRead::ReadPolyLine() { - DxfPolyline polyline; + Dxf_POLYLINE polyline; while (!m_ifs.eof()) { get_line(); const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); @@ -2724,7 +2915,7 @@ bool CDxfRead::ReadPolyLine() // next item found ResolveColorIndex(); if (m_str == "VERTEX") { - DxfVertex vertex; + Dxf_VERTEX vertex; if (ReadVertex(&vertex)) polyline.vertices.push_back(std::move(vertex)); } @@ -2816,10 +3007,7 @@ void CDxfRead::OnReadEllipse(const DxfCoords& c, bool CDxfRead::ReadInsert() { - DxfCoords c = {}; // coordinate - DxfScale s = {1., 1., 1.}; // scale - double rot = 0.0; // rotation - std::string name; + Dxf_INSERT insert; while (!m_ifs.eof()) { get_line(); @@ -2827,7 +3015,7 @@ bool CDxfRead::ReadInsert() if (n == 0) { // next item found ResolveColorIndex(); - OnReadInsert(c, s, name, rot * M_PI/180); + OnReadInsert(insert); return true; } else if (isStringToErrorValue(n)) { @@ -2837,38 +3025,38 @@ bool CDxfRead::ReadInsert() get_line(); switch (n){ - case 10: - case 20: - case 30: - // 3d coords - HandleCoordCode(n, &c); + case 2: + insert.blockName = m_str; + break; + case 10: case 20: case 30: + HandleCoordCode(n, &insert.insertPoint); break; case 41: - // scale x - s.x = stringToDouble(m_str); + insert.scaleFactor.x = stringToDouble(m_str); break; case 42: - // scale y - s.y = stringToDouble(m_str); + insert.scaleFactor.y = stringToDouble(m_str); break; case 43: - // scale z - s.z = stringToDouble(m_str); + insert.scaleFactor.z = stringToDouble(m_str); break; case 50: - // rotation - rot = stringToDouble(m_str); + insert.rotationAngle = stringToDouble(m_str); break; - case 2: - // block name - name = m_str; + case 70: + insert.columnCount = stringToInt(m_str); break; - case 100: - case 39: - case 210: - case 220: - case 230: - // skip the next line + case 71: + insert.rowCount = stringToInt(m_str); + break; + case 44: + insert.columnSpacing = mm(stringToDouble(m_str)); + break; + case 45: + insert.rowSpacing = mm(stringToDouble(m_str)); + break; + case 210: case 220: case 230: + HandleCoordCode<210, 220, 230>(n, &insert.extrusionDirection); break; default: HandleCommonGroupCode(n); @@ -2902,21 +3090,15 @@ bool CDxfRead::ReadDimension() get_line(); switch (n){ - case 13: - case 23: - case 33: + case 13: case 23: case 33: // start coords HandleCoordCode<13, 23, 33>(n, &s); break; - case 14: - case 24: - case 34: + case 14: case 24: case 34: // end coords HandleCoordCode<14, 24, 34>(n, &e); break; - case 10: - case 20: - case 30: + case 10: case 20: case 30: // dimline coords HandleCoordCode<10, 20, 30>(n, &p); break; @@ -3058,6 +3240,56 @@ bool CDxfRead::ReadLayer() break; } } + + return false; +} + +bool CDxfRead::ReadStyle() +{ + Dxf_STYLE style; + + while (!m_ifs.eof()) { + get_line(); + const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + if (n == 0) { + if (style.name.empty()) { + this->ReportError_readInteger("DXF::ReadStyle() - no style name"); + return false; + } + + m_mapStyle.insert({ style.name, style }); + return true; + } + else if (isStringToErrorValue(n)) { + this->ReportError_readInteger("DXF::ReadStyle()"); + return false; + } + + get_line(); + switch (n) { + case 2: + style.name = m_str; + break; + case 40: + style.fixedTextHeight = mm(stringToDouble(m_str)); + break; + case 41: + style.widthFactor = stringToDouble(m_str); + break; + case 50: + style.obliqueAngle = stringToDouble(m_str); + break; + case 3: + style.primaryFontFileName = m_str; + break; + case 4: + style.bigFontFileName = m_str; + break; + default: + break; // skip the next line + } + } + return false; } @@ -3080,9 +3312,9 @@ bool CDxfRead::ReadVersion() assert(VersionNames.size() == RNewer - ROlder - 1); get_line(); get_line(); - std::vector::const_iterator first = VersionNames.cbegin(); - std::vector::const_iterator last = VersionNames.cend(); - std::vector::const_iterator found = std::lower_bound(first, last, m_str); + auto first = VersionNames.cbegin(); + auto last = VersionNames.cend(); + auto found = std::lower_bound(first, last, m_str); if (found == last) { m_version = RNewer; } @@ -3209,8 +3441,6 @@ void CDxfRead::DoRead(bool ignore_errors) } else if (m_str == "LAYER" ) { - //get_line(); - //get_line(); if (!ReadLayer()) { this->ReportError("DXF::DoRead() - Failed to read layer"); //return; Some objects or tables can have "LAYER" as name... @@ -3218,6 +3448,11 @@ void CDxfRead::DoRead(bool ignore_errors) continue; } + else if (m_str == "STYLE" ) { + ReadStyle(); + continue; + } + else if (m_str == "BLOCK" ) { if (!ReadBlockInfo()) { this->ReportError("DXF::DoRead()f - Failed to read block info"); @@ -3251,11 +3486,20 @@ void CDxfRead::DoRead(bool ignore_errors) } continue; } - else if (m_str == "MTEXT" || m_str == "TEXT") { + else if (m_str == "MTEXT") { + try { + ReadMText(); + } catch (const std::runtime_error& err) { + this->ReportError("DXF::DoRead() - Failed to read MTEXT\nError: " + std::string(err.what())); + return; + } + continue; + } + else if (m_str == "TEXT") { try { ReadText(); } catch (const std::runtime_error& err) { - this->ReportError("DXF::DoRead() - Failed to read text\nError: " + std::string(err.what())); + this->ReportError("DXF::DoRead() - Failed to read TEXT\nError: " + std::string(err.what())); return; } continue; @@ -3309,6 +3553,13 @@ void CDxfRead::DoRead(bool ignore_errors) } continue; } + else if (m_str == "SOLID") { + if (!ReadSolid()) { + this->ReportError("DXF::DoRead() - Failed to read Solid"); + return; + } + continue; + } } get_line(); diff --git a/src/io_dxf/dxf.h b/src/io_dxf/dxf.h index 7361672e..1ab93d81 100644 --- a/src/io_dxf/dxf.h +++ b/src/io_dxf/dxf.h @@ -15,10 +15,11 @@ #include #include #include -#include +#include #include #include #include +#include #include #include "freecad.h" @@ -50,12 +51,6 @@ typedef enum eParsecs } eDxfUnits_t; -enum class AttachmentPoint { - TopLeft = 1, TopCenter, TopRight, - MiddleLeft, MiddleCenter, MiddleRight, - BottomLeft, BottomCenter, BottomRight -}; - struct DxfCoords { double x; double y; @@ -68,15 +63,127 @@ struct DxfScale { double z; }; -struct DxfText { - DxfCoords point = {}; - double height = 0.03082; +struct Dxf_STYLE { + // Code: 2 + std::string name; + // Code: 40 + double fixedTextHeight = 0; + // Code: 41 + double widthFactor = 1.; + // Code: 50 + // AutoCad documentation doesn't specify units, but "Group Codes in Numerical Order" section + // states that codes 50-58 are in degrees + double obliqueAngle = 0.; + // Code: 3 + std::string primaryFontFileName; + // Code: 4 + std::string bigFontFileName; + + // TODO Code 70(standard flag values) + // TODO Code 71(text generation flags) + // TODO Code 42(last height used) +}; + +struct Dxf_TEXT { + // Code: 39 + double thickness = 0.; + // Code: 10, 20, 30 + DxfCoords firstAlignmentPoint = {}; + // Code: 40 + double height = 0.; + // Code: 1 std::string str; - double rotation = 0.; // radians - AttachmentPoint attachPoint = AttachmentPoint::TopLeft; + // Code: 50 + // AutoCad documentation doesn't specify units, but "Group Codes in Numerical Order" section + // states that codes 50-58 are in degrees + double rotationAngle = 0.; + // Code: 41 + // "This value is also adjusted when fit-type text is used" + double relativeXScaleFactorWidth = 1.; + // Code: 51 + // AutoCad documentation doesn't specify units, but "Group Codes in Numerical Order" section + // states that codes 50-58 are in degrees + double obliqueAngle = 0.; + // Code: 7 + std::string styleName; + + // TODO Code 71(text generation flags) + + enum class HorizontalJustification { + Left = 0, Center = 1, Right = 2, Aligned = 3, Middle = 4, Fit = 5 + }; + // Code: 72 + HorizontalJustification horizontalJustification = HorizontalJustification::Left; + // Code: 11, 21, 31 + DxfCoords secondAlignmentPoint = {}; + // Code: 210, 220, 230 + DxfCoords extrusionDirection = {0., 0., 1.}; + + enum class VerticalJustification { + Baseline = 0, Bottom = 1, Middle = 2, Top = 3 + }; + // Code: 73 + VerticalJustification verticalJustification = VerticalJustification::Baseline; }; -struct DxfVertex { +struct Dxf_MTEXT { + enum class AttachmentPoint { + TopLeft = 1, TopCenter, TopRight, + MiddleLeft, MiddleCenter, MiddleRight, + BottomLeft, BottomCenter, BottomRight + }; + + // Code: 10, 20, 30 + DxfCoords insertionPoint = {}; + // Code: 40 + double height = 0.; + // Code: 41 + double referenceRectangleWidth = 0; + // Code 71 + AttachmentPoint attachmentPoint = AttachmentPoint::TopLeft; + + // TODO Code 72(drawing direction) + + // Code: 1, 3 + std::string str; + + // TODO Code 7(text sytle name) + + // Code: 210, 220, 230 + DxfCoords extrusionDirection = {0., 0., 1.}; + + // Code: 11, 21, 31 + DxfCoords xAxisDirectionVector; // WCS + + // NOTE AutoCad documentation states that codes 42, 43 are "read-only, ignored if supplied" + + double rotationAngle = 0.; // radians(AutoCad documentation) + + // TODO Code 73(line spacing style) + // TODO Code 44(line spacing factor) + // TODO Code 90(background fill setting) + // TODO Code 420-429(background color, if RGB) + // TODO Code 430-439(background color, if name) + // TODO Code 45(fill box scale) + // TODO Code 63(background fill color) + // TODO Code 441(transparency of background fill color) + // TODO Codes for columns: 75, 76, 78, 79, 48, 49, 50 + + enum class ColumnType { None = 0, Static, Dynamic }; + bool acadHasColumnInfo = false; + ColumnType acadColumnInfo_Type = ColumnType::None; + bool acadColumnInfo_AutoHeight = false; + int acadColumnInfo_Count = 0; + bool acadColumnInfo_FlowReversed = false; + double acadColumnInfo_Width = 0.; + double acadColumnInfo_GutterWidth = 0.; + + bool acadHasDefinedHeight = false; + double acadDefinedHeight = 0.; + +}; + +struct Dxf_VERTEX { enum class Bulge { StraightSegment = 0, SemiCircle = 1 }; enum Flag { None = 0, @@ -96,7 +203,7 @@ struct DxfVertex { Flags flags = Flag::None; }; -struct DxfPolyline { +struct Dxf_POLYLINE { enum Flag { None = 0, Closed = 1, @@ -127,7 +234,44 @@ struct DxfPolyline { double smoothSurfaceMDensity = 0.; double smoothSurfaceNDensity = 0.; double extrusionDir[3] = { 0., 0., 1. }; - std::vector vertices; + std::vector vertices; +}; + +struct Dxf_INSERT { + // Code: 2 + std::string blockName; + // Code: 10, 20, 30 + DxfCoords insertPoint = {}; // OCS + // Code: 41, 42, 43 + DxfScale scaleFactor = { 1., 1., 1. }; + // Code: 50 + double rotationAngle = 0.; + // Code: 70 + int columnCount = 1; + // Code: 71 + int rowCount = 1; + // Code: 44 + double columnSpacing = 0.; + // Code: 45 + double rowSpacing = 0.; + // Code: 210, 220, 230 + DxfCoords extrusionDirection = { 0., 0., 1. }; +}; + +struct Dxf_SOLID { + // Code: 10, 20, 30 + DxfCoords corner1; + // Code: 11, 21, 31 + DxfCoords corner2; + // Code: 12, 22, 32 + DxfCoords corner3; + // Code: 13, 23, 33 + DxfCoords corner4; + bool hasCorner4 = false; + // Code: 39 + double thickness = 0.; + // Code: 210, 220, 230 + DxfCoords extrusionDirection = { 0., 0., 1. }; }; //spline data for reading @@ -422,14 +566,17 @@ class CDxfRead std::streamsize m_gcount = 0; int m_line_nb = 0; - // Mapping from layer name -> layer color index - std::map m_layer_ColorIndex_map; + std::unordered_map m_layer_ColorIndex_map; const ColorIndex_t ColorBylayer = 256; + std::unordered_map m_mapStyle; + bool ReadUnits(); bool ReadLayer(); + bool ReadStyle(); bool ReadLine(); + void ReadMText(); void ReadText(); bool ReadArc(); bool ReadCircle(); @@ -438,7 +585,8 @@ class CDxfRead bool ReadSpline(); bool ReadLwPolyLine(); bool ReadPolyLine(); - bool ReadVertex(DxfVertex* vertex); + bool ReadVertex(Dxf_VERTEX* vertex); + bool ReadSolid(); void OnReadArc( double start_angle, @@ -509,15 +657,19 @@ class CDxfRead double mm(double value) const; + const Dxf_STYLE* findStyle(const std::string& name) const; + void DoRead(bool ignore_errors = false); // this reads the file and calls the following functions virtual void OnReadLine(const DxfCoords& s, const DxfCoords& e, bool hidden) = 0; - virtual void OnReadPolyline(const DxfPolyline&) = 0; + virtual void OnReadPolyline(const Dxf_POLYLINE&) = 0; virtual void OnReadPoint(const DxfCoords& s) = 0; - virtual void OnReadText(const DxfText&) = 0; + virtual void OnReadText(const Dxf_TEXT&) = 0; + + virtual void OnReadMText(const Dxf_MTEXT&) = 0; virtual void OnReadArc( const DxfCoords& s, const DxfCoords& e, const DxfCoords& c, bool dir, bool hidden @@ -537,12 +689,9 @@ class CDxfRead virtual void OnReadSpline(struct SplineData& sd) = 0; - virtual void OnReadInsert( - const DxfCoords& point, - const DxfScale& scale, - const std::string& name, - double rotation - ) = 0; + virtual void OnReadInsert(const Dxf_INSERT& ins) = 0; + + virtual void OnReadSolid(const Dxf_SOLID& solid) = 0; virtual void OnReadDimension( const DxfCoords& s, diff --git a/src/io_dxf/io_dxf.cpp b/src/io_dxf/io_dxf.cpp index f4b2dd0a..07942a28 100644 --- a/src/io_dxf/io_dxf.cpp +++ b/src/io_dxf/io_dxf.cpp @@ -27,7 +27,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -99,15 +101,17 @@ class DxfReader::Internal : public CDxfRead { // CDxfRead's virtual functions void OnReadLine(const DxfCoords& s, const DxfCoords& e, bool hidden) override; - void OnReadPolyline(const DxfPolyline& polyline) override; + void OnReadPolyline(const Dxf_POLYLINE& polyline) override; void OnReadPoint(const DxfCoords& s) override; - void OnReadText(const DxfText& text) override; + void OnReadText(const Dxf_TEXT& text) override; + void OnReadMText(const Dxf_MTEXT& text) override; void OnReadArc(const DxfCoords& s, const DxfCoords& e, const DxfCoords& c, bool dir, bool hidden) override; void OnReadCircle(const DxfCoords& s, const DxfCoords& c, bool dir, bool hidden) override; void OnReadEllipse(const DxfCoords& c, 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 DxfCoords& point, const DxfScale& scale, const std::string& name, double rotation) override; + void OnReadInsert(const Dxf_INSERT& ins) override; void OnReadDimension(const DxfCoords& s, const DxfCoords& e, const DxfCoords& point, double rotation) override; + void OnReadSolid(const Dxf_SOLID& solid) override; void ReportError(const std::string& msg) override; void AddGraphics() const override; @@ -394,10 +398,10 @@ void DxfReader::Internal::OnReadLine(const DxfCoords& s, const DxfCoords& e, boo this->addShape(edge); } -void DxfReader::Internal::OnReadPolyline(const DxfPolyline& polyline) +void DxfReader::Internal::OnReadPolyline(const Dxf_POLYLINE& polyline) { const auto& vertices = polyline.vertices; - const bool isPolylineClosed = polyline.flags & DxfPolyline::Flag::Closed; + const bool isPolylineClosed = polyline.flags & Dxf_POLYLINE::Flag::Closed; const int nodeCount = CppUtils::safeStaticCast(vertices.size() + (isPolylineClosed ? 1 : 0)); MeshUtils::Polygon3dBuilder polygonBuilder(nodeCount); for (unsigned i = 0; i < vertices.size(); ++i) @@ -416,46 +420,124 @@ void DxfReader::Internal::OnReadPoint(const DxfCoords& s) this->addShape(vertex); } -void DxfReader::Internal::OnReadText(const DxfText& text) +void DxfReader::Internal::OnReadText(const Dxf_TEXT& text) { if (!m_params.importAnnotations) return; - const gp_Pnt pt = this->toPnt(text.point); + const gp_Pnt pt = this->toPnt(text.firstAlignmentPoint); const std::string layerName = this->LayerName(); - if (!startsWith(layerName, "BLOCKS")) { - const std::string& fontName = m_params.fontNameForTextObjects; - const double fontHeight = 4 * text.height * m_params.scaling; - Font_BRepFont brepFont; - if (brepFont.Init(fontName.c_str(), Font_FA_Regular, fontHeight)) { - gp_Trsf rotTrsf; - if (!MathUtils::fuzzyIsNull(text.rotation)) - rotTrsf.SetRotation(gp_Ax1(pt, gp::DZ()), text.rotation); - - const int ap = static_cast(text.attachPoint); - Graphic3d_HorizontalTextAlignment hAttachPnt = Graphic3d_HTA_LEFT; - if (ap == 2 || ap == 5 || ap == 8) - hAttachPnt = Graphic3d_HTA_CENTER; - else if (ap == 3 || ap == 6 || ap == 9) - hAttachPnt = Graphic3d_HTA_RIGHT; - - Graphic3d_VerticalTextAlignment vAttachPnt = Graphic3d_VTA_TOP; - if (ap == 4 || ap == 5 || ap == 6) - vAttachPnt = Graphic3d_VTA_CENTER; - else if (ap == 7 || ap == 8 || ap == 9) - vAttachPnt = Graphic3d_VTA_BOTTOM; - - const gp_Ax3 locText(pt, gp::DZ(), gp::DX().Transformed(rotTrsf)); - Font_BRepTextBuilder brepTextBuilder; - const TopoDS_Shape shapeText = brepTextBuilder.Perform( - brepFont, string_conv(text.str), locText, hAttachPnt, vAttachPnt - ); - this->addShape(shapeText); - } - else { - m_messenger->emitWarning(fmt::format("Font_BRepFont is null for '{}'", fontName)); - } + if (startsWith(layerName, "BLOCKS")) + return; + + const Dxf_STYLE* ptrStyle = this->findStyle(text.styleName); + std::string fontName = ptrStyle ? ptrStyle->name : m_params.fontNameForTextObjects; + auto fnToLower = [](const std::string& str) { + std::string lstr = str; + for (char& c : lstr) + c = std::tolower(c, std::locale::classic()); + return lstr; + }; + + if (fnToLower(fontName) == "arial_narrow") + fontName.replace(5, 1, " "); + + const double fontHeight = 1.4 * text.height * m_params.scaling; + Font_BRepFont brepFont; + brepFont.SetWidthScaling(static_cast(text.relativeXScaleFactorWidth)); + if (!brepFont.Init(fontName.c_str(), Font_FA_Regular, fontHeight/*, Font_StrictLevel_Aliases*/)) { + m_messenger->emitWarning(fmt::format("Font_BRepFont is null for '{}'", fontName)); + return; + } + + gp_Trsf rotTrsf; + if (!MathUtils::fuzzyIsNull(text.rotationAngle)) + rotTrsf.SetRotation(gp_Ax1(pt, gp::DZ()), UnitSystem::radians(text.rotationAngle * Quantity_Degree)); + +#if 0 + const Dxf_TEXT::HorizontalJustification hjust = text.horizontalJustification; + Graphic3d_HorizontalTextAlignment hAlign = Graphic3d_HTA_LEFT; + switch (hjust) { + case Dxf_TEXT::HorizontalJustification::Center: + case Dxf_TEXT::HorizontalJustification::Middle: + hAlign = Graphic3d_HTA_CENTER; + break; + case Dxf_TEXT::HorizontalJustification::Right: + hAlign = Graphic3d_HTA_RIGHT; + break; + } + + const Dxf_TEXT::VerticalJustification vjust = text.verticalJustification; + Graphic3d_VerticalTextAlignment vAlign = Graphic3d_VTA_TOP; + switch (vjust) { + case Dxf_TEXT::VerticalJustification::Bottom: + vAlign = Graphic3d_VTA_BOTTOM; + break; + case Dxf_TEXT::VerticalJustification::Middle: + vAlign = Graphic3d_VTA_CENTER; + break; + } +#endif + + const gp_Ax3 locText(pt, gp::DZ(), gp::DX().Transformed(rotTrsf)); + Font_BRepTextBuilder brepTextBuilder; + const auto textStr = string_conv(text.str); + const TopoDS_Shape shapeText = brepTextBuilder.Perform(brepFont, textStr, locText/*, hAlign, vAlign*/); + this->addShape(shapeText); +} + +void DxfReader::Internal::OnReadMText(const Dxf_MTEXT& text) +{ + if (!m_params.importAnnotations) + return; + + const gp_Pnt pt = this->toPnt(text.insertionPoint); + const std::string layerName = this->LayerName(); + if (startsWith(layerName, "BLOCKS")) + return; + + const std::string& fontName = m_params.fontNameForTextObjects; + const double fontHeight = 1.4 * text.height * m_params.scaling; + Font_BRepFont brepFont; + if (!brepFont.Init(fontName.c_str(), Font_FA_Regular, fontHeight)) { + m_messenger->emitWarning(fmt::format("Font_BRepFont is null for '{}'", fontName)); + return; } + + gp_Trsf rotTrsf; + if (!MathUtils::fuzzyIsNull(text.rotationAngle)) + rotTrsf.SetRotation(gp_Ax1(pt, gp::DZ()), text.rotationAngle); + + const int ap = static_cast(text.attachmentPoint); + Graphic3d_HorizontalTextAlignment hAttachPnt = Graphic3d_HTA_LEFT; + if (ap == 2 || ap == 5 || ap == 8) + hAttachPnt = Graphic3d_HTA_CENTER; + else if (ap == 3 || ap == 6 || ap == 9) + hAttachPnt = Graphic3d_HTA_RIGHT; + + Graphic3d_VerticalTextAlignment vAttachPnt = Graphic3d_VTA_TOP; + if (ap == 4 || ap == 5 || ap == 6) + vAttachPnt = Graphic3d_VTA_CENTER; + else if (ap == 7 || ap == 8 || ap == 9) + vAttachPnt = Graphic3d_VTA_BOTTOM; + + OccHandle textFormat = new Font_TextFormatter; + textFormat->SetupAlignment(hAttachPnt, vAttachPnt); + textFormat->Append(string_conv(text.str), *brepFont.FTFont()); +#if 0 + // Font_TextFormatter computes weird ResultWidth() so wrapping is currently broken + if (text.acadHasColumnInfo && text.acadColumnInfo_Width > 0.) { + textFormat->SetWordWrapping(true); + textFormat->SetWrapping(text.acadColumnInfo_Width); + } +#endif + + textFormat->Format(); + + const gp_Ax3 locText(pt, gp::DZ(), gp::DX().Transformed(rotTrsf)); + Font_BRepTextBuilder brepTextBuilder; + const TopoDS_Shape shapeText = brepTextBuilder.Perform(brepFont, textFormat, locText); + this->addShape(shapeText); } // Excerpted from FreeCad/src/Mod/Import/App/ImpExpDxf @@ -542,11 +624,9 @@ void DxfReader::Internal::OnReadSpline(SplineData& sd) } // Excerpted from FreeCad/src/Mod/Import/App/ImpExpDxf -void DxfReader::Internal::OnReadInsert( - const DxfCoords& point, const DxfScale& scale, const std::string& name, double rotation - ) +void DxfReader::Internal::OnReadInsert(const Dxf_INSERT& ins) { - const std::string prefix = std::string("BLOCKS ") + name + " "; + const std::string prefix = "BLOCKS " + ins.blockName + " "; for (const auto& [k, vecEntity] : m_layers) { if (!startsWith(k, prefix)) continue; // Skip @@ -560,16 +640,19 @@ void DxfReader::Internal::OnReadInsert( if (comp.IsNull()) continue; // Skip - if (!MathUtils::fuzzyEqual(scale.x, scale.y) || !MathUtils::fuzzyEqual(scale.x, scale.y)) { + if (!MathUtils::fuzzyEqual(ins.scaleFactor.x, ins.scaleFactor.y) + || !MathUtils::fuzzyEqual(ins.scaleFactor.x, ins.scaleFactor.y) + ) + { m_messenger->emitWarning( fmt::format("OnReadInsert('{}') - non-uniform scales aren't supported({}, {}, {})", - name, scale.x, scale.y, scale.z + ins.blockName, ins.scaleFactor.x, ins.scaleFactor.y, ins.scaleFactor.z ) ); } auto fnNonNull = [](double v) { return !MathUtils::fuzzyIsNull(v) ? v : 1.; }; - const double avgScale = std::abs(fnNonNull((scale.x + scale.y + scale.z) / 3.)); + const double avgScale = std::abs(fnNonNull((ins.scaleFactor.x + ins.scaleFactor.y + ins.scaleFactor.z) / 3.)); if (!MathUtils::fuzzyEqual(avgScale, 1.)) { gp_Trsf trsf; trsf.SetScaleFactor(avgScale); @@ -579,17 +662,19 @@ void DxfReader::Internal::OnReadInsert( } else { m_messenger->emitWarning( - fmt::format("OnReadInsert('{}') - scaling failed({}, {}, {})", name, scale.x, scale.y, scale.z) + fmt::format("OnReadInsert('{}') - scaling failed({}, {}, {})", + ins.blockName, ins.scaleFactor.x, ins.scaleFactor.y, ins.scaleFactor.z + ) ); } } gp_Trsf trsfRotZ; - if (!MathUtils::fuzzyIsNull(rotation)) - trsfRotZ.SetRotation(gp::OZ(), rotation); + if (!MathUtils::fuzzyIsNull(ins.rotationAngle)) + trsfRotZ.SetRotation(gp::OZ(), ins.rotationAngle); gp_Trsf trsfMove; - trsfMove.SetTranslation(this->toPnt(point).XYZ()); + trsfMove.SetTranslation(this->toPnt(ins.insertPoint).XYZ()); comp.Location(trsfRotZ * trsfMove); this->addShape(comp); @@ -610,6 +695,36 @@ void DxfReader::Internal::OnReadDimension(const DxfCoords& s, const DxfCoords& e } } +void DxfReader::Internal::OnReadSolid(const Dxf_SOLID& solid) +{ + const gp_Pnt p1 = this->toPnt(solid.corner1); + const gp_Pnt p2 = this->toPnt(solid.corner2); + const gp_Pnt p3 = this->toPnt(solid.corner3); + const gp_Pnt p4 = this->toPnt(solid.corner4); + + TopoDS_Face face; + try { + BRepBuilderAPI_MakeWire makeWire; + makeWire.Add(BRepBuilderAPI_MakeEdge(p1, p2)); + if (solid.hasCorner4 && !p3.IsEqual(p4, Precision::Confusion())) { + makeWire.Add(BRepBuilderAPI_MakeEdge(p2, p4)); + makeWire.Add(BRepBuilderAPI_MakeEdge(p4, p3)); + } + else { + makeWire.Add(BRepBuilderAPI_MakeEdge(p2, p3)); + } + + makeWire.Add(BRepBuilderAPI_MakeEdge(p3, p1)); + if (makeWire.IsDone()) + face = BRepBuilderAPI_MakeFace(makeWire.Wire(), true/*onlyPlane*/); + } catch (...) { + m_messenger->emitError("OnReadSolid() failed"); + } + + if (!face.IsNull()) + this->addShape(face); +} + void DxfReader::Internal::ReportError(const std::string& msg) { m_messenger->emitError(msg); From f48ae1c3911e8d35e778cfb11854b548c9cefa7a Mon Sep 17 00:00:00 2001 From: Hugues Delorme Date: Wed, 6 Dec 2023 10:06:05 +0100 Subject: [PATCH 09/10] IO_Dxf: factorize code in CDxfRead::DoRead() --- src/io_dxf/dxf.cpp | 273 ++++++++++++++++++--------------------------- src/io_dxf/dxf.h | 17 ++- 2 files changed, 118 insertions(+), 172 deletions(-) diff --git a/src/io_dxf/dxf.cpp b/src/io_dxf/dxf.cpp index 7eee415f..2260ca36 100644 --- a/src/io_dxf/dxf.cpp +++ b/src/io_dxf/dxf.cpp @@ -17,6 +17,7 @@ # include #endif +#include #include #include @@ -2346,7 +2347,7 @@ bool CDxfRead::ReadCircle() return false; } -void CDxfRead::ReadMText() +bool CDxfRead::ReadMText() { Dxf_MTEXT text; bool withinAcadColumnInfo = false; @@ -2367,7 +2368,7 @@ void CDxfRead::ReadMText() text.str = this->toUtf8(text.str); OnReadMText(text); - return; + return true; } get_line(); @@ -2501,9 +2502,11 @@ void CDxfRead::ReadMText() break; } } + + return false; } -void CDxfRead::ReadText() +bool CDxfRead::ReadText() { Dxf_TEXT text; @@ -2513,7 +2516,7 @@ void CDxfRead::ReadText() if (n == 0) { ResolveColorIndex(); OnReadText(text); - return; + return true; } get_line(); @@ -2563,6 +2566,8 @@ void CDxfRead::ReadText() break; } } + + return false; } bool CDxfRead::ReadEllipse() @@ -2898,6 +2903,32 @@ bool CDxfRead::ReadSolid() return false; } +bool CDxfRead::ReadSection() +{ + m_section_name.clear(); + get_line(); + get_line(); + if (m_str != "ENTITIES") + m_section_name = m_str; + + m_block_name.clear(); + return true; +} + +bool CDxfRead::ReadTable() +{ + get_line(); + get_line(); + return true; +} + +bool CDxfRead::ReadEndSec() +{ + m_section_name.clear(); + m_block_name.clear(); + return true; +} + bool CDxfRead::ReadPolyLine() { Dxf_POLYLINE polyline; @@ -3181,7 +3212,7 @@ void CDxfRead::put_line(const std::string& value) m_unused_line = value; } -bool CDxfRead::ReadUnits() +bool CDxfRead::ReadInsUnits() { get_line(); // Skip to next line. get_line(); // Skip to next line. @@ -3196,6 +3227,17 @@ bool CDxfRead::ReadUnits() } } +bool CDxfRead::ReadMeasurement() +{ + get_line(); + get_line(); + const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); + if (n == 0) + m_measurement_inch = true; + + return true; +} + bool CDxfRead::ReadLayer() { std::string layername; @@ -3293,7 +3335,7 @@ bool CDxfRead::ReadStyle() return false; } -bool CDxfRead::ReadVersion() +bool CDxfRead::ReadAcadVer() { static const std::vector VersionNames = { // This table is indexed by eDXFVersion_t - (ROlder+1) @@ -3331,7 +3373,7 @@ bool CDxfRead::ReadVersion() return ResolveEncoding(); } -bool CDxfRead::ReadDWGCodePage() +bool CDxfRead::ReadDwgCodePage() { get_line(); get_line(); @@ -3379,9 +3421,35 @@ void CDxfRead::DoRead(bool ignore_errors) { m_ignore_errors = ignore_errors; m_gcount = 0; - if (m_fail) { + if (m_fail) return; - } + + std::unordered_map> mapHeaderVarHandler; + mapHeaderVarHandler.insert({ "$INSUNITS", [=]{ return ReadInsUnits(); } }); + mapHeaderVarHandler.insert({ "$MEASUREMENT", [=]{ return ReadMeasurement(); } }); + mapHeaderVarHandler.insert({ "$ACADVER", [=]{ return ReadAcadVer(); } }); + mapHeaderVarHandler.insert({ "$DWGCODEPAGE", [=]{ return ReadDwgCodePage(); } }); + + std::unordered_map> mapEntityHandler; + mapEntityHandler.insert({ "ARC", [=]{ return ReadArc(); } }); + mapEntityHandler.insert({ "BLOCK", [=]{ return ReadBlockInfo(); } }); + mapEntityHandler.insert({ "CIRCLE", [=]{ return ReadCircle(); } }); + mapEntityHandler.insert({ "DIMENSION", [=]{ return ReadDimension(); } }); + mapEntityHandler.insert({ "ELLIPSE", [=]{ return ReadEllipse(); } }); + mapEntityHandler.insert({ "INSERT", [=]{ return ReadInsert(); } }); + mapEntityHandler.insert({ "LAYER", [=]{ return ReadLayer(); } }); + mapEntityHandler.insert({ "LINE", [=]{ return ReadLine(); } }); + mapEntityHandler.insert({ "LWPOLYLINE", [=]{ return ReadLwPolyLine(); } }); + mapEntityHandler.insert({ "MTEXT", [=]{ return ReadMText(); } }); + mapEntityHandler.insert({ "POINT", [=]{ return ReadPoint(); } }); + mapEntityHandler.insert({ "POLYLINE", [=]{ return ReadPolyLine(); } }); + mapEntityHandler.insert({ "SECTION", [=]{ return ReadSection(); } }); + mapEntityHandler.insert({ "SOLID", [=]{ return ReadSolid(); } }); + mapEntityHandler.insert({ "SPLINE", [=]{ return ReadSpline(); } }); + mapEntityHandler.insert({ "STYLE", [=]{ return ReadStyle(); } }); + mapEntityHandler.insert({ "TEXT", [=]{ return ReadText(); } }); + mapEntityHandler.insert({ "TABLE", [=]{ return ReadTable(); } }); + mapEntityHandler.insert({ "ENDSEC", [=]{ return ReadEndSec(); } }); get_line(); @@ -3389,176 +3457,47 @@ void CDxfRead::DoRead(bool ignore_errors) while (!m_ifs.eof()) { m_ColorIndex = ColorBylayer; // Default - if (m_str == "$INSUNITS") { - if (!ReadUnits()) { - return; - } - continue; - } // End if - then - - if (m_str == "$MEASUREMENT") { - get_line(); - get_line(); - const int n = stringToInt(m_str, StringToErrorMode::ReturnErrorValue); - if (n == 0) - m_measurement_inch = true; - - continue; - } // End if - then - - if (m_str == "$ACADVER") { - if (!ReadVersion()) { - return; - } - continue; - } // End if - then - - if (m_str == "$DWGCODEPAGE") { - if (!ReadDWGCodePage()) { - return; + { // Handle header variable + auto itHandler = mapHeaderVarHandler.find(m_str); + if (itHandler != mapHeaderVarHandler.cend()) { + const auto& fn = itHandler->second; + if (fn()) + continue; + else + return; } - continue; - } // End if - then + } if (m_str == "0") { get_line(); if (m_str == "0") get_line(); // Skip again - if (m_str == "SECTION") { - m_section_name.clear(); - get_line(); - get_line(); - if (m_str != "ENTITIES") { - m_section_name = m_str; - } - m_block_name.clear(); - - } // End if - then - else if (m_str == "TABLE") { - get_line(); - get_line(); - } - - else if (m_str == "LAYER" ) { - if (!ReadLayer()) { - this->ReportError("DXF::DoRead() - Failed to read layer"); - //return; Some objects or tables can have "LAYER" as name... - } - continue; - } - - else if (m_str == "STYLE" ) { - ReadStyle(); - continue; - } - - else if (m_str == "BLOCK" ) { - if (!ReadBlockInfo()) { - this->ReportError("DXF::DoRead()f - Failed to read block info"); - return; - } - continue; - } // End if - then - - else if (m_str == "ENDSEC" ) { - m_section_name.clear(); - m_block_name.clear(); - } // End if - then - else if (m_str == "LINE") { - if (!ReadLine()) { - this->ReportError("DXF::DoRead() - Failed to read line"); - return; - } - continue; - } - else if (m_str == "ARC") { - if (!ReadArc()) { - this->ReportError("DXF::DoRead() - Failed to read arc"); - return; - } - continue; - } - else if (m_str == "CIRCLE") { - if (!ReadCircle()) { - this->ReportError("DXF::DoRead() - Failed to read circle"); - return; - } - continue; - } - else if (m_str == "MTEXT") { + auto itHandler = mapEntityHandler.find(m_str); + if (itHandler != mapEntityHandler.cend()) { + const auto& fn = itHandler->second; + bool okRead = false; + std::string exceptionMsg; try { - ReadMText(); + okRead = fn(); } catch (const std::runtime_error& err) { - this->ReportError("DXF::DoRead() - Failed to read MTEXT\nError: " + std::string(err.what())); - return; + exceptionMsg = err.what(); } - continue; - } - else if (m_str == "TEXT") { - try { - ReadText(); - } catch (const std::runtime_error& err) { - this->ReportError("DXF::DoRead() - Failed to read TEXT\nError: " + std::string(err.what())); - return; - } - continue; - } - else if (m_str == "ELLIPSE") { - if (!ReadEllipse()) { - this->ReportError("DXF::DoRead() - Failed to read ellipse"); - return; - } - continue; - } - else if (m_str == "SPLINE") { - if (!ReadSpline()) { - this->ReportError("DXF::DoRead() - Failed to read spline"); - return; - } - continue; - } - else if (m_str == "LWPOLYLINE") { - if (!ReadLwPolyLine()) { - this->ReportError("DXF::DoRead() - Failed to read LW Polyline"); - return; - } - continue; - } - else if (m_str == "POLYLINE") { - if (!ReadPolyLine()) { - this->ReportError("DXF::DoRead() - Failed to read Polyline"); - return; - } - continue; - } - else if (m_str == "POINT") { - if (!ReadPoint()) { - this->ReportError("DXF::DoRead() - Failed to read Point"); - return; - } - continue; - } - else if (m_str == "INSERT") { - if (!ReadInsert()) { - this->ReportError("DXF::DoRead() - Failed to read Insert"); - return; - } - continue; - } - else if (m_str == "DIMENSION") { - if (!ReadDimension()) { - this->ReportError("DXF::DoRead() - Failed to read Dimension"); - return; + + if (okRead) { + continue; } - continue; - } - else if (m_str == "SOLID") { - if (!ReadSolid()) { - this->ReportError("DXF::DoRead() - Failed to read Solid"); - return; + else { + std::string errMsg = "DXF::DoRead() - Failed to read " + m_str; + if (!exceptionMsg.empty()) + errMsg += "\nError: " + exceptionMsg; + + this->ReportError(errMsg); + if (m_str == "LAYER") // Some objects or tables can have "LAYER" as name... + continue; + else + return; } - continue; } } diff --git a/src/io_dxf/dxf.h b/src/io_dxf/dxf.h index 1ab93d81..39344d83 100644 --- a/src/io_dxf/dxf.h +++ b/src/io_dxf/dxf.h @@ -570,14 +570,19 @@ class CDxfRead std::unordered_map m_layer_ColorIndex_map; const ColorIndex_t ColorBylayer = 256; + // Map styleName to Style object std::unordered_map m_mapStyle; - bool ReadUnits(); + bool ReadInsUnits(); + bool ReadMeasurement(); + bool ReadAcadVer(); + bool ReadDwgCodePage(); + bool ReadLayer(); bool ReadStyle(); bool ReadLine(); - void ReadMText(); - void ReadText(); + bool ReadMText(); + bool ReadText(); bool ReadArc(); bool ReadCircle(); bool ReadEllipse(); @@ -587,6 +592,9 @@ class CDxfRead bool ReadPolyLine(); bool ReadVertex(Dxf_VERTEX* vertex); bool ReadSolid(); + bool ReadSection(); + bool ReadTable(); + bool ReadEndSec(); void OnReadArc( double start_angle, @@ -607,8 +615,7 @@ class CDxfRead bool ReadInsert(); bool ReadDimension(); bool ReadBlockInfo(); - bool ReadVersion(); - bool ReadDWGCodePage(); + bool ResolveEncoding(); template From 5f66a7a205bbe825ee4fde7437d6cb8781f6dd70 Mon Sep 17 00:00:00 2001 From: Hugues Delorme Date: Wed, 6 Dec 2023 10:06:28 +0100 Subject: [PATCH 10/10] IO_Dxf: fix compilation error for OpenCascade < 7.5 --- src/io_dxf/io_dxf.cpp | 56 ++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/io_dxf/io_dxf.cpp b/src/io_dxf/io_dxf.cpp index 07942a28..097587b1 100644 --- a/src/io_dxf/io_dxf.cpp +++ b/src/io_dxf/io_dxf.cpp @@ -60,6 +60,15 @@ bool startsWith(std::string_view str, std::string_view prefix) return str.substr(0, prefix.size()) == prefix; } +std::string toLowerCase_C(const std::string& str) +{ + std::string lstr = str; + for (char& c : lstr) + c = std::tolower(c, std::locale::classic()); + + return lstr; +} + const Enumeration& systemFontNames() { static Enumeration fontNames; @@ -432,14 +441,8 @@ void DxfReader::Internal::OnReadText(const Dxf_TEXT& text) const Dxf_STYLE* ptrStyle = this->findStyle(text.styleName); std::string fontName = ptrStyle ? ptrStyle->name : m_params.fontNameForTextObjects; - auto fnToLower = [](const std::string& str) { - std::string lstr = str; - for (char& c : lstr) - c = std::tolower(c, std::locale::classic()); - return lstr; - }; - - if (fnToLower(fontName) == "arial_narrow") + // "ARIAL_NARROW" -> "ARIAL NARROW" + if (toLowerCase_C(fontName) == "arial_narrow") fontName.replace(5, 1, " "); const double fontHeight = 1.4 * text.height * m_params.scaling; @@ -455,6 +458,8 @@ void DxfReader::Internal::OnReadText(const Dxf_TEXT& text) rotTrsf.SetRotation(gp_Ax1(pt, gp::DZ()), UnitSystem::radians(text.rotationAngle * Quantity_Degree)); #if 0 + // TEXT justification is subtle(eg baseline and fit modes) + // See doc https://ezdxf.readthedocs.io/en/stable/tutorials/text.html const Dxf_TEXT::HorizontalJustification hjust = text.horizontalJustification; Graphic3d_HorizontalTextAlignment hAlign = Graphic3d_HTA_LEFT; switch (hjust) { @@ -482,7 +487,7 @@ void DxfReader::Internal::OnReadText(const Dxf_TEXT& text) const gp_Ax3 locText(pt, gp::DZ(), gp::DX().Transformed(rotTrsf)); Font_BRepTextBuilder brepTextBuilder; const auto textStr = string_conv(text.str); - const TopoDS_Shape shapeText = brepTextBuilder.Perform(brepFont, textStr, locText/*, hAlign, vAlign*/); + const TopoDS_Shape shapeText = brepTextBuilder.Perform(brepFont, textStr, locText); this->addShape(shapeText); } @@ -509,34 +514,37 @@ void DxfReader::Internal::OnReadMText(const Dxf_MTEXT& text) rotTrsf.SetRotation(gp_Ax1(pt, gp::DZ()), text.rotationAngle); const int ap = static_cast(text.attachmentPoint); - Graphic3d_HorizontalTextAlignment hAttachPnt = Graphic3d_HTA_LEFT; + Graphic3d_HorizontalTextAlignment hAlign = Graphic3d_HTA_LEFT; if (ap == 2 || ap == 5 || ap == 8) - hAttachPnt = Graphic3d_HTA_CENTER; + hAlign = Graphic3d_HTA_CENTER; else if (ap == 3 || ap == 6 || ap == 9) - hAttachPnt = Graphic3d_HTA_RIGHT; + hAlign = Graphic3d_HTA_RIGHT; - Graphic3d_VerticalTextAlignment vAttachPnt = Graphic3d_VTA_TOP; + Graphic3d_VerticalTextAlignment vAlign = Graphic3d_VTA_TOP; if (ap == 4 || ap == 5 || ap == 6) - vAttachPnt = Graphic3d_VTA_CENTER; + vAlign = Graphic3d_VTA_CENTER; else if (ap == 7 || ap == 8 || ap == 9) - vAttachPnt = Graphic3d_VTA_BOTTOM; + vAlign = Graphic3d_VTA_BOTTOM; + const auto occTextStr = string_conv(text.str); + const gp_Ax3 locText(pt, gp::DZ(), gp::DX().Transformed(rotTrsf)); + Font_BRepTextBuilder brepTextBuilder; +#if OCC_VERSION_HEX >= OCC_VERSION_CHECK(7, 5, 0) OccHandle textFormat = new Font_TextFormatter; - textFormat->SetupAlignment(hAttachPnt, vAttachPnt); - textFormat->Append(string_conv(text.str), *brepFont.FTFont()); -#if 0 - // Font_TextFormatter computes weird ResultWidth() so wrapping is currently broken + textFormat->SetupAlignment(hAlign, vAlign); + textFormat->Append(occTextStr, *brepFont.FTFont()); + /* Font_TextFormatter computes weird ResultWidth() so wrapping is currently broken if (text.acadHasColumnInfo && text.acadColumnInfo_Width > 0.) { textFormat->SetWordWrapping(true); textFormat->SetWrapping(text.acadColumnInfo_Width); } -#endif - + */ textFormat->Format(); - - const gp_Ax3 locText(pt, gp::DZ(), gp::DX().Transformed(rotTrsf)); - Font_BRepTextBuilder brepTextBuilder; const TopoDS_Shape shapeText = brepTextBuilder.Perform(brepFont, textFormat, locText); +#else + const TopoDS_Shape shapeText = brepTextBuilder.Perform(brepFont, occTextStr, locText, hAlign, vAlign); +#endif + this->addShape(shapeText); }