/****************************************************************************** ** libDXFrw - Library to read/write DXF files (ascii & binary) ** ** ** ** Copyright (C) 2016-2021 A. Stebich (librecad@mail.lordofbikes.de) ** ** Copyright (C) 2011-2015 José F. Soriano, rallazz@gmail.com ** ** ** ** This library is free software, licensed under the terms of the GNU ** ** General Public License as published by the Free Software Foundation, ** ** either version 2 of the License, or (at your option) any later version. ** ** You should have received a copy of the GNU General Public License ** ** along with this program. If not, see . ** ******************************************************************************/ #include "libdxfrw.h" #include #include #include #include #include #include "intern/drw_textcodec.h" #include "intern/dxfreader.h" #include "intern/dxfwriter.h" #include "intern/drw_dbg.h" #include "intern/dwgutil.h" #define FIRSTHANDLE 48 dxfRW::dxfRW(const char* name){ DRW_DBGSL(DRW_dbg::Level::None); fileName = name; reader = nullptr; writer = nullptr; applyExt = false; elParts = 128; //parts number when convert ellipse to polyline } dxfRW::~dxfRW(){ delete reader; delete writer; for (auto it=imageDef.begin(); it!=imageDef.end(); ++it) { delete *it; } imageDef.clear(); } void dxfRW::setDebug(DRW::DebugLevel lvl){ switch (lvl){ case DRW::DebugLevel::Debug: DRW_DBGSL(DRW_dbg::Level::Debug); break; case DRW::DebugLevel::None: DRW_DBGSL(DRW_dbg::Level::None); } } #define ERR_UNKNOWN return setError(DRW::BAD_UNKNOWN); #define ERR_TABLES return setError(DRW::BAD_READ_TABLES); #define ERR_BAD_CODE return setError( DRW::BAD_CODE_PARSED); bool dxfRW::readAscii(DRW_Interface *interface_, bool ext, std::string& content) { if (nullptr == interface_) { ERR_UNKNOWN; } applyExt = ext; std::istringstream filestr(content); iface = interface_; reader = new dxfReaderAscii(&filestr); bool isOk {processDxf()}; setVersion((DRW::Version) reader->getVersion()); delete reader; reader = nullptr; return isOk; } bool dxfRW::read(DRW_Interface *interface_, bool ext){ drw_assert(fileName.empty() == false); if (nullptr == interface_) { ERR_UNKNOWN; } applyExt = ext; std::ifstream filestr; DRW_DBG("dxfRW::read 1def\n"); filestr.open (fileName.c_str(), std::ios_base::in | std::ios::binary); if (!filestr.is_open() || !filestr.good()) { return setError(DRW::BAD_OPEN); } char line[22]; char line2[22] = "AutoCAD Binary DXF\r\n"; line2[20] = (char)26; line2[21] = '\0'; filestr.read (line, 22); filestr.close(); iface = interface_; DRW_DBG("dxfRW::read 2\n"); if (strncmp(line, line2, 21) == 0) { filestr.open (fileName.c_str(), std::ios_base::in | std::ios::binary); binFile = true; //skip sentinel filestr.seekg (22, std::ios::beg); reader = new dxfReaderBinary(&filestr); DRW_DBG("dxfRW::read binary file\n"); } else { binFile = false; filestr.open (fileName.c_str(), std::ios_base::in); reader = new dxfReaderAscii(&filestr); } bool isOk {processDxf()}; filestr.close(); setVersion((DRW::Version) reader->getVersion()); delete reader; reader = nullptr; return isOk; } bool dxfRW::write(DRW_Interface *interface_, DRW::Version ver, bool bin){ bool isOk = false; std::ofstream filestr; setVersion(ver); binFile = bin; iface = interface_; if (binFile) { filestr.open (fileName.c_str(), std::ios_base::out | std::ios::binary | std::ios::trunc); //write sentinel filestr << "AutoCAD Binary DXF\r\n" << (char)26 << '\0'; writer = new dxfWriterBinary(&filestr); DRW_DBG("dxfRW::read binary file\n"); } else { filestr.open (fileName.c_str(), std::ios_base::out | std::ios::trunc); writer = new dxfWriterAscii(&filestr); std::string comm = std::string("dxfrw ") + std::string(DRW_VERSION); writeString(999, comm); } // DRW_Header header; iface->writeHeader(header); writeString(0, "SECTION"); entCount = FIRSTHANDLE; // header.write(writer, version); writeHeader(); writeSectionEnd(); if (afterAC1009) { writeSectionStart("CLASSES"); writeSectionEnd(); } writeSectionStart("TABLES"); writeTables(); writeSectionEnd(); writeSectionStart("BLOCKS"); writeBlocks(); writeSectionEnd(); writeSectionStart("ENTITIES"); iface->writeEntities(); writeSectionEnd(); if (afterAC1009) { writeSectionStart("OBJECTS"); writeObjects(); writeSectionEnd(); } writeName("EOF"); filestr.flush(); filestr.close(); isOk = true; delete writer; writer = nullptr; return isOk; } void dxfRW::writeHeader() { /*RLZ: TODO complete all vars to AC1024*/ int varInt; std::string varStr; writeString(2, "HEADER"); writeString(9, "$ACADVER"); switch (version) { case DRW::AC1006: //unsupported version acad 10 case DRW::AC1009: //acad 11 & 12 varStr = "AC1009"; break; case DRW::AC1012: //unsupported version acad 13 case DRW::AC1014: //acad 14 varStr = "AC1014"; break; case DRW::AC1015: //acad 2000 varStr = "AC1015"; break; case DRW::AC1018: //acad 2004 varStr = "AC1018"; break; /* case DRW::AC1021: //acad 2007 varStr = "AC1021"; break;*/ case DRW::AC1024: //acad 2010 varStr = "AC1024"; break; case DRW::AC1027: //acad 2013 varStr = "AC1027"; break; default: //acad 2007 default version varStr = "AC1021"; break; } writeString(1, varStr); writer->setVersion(varStr, true); header.getStr("$ACADVER", &varStr); header.getStr("$ACADMAINTVER", &varStr); if (!header.getStr("$DWGCODEPAGE", &varStr)) { varStr = "ANSI_1252"; } writeString(9, "$DWGCODEPAGE"); writer->setCodePage(varStr); writeString(3, writer->getCodePage()); DRW_Coord zeroCoord{0.0, 0.0, 0.0}; DRW_Coord maxCoord{ 1.0000000000000000E+020, 1.0000000000000000E+020, 1.0000000000000000E+020 }; writeVar("$TITLE", ""); writeVar("$SUBJECT", ""); writeVar("$AUTHOR", ""); writeVar("$KEYWORDS", ""); writeVar("$COMMENTS", ""); DRW_Coord xVectorCoord(1.0, 0.0, 0.0); DRW_Coord yVectorCoord(0.0, 1.0, 0.0); writeVar("$INSBASE", 10, zeroCoord); writeVar("$EXTMIN", 10, maxCoord); writeVar("$EXTMAX", 10, maxCoord); writeVar2D("$LIMMIN", 10, zeroCoord); writeVar2D("$LIMMAX", 10, {420.0,297.0, 0.0}); writeVar("$ORTHOMODE", 0); writeVar("$REGENMODE", 1); writeVar("$FILLMODE", 1); writeVar("$QTEXTMODE", 0); writeVar("$MIRRTEXT", 0); if (version == DRW::AC1009){ writeVar("$DRAGMODE", 2, 70); } writeVar("$LTSCALE", 1.0, 40); if (version == DRW::AC1009){ writeVar("$OSMODE", 0, 70); } writeVar("$ATTMODE", 0, 70); writeVar("$TEXTSIZE", 2.5, 40); writeVar("$TRACEWID", 15.68, 40); writeVar("$TEXTSTYLE", "STANDARD", 7); writeVar("$CLAYER", "0", 8); // todo - store current layer writeVar("$CELTYPE", "BYLAYER", 6); writeVar("$CECOLOR", 256, 62); if (afterAC1009){ writeVar("$CELTSCALE", 1.0, 40); writeVar("$DISPSILH", 9, 70); } // dimvars writeVar("$DIMSCALE", 2.5); writeVar("$DIMASZ", 2.5); writeVar("$DIMEXO", 0.625); writeVar("$DIMDLI", 3.75); writeVar("$DIMRND", 0.0); writeVar("$DIMDLE", 0.0); writeVar("$DIMEXE", 1.25); writeVar("$DIMTP", 0.0); writeVar("$DIMTM", 0.0); writeVar("$DIMTXT", 2.5); writeVar("$DIMCEN", 2.5); writeVar("$DIMTSZ", 0.0); writeVar("$DIMTOL", 0); writeVar("$DIMLIM", 0); writeVar("$DIMTIH", 0); writeVar("$DIMTOH", 0); writeVar("$DIMSE1", 0); writeVar("$DIMSE2", 0); writeVar("$DIMTAD", 1); writeVar("$DIMZIN", 8); writeVar("$DIMBLK", ""); writeVar("$DIMASO", 1); writeVar("$DIMSHO", 1); writeVar( "$DIMPOST", ""); writeVar( "$DIMAPOST", ""); writeVar("$DIMALT", 0); writeVar("$DIMALTD", 3); writeVar("$DIMALTF", 0.03937); writeVar("$DIMLFAC", 1.0); writeVar("$DIMTOFL", 1); writeVar("$DIMTVP", 0.0); writeVar("$DIMTIX", 0); writeVar("$DIMSOXD", 0); writeVar("$DIMSAH", 0); writeVar("$DIMBLK1", ""); writeVar("$DIMBLK2", ""); writeVar("$DIMSTYLE", "STANDARD", 2); writeVar("$DIMCLRD", 0); writeVar("$DIMCLRE", 0); writeVar("$DIMCLRT", 0); writeVar("$DIMTFAC", 1.0); writeVar("$DIMGAP", 0.625); //post r12 dim vars if (afterAC1009) { writeVar("$DIMJUST", 0); writeVar("$DIMSD1", 0); writeVar("$DIMSD2", 0); writeVar("$DIMTOLJ", 0); writeVar("$DIMTZIN", 8); writeVar("$DIMALTZ", 0); writeVar("$DIMALTTZ", 0); writeVar("$DIMUPT", 0); writeVar("$DIMDEC", 2); writeVar("$DIMTDEC", 2); writeVar("$DIMALTU", 2); writeVar("$DIMALTTD", 3); writeVar("$DIMTXSTY", "STANDARD", 7); writeVar("$DIMAUNIT", 0); writeVar("$DIMADEC", 0); writeVar("$DIMALTRND", 0.0); writeVar("$DIMAZIN", 0); writeVar("$DIMDSEP", 44); writeVar("$DIMATFIT", 3); writeVar("$DIMFRAC", 0); writeVar("$DIMLDRBLK", "STANDARD"); //verify if exist "$DIMLUNIT" or obsolete "$DIMUNIT" (pre v2000) int varInt; if ( !header.getInt("$DIMLUNIT", &varInt) ){ if (!header.getInt("$DIMUNIT", &varInt)) varInt = 2; } //verify valid values from 1 to 6 if (varInt < 1 || varInt > 6) { varInt = 2; } if (afterAC1014) { writeVarExp("$DIMLUNIT", varInt, 70); } else { writeVarExp("$DIMUNIT", varInt, 70); } writeVar("$DIMLWD", -2); writeVar("$DIMLWE", -2); writeVar("$DIMTMOVE", 0); if (afterAC1018) {// and post v2004 dim vars writeVar("$DIMFXL", 1.0); writeVar("$DIMFXLON", 0); writeVar("$DIMJOGANG", 0.7854); writeVar("$DIMTFILL", 0); writeVar("$DIMTFILLCLR", 0); writeVar("$DIMARCSYM", 0); writeVar("$DIMLTYPE", "", 6); writeVar("$DIMLTEX1", "", 6); writeVar("$DIMLTEX2", "", 6); if (version > DRW::AC1021) {// and post v2007 dim vars writeVar("$DIMTXTDIRECTION", 0); } }// end post v2004 dim vars }//end post r12 dim vars writeVar("$LUNITS", 2, 70); writeVar("$LUPREC", 4, 70); writeVar("$SKETCHINC", 1.0, 40); writeVar("$FILLETRAD", 0.0, 40); writeVar("$AUNITS", 2, 70); writeVar("$AUPREC", 0, 70); writeVar("$MENU", ".", 1); writeVar("$ELEVATION", 0.0, 40); writeVar("$PELEVATION", 0.0, 40); writeVar("$THICKNESS", 0.0, 40); writeVar("$LIMCHECK", 0, 70); if (version < DRW::AC1015) { writeVar("$BLIPMODE", 0, 70); } writeVar("$CHAMFERA", 0.0, 40); writeVar("$CHAMFERB", 0.0, 40); if (afterAC1009) { writeVar("$CHAMFERC", 0.0, 40); writeVar("$CHAMFERD", 0.0, 40); } writeVar("$SKPOLY", 0, 70); //rlz: todo, times writeVar("$USRTIMER", 1, 70); writeVar("$ANGBASE", 0.0, 50); writeVar("$ANGDIR", 0, 70); writeVar("$PDMODE", 34, 70); writeVar("$PDSIZE", 0.0, 40); writeVar("$PLINEWID", 0.0, 40); if (afterAC1012) { writeVar("$COORDS", 2, 70); } writeVar("$SPLFRAME", 0, 70); writeVar("$SPLINETYPE", 2, 70); writeVar("$SPLINESEGS", 8, 70); if (version < DRW::AC1012) { writeVar("$ATTDIA", 1, 70); writeVar("$ATTREQ", 1, 70); writeVar("$HANDLING", 1, 70); } writeString(9, "$HANDSEED"); //RLZ dxfHex(5, 0xFFFF); writer->writeString(5, "20000"); writeVar("$SURFTAB1", 6, 70); writeVar("$SURFTAB2", 6, 70); writeVar("$SURFTYPE", 6, 70); writeVar("$SURFU", 6, 70); writeVar("$SURFV", 6, 70); if (afterAC1009) { writeVar("$UCSBASE", "", 2); } writeVar("$UCSNAME", "", 2); writeVar("$UCSORG", 10, zeroCoord); writeVar("$UCSXDIR", 10, xVectorCoord); writeVar("$UCSYDIR", 10, yVectorCoord); if (afterAC1009) { //begin post r12 UCS vars writeVar("$UCSORTHOREF", "", 2); writeVar("$UCSORTHOVIEW", 0, 70); writeVar("$UCSORGTOP", 10, zeroCoord); writeVar("$UCSORGBOTTOM", 10, zeroCoord); writeVar("$UCSORGLEFT", 10, zeroCoord); writeVar("$UCSORGRIGHT", 10, zeroCoord); writeVar("$UCSORGFRONT", 10, zeroCoord); writeVar("$UCSORGBACK", 10, zeroCoord); writeVar("$PUCSBASE", "", 2); } //end post r12 UCS vars writeVar("$PUCSNAME", "", 2); writeVar("$PUCSORG", 10, zeroCoord); writeVar("$PUCSXDIR", 10, xVectorCoord); writeVar("$PUCSYDIR", 10, yVectorCoord); if (afterAC1009) { //begin post r12 PUCS vars writeVar("$PUCSORTHOREF", "", 2); writeVar("$PUCSORTHOVIEW", 0, 70); writeVar("$PUCSORGTOP", 10, zeroCoord); writeVar("$PUCSORGBOTTOM", 10, zeroCoord); writeVar("$PUCSORGLEFT", 10, zeroCoord); writeVar("$PUCSORGRIGHT", 10, zeroCoord); writeVar("$PUCSORGFRONT", 10, zeroCoord); writeVar("$PUCSORGBACK", 10, zeroCoord); } //end post r12 PUCS vars writeVar("$USERI1", 0, 70); writeVar("$USERI2", 0, 70); writeVar("$USERI3", 0, 70); writeVar("$USERI4", 0, 70); writeVar("$USERI5", 0, 70); writeVar("$USERR1", 0.0, 40); writeVar("$USERR2", 0.0, 40); writeVar("$USERR3", 0.0, 40); writeVar("$USERR4", 0.0, 40); writeVar("$USERR5", 0.0, 40); writeVar("$WORLDVIEW", 1, 70); writeVar("$SHADEDGE", 3, 70); writeVar("$SHADEDIF", 70, 70); writeVar("$TILEMODE", 1, 70); writeVar("$MAXACTVP", 64, 70); if (afterAC1009) { //begin post r12 PUCS vars writeVar("$PINSBASE", 10, zeroCoord); } writeVar("$PLIMCHECK", 0, 70); writeVar("$PEXTMIN", 10, zeroCoord); writeVar("$PEXTMAX", 10, zeroCoord); /* RLZ: moved to active VPORT, but can write in header if present*/ writeVarOpt("$GRIDMODE", 70); writeVarOpt("$SNAPSTYLE", 70); writeVar2DOpt("$GRIDUNIT", 10); writeVar2DOpt("$VIEWCTR", 10); /* RLZ: moved to active VPORT, but can write in header if present*/ writeVar2D("$PLIMMIN", 10, zeroCoord); writeVar2D("$PLIMMAX", 10, {297.0, 210.0, 0.0}); writeVar("$UNITMODE", 0, 70); writeVar("$VISRETAIN", 1, 70); writeVar("$PLINEGEN", 0, 70); writeVar("$PSLTSCALE", 1, 70); if (afterAC1009){//start port r12 vars writeVar("$TREEDEPTH", 3020, 70); writeVar("$CMLSTYLE", "Standard", 2); writeVar("$CMLJUST", 0, 70); writeVar("$CMLSCALE", 20.0, 40); writeVar("$PROXYGRAPHICS", 1, 70); int insunits {DRW_Header::Units::None}; header.getInt("$INSUNITS", &insunits); // get $INSUNITS now to evaluate $MEASUREMENT header.getInt("$MEASUREMENT", &varInt); // just remove the variable from list writeVarExp("$MEASUREMENT", DRW_Header::measurement( insunits), 70); writeVar("$CELWEIGHT", -1, 370); writeVar("$ENDCAPS", 0, 280); writeVar("$JOINSTYLE", 0, 280); writeVar("$LWDISPLAY", 0, 290); if (afterAC1014) { writeVarExp("$INSUNITS", insunits, 70); // already fetched above for $MEASUREMENT } writeVar("$HYPERLINKBASE", "", 1); writeVar("$STYLESHEET", "", 1); writeVar("$XEDIT", 1, 290); writeVar("$CEPSNTYPE", 0, 380); writeVar("$PSTYLEMODE", 1, 290); //RLZ: here $FINGERPRINTGUID and $VERSIONGUID, do not add? writeVar("$EXTNAMES", 1, 290); writeVar("$PSVPSCALE", 0.0, 40); writeVar("$OLESTARTUP", 0, 290); } if (afterAC1018) {// and post v2007 vars writeVar("$CAMERADISPLAY", 0, 290); writeVar("$LENSLENGTH", 50.0, 40); writeVar("$CAMERAHEIGHT", 0.0, 40); writeVar("$STEPSPERSEC", 2.0, 40); writeVar("$STEPSIZE", 50.0, 40); writeVar("$3DDWFPREC", 2.0, 40); writeVar("$PSOLWIDTH", 5.0, 40); writeVar("$PSOLHEIGHT", 80.0, 40); writeVar("$LOFTANG1", M_PI_2, 40); writeVar("$LOFTANG2", M_PI_2, 40); writeVar("$LOFTMAG1", 0.0, 40); writeVar("$LOFTMAG2", 0.0, 40); writeVar("$LOFTPARAM", 7, 70); writeVar("$LOFTNORMALS", 1, 280); writeVar("$LATITUDE", 1.0); writeVar("$LONGITUDE", 1.0); writeVar("$NORTHDIRECTION", 0.0); //$CMATERIAL is a handle writeVar("$TIMEZONE", -8000); writeVar("$LIGHTGLYPHDISPLAY", 1, 280); writeVar("$TILEMODELIGHTSYNCH", 1, 280); writeVar("$SOLIDHIST", 1, 280); writeVar("$SHOWHIST", 1, 280); writeVar("$DWFFRAME", 2, 280); writeVar("$DGNFRAME", 0, 280); writeVar("$REALWORLDSCALE", 1, 290); writeVar("$INTERFERECOLOR", 1, 62); //$INTERFEREOBJVS is a handle //$INTERFEREVPVS is a handle writeVar("$CSHADOW", 0, 280); writeVar("$SHADOWPLANELOCATION", 0.0, 40); } for (auto it :header.customVars) { std::string key = it.first; DRW_Variant* var = it.second; auto val = var->content.s; if (!val->empty()) { writeString(9, "$CUSTOMPROPERTYTAG"); writeString(1, key); writeString(9, "$CUSTOMPROPERTY"); writeString(1, *val); } } } bool dxfRW::writeEntity(DRW_Entity *ent) { ent->handle = ++entCount; writeHandle(5, ent->handle); writeSubClassOpt("Entity"); if (ent->space == 1) { writeInt16(67, 1); } if (afterAC1009) { writeUtf8String(8, ent->layer); writeUtf8String(6, ent->lineType); } else { writeUtf8Caps(8, ent->layer); writeUtf8Caps(6, ent->lineType); } writeInt16(62, ent->color); if (afterAC1015 && ent->color24 >= 0) { writeInt32(420, ent->color24); } if (afterAC1014) { writeInt16(370, DRW_LW_Conv::lineWidth2dxfInt(ent->lWeight)); } if (version >= DRW::AC1014) { writeAppData(ent->appData); } return true; } bool dxfRW::writeAppData(const std::list>& appData) { for(const auto& group : appData) { //Search for application name bool found = false; for(const auto& data : group) { if(data.code() == 102 && data.type() == DRW_Variant::STRING) { writeString(102, "{" + *(data.content.s)); found = true; break; } } if (found) { for (const auto& data : group) { if (data.code() == 102) { continue; } switch (data.type()) { case DRW_Variant::STRING: writeString(data.code(), *(data.content.s)); break; case DRW_Variant::INTEGER: writeInt32(data.code(), data.content.i); break; case DRW_Variant::DOUBLE: writeDouble(data.code(), data.content.i); break; default: break; } } writeString(102, "}"); } } return true; } bool dxfRW::writeLineTypeGenerics(DRW_LType *ent, int handle) { writeName("LTYPE"); std::string strname = ent->name; transform(strname.begin(), strname.end(), strname.begin(),::toupper); if (afterAC1009) { auto text = toHexStr(handle); writeString(5, text); if (afterAC1012) { writeString(330, "5"); } writeSymTypeRecord("Linetype"); writeUtf8String(2, ent->name); m_writingContext.lineTypesMap.emplace_back(std::pair(strname, handle)); } else { writeUtf8Caps(2, strname); } return true; } bool dxfRW::writeLineType(DRW_LType *ent){ std::string strname = ent->name; transform(strname.begin(), strname.end(), strname.begin(),::toupper); //do not write linetypes handled by library if (strname == "BYLAYER" || strname == "BYBLOCK" || strname == "CONTINUOUS") { return true; } writeLineTypeGenerics(ent, ++entCount); writeInt16(70, ent->flags); writeUtf8String(3, ent->desc); ent->update(); writeInt16(72, 65); writeInt16(73, ent->size); writeDouble(40, ent->length); size_t size = ent->path.size(); for (unsigned int i = 0; i< size; i++){ writeDouble(49, ent->path.at(i)); if (afterAC1009) { writeInt16(74, 0); } } return true; } bool dxfRW::writeLayer(DRW_Layer *ent){ writeName("LAYER"); if (!wlayer0 && ent->name == "0") { wlayer0 = true; if (afterAC1009) { writeString(5, "10"); } } else { if (afterAC1009) { writeString(5, toHexStr(++entCount)); } } if (afterAC1012) { writeString(330, "2"); } if (afterAC1009) { writeSymTypeRecord("Layer"); writeUtf8String(2, ent->name); } else { writeUtf8Caps(2, ent->name); } writeInt16(70, ent->flags); writeInt16(62, ent->color); if (afterAC1015 && ent->color24 >= 0) { writeInt32(420, ent->color24); } if (afterAC1009) { writeUtf8String(6, ent->lineType); if (!ent->plotF) { writeBool(290, ent->plotF); } writeInt16(370, DRW_LW_Conv::lineWidth2dxfInt(ent->lWeight)); writeString(390, "F"); } else { writeUtf8Caps(6, ent->lineType); } if (!ent->extData.empty()){ writeExtData(ent->extData); } // writeString(347, "10012"); return true; } bool dxfRW::writeUCS(DRW_UCS* ent){ writeName("UCS"); if (afterAC1009) { writeString(5, toHexStr(++entCount)); if (afterAC1012) { writeString(330, "42"); // Soft-pointer ID/handle to owner object, fixme - check whether id is fixed as for layers? } writeSymTypeRecord("UCS"); writeUtf8String(2, ent->name); } else { writeUtf8Caps(2, ent->name); } writeInt16(70, ent->flags); writeCoord(10, ent->origin); writeCoord(11, ent->xAxisDirection); writeCoord(12, ent->yAxisDirection); writeInt16(79, 0); //ID/handle of base UCS if this is an orthographic. This code is not present if the 79 code is 0. // If this code is not present and 79 code is non-zero, then base UCS is assumed to be WORLD // fixme - review this. Probably we'll skip support of it? // writeInt16(346, 0); writeDouble(146, ent->elevation); writeDouble(71, ent->orthoType); writeCoord(13, ent->orthoOrigin); return true; } bool dxfRW::writeView(DRW_View *ent){ writeName("VIEW"); if (afterAC1009) { writeString(5, toHexStr(++entCount)); if (afterAC1012) { writeString(330, "42"); // Soft-pointer ID/handle to owner object, fixme - check whether id is fixed as for layers? } writeSymTypeRecord("View"); writeUtf8String(2, ent->name); } else { writeUtf8Caps(2, ent->name); } writeInt16(70, ent->flags); writeDouble(40, ent->size.y); writeDouble(10, ent->center.x); writeDouble(20, ent->center.y); writeDouble(41, ent->size.x); writeCoord(11, ent->viewDirectionFromTarget); writeCoord(12, ent->targetPoint); writeDouble(42, ent->lensLen); writeDouble(43, ent->frontClippingPlaneOffset); writeDouble(44, ent->backClippingPlaneOffset); writeDouble(50, ent->twistAngle); writeInt16(71, ent->viewMode); writeInt16(281, ent->renderMode); writeBool(72, ent->hasUCS); writeBool(73, ent->cameraPlottable); /* * fixme - investigate deep whether we should support these attributes writeString(332, "42"); // Soft-pointer ID/handle to background object (optional) writeString(334, "42"); // Soft-pointer ID/handle to live section object (optional) writeString(348, "42"); // Hard-pointer ID/handle to visual style object (optional) */ if (ent->hasUCS){ writeCoord(110, ent->ucsOrigin); writeCoord(111, ent->ucsXAxis); writeCoord(112, ent->ucsYAxis); writeInt16(79, ent->ucsOrthoType); writeDouble(146, ent->ucsElevation); /* * fixme - investigate deep whether we should support these attributes //ID/handle of AcDbUCSTableRecord if UCS is a named UCS. If not present, then UCS is unnamed (appears only if code 72 is set to 1) writeString(345, "42"); // Soft-pointer ID/handle to live section object (optional) writeString(346, "42"); */ } return true; } bool dxfRW::writeTextstyle(DRW_Textstyle *ent){ writeName("STYLE"); //stringstream cause crash in OS/X, bug#3597944 std::string name=ent->name; transform(name.begin(), name.end(), name.begin(), toupper); if (!dimstyleStd) { if (name == "STANDARD"){ dimstyleStd = true; } } if (afterAC1009) { writeString(5, toHexStr(++entCount)); m_writingContext.textStyleMap[name] = entCount; if (afterAC1012) { writeString(330, "2"); } writeSymTypeRecord("TextStyle"); writeUtf8String(2, ent->name); } else { writeUtf8Caps(2, ent->name); } writeInt16(70, ent->flags); writeDouble(40, ent->height); writeDouble(41, ent->width); writeDouble(50, ent->oblique); writeInt16(71, ent->genFlag); writeDouble(42, ent->lastHeight); if (afterAC1009) { writeUtf8String(3, ent->font); writeUtf8String(4, ent->bigFont); if (ent->fontFamily != 0) { writeInt32(1071, ent->fontFamily); } } else { writeUtf8Caps(3, ent->font); writeUtf8Caps(4, ent->bigFont); } return true; } bool dxfRW::writeVport(DRW_Vport *ent){ if (!dimstyleStd) { ent->name = "*ACTIVE"; dimstyleStd = true; } writeName( "VPORT"); if (afterAC1009) { writeString(5, toHexStr(++entCount)); if (afterAC1012) { writeString(330, "2"); } writeSymTypeRecord("Viewport"); writeUtf8String(2, ent->name); } else { writeUtf8Caps(2, ent->name); } writeInt16(70, ent->flags); writeDouble(10, ent->lowerLeft.x); writeDouble(20, ent->lowerLeft.y); writeDouble(11, ent->UpperRight.x); writeDouble(21, ent->UpperRight.y); writeDouble(12, ent->center.x); writeDouble(22, ent->center.y); writeDouble(13, ent->snapBase.x); writeDouble(23, ent->snapBase.y); writeDouble(14, ent->snapSpacing.x); writeDouble(24, ent->snapSpacing.y); writeDouble(15, ent->gridSpacing.x); writeDouble(25, ent->gridSpacing.y); writeCoord(16, ent->viewDir); writeCoord(17, ent->viewTarget); writeDouble(40, ent->height); writeDouble(41, ent->ratio); writeDouble(42, ent->lensHeight); writeDouble(43, ent->frontClip); writeDouble(44, ent->backClip); writeDouble(50, ent->snapAngle); writeDouble(51, ent->twistAngle); writeInt16(71, ent->viewMode); writeInt16(72, ent->circleZoom); writeInt16(73, ent->fastZoom); writeInt16(74, ent->ucsIcon); writeInt16(75, ent->snap); writeInt16(76, ent->grid); writeInt16(77, ent->snapStyle); writeInt16(78, ent->snapIsopair); if (afterAC1014) { writeInt16(281, 0); writeInt16(65, 1); writeDouble(110, 0.0); // fixme - write as coords writeDouble(120, 0.0); writeDouble(130, 0.0); writeDouble(111, 1.0); writeDouble(121, 0.0); writeDouble(131, 0.0); writeDouble(112, 0.0); writeDouble(122, 1.0); writeDouble(132, 0.0); writeInt16(79, 0); writeDouble(146, 0.0); if (afterAC1018) { writeString(348, "10020"); writeInt16(60, ent->gridBehavior);//v2007 undocummented see DRW_Vport class writeInt16(61, 5); writeBool(292, 1); writeInt16(282, 1); writeDouble(141, 0.0); writeDouble(142, 0.0); writeInt16(63, 250); writeInt32(421, 3358443); } } return true; } bool dxfRW::writeDouble(int code, DRW_Dimstyle* ent, const std::string& name) { double val; if (ent->get(name, val)) { writeDouble(code, val); } return true; } bool dxfRW::writeInt16(int code, DRW_Dimstyle* ent, const std::string& name) { int val; if (ent->get(name, val)) { writeInt16(code, val); } return true; } bool dxfRW::writeUtf8String(int code, DRW_Dimstyle* ent, const std::string& name) { std::string val; if (ent->get(name, val)) { writeUtf8String(code, val); } return true; } bool dxfRW::writeDimstyle(DRW_Dimstyle *ent) { writeName("DIMSTYLE"); // if (!dimstyleStd) { // std::string name = ent->name; // std::transform(name.begin(), name.end(), name.begin(),::toupper); // if (name == "STANDARD") // dimstyleStd = true; // } if (afterAC1009) { writeString(105, toHexStr(++entCount)); if (afterAC1012) { writeString(330, "A"); } writeSymTypeRecord("DimStyle"); writeUtf8String(2, ent->name); } else { writeUtf8Caps(2, ent->name); } writeInt16(70, ent->flags); //DRW_Dimstyle::ValueHolder var; writeUtf8String(3, ent, "$DIMPOST"); writeUtf8String(4, ent, "$DIMAPOST"); writeUtf8String(5, ent, "$DIMBLK"); writeUtf8String(6, ent, "$DIMBLK1"); writeUtf8String(7, ent, "$DIMBLK2"); writeDouble(40, ent, "$DIMSCALE"); writeDouble(41, ent, "$DIMASZ"); writeDouble(42, ent, "$DIMEXO"); writeDouble(43, ent, "$DIMDLI"); writeDouble(44, ent, "$DIMEXE"); writeDouble(45, ent, "$DIMRND"); writeDouble(46, ent, "$DIMDLE"); writeDouble(47, ent, "$DIMTP"); writeDouble(48, ent, "$DIMTM"); if (afterAC1018) { writeDouble(49, ent, "$DIMFXL"); writeInt16(69, ent, "$DIMTFILL"); writeInt16(70, ent, "$DIMTFILLCLR"); } writeDouble(140, ent, "$DIMTXT"); writeDouble(141, ent, "$DIMCEN"); writeDouble(142, ent, "$DIMTSZ"); writeDouble(143, ent, "$DIMALTF"); writeDouble(144, ent, "$DIMLFAC"); writeDouble(145, ent, "$DIMTVP"); writeDouble(146, ent, "$DIMTFAC"); writeDouble(147, ent, "$DIMGAP"); if (afterAC1014) { writeDouble(148, ent, "$DIMALTRND"); } writeInt16(71, ent, "$DIMTOL"); writeInt16(72, ent, "$DIMLIM"); writeInt16(72, ent, "$DIMLIM"); writeInt16(73, ent, "$DIMTIH"); writeInt16(74, ent, "$DIMTOH"); writeInt16(75, ent, "$DIMSE1"); writeInt16(76, ent, "$DIMSE2"); writeInt16(77, ent, "$DIMTAD"); writeInt16(78, ent, "$DIMZIN"); if (afterAC1014) { writeInt16(79, ent, "$DIMAZIN"); } writeInt16(170, ent, "$DIMALT"); writeInt16(171, ent, "$DIMALTD"); writeInt16(172, ent, "$DIMTOFL"); writeInt16(173, ent, "$DIMSAH"); writeInt16(174, ent, "$DIMTIX"); writeInt16(175, ent, "$DIMSOXD"); writeInt16(176, ent, "$DIMCLRD"); writeInt16(177, ent, "$DIMCLRE"); writeInt16(178, ent, "$DIMCLRT"); if (afterAC1014) { writeInt16(179, ent, "$DIMADEC"); } if (afterAC1009) { if (version < DRW::AC1015) { writeInt16(270, ent, "$DIMLUNIT"); // obsolete dimunit... } writeInt16(271, ent, "$DIMDEC"); writeInt16(272, ent, "$DIMTDEC"); writeInt16(273, ent, "$DIMALTU"); writeInt16(274, ent, "$DIMALTTD"); writeInt16(275, ent, "$DIMAUNIT"); } if (afterAC1014) { writeInt16(276, ent, "$DIMFRAC"); writeInt16(277, ent, "$DIMLUNIT"); writeInt16(278, ent, "$DIMDSEP"); writeInt16(279, ent, "$DIMTMOVE"); } if (afterAC1009) { writeInt16(280, ent, "$DIMJUST"); writeInt16(281, ent, "$DIMSD1"); writeInt16(282, ent, "$DIMSD2"); writeInt16(283, ent, "$DIMTOLJ"); writeInt16(284, ent, "$DIMTZIN"); writeInt16(285, ent, "$DIMALTZ"); writeInt16(286, ent, "$DIMALTTZ"); if (version < DRW::AC1015) { writeInt16(287, ent, "$DIMATFIT"); } writeInt16(288, ent, "$DIMUPT"); } if (afterAC1014) { writeInt16(289, ent, "$DIMATFIT"); } if (afterAC1018) { writeInt16(290, ent, "$DIMFXLON"); } if (afterAC1009) { writeInt16(292, ent, "$DIMTXTDIRECTION"); // fixme - which version? writeUtf8String(340, ent, "$DIMTXSTY"); } if (afterAC1014) { writeUtf8String(341, ent, "_$DIMLDRBLK"); // block id for arrow writeUtf8String(342, ent, "_$DIMBLK"); // block id for arrow writeUtf8String(343, ent, "_$DIMBLK1"); // block id for arrow writeUtf8String(344, ent, "_$DIMBLK2"); // block id for arrow writeUtf8String(345, ent, "$DIMLTYPE"); // ref to linetype... // writeUtf8String(346, ent, "$DIMLTYPE"); // enum linetype name writeUtf8String(347, ent, "$DIMLTEX1"); // block it for arrow writeUtf8String(348, ent, "$DIMLTEX2"); // block it for arrow writeInt16(371, ent, "$DIMLWD"); writeInt16(372, ent, "$DIMLWE"); writeInt16(90, ent, "$DIMARCSYM"); } if (!ent->extData.empty()) { writeExtData(ent->extData); } return true; } bool dxfRW::writeAppId(DRW_AppId *ent){ std::string strname = ent->name; transform(strname.begin(), strname.end(), strname.begin(),::toupper); //do not write mandatory ACAD appId, handled by library if (strname == "ACAD") { return true; } writeName("APPID"); if (afterAC1009) { writeString(5, toHexStr(++entCount)); if (afterAC1014) { writeString(330, "9"); } writeSymTypeRecord("RegApp"); writeUtf8String(2, ent->name); } else { writeUtf8Caps(2, ent->name); } writeInt16(70, ent->flags); return true; } bool dxfRW::writePoint(DRW_Point *ent) { writeName( "POINT"); writeEntity(ent); writeSubClassOpt("Point"); writeCoord(10, ent->basePoint); return true; } bool dxfRW::writeLine(DRW_Line *ent) { writeName("LINE"); writeEntity(ent); writeSubClassOpt("Line"); writeCoord(10, ent->basePoint); writeCoord(11, ent->secPoint); return true; } bool dxfRW::writeRay(DRW_Ray *ent) { writeName("RAY"); writeEntity(ent); writeSubClassOpt("Ray"); DRW_Coord crd = ent->secPoint; crd.unitize(); writeCoord(10, ent->basePoint); writeCoord(11, crd); return true; } bool dxfRW::writeXline(DRW_Xline *ent) { writeName("XLINE"); writeEntity(ent); writeSubClassOpt("Xline"); DRW_Coord crd = ent->secPoint; crd.unitize(); writeCoord(10, ent->basePoint); writeCoord(11, crd); return true; } bool dxfRW::writeCircle(DRW_Circle *ent) { writeName("CIRCLE"); writeEntity(ent); writeSubClassOpt("Circle"); writeCoord(10, ent->basePoint); writeDouble(40, ent->radious); return true; } bool dxfRW::writeArc(DRW_Arc *ent) { writeName("ARC"); writeEntity(ent); writeSubClassOpt("Circle"); writeCoord(10, ent->basePoint); writeDouble(40, ent->radious); writeSubClassOpt("Arc"); writeDouble(50, ent->staangle*ARAD); writeDouble(51, ent->endangle*ARAD); return true; } bool dxfRW::writeEllipse(DRW_Ellipse *ent){ //verify axis/ratio and params for full ellipse ent->correctAxis(); if (afterAC1009) { writeName("ELLIPSE"); writeEntity(ent); writeSubClassOpt("Ellipse"); writeCoord(10, ent->basePoint); writeCoord(11, ent->secPoint); writeDouble(40, ent->ratio); writeDouble(41, ent->staparam); writeDouble(42, ent->endparam); } else { DRW_Polyline pol; //RLZ: copy properties ent->toPolyline(&pol, elParts); writePolyline(&pol); } return true; } bool dxfRW::writeTrace(DRW_Trace *ent){ writeName("TRACE"); writeEntity(ent); writeSubClassOpt("Trace"); writeCoord(10, ent->basePoint); writeCoord(11, ent->secPoint); writeCoord(12, ent->thirdPoint); writeCoord(13, ent->fourPoint); return true; } bool dxfRW::writeSolid(DRW_Solid *ent){ writeName("SOLID"); writeEntity(ent); writeSubClassOpt("Trace"); writeCoord(10, ent->basePoint); writeCoord(11, ent->secPoint); writeCoord(12, ent->thirdPoint); writeCoord(13, ent->fourPoint); return true; } bool dxfRW::write3dface(DRW_3Dface *ent){ writeName( "3DFACE"); writeEntity(ent); writeSubClassOpt("Face"); writeCoord(10, ent->basePoint); writeCoord(11, ent->secPoint); writeCoord(12, ent->thirdPoint); writeCoord(13, ent->fourPoint); writeInt16(70, ent->invisibleflag); return true; } bool dxfRW::writeLWPolyline(DRW_LWPolyline *ent){ if (afterAC1009) { writeName("LWPOLYLINE"); writeEntity(ent); writeSubClassOpt("Polyline"); ent->vertexnum = ent->vertlist.size(); writeInt32(90, ent->vertexnum); writeInt16(70, ent->flags); writeDouble(43, ent->width); writeDoubleOpt(38, ent->elevation); writeDoubleOpt(39, ent->thickness); for (int i = 0; i< ent->vertexnum; i++){ auto& v = ent->vertlist.at(i); writeDouble(10, v->x); writeDouble(20, v->y); writeDoubleOpt(40, v->stawidth); writeDoubleOpt(41, v->endwidth); writeDoubleOpt(42, v->bulge); } } else { //RLZ: TODO convert lwpolyline in polyline (not exist in acad 12) } return true; } bool dxfRW::writePolyline(DRW_Polyline *ent) { writeName("POLYLINE"); writeEntity(ent); if (afterAC1009) { if (ent->flags & 8 || ent->flags & 16) { writeSubClass("3dPolyline"); } else { writeSubClass("2dPolyline"); } } else { writeInt16(66, 1); } DRW_Coord coord(0, 0, ent->basePoint.z); writeCoord(10, coord); writeDoubleOpt(39, ent->thickness); writeInt16(70, ent->flags); writeDoubleOpt(40, ent->defstawidth); writeDoubleOpt(41, ent->defendwidth); if (ent->flags & 16 || ent->flags & 32) { writeInt16(71, ent->vertexcount); writeInt16(72, ent->facecount); } if (ent->smoothM != 0) { writeInt16(73, ent->smoothM); } if (ent->smoothN != 0) { writeInt16(74, ent->smoothN); } if (ent->curvetype != 0) { writeInt16(75, ent->curvetype); } DRW_Coord crd = ent->extPoint; if (crd.x != 0 || crd.y != 0 || crd.z != 1) { writeCoord(210, crd); } DRW_Coord zero(0,0,0); int vertexnum = ent->vertlist.size(); for (int i = 0; i< vertexnum; i++){ DRW_Vertex *v = ent->vertlist.at(i).get(); writeName( "VERTEX"); writeEntity(ent); writeSubClassOpt("Vertex"); if ( (v->flags & 128) && !(v->flags & 64) ) { writeCoord(10, zero); } else { writeCoord(10, v->basePoint); } writeDoubleOpt(40, v->stawidth); writeDoubleOpt(41, v->endwidth); writeDoubleOpt(42, v->bulge); if (v->flags != 0) { writeInt16(70, ent->flags); } if (v->flags & 2) { writeDouble(50, v->tgdir); } if ( v->flags & 128 ) { if (v->vindex1 != 0) { writeInt16(71, v->vindex1); } if (v->vindex2 != 0) { writeInt16(72, v->vindex2); } if (v->vindex3 != 0) { writeInt16(73, v->vindex3); } if (v->vindex4 != 0) { writeInt16(74, v->vindex4); } if ( !(v->flags & 64) ) { writeInt32(91, v->identifier); } } } writeName("SEQEND"); writeEntity(ent); return true; } bool dxfRW::writeSpline(DRW_Spline *ent){ if (afterAC1009) { writeName("SPLINE"); writeEntity(ent); writeSubClassOpt("Spline"); writeCoord(210, ent->normalVec); writeInt16(70, ent->flags); writeInt16(71, ent->degree); writeInt16(72, ent->nknots); writeInt16(73, ent->ncontrol); writeInt16(74, ent->nfit); writeDouble(42, ent->tolknot); writeDouble(43, ent->tolcontrol); writeDouble(44, ent->tolfit); //RLZ: warning check if nknots are correct and ncontrol for (int i = 0; i< ent->nknots; i++){ writeDouble(40, ent->knotslist.at(i)); } size_t size = ent->weightlist.size(); for (std::size_t i = 0; i< size; i++) { writeDouble(41, ent->weightlist.at(i)); } for (int i = 0; i< ent->ncontrol; i++){ auto crd = ent->controllist.at(i); writeCoord(10, *crd); } for (int i = 0; i< ent->nfit; i++){ auto crd = ent->fitlist.at(i); writeCoord(11, *crd); } } else { //RLZ: TODO convert spline in polyline (not exist in acad 12) } return true; } bool dxfRW::writeHatch(DRW_Hatch *ent){ if (afterAC1009) { writeName("HATCH"); writeEntity(ent); writeSubClassOpt("Hatch"); writeDouble(10, 0.0); writeDouble(20, 0.0); writeDouble(30, ent->basePoint.z); writeCoord(210, ent->extPoint); writeString(2, ent->name); writeInt16(70, ent->solid); writeInt16(71, ent->associative); ent->loopsnum = ent->looplist.size(); writeInt16(91, ent->loopsnum); //write paths data for (int i = 0; i< ent->loopsnum; i++){ DRW_HatchLoop *loop = ent->looplist.at(i).get(); writeInt16(92, loop->type); if ((loop->type & 2) == 2) { //RLZ: polyline boundary writeme } else { //boundary path loop->update(); writeInt16(93, loop->numedges); for (int j = 0; jnumedges; ++j) { switch ((loop->objlist.at(j))->eType) { case DRW::LINE: { writeInt16(72, 1); auto l = static_cast(loop->objlist.at(j).get()); writeDouble(10, l->basePoint.x); // fixme - sand - short version of vector write!! writeDouble(20, l->basePoint.y); writeDouble(11, l->secPoint.x); // fixme - sand - short version of vector write!! writeDouble(21, l->secPoint.y); break; } case DRW::ARC: { writeInt16(72, 2); auto a = static_cast(loop->objlist.at(j).get()); writeDouble(10, a->basePoint.x); // fixme - sand - short version of vector write!! writeDouble(20, a->basePoint.y); writeDouble(40, a->radious); writeDouble(50, a->staangle * ARAD); writeDouble(51, a->endangle * ARAD); writeInt16(73, a->isccw); break; } case DRW::ELLIPSE: { writeInt16(72, 3); auto a = static_cast(loop->objlist.at(j).get()); a->correctAxis(); writeDouble(10, a->basePoint.x); // fixme - sand - short version of vector write!! writeDouble(20, a->basePoint.y); writeDouble(11, a->secPoint.x); // fixme - sand - short version of vector write!! writeDouble(21, a->secPoint.y); writeDouble(40, a->ratio); writeDouble(50, a->staparam * ARAD); writeDouble(51, a->endparam * ARAD); writeInt16(73, a->isccw); break; } case DRW::SPLINE: //RLZ: spline boundary writeme // writeInt16(72, 4); break; default: break; } } writeInt16(97, 0); } } writeInt16(75, ent->hstyle); writeInt16(76, ent->hpattern); if (!ent->solid){ writeDouble(52, ent->angle); writeDouble(41, ent->scale); writeInt16(77, ent->doubleflag); writeInt16(78, ent->deflines); } /* if (ent->deflines > 0){ writeInt16(78, ent->deflines); }*/ writeInt32(98, 0); } else { //RLZ: TODO verify in acad12 } return true; } bool dxfRW::writeLeader(DRW_Leader *ent){ if (afterAC1009) { writeName("LEADER"); writeEntity(ent); writeSubClass("Leader"); writeUtf8String(3, ent->style); writeInt16(71, ent->arrow); writeInt16(72, ent->leadertype); writeInt16(73, ent->flag); writeInt16(74, ent->hookline); writeInt16(75, ent->hookflag); writeDouble(40, ent->textheight); writeDouble(41, ent->textwidth); writeDouble(76, ent->vertnum); // fixme - review why twice?? and double instead of int size_t size = ent->vertexlist.size(); writeDouble(76, size); for (unsigned int i=0; ivertexlist.at(i); writeCoord(10, *vert); } } else { //RLZ: todo not supported by acad 12 saved as unnamed block } return true; } bool dxfRW::writeDimension(DRW_Dimension *ent) { if (afterAC1009) { writeName("DIMENSION"); writeEntity(ent); writeSubClass("Dimension"); if (!ent->getName().empty()){ writeString(2, ent->getName()); } writeCoord(10, ent->getDefPoint()); writeCoord(11, ent->getTextPoint()); if (!(ent->type & 32)) { // fixme - sand - ordinate type support !!!?? ent->type = ent->type +32; } writeInt16(70, ent->type); if (!(ent->getText().empty()) ) { writeUtf8String(1, ent->getText()); } writeInt16(71, ent->getAlign()); if (ent->getTextLineStyle() != 1) { writeInt16(72, ent->getTextLineStyle()); } if (ent->getTextLineFactor() != 1){ writeDouble(41, ent->getTextLineFactor()); } writeUtf8String(3, ent->getStyle()); if (ent->getTextLineFactor() != 0){ writeDouble(53, ent->getDir()); } writeDoubleOpt(51, ent->getHDir()); writeCoord(210, ent->getExtrusion()); if (ent->getFlipArrow1()) { writeBool(74,true); } if (ent->getFlipArrow2()) { writeBool(75,true); } switch (ent->eType) { case DRW::DIMALIGNED: case DRW::DIMLINEAR: { auto* dd = static_cast(ent); writeSubClass("AlignedDimension"); DRW_Coord crd = dd->getClonepoint(); if (crd.x != 0 || crd.y != 0 || crd.z != 0) { writeCoord(12, crd); } writeCoord(13, dd->getDef1Point()); writeCoord(14, dd->getDef2Point()); if (ent->eType == DRW::DIMLINEAR) { auto dl = static_cast(ent); writeSubClass("RotatedDimension"); // writeDouble(50, dl->getAngle()); writeDoubleOpt(50, dl->getAngle()); // writeDouble(52, dl->getOblique()); writeDoubleOpt(52, dl->getOblique()); } break; } case DRW::DIMRADIAL: { auto* dd = static_cast(ent); writeSubClass("RadialDimension"); writeCoord(15, dd->getDiameterPoint()); writeDouble(40, dd->getLeaderLength()); break; } case DRW::DIMDIAMETRIC: { auto* dd = static_cast(ent); writeSubClass("DiametricDimension"); writeCoord(15, dd->getDiameter1Point()); writeDouble(40, dd->getLeaderLength()); break; } case DRW::DIMANGULAR: { auto* dd = static_cast(ent); writeSubClass("2LineAngularDimension"); writeCoord(13, dd->getFirstLine1()); writeCoord(14, dd->getFirstLine2()); writeCoord(15, dd->getSecondLine1()); writeCoord(16, dd->getDimPoint()); break; } case DRW::DIMANGULAR3P: { auto* dd = static_cast(ent); writeCoord(13, dd->getFirstLine()); writeCoord(14, dd->getSecondLine()); writeCoord(15, dd->getVertexPoint()); break; } case DRW::DIMORDINATE: { auto* dd = static_cast(ent); writeSubClass("OrdinateDimension"); writeCoord(13, dd->getFirstLine()); writeCoord(14, dd->getSecondLine()); break; } default: break; } writeEntityExtData(ent); } else { //RLZ: todo not supported by acad 12 saved as unnamed block } return true; } bool dxfRW::writeEntityExtData(DRW_Entity* ent) { for (auto r: ent->extData) { auto type = r->type(); switch (type) { case DRW_Variant::INTEGER: { writeInt16(r->code(), r->i_val()); break; } case DRW_Variant::DOUBLE: { writeDouble(r->code(), r->d_val()); break; } case DRW_Variant::STRING: { writeString(r->code(), r->c_str()); break; } case DRW_Variant::COORD: { // fixme - sand - ext data - process writing ext data coordinate??? // writeString(r->code(), r->setCoordX()); break; } default: break; } } return true; } bool dxfRW::writeInsert(DRW_Insert *ent){ writeName("INSERT"); writeEntity(ent); if (afterAC1009) { writeSubClass("BlockReference"); writeUtf8String(2, ent->name); } else { writeUtf8Caps(2, ent->name); } writeCoord(10, ent->basePoint); writeDouble(41, ent->xscale); writeDouble(42, ent->yscale); writeDouble(43, ent->zscale); writeDouble(50, (ent->angle)*ARAD); //in dxf angle is writed in degrees writeInt16(70, ent->colcount); writeInt16(71, ent->rowcount); writeDouble(44, ent->colspace); writeDouble(45, ent->rowspace); return true; } bool dxfRW::writeText(DRW_Text *ent) { writeName("TEXT"); writeEntity(ent); writeSubClassOpt("Text"); // writeDouble(39, ent->thickness); writeCoord(10, ent->basePoint); writeDouble(40, ent->height); writeUtf8String(1, ent->text); writeDouble(50, ent->angle); writeDouble(41, ent->widthscale); writeDouble(51, ent->oblique); if (afterAC1009) { writeUtf8String(7, ent->style); } else { writeUtf8Caps(7, ent->style); } writeInt16(71, ent->textgen); if (ent->alignH != DRW_Text::HLeft) { writeInt16(72, ent->alignH); } if (ent->alignH != DRW_Text::HLeft || ent->alignV != DRW_Text::VBaseLine) { writeCoord(11, ent->secPoint); } writeCoord(210, ent->extPoint); if (afterAC1009) { writeSubClass("Text"); } if (ent->alignV != DRW_Text::VBaseLine) { writeInt16(73, ent->alignV); } return true; } bool dxfRW::writeMText(DRW_MText *ent){ if (afterAC1009) { writeName("MTEXT"); writeEntity(ent); writeSubClass("MText"); writeCoord(10, ent->basePoint); writeDouble(40, ent->height); writeDouble(41, ent->widthscale); writeInt16(71, ent->textgen); writeInt16(72, ent->alignH); std::string text = writer->fromUtf8String(ent->text); int i; for(i =0; (text.size()-i) > 250; ) { writeString(3, text.substr(i, 250)); i +=250; } writeString(1, text.substr(i)); writeString(7, ent->style); writeCoord(210, ent->extPoint); writeDouble(50, ent->angle); writeInt16(73, ent->alignV); writeDouble(44, ent->interlin); //RLZ ... 11, 21, 31 needed? } else { //RLZ: TODO convert mtext in text lines (not exist in acad 12) } return true; } bool dxfRW::writeViewport(DRW_Viewport *ent) { writeName( "VIEWPORT"); writeEntity(ent); writeSubClassOpt("Viewport"); writeCoord(10, ent->basePoint); writeDouble(40, ent->pswidth); writeDouble(41, ent->psheight); writeInt16(68, ent->vpstatus); writeInt16(69, ent->vpID); writeDouble(12, ent->centerPX);//RLZ: verify if exist in V12 writeDouble(22, ent->centerPY);//RLZ: verify if exist in V12 return true; } DRW_ImageDef* dxfRW::writeImage(DRW_Image *ent, std::string name){ if (afterAC1009) { //search if exist imagedef with this mane (image inserted more than 1 time) //RLZ: imagedef_reactor seem needed to read in acad DRW_ImageDef *id = nullptr; size_t size = imageDef.size(); for (unsigned int i=0; iname == name ) { id = image_def; continue; // fixme sand - why it is so? } } if (id == nullptr) { id = new DRW_ImageDef(); imageDef.push_back(id); id->handle = ++entCount; } id->name = name; std::string idReactor = toHexStr(++entCount); writeName("IMAGE"); writeEntity(ent); writeSubClass("RasterImage"); writeCoord(10, ent->basePoint); writeCoord(11, ent->secPoint); writeCoord(12, ent->vVector); writeDouble(13, ent->sizeu); writeDouble(23, ent->sizev); writeString(340, toHexStr(id->handle)); writeInt16(70, 1); writeInt16(280, ent->clip); writeInt16(281, ent->brightness); writeInt16(282, ent->contrast); writeInt16(283, ent->fade); writeString(360, idReactor); id->reactors[idReactor] = toHexStr(ent->handle); return id; } return nullptr; //not exist in acad 12 } bool dxfRW::writeBlockRecord(std::string name){ if (afterAC1009) { writeName("BLOCK_RECORD"); writeString(5, toHexStr(++entCount)); // Handle (all except DIMSTYLE) m_writingContext.blockMap[name] = entCount; entCount = 2+entCount;//reserve 2 for BLOCK & ENDBLOCK if (afterAC1014) { writeString(330, "1"); // Soft-pointer ID/handle to owner object } writeSymTypeRecord("Block"); writeUtf8String(2, name); //Block name if (afterAC1018) { // writeInt16(340, 22); // Hard-pointer ID/handle to associated LAYOUT object writeInt16(70, 0); // Block insertion units. writeInt16(280, 1); // Block explodability writeInt16(281, 0); // Block scalability } } return true; } bool dxfRW::writeBlock(DRW_Block *bk){ if (writingBlock) { writeName("ENDBLK"); if (afterAC1009) { writeString(5, toHexStr(currHandle+2)); if (afterAC1014) { writeString(330, toHexStr(currHandle)); } writeSubClass("Entity"); } writeString(8, "0"); writeSubClassOpt("BlockEnd"); } writingBlock = true; writeName("BLOCK"); if (afterAC1009) { currHandle = (*(m_writingContext.blockMap.find(bk->name))).second; writeString(5, toHexStr(currHandle+1)); if (afterAC1014) { writeString(330, toHexStr(currHandle)); } writeSubClass("Entity"); } writeString(8, "0"); if (afterAC1009) { writeSubClass("BlockBegin"); writeUtf8String(2, bk->name); } else { writeUtf8Caps(2, bk->name); } writeInt16(70, bk->flags); writeCoord(10, bk->basePoint); if (afterAC1009) { writeUtf8String(3, bk->name); } else { writeUtf8Caps(3, bk->name); } if(afterAC1014) { writeAppData(bk->appData); } writeString(1, ""); return true; } void dxfRW::writeViewPortTable() { writeTableStart("VPORT", "8", 1); dimstyleStd =false; iface->writeVports(); if (!dimstyleStd) { DRW_Vport portact; portact.name = "*ACTIVE"; writeVport(&portact); } writeTableEnd(); } void dxfRW::writeLayerTable() { writeTableStart("LAYER", "2", 1); wlayer0 = false; iface->writeLayers(); if (!wlayer0) { DRW_Layer lay0; lay0.name = "0"; writeLayer(&lay0); } writeTableEnd(); } void dxfRW::writeLineTypeTable() { writeTableStart("LTYPE", "5", 4); //Mandatory linetypes DRW_LType lt; lt.reset(); lt.name = "ByBlock"; writeLineTypeGenerics(<, 20); writeInt16(70, 0); writeString(3, ""); writeInt16(72, 65); writeInt16(73, 0); writeDouble(40, 0.0); lt.name = "ByLayer"; writeLineTypeGenerics(<, 21); writeInt16(70, 0); writeString(3, ""); writeInt16(72, 65); writeInt16(73, 0); writeDouble(40, 0.0); lt.name = "Continuous"; writeLineTypeGenerics(<, 22); writeInt16(70, 0); writeString(3, "Solid line"); writeInt16(72, 65); writeInt16(73, 0); writeDouble(40, 0.0); //Application linetypes iface->writeLTypes(); writeTableEnd(); } void dxfRW::writeStyleTable() { writeTableStart("STYLE", "3", 3); dimstyleStd =false; iface->writeTextstyles(); if (!dimstyleStd) { DRW_Textstyle tsty; tsty.name = "Standard"; writeTextstyle(&tsty); } writeTableEnd(); } void dxfRW::writeUCSTable() { writeTableStart("UCS", "7", 0); iface->writeUCSs(); writeTableEnd(); } void dxfRW::writeViewTable() { writeTableStart("VIEW", "6", 0); iface->writeViews(); writeTableEnd(); } void dxfRW::writeAppIdTable() { writeTableStart("APPID", "9", 1); writeName("APPID"); if (afterAC1009) { writeString(5, "12"); if (afterAC1014) { writeString(330, "9"); } writeSymTypeRecord("RegApp"); } writeString(2, "ACAD"); writeInt16(70, 0); iface->writeAppId(); writeTableEnd(); } void dxfRW::writeBlockRecordTable() { if (afterAC1009) { writeTableName("BLOCK_RECORD"); writeString(5, "1"); if (afterAC1014) { writeString(330, "0"); } writeSymTable(); writeInt16(70, 2); //end table def writeName("BLOCK_RECORD"); writeString(5, "1F"); if (afterAC1014) { writeString(330, "1"); } writeSymTypeRecord("Block"); writeString(2, "*Model_Space"); if (afterAC1018) { // writeInt16(340, 22); writeInt16(70, 0); writeInt16(280, 1); writeInt16(281, 0); } writeName("BLOCK_RECORD"); writeString(5, "1E"); if (afterAC1014) { writeString(330, "1"); } writeSymTypeRecord("Block"); writeString(2, "*Paper_Space"); if (afterAC1018) { // writeInt16(340, 22); writeInt16(70, 0); writeInt16(280, 1); writeInt16(281, 0); } } /* always call writeBlockRecords to iface for prepare unnamed blocks */ iface->writeBlockRecords(); if (afterAC1009) { writeTableEnd(); } } void dxfRW::writeDimStyleTable() { writeTableStart("DIMSTYLE", "A", 1); if (afterAC1014) { writeSubClass("DimStyleTable"); writeInt16(71, 1); //end table def } // dimstyleStd =false; iface->writeDimstyles(); writeTableEnd(); } bool dxfRW::writeTables() { writeViewPortTable(); writeLineTypeTable(); writeLayerTable(); writeStyleTable(); writeUCSTable(); writeViewTable(); writeAppIdTable(); writeBlockRecordTable(); writeDimStyleTable(); return true; } bool dxfRW::writeBlocks() { writeName("BLOCK"); if (afterAC1009) { writeString(5, "20"); if (afterAC1014) { writeString(330, "1F"); } writeSubClass("Entity"); } writeString(8, "0"); if (afterAC1009) { writeSubClass("BlockBegin"); writeString(2, "*Model_Space"); } else writeString(2, "$MODEL_SPACE"); writeInt16(70, 0); writeDouble(10, 0.0); writeDouble(20, 0.0); writeDouble(30, 0.0); if (afterAC1009) writeString(3, "*Model_Space"); else writeString(3, "$MODEL_SPACE"); writeString(1, ""); writeName("ENDBLK"); if (afterAC1009) { writeString(5, "21"); if (afterAC1014) { writeString(330, "1F"); } writeSubClass("Entity"); } writeString(8, "0"); if (afterAC1009) writeSubClass("BlockEnd"); writeName("BLOCK"); if (afterAC1009) { writeString(5, "1C"); if (afterAC1014) { writeString(330, "1B"); } writeSubClass("Entity"); } writeString(8, "0"); if (afterAC1009) { writeSubClass("BlockBegin"); writeString(2, "*Paper_Space"); } else writeString(2, "$PAPER_SPACE"); writeInt16(70, 0); writeDouble(10, 0.0); writeDouble(20, 0.0); writeDouble(30, 0.0); if (afterAC1009) writeString(3, "*Paper_Space"); else writeString(3, "$PAPER_SPACE"); writeString(1, ""); writeName( "ENDBLK"); if (afterAC1009) { writeString(5, "1D"); if (afterAC1014) { writeString(330, "1F"); } writeSubClass("Entity"); } writeString(8, "0"); if (afterAC1009) writeSubClass("BlockEnd"); writingBlock = false; iface->writeBlocks(); if (writingBlock) { writingBlock = false; writeName( "ENDBLK"); if (afterAC1009) { writeString(5, toHexStr(currHandle+2)); // writeString(5, "1D"); if (afterAC1014) { writeString(330, toHexStr(currHandle)); } writeSubClass("Entity"); } writeString(8, "0"); if (afterAC1009) writeSubClass("BlockEnd"); } return true; } bool dxfRW::writeObjects() { writeName("DICTIONARY"); std::string imgDictH; writeString(5, "C"); if (afterAC1014) { writeString(330, "0"); } writeSubClass("Dictionary"); writeInt16(281, 1); writeString(3, "ACAD_GROUP"); writeString(350, "D"); if (!imageDef.empty()) { writeString(3, "ACAD_IMAGE_DICT"); imgDictH = toHexStr(++entCount); writeString(350, imgDictH); } writeName("DICTIONARY"); writeString(5, "D"); writeString(330, "C"); writeSubClass("Dictionary"); writeInt16(281, 1); //write IMAGEDEF_REACTOR for (unsigned int i=0; ireactors.begin() ; it != id->reactors.end(); ++it ) { writeName( "IMAGEDEF_REACTOR"); writeString(5, (*it).first); writeString(330, (*it).second); writeSubClass("RasterImageDefReactor"); writeInt16(90, 2); //version 2=R14 to v2010 writeString(330, (*it).second); } } if (!imageDef.empty()) { writeName("DICTIONARY"); writeString(5, imgDictH); writeString(330, "C"); writeSubClass("Dictionary"); writeInt16(281, 1); for (unsigned int i=0; iname.find_last_of("/\\"); f2 =imageDef.at(i)->name.find_last_of('.'); ++f1; writeString(3, imageDef.at(i)->name.substr(f1,f2-f1)); writeString(350, toHexStr(imageDef.at(i)->handle) ); } } for (unsigned int i=0; ihandle) ); if (afterAC1014) { // writeString(330, "0"); handle to DICTIONARY } writeString(102, "{ACAD_REACTORS"); for (auto it=id->reactors.begin() ; it != id->reactors.end(); ++it ) { writeString(330, (*it).first); } writeString(102, "}"); writeSubClass("RasterImageDef"); writeInt16(90, 0); //version 0=R14 to v2010 writeUtf8String(1, id->name); writeDouble(10, id->u); writeDouble(20, id->v); writeDouble(11, id->up); writeDouble(21, id->vp); writeInt16(280, id->loaded); writeInt16(281, id->resolution); } //no more needed imageDef, delete it while (!imageDef.empty()) { imageDef.pop_back(); } iface->writeObjects(); return true; } bool dxfRW::writeExtData(const std::vector &ed){ for (auto it=ed.begin(); it!=ed.end(); ++it){ switch ((*it)->code()) { case 1000: case 1001: case 1002: case 1003: case 1004: case 1005: { int cc = (*it)->code(); if ((*it)->type() == DRW_Variant::STRING) writeUtf8String(cc, *(*it)->content.s); // writeUtf8String((*it)->code, (*it)->content.s); break; } case 1010: case 1011: case 1012: case 1013: if ((*it)->type() == DRW_Variant::COORD) { writeDouble((*it)->code(), (*it)->content.v->x); writeDouble((*it)->code() + 10, (*it)->content.v->y); writeDouble((*it)->code() + 20, (*it)->content.v->z); } break; case 1040: case 1041: case 1042: if ((*it)->type() == DRW_Variant::DOUBLE) writeDouble((*it)->code(), (*it)->content.d); break; case 1070: if ((*it)->type() == DRW_Variant::INTEGER) writeInt16((*it)->code(), (*it)->content.i); break; case 1071: if ((*it)->type() == DRW_Variant::INTEGER) writeInt32((*it)->code(), (*it)->content.i); break; default: break; } } return true; } /********* Reader Process *********/ bool dxfRW::processDxf() { DRW_DBG("dxfRW::processDxf() start processing dxf\n"); int code {-1}; bool inSection {false}; reader->setIgnoreComments( false); while (readRec(&code)) { DRW_DBG(code); DRW_DBG(" code\n"); /* at this level we should only get: 999 - Comment 0 - SECTION or EOF 2 - section name everything else between "2 - section name" and "0 - ENDSEC" is handled in process() methods */ switch (code) { case 999: { // when DXF was created by libdxfrw, first record is a comment with dxfrw version info header.addComment(getString()); continue; } case 0: { // ignore further comments, as libdxfrw doesn't support comments in sections reader->setIgnoreComments(true); if (!inSection) { std::string sectionstr{getString()}; if ("SECTION" == sectionstr) { DRW_DBG(sectionstr); DRW_DBG(" new section\n"); inSection = true; continue; } if ("EOF" == sectionstr) { return true; //found EOF terminate } } else { // in case SECTION was unknown or not supported if ("ENDSEC" == getString()) { inSection = false; } } break; } case 2: { if (inSection) { bool processed{false}; std::string sectionname{getString()}; DRW_DBG(sectionname); DRW_DBG(" process section\n"); if ("HEADER" == sectionname) { processed = processHeader(); } else if ("TABLES" == sectionname) { processed = processTables(); } else if ("BLOCKS" == sectionname) { processed = processBlocks(); } else if ("ENTITIES" == sectionname) { processed = processEntities(false); } else if ("OBJECTS" == sectionname) { processed = processObjects(); } else { //TODO handle CLASSES DRW_DBG(sectionname); DRW_DBG(" section unknown or not supported\n"); continue; } if (!processed) { DRW_DBG(" failed\n"); return setError(DRW::BAD_READ_SECTION); } inSection = false; } continue; } default: // landing here means an unknown or not supported SECTION inSection = false; break; } } if (0 == code && "EOF" == getString()) { // in case the final EOF has no newline we end up here! // this is caused by filestr->good() which is false for missing newline on EOF return true; } return setError(DRW::BAD_UNKNOWN); } /********* Header Section *********/ bool dxfRW::processHeader() { DRW_DBG("dxfRW::processHeader\n"); int code; std::string sectionstr; while (readRec(&code)) { DRW_DBG(code); DRW_DBG(" processHeader\n"); if (code == 0) { sectionstr = getString(); DRW_DBG(sectionstr); DRW_DBG(" processHeader\n\n"); if (sectionstr == "ENDSEC") { iface->addHeader(&header); return true; //found ENDSEC terminate } DRW_DBG("unexpected 0 code in header!\n"); return setError(DRW::BAD_READ_HEADER); } if (!header.parseCode(code, reader)) { return setError( DRW::BAD_CODE_PARSED); } } return setError(DRW::BAD_READ_HEADER); } /********* Tables Section *********/ bool dxfRW::processTables() { DRW_DBG("dxfRW::processTables\n"); int code; std::string sectionstr; bool more = true; std::vector dimstyles; while (readRec(&code)) { DRW_DBG(code); DRW_DBG("\n"); if (code == 0) { sectionstr = getString(); DRW_DBG(sectionstr); DRW_DBG(" processTables\n\n"); if (sectionstr == "TABLE") { more = readRec(&code); DRW_DBG(code); DRW_DBG("\n"); if (!more) { return setError(DRW::BAD_READ_TABLES); //wrong dxf file } if (code == 2) { sectionstr = getString(); DRW_DBG(sectionstr); DRW_DBG(" processTables\n\n"); //found section, process it if (sectionstr == "LTYPE") { processLType(); } else if (sectionstr == "LAYER") { processLayer(); } else if (sectionstr == "STYLE") { processTextStyle(); } else if (sectionstr == "VPORT") { processVports(); } else if (sectionstr == "VIEW") { processView(); } else if (sectionstr == "UCS") { processUCS(); } else if (sectionstr == "APPID") { processAppId(); } else if (sectionstr == "DIMSTYLE") { processDimStyle(dimstyles); } else if (sectionstr == "BLOCK_RECORD") { processBlockRecord(); } } } else if (sectionstr == "ENDSEC") { for (auto it=dimstyles.begin(); it!=dimstyles.end(); ++it) { it->resolveRefs(m_readingContext); iface->addDimStyle(*it); } return true; //found ENDSEC terminate } } } return setError(DRW::BAD_READ_TABLES); } bool dxfRW::processBlockRecord() { DRW_DBG("dxfRW::processBlockRecord"); DRW_Block_Record blockRecord; return doProcessTableEntry("BLOCK_RECORD", blockRecord, [this](DRW_TableEntry* r){ auto br = static_cast(r); duint32 handle = br->handle; m_readingContext.blockRecordMap[handle] = br; }, false); } bool dxfRW::processUCS(){ DRW_DBG("dxfRW::processUCS\n"); DRW_UCS ucs; return doProcessTableEntry("UCS", ucs, [this](DRW_TableEntry* e){ auto ent = static_cast(e); iface->addUCS(*ent); }); } bool dxfRW::processView() { DRW_DBG("dxfRW::processView\n"); DRW_View view; return doProcessTableEntry("VIEW", view, [this](DRW_TableEntry* e){ auto ent = static_cast(e); iface->addView(*ent); }); } bool dxfRW::processLType() { DRW_DBG("dxfRW::processLType\n"); DRW_LType ltype; return doProcessTableEntry("LTYPE", ltype, [this](DRW_TableEntry* l){ auto ltp = static_cast(l); ltp->update(); int handle = ltp->handle; m_readingContext.lineTypeMap[handle] = ltp; iface->addLType(*ltp); }, false); } bool dxfRW::processLayer() { DRW_DBG("dxfRW::processLayer\n"); DRW_Layer layer; return doProcessTableEntry("LAYER", layer, [this](DRW_TableEntry* l){ auto layer = static_cast(l); iface->addLayer(*layer); }); } bool dxfRW::processDimStyle(std::vector& styles) { DRW_DBG("dxfRW::processDimStyle"); DRW_Dimstyle dimSty; return doProcessTableEntry("DIMSTYLE", dimSty, [&styles](DRW_TableEntry* e){ auto ent = static_cast(e); styles.push_back(*ent); }, false); } bool dxfRW::doProcessTableEntry(const std::string §ionName, DRW_TableEntry& startEntry, DRW_TableEntryFunc applyFunc, bool reuseEntity) { DRW_DBG("dxfRW::processLayer\n"); int code; std::string sectionstr; bool reading = false; DRW_TableEntry* entry; if (reuseEntity) { entry = &startEntry; } else { entry = startEntry.newInstance(); } while (readRec(&code)) { DRW_DBG(code); DRW_DBG("\n"); if (code == 0) { if (reading) { applyFunc(entry); } sectionstr = getString(); DRW_DBG(sectionstr); DRW_DBG("\n"); if (sectionstr == sectionName) { reading = true; if (reuseEntity) { entry->reset(); } else { entry = entry->newInstance(); } } else if (sectionstr == "ENDTAB") { return true; //found ENDTAB terminate } } else if (reading) { if (!entry->parseCode(code, reader)) { if (!reuseEntity) { delete entry; } return setError( DRW::BAD_CODE_PARSED); } } } return setError(DRW::BAD_READ_TABLES); } bool dxfRW::processTextStyle(){ DRW_DBG("dxfRW::processTextStyle"); int code; std::string sectionstr; bool reading = false; auto* textStyle = new DRW_Textstyle; while (readRec(&code)) { DRW_DBG(code); DRW_DBG("\n"); if (code == 0) { if (reading) { m_readingContext.textStyles[textStyle->handle] = textStyle; iface->addTextStyle(*textStyle); } sectionstr = getString(); DRW_DBG(sectionstr); DRW_DBG("\n"); if (sectionstr == "STYLE") { reading = true; textStyle = new DRW_Textstyle(); } else if (sectionstr == "ENDTAB") { return true; //found ENDTAB terminate } } else if (reading) { if (!textStyle->parseCode(code, reader)) { return setError( DRW::BAD_CODE_PARSED); } } } return setError(DRW::BAD_READ_TABLES); } bool dxfRW::processVports(){ DRW_DBG("dxfRW::processVports"); DRW_Vport vp; return doProcessTableEntry("VPORT", vp, [this](DRW_TableEntry* e){ auto ent = static_cast(e); iface->addVport(*ent); }); } bool dxfRW::processAppId(){ DRW_DBG("dxfRW::processAppId"); DRW_AppId vp; return doProcessTableEntry("APPID", vp, [this](DRW_TableEntry* e){ auto ent = static_cast(e); iface->addAppId(*ent); }); } /********* Block Section *********/ bool dxfRW::processBlocks() { DRW_DBG("dxfRW::processBlocks\n"); int code; std::string sectionstr; while (readRec(&code)) { DRW_DBG(code); DRW_DBG("\n"); if (code == 0) { sectionstr = getString(); DRW_DBG(sectionstr); DRW_DBG("\n"); if (sectionstr == "BLOCK") { processBlock(); } else if (sectionstr == "ENDSEC") { return true; //found ENDSEC terminate } } } return setError(DRW::BAD_READ_BLOCKS); } bool dxfRW::processBlock() { DRW_DBG("dxfRW::processBlock"); DRW_Block block; return doProcessParseable(block, [this](DRW_ParseableEntity* e) { auto ent = static_cast(e); iface->addBlock(*ent); if (nextentity == "ENDBLK") { //found ENDBLK, terminate iface->endBlock(); } else { processEntities(true); iface->endBlock(); } },DRW::BAD_READ_BLOCKS); } /********* Entities Section *********/ bool dxfRW::processEntities(bool isblock) { DRW_DBG("dxfRW::processEntities\n"); int code; if (!readRec(&code)){ return setError(DRW::BAD_READ_ENTITIES); } if (code == 0) { nextentity = getString(); } else if (!isblock) { return setError(DRW::BAD_READ_ENTITIES); //first record in entities is 0 } bool processed {false}; do { if (nextentity == "ENDSEC" || nextentity == "ENDBLK") { return true; //found ENDSEC or ENDBLK terminate } if (nextentity == "LINE") { processed = processLine(); } else if (nextentity == "CIRCLE") { processed = processCircle(); } else if (nextentity == "ARC") { processed = processArc(); } else if (nextentity == "POINT") { processed = processPoint(); } else if (nextentity == "LWPOLYLINE") { processed = processLWPolyline(); } else if (nextentity == "POLYLINE") { processed = processPolyline(); }else if (nextentity == "TEXT") { processed = processText(); } else if (nextentity == "MTEXT") { processed = processMText(); } else if (nextentity == "HATCH") { processed = processHatch(); } else if (nextentity == "DIMENSION") { processed = processDimension(); } else if (nextentity == "INSERT") { processed = processInsert(); } else if (nextentity == "TOLERANCE") { processed = processTolerance(); } else if (nextentity == "SOLID") { processed = processSolid(); }else if (nextentity == "SPLINE") { processed = processSpline(); }else if (nextentity == "LEADER") { processed = processLeader(); } else if (nextentity == "ELLIPSE") { processed = processEllipse(); } else if (nextentity == "VIEWPORT") { processed = processViewport(); } else if (nextentity == "IMAGE") { processed = processImage(); } else if (nextentity == "TRACE") { processed = processTrace(); } else if (nextentity == "3DFACE") { processed = process3dface(); } else if (nextentity == "RAY") { processed = processRay(); } else if (nextentity == "XLINE") { processed = processXline(); } else if (nextentity == "ARC_DIMENSION") { processed = processArcDimension(); } else { if (!readRec(&code)) { return setError(DRW::BAD_READ_ENTITIES); //end of file without ENDSEC } if (code == 0) { nextentity = getString(); } processed = true; } } while (processed); return setError(DRW::BAD_READ_ENTITIES); } bool dxfRW::doProcessEntity(DRW_Entity& ent, DRW_EntityFunc applyFunc) { int code; while (readRec(&code)) { DRW_DBG(code); DRW_DBG("\n"); if (0 == code) { nextentity = getString(); DRW_DBG(nextentity); DRW_DBG("\n"); if (applyExt) { ent.applyExtrusion(); } applyFunc(&ent); return true; //found new entity or ENDSEC, terminate } if (!ent.parseCode(code, reader)) { return setError( DRW::BAD_CODE_PARSED); } } return setError(DRW::BAD_READ_ENTITIES); } bool dxfRW::doProcessParseable(DRW_ParseableEntity &ent, DRW_ParseableFunc applyFunc, const DRW::error sectionError) { int code; while (readRec(&code)) { DRW_DBG(code); DRW_DBG("\n"); if (0 == code) { nextentity = getString(); DRW_DBG(nextentity); DRW_DBG("\n"); applyFunc(&ent); return true; //found new entity or ENDSEC, terminate } if (!ent.parseCode(code, reader)) { return setError( DRW::BAD_CODE_PARSED); } } return setError(sectionError); } bool dxfRW::processEllipse() { DRW_DBG("dxfRW::processEllipse"); DRW_Ellipse ellipse; return doProcessEntity(ellipse, [this](DRW_Entity* e){ auto ent = static_cast(e); iface->addEllipse(*ent); }); } bool dxfRW::processTrace() { DRW_DBG("dxfRW::processTrace"); DRW_Trace trace; return doProcessEntity(trace,[this](DRW_Entity* e){ auto ent = static_cast(e); iface->addTrace(*ent); }); } bool dxfRW::processSolid() { DRW_DBG("dxfRW::processSolid"); DRW_Solid solid; return doProcessEntity(solid,[this](DRW_Entity* e){ auto ent = static_cast(e); iface->addSolid(*ent); }); } bool dxfRW::process3dface() { DRW_DBG("dxfRW::process3dface"); DRW_3Dface face; return doProcessParseable(face,[this](DRW_ParseableEntity* e){ auto ent = static_cast(e); iface->add3dFace(*ent); }); } bool dxfRW::processViewport() { DRW_DBG("dxfRW::processViewport"); DRW_Viewport vp; return doProcessParseable(vp,[this](DRW_ParseableEntity* e){ auto ent = static_cast(e); iface->addViewport(*ent); }); } bool dxfRW::processPoint() { DRW_DBG("dxfRW::processPoint\n"); DRW_Point point; return doProcessParseable(point,[this](DRW_ParseableEntity* e){ auto ent = static_cast(e); iface->addPoint(*ent); }); } bool dxfRW::processLine() { DRW_DBG("dxfRW::processLine\n"); DRW_Line line; return doProcessParseable(line, [this](DRW_ParseableEntity* e){ auto ent = static_cast(e); iface->addLine(*ent); }); } bool dxfRW::processRay() { DRW_DBG("dxfRW::processRay\n"); DRW_Ray line; return doProcessParseable(line,[this](DRW_ParseableEntity* e){ auto ent = static_cast(e); iface->addRay(*ent); }); } bool dxfRW::processXline() { DRW_DBG("dxfRW::processXline\n"); DRW_Xline line; return doProcessParseable(line,[this](DRW_ParseableEntity* e){ auto ent = static_cast(e); iface->addXline(*ent); }); } bool dxfRW::processCircle() { DRW_DBG("dxfRW::processPoint\n"); DRW_Circle circle; return doProcessEntity(circle, [this](DRW_Entity* e){ auto ent = static_cast(e); iface->addCircle(*ent); }); } bool dxfRW::processArc() { DRW_DBG("dxfRW::processPoint\n"); DRW_Arc arc; return doProcessEntity(arc, [this](DRW_Entity* e){ auto ent = static_cast(e); iface->addArc(*ent); }); } bool dxfRW::processInsert() { DRW_DBG("dxfRW::processInsert"); DRW_Insert insert; return doProcessParseable(insert,[this](DRW_ParseableEntity* e){ auto ent = static_cast(e); iface->addInsert(*ent); }); } bool dxfRW::processLWPolyline() { DRW_DBG("dxfRW::processLWPolyline"); DRW_LWPolyline pl; return doProcessEntity(pl, [this](DRW_Entity* e){ auto ent = static_cast(e); iface->addLWPolyline(*ent); }); } bool dxfRW::processPolyline() { DRW_DBG("dxfRW::processPolyline"); int code; DRW_Polyline pl; while (readRec(&code)) { DRW_DBG(code); DRW_DBG("\n"); if (0 == code) { nextentity = getString(); DRW_DBG(nextentity); DRW_DBG("\n"); if (nextentity != "VERTEX") { iface->addPolyline(pl); return true; //found new entity or ENDSEC, terminate } if (!processVertex(&pl)) { return false; }; } if (!pl.parseCode(code, reader)) { //parseCode just initialize the members of pl return setError(DRW::BAD_CODE_PARSED); } } return setError(DRW::BAD_READ_ENTITIES); } bool dxfRW::processVertex(DRW_Polyline *pl) { DRW_DBG("dxfRW::processVertex"); int code; auto v = std::make_shared(); while (readRec(&code)) { DRW_DBG(code); DRW_DBG("\n"); if(0 == code) { pl->appendVertex(v); nextentity = getString(); DRW_DBG(nextentity); DRW_DBG("\n"); if (nextentity == "SEQEND") { return true; //found SEQEND no more vertex, terminate } if (nextentity == "VERTEX"){ v = std::make_shared(); //another vertex } } if (!v->parseCode(code, reader)) { //the members of v are reinitialized here return setError(DRW::BAD_CODE_PARSED); } } return setError(DRW::BAD_READ_ENTITIES); } bool dxfRW::processTolerance() { DRW_DBG("dxfRW::processTolerance\n"); DRW_Tolerance tol; return doProcessParseable(tol,[this](DRW_ParseableEntity* e){ auto ent = static_cast(e); iface->addTolerance(*ent); }); } bool dxfRW::processText() { DRW_DBG("dxfRW::processText"); DRW_Text txt; return doProcessParseable(txt,[this](DRW_ParseableEntity* e){ auto ent = static_cast(e); iface->addText(*ent); }); } bool dxfRW::processMText() { DRW_DBG("dxfRW::processMText"); DRW_MText txt; return doProcessParseable(txt,[this](DRW_ParseableEntity* e){ auto ent = static_cast(e); ent->updateAngle(); iface->addMText(*ent); }); } bool dxfRW::processHatch() { DRW_DBG("dxfRW::processHatch"); DRW_Hatch hatch; return doProcessParseable(hatch,[this](DRW_ParseableEntity* e){ auto ent = static_cast(e); iface->addHatch(ent); }); } bool dxfRW::processSpline() { DRW_DBG("dxfRW::processSpline"); DRW_Spline sp; return doProcessParseable(sp,[this](DRW_ParseableEntity* e){ auto ent = static_cast(e); iface->addSpline(ent); }); } bool dxfRW::processImage() { DRW_DBG("dxfRW::processImage"); DRW_Image img; return doProcessParseable(img,[this](DRW_ParseableEntity* e){ auto ent = static_cast(e); iface->addImage(ent); }); } bool dxfRW::processArcDimension() { DRW_DBG("dxfRW::processArcDimension"); int code; DRW_ArcDimension dim; while (readRec(&code)) { DRW_DBG(code); DRW_DBG("\n"); if (0 == code) { nextentity = getString(); DRW_DBG(nextentity); DRW_DBG("\n"); // fixme - sand - restore ARCDimension // iface->addArcDimension(&dim); return true; //found new entity or ENDSEC, terminate } if (!dim.parseCode(code, reader)) { return setError( DRW::BAD_CODE_PARSED); } } return setError(DRW::BAD_READ_ENTITIES); } bool dxfRW::processDimension() { DRW_DBG("dxfRW::processDimension"); DRW_Dimension dim; return doProcessParseable(dim,[this](DRW_ParseableEntity* e){ auto ent = static_cast(e); int type = ent->type & 0x0F; switch (type) { case 0: { DRW_DimLinear d(*ent); iface->addDimLinear(&d); break; } case 1: { DRW_DimAligned d(*ent); iface->addDimAlign(&d); break; } case 2: { DRW_DimAngular d(*ent); iface->addDimAngular(&d); break; } case 3: { DRW_DimDiametric d(*ent); iface->addDimDiametric(&d); break; } case 4: { DRW_DimRadial d(*ent); iface->addDimRadial(&d); break; } case 5: { DRW_DimAngular3p d(*ent); iface->addDimAngular3P(&d); break; } case 6: { DRW_DimOrdinate d(*ent); iface->addDimOrdinate(&d); break; } default: break; } }); } bool dxfRW::processLeader() { DRW_DBG("dxfRW::processLeader"); DRW_Leader leader; return doProcessParseable(leader,[this](DRW_ParseableEntity* e){ auto ent = static_cast(e); iface->addLeader(ent); return true; }); } /********* Objects Section *********/ bool dxfRW::processObjects() { DRW_DBG("dxfRW::processObjects\n"); int code; if (!readRec(&code) || 0 != code){ return setError(DRW::BAD_READ_OBJECTS); //first record in objects must be 0 } bool processed {false}; nextentity = getString(); do { if ("ENDSEC" == nextentity) { return true; //found ENDSEC terminate } if ("IMAGEDEF" == nextentity) { processed = processImageDef(); } else if ("PLOTSETTINGS" == nextentity) { processed = processPlotSettings(); } else { if (!readRec(&code)) { return setError(DRW::BAD_READ_OBJECTS); //end of file without ENDSEC } if (code == 0) { nextentity = getString(); } processed = true; } } while (processed); return setError(DRW::BAD_READ_OBJECTS); } bool dxfRW::processImageDef() { DRW_DBG("dxfRW::processImageDef"); DRW_ImageDef img; return doProcessParseable(img,[this](DRW_ParseableEntity* e){ auto ent = static_cast(e); iface->linkImage(ent); }); } bool dxfRW::processPlotSettings() { DRW_DBG("dxfRW::processPlotSettings"); DRW_PlotSettings ps; return doProcessParseable(ps,[this](DRW_ParseableEntity* e){ auto ent = static_cast(e); iface->addPlotSettings(ent); }); } bool dxfRW::writePlotSettings(DRW_PlotSettings *ent) { writeName("PLOTSETTINGS"); writeString(5, toHexStr(++entCount)); writeSubClass("PlotSettings"); writeUtf8String(6, ent->plotViewName); writeDouble(40, ent->marginLeft); writeDouble(41, ent->marginBottom); writeDouble(42, ent->marginRight); writeDouble(43, ent->marginTop); return true; } /** utility function * convert a int to string in hex **/ std::string dxfRW::toHexStr(int n){ #if defined(__APPLE__) char buffer[9]= {'\0'}; snprintf(buffer,9, "%X", n); return std::string(buffer); #else std::ostringstream Convert; Convert << std::uppercase << std::hex << n; return Convert.str(); #endif } int dxfRW::getBlockRecordHandleToWrite(const std::string &blockName) const { // fixme - sand - so far, the exact match of block it expected! // check whether case insensitive search is needed. If it is, the code should be like below... // std::string txstyname = blockName; // std::transform(txstyname.begin(), txstyname.end(), txstyname.begin(),::toupper); // if(blockMap.count(blockName) > 0) { // auto pair = blockMap.find(blockName); if(m_writingContext.blockMap.count(blockName) > 0) { auto pair = m_writingContext.blockMap.find(blockName); int blkHandle = pair->second; return blkHandle; } return -1; } int dxfRW::getTextStyleHandle(const std::string &styleName) const { if (!styleName.empty()) { auto name = styleName; std::transform(name.begin(), name.end(), name.begin(), toupper); if(m_writingContext.textStyleMap.count(name) > 0) { auto pair = m_writingContext.textStyleMap.find(name); int blkHandle = pair->second; return blkHandle; } } return -1; } DRW::Version dxfRW::getVersion() const { return version; } DRW::error dxfRW::getError() const{ return error; } // fixme - sand - add more informative errors collecting... bool dxfRW::setError(const DRW::error lastError){ error = lastError; return (DRW::BAD_NONE == error); } void dxfRW::setVersion(DRW::Version v) { version = v; afterAC1009 = v > DRW::AC1009; afterAC1012 = v > DRW::AC1012; afterAC1014 = v > DRW::AC1014; afterAC1015 = v > DRW::AC1015; afterAC1018 = v > DRW::AC1018; } bool dxfRW::writeString(int code, const std::string &text) { return writer->writeString(code, text); } bool dxfRW::writeDouble(int code, double d) { return writer->writeDouble(code, d); } bool dxfRW::writeDoubleOpt(int code, double d) { if (d != 0.0) { return writer->writeDouble(code, d); } return true; } bool dxfRW::writeUtf8String(int code, const std::string &text) { return writer->writeUtf8String(code, text); } bool dxfRW::writeUtf8Caps(int code, const std::string &text) { return writer->writeUtf8Caps(code, text); } bool dxfRW::writeHandle(int code, int handle) { return writer->writeString(code, toHexStr(handle)); } bool dxfRW::writeInt16(int code, int val) { return writer->writeInt16(code, val); } bool dxfRW::writeInt32(int code, int val) { return writer->writeInt32(code, val); } bool dxfRW::writeBool(int code, bool val) { return writer->writeBool(code, val); } bool dxfRW::readRec(int* codeData) { return reader->readRec(codeData); } std::string dxfRW::getString() { return reader->getString(); } void dxfRW::writeSectionStart(const std::string &name) { writeString(0, "SECTION"); writeString(2, name); } void dxfRW::writeSectionEnd() { writeString(0, "ENDSEC"); } void dxfRW::writeSymTypeRecord(const std::string &typeName) { writeString(100, "AcDbSymbolTableRecord"); writeString(100, "AcDb"+typeName+"TableRecord"); } void dxfRW::writeSubClass(const std::string &typeName) { writeString(100, "AcDb"+typeName); } void dxfRW::writeSubClassOpt(const std::string& name) { if (afterAC1009) { writeSubClass(name); } } void dxfRW::writeTableStart(const std::string &name, const std::string handle, int maxEntriesNumber, int handleCode) { writeTableName(name); if (afterAC1009) { writeString(handleCode, handle); if (afterAC1014) { writeString(330, "0"); } writeSymTable(); } writeInt16(70, maxEntriesNumber); //end table def } void dxfRW::writeTableName(const std::string &name) { writeString(0, "TABLE"); writeString(2, name); } void dxfRW::writeName(const std::string &name) { writeString(0, name); } void dxfRW::writeTableEnd() { writeString(0, "ENDTAB"); } void dxfRW::writeSymTable() { writeString(100, "AcDbSymbolTable"); } void dxfRW::writeCoord(int startCode, const DRW_Coord& coord) { writeDouble(startCode, coord.x); writeDouble(startCode + 10, coord.y); writeDoubleOpt(startCode + 20, coord.z); } // code 40 void dxfRW::writeVar( const std::string &name, double defaultValue, int varCode) { double varDouble; writeString(9, name); if (header.getDouble(name, &varDouble)) { writeDouble(varCode, varDouble); } else { writeDouble(varCode, defaultValue); } } // varcode 70 void dxfRW::writeVar( const std::string &name, int defaultValue, int varCode) { int varInt; writeString(9, name); if (header.getInt(name, &varInt)) { writeInt16(varCode, varInt); } else { writeInt16(varCode, defaultValue); } } void dxfRW::writeVarExp( const std::string &name, int value, int varCode) { writeString(9, name); writeInt16(varCode, value); } void dxfRW::writeVarOpt(const std::string& name, int varCode) { int varInt; if (header.getInt(name, &varInt)) { writeString(9, name); writeInt16(varCode, varInt); } } // varcode 1 void dxfRW::writeVar(const std::string &name, const std::string &defaultValue, int varCode) { std::string varStr; writeString(9, name); if (header.getStr(name, &varStr)) { if (version == DRW::AC1009) { writeUtf8Caps(varCode, varStr); } else { writeUtf8String(varCode, varStr); } } else { writeString(varCode, defaultValue); } } void dxfRW::writeVar(const std::string& name, int startCode,const DRW_Coord& defaultCoord) { writer->writeString(9, name); DRW_Coord varCoord; if (header.getCoord(name, &varCoord)) { writer->writeDouble(startCode, varCoord.x); writer->writeDouble(startCode + 10, varCoord.y); writer->writeDouble(startCode + 20, varCoord.z); } else { writer->writeDouble(startCode, defaultCoord.x); writer->writeDouble(startCode + 10,defaultCoord.y); writer->writeDouble(startCode + 20,defaultCoord.z); } } void dxfRW::writeVar2D(const std::string& name, int startCode, const DRW_Coord& defaultCoord) { writer->writeString(9, name); DRW_Coord varCoord; if (header.getCoord(name, &varCoord)) { writer->writeDouble(startCode, varCoord.x); writer->writeDouble(startCode + 10, varCoord.y); } else { writer->writeDouble(startCode, defaultCoord.x); writer->writeDouble(startCode + 10,defaultCoord.y); } } void dxfRW::writeVar2DOpt(const std::string& name, int startCode) { DRW_Coord varCoord; if (header.getCoord(name, &varCoord)) { writer->writeString(9, name); writer->writeDouble(startCode, varCoord.x); writer->writeDouble(startCode + 10, varCoord.y); } }