3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // Portions copyright (C) 2001-2003 RibbonSoft
7 // Copyright (C) 2010 Underground Software
8 // See the README and GPLv2 files for licensing and warranty information
10 // JLH = James L. Hammons <jlhamm@acm.org>
13 // --- ---------- -----------------------------------------------------------
14 // JLH 05/28/2010 Added this text. :-)
17 #include "filterdxf.h"
21 #include "dl_attributes.h"
23 #include "dl_writer_ascii.h"
24 #include "dimaligned.h"
25 #include "dimangular.h"
26 #include "dimdiametric.h"
27 #include "dimlinear.h"
28 #include "dimradial.h"
35 * Default constructor.
38 FilterDXF::FilterDXF(): FilterInterface()
40 DEBUG->print("FilterDXF::FilterDXF()");
42 addImportFormat(RS2::FormatDXF);
43 addExportFormat(RS2::FormatDXF);
44 addExportFormat(RS2::FormatDXF12);
51 currentContainer = NULL;
53 //exportVersion = DL_Codes::VER_2002;
54 //systemVariables.setAutoDelete(true);
55 DEBUG->print("FilterDXF::FilterDXF(): OK");
61 FilterDXF::~FilterDXF()
63 DEBUG->print("FilterDXF::~FilterDXF()");
64 DEBUG->print("FilterDXF::~FilterDXF(): OK");
68 * Implementation of the method used for RS_Import to communicate
71 * @param g The graphic in which the entities from the file
72 * will be created or the graphics from which the entities are
73 * taken to be stored in a file.
75 bool FilterDXF::fileImport(Drawing & g, const QString & file, RS2::FormatType /*type*/)
77 DEBUG->print("FilterDXF::fileImport");
80 DEBUG->print("DXF Filter: importing file '%s'...", (const char *)QFile::encodeName(file));
83 currentContainer = graphic;
86 DEBUG->print("graphic->countLayers(): %d", graphic->countLayers());
88 //graphic->setAutoUpdateBorders(false);
89 DEBUG->print("FilterDXF::fileImport: reading file");
90 bool success = dxf.in((const char *)QFile::encodeName(file), this);
91 DEBUG->print("FilterDXF::fileImport: reading file: OK");
92 //graphic->setAutoUpdateBorders(true);
96 DEBUG->print(Debug::D_WARNING, "Cannot open DXF file '%s'.",
97 (const char *)QFile::encodeName(file));
101 DEBUG->print("FilterDXF::fileImport: adding variables");
103 // add some variables that need to be there for DXF drawings:
104 if (graphic->getVariableString("$DIMSTYLE", "").isEmpty())
106 DEBUG->print("FilterDXF::fileImport: adding DIMSTYLE");
107 graphic->addVariable("$DIMSTYLE", "Standard", 2);
108 DEBUG->print("FilterDXF::fileImport: adding DIMSTYLE: OK");
111 DEBUG->print("FilterDXF::fileImport: adding variables: OK");
113 DEBUG->print("FilterDXF::fileImport: updating inserts");
114 graphic->updateInserts();
115 DEBUG->print("FilterDXF::fileImport: updating inserts: OK");
117 DEBUG->print("FilterDXF::fileImport OK");
118 //DEBUG->timestamp();
124 * Implementation of the method which handles layers.
126 void FilterDXF::addLayer(const DL_LayerData& data) {
127 DEBUG->print("FilterDXF::addLayer");
128 DEBUG->print(" adding layer: %s", data.name.c_str());
130 DEBUG->print("FilterDXF::addLayer: creating layer");
131 Layer* layer = new Layer(data.name.c_str());
132 DEBUG->print("FilterDXF::addLayer: set pen");
133 layer->setPen(attributesToPen(attributes));
134 //layer->setFlags(data.flags&0x07);
136 DEBUG->print("FilterDXF::addLayer: flags");
137 if (data.flags&0x01) {
140 if (data.flags&0x04) {
144 DEBUG->print("FilterDXF::addLayer: add layer to graphic");
145 graphic->addLayer(layer);
146 DEBUG->print("FilterDXF::addLayer: OK");
150 * Implementation of the method which handles blocks.
152 * @todo Adding blocks to blocks (stack for currentContainer)
154 void FilterDXF::addBlock(const DL_BlockData & data)
156 DEBUG->print("FilterDXF::addBlock");
157 DEBUG->print(" adding block: %s", data.name.c_str());
159 // Prevent special blocks (paper_space, model_space) from being added:
160 if (QString(data.name.c_str()).toLower() != "*paper_space0"
161 && QString(data.name.c_str()).toLower() != "*paper_space"
162 && QString(data.name.c_str()).toLower() != "*model_space"
163 && QString(data.name.c_str()).toLower() != "$paper_space0"
164 && QString(data.name.c_str()).toLower() != "$paper_space"
165 && QString(data.name.c_str()).toLower() != "$model_space")
168 #ifndef RS_NO_COMPLEX_ENTITIES
169 if (QString(data.name.c_str()).startsWith("__CE"))
171 EntityContainer * ec = new EntityContainer();
173 currentContainer = ec;
174 graphic->addEntity(ec);
175 //currentContainer->setLayer(graphic->findLayer("0"));
180 Vector bp(data.bpx, data.bpy);
181 Block * block = new Block(graphic, BlockData(data.name.c_str(), bp, false));
182 //block->setFlags(flags);
184 if (graphic->addBlock(block))
185 currentContainer = block;
186 #ifndef RS_NO_COMPLEX_ENTITIES
193 * Implementation of the method which closes blocks.
195 void FilterDXF::endBlock()
197 currentContainer = graphic;
201 * Implementation of the method which handles point entities.
203 void FilterDXF::addPoint(const DL_PointData & data)
205 Vector v(data.x, data.y);
206 Point * entity = new Point(currentContainer, PointData(v));
207 setEntityAttributes(entity, attributes);
208 currentContainer->addEntity(entity);
212 * Implementation of the method which handles line entities.
214 void FilterDXF::addLine(const DL_LineData & data)
216 DEBUG->print("FilterDXF::addLine");
218 Vector v1(data.x1, data.y1);
219 Vector v2(data.x2, data.y2);
221 DEBUG->print("FilterDXF::addLine: create line");
223 if (currentContainer == NULL)
224 DEBUG->print("FilterDXF::addLine: currentContainer is NULL");
226 Line * entity = new Line(currentContainer, LineData(v1, v2));
227 DEBUG->print("FilterDXF::addLine: set attributes");
228 setEntityAttributes(entity, attributes);
230 DEBUG->print("FilterDXF::addLine: add entity");
232 currentContainer->addEntity(entity);
234 DEBUG->print("FilterDXF::addLine: OK");
238 * Implementation of the method which handles arc entities.
240 * @param angle1 Start angle in deg (!)
241 * @param angle2 End angle in deg (!)
243 void FilterDXF::addArc(const DL_ArcData& data) {
244 DEBUG->print("FilterDXF::addArc");
245 //printf("LINE (%12.6f, %12.6f, %12.6f) (%12.6f, %12.6f, %12.6f)\n",
246 // p1[0], p1[1], p1[2],
247 // p2[0], p2[1], p2[2]);
248 Vector v(data.cx, data.cy);
249 ArcData d(v, data.radius,
253 Arc* entity = new Arc(currentContainer, d);
254 setEntityAttributes(entity, attributes);
256 currentContainer->addEntity(entity);
262 * Implementation of the method which handles ellipse entities.
264 * @param angle1 Start angle in rad (!)
265 * @param angle2 End angle in rad (!)
267 void FilterDXF::addEllipse(const DL_EllipseData& data) {
268 DEBUG->print("FilterDXF::addEllipse");
270 Vector v1(data.cx, data.cy);
271 Vector v2(data.mx, data.my);
273 EllipseData ed(v1, v2,
278 Ellipse* entity = new Ellipse(currentContainer, ed);
279 setEntityAttributes(entity, attributes);
281 currentContainer->addEntity(entity);
287 * Implementation of the method which handles circle entities.
289 void FilterDXF::addCircle(const DL_CircleData& data) {
290 DEBUG->print("FilterDXF::addCircle");
291 //printf("LINE (%12.6f, %12.6f, %12.6f) (%12.6f, %12.6f, %12.6f)\n",
292 // p1[0], p1[1], p1[2],
293 // p2[0], p2[1], p2[2]);
295 Vector v(data.cx, data.cy);
296 CircleData d(v, data.radius);
297 Circle* entity = new Circle(currentContainer, d);
298 setEntityAttributes(entity, attributes);
300 currentContainer->addEntity(entity);
306 * Implementation of the method which handles polyline entities.
308 void FilterDXF::addPolyline(const DL_PolylineData& data) {
309 DEBUG->print("FilterDXF::addPolyline");
310 //DEBUG->print("FilterDXF::addPolyline()");
311 PolylineData d(Vector(false),
314 polyline = new Polyline(currentContainer, d);
315 setEntityAttributes(polyline, attributes);
317 currentContainer->addEntity(polyline);
323 * Implementation of the method which handles polyline vertices.
325 void FilterDXF::addVertex(const DL_VertexData& data) {
326 DEBUG->print("FilterDXF::addVertex(): %f/%f bulge: %f",
327 data.x, data.y, data.bulge);
329 Vector v(data.x, data.y);
331 if (polyline!=NULL) {
332 polyline->addVertex(v, data.bulge);
339 * Implementation of the method which handles splines.
341 void FilterDXF::addSpline(const DL_SplineData& data) {
342 DEBUG->print("FilterDXF::addSpline: degree: %d", data.degree);
344 if (data.degree>=1 && data.degree<=3) {
345 SplineData d(data.degree, ((data.flags&0x1)==0x1));
346 spline = new Spline(currentContainer, d);
347 setEntityAttributes(spline, attributes);
349 currentContainer->addEntity(spline);
351 DEBUG->print(Debug::D_WARNING,
352 "FilterDXF::addSpline: Invalid degree for spline: %d. "
353 "Accepted values are 1..3.", data.degree);
357 /*virtual*/ void FilterDXF::addKnot(const DL_KnotData &)
362 * Implementation of the method which handles spline control points.
364 void FilterDXF::addControlPoint(const DL_ControlPointData & data)
366 DEBUG->print("FilterDXF::addControlPoint: %f/%f", data.x, data.y);
368 Vector v(data.x, data.y);
372 spline->addControlPoint(v);
378 * Implementation of the method which handles inserts.
380 void FilterDXF::addInsert(const DL_InsertData & data)
382 DEBUG->print("FilterDXF::addInsert");
384 if (QString(data.name.c_str()).left(3) == "A$C")
387 Vector ip(data.ipx, data.ipy);
388 Vector sc(data.sx, data.sy);
389 Vector sp(data.colSp, data.rowSp);
391 //cout << "Insert: " << name << " " << ip << " " << cols << "/" << rows << endl;
393 InsertData d(data.name.c_str(), ip, sc, data.angle / ARAD, data.cols, data.rows,
394 sp, NULL, RS2::NoUpdate);
395 Insert * entity = new Insert(currentContainer, d);
396 setEntityAttributes(entity, attributes);
397 DEBUG->print(" id: %d", entity->getId());
399 currentContainer->addEntity(entity);
402 /*virtual*/ void FilterDXF::addTrace(const DL_TraceData &)
406 /*virtual*/ void FilterDXF::addSolid(const DL_SolidData &)
411 * Implementation of the method which handles text
412 * chunks for MText entities.
414 void FilterDXF::addMTextChunk(const char * text)
416 DEBUG->print("FilterDXF::addMTextChunk: %s", text);
418 //mtext += QString::fromUtf8(text);
421 QCString locallyEncoded = text;
422 QString enc = System::getEncoding(variables.getString("$DWGCODEPAGE", "ANSI_1252"));
423 QTextCodec *codec = QTextCodec::codecForName(enc); // get the codec for Japanese
425 mtext += codec->toUnicode(toNativeString(locallyEncoded));
427 mtext += toNativeString(text);
434 * Implementation of the method which handles
435 * multi texts (MTEXT).
437 void FilterDXF::addMText(const DL_MTextData & data)
439 DEBUG->print("FilterDXF::addMText: %s", data.text.c_str());
441 Vector ip(data.ipx, data.ipy);
444 RS2::TextDrawingDirection dir;
445 RS2::TextLineSpacingStyle lss;
446 QString sty = data.style.c_str();
448 if (data.attachmentPoint <= 3)
449 valign = RS2::VAlignTop;
450 else if (data.attachmentPoint <= 6)
451 valign = RS2::VAlignMiddle;
453 valign = RS2::VAlignBottom;
455 if (data.attachmentPoint % 3 == 1)
456 halign = RS2::HAlignLeft;
457 else if (data.attachmentPoint % 3 == 2)
458 halign = RS2::HAlignCenter;
460 halign = RS2::HAlignRight;
462 if (data.drawingDirection == 1)
463 dir = RS2::LeftToRight;
464 else if (data.drawingDirection == 3)
465 dir = RS2::TopToBottom;
469 if (data.lineSpacingStyle == 1)
474 mtext += QString(data.text.c_str());
476 QString locallyEncoded = mtext;
477 QString enc = System::getEncoding(variables.getString("$DWGCODEPAGE", "ANSI_1252"));
478 // get the codec for Japanese
479 QTextCodec * codec = QTextCodec::codecForName(enc.toAscii());
482 mtext = codec->toUnicode(toNativeString(locallyEncoded).toAscii());
484 mtext = toNativeString(mtext);
486 // use default style for the drawing:
489 // japanese, cyrillic:
490 QString codepage = variables.getString("$DWGCODEPAGE", "ANSI_1252");
492 if (codepage == "ANSI_932" || codepage == "ANSI_1251")
495 sty = variables.getString("$TEXTSTYLE", "Standard");
498 DEBUG->print("Text as unicode:");
499 DEBUG->printUnicode(mtext);
501 TextData d(ip, data.height, data.width, valign, halign, dir, lss,
502 data.lineSpacingFactor, mtext, sty, data.angle, RS2::NoUpdate);
503 Text * entity = new Text(currentContainer, d);
505 setEntityAttributes(entity, attributes);
507 currentContainer->addEntity(entity);
515 * Implementation of the method which handles
518 void FilterDXF::addText(const DL_TextData& data) {
519 DEBUG->print("FilterDXF::addText");
522 double angle = data.angle;
524 // TODO: check, maybe implement a separate TEXT instead of using MTEXT
526 // baseline has 5 vertical alignment modes:
527 if (data.vJustification!=0 || data.hJustification!=0) {
528 switch (data.hJustification) {
530 case 0: // left aligned
532 refPoint = Vector(data.apx, data.apy);
536 refPoint = Vector(data.apx, data.apy);
538 case 2: // right aligned
540 refPoint = Vector(data.apx, data.apy);
542 case 3: // aligned (TODO)
544 refPoint = Vector((data.ipx+data.apx)/2.0,
545 (data.ipy+data.apy)/2.0);
547 Vector(data.ipx, data.ipy).angleTo(
548 Vector(data.apx, data.apy));
550 case 4: // Middle (TODO)
552 refPoint = Vector(data.apx, data.apy);
554 case 5: // fit (TODO)
556 refPoint = Vector((data.ipx+data.apx)/2.0,
557 (data.ipy+data.apy)/2.0);
559 Vector(data.ipx, data.ipy).angleTo(
560 Vector(data.apx, data.apy));
564 switch (data.vJustification) {
568 attachmentPoint += 6;
572 attachmentPoint += 3;
579 //attachmentPoint = (data.hJustification+1)+(3-data.vJustification)*3;
581 refPoint = Vector(data.ipx, data.ipy);
584 int drawingDirection = 5;
585 double width = 100.0;
588 addMText(DL_MTextData(
597 data.text.c_str(), data.style,
604 * Implementation of the method which handles
605 * dimensions (DIMENSION).
607 DimensionData FilterDXF::convDimensionData(
608 const DL_DimensionData& data) {
610 Vector defP(data.dpx, data.dpy);
611 Vector midP(data.mpx, data.mpy);
614 RS2::TextLineSpacingStyle lss;
615 QString sty = data.style.c_str();
616 QString t; //= data.text;
618 // middlepoint of text can be 0/0 which is considered to be invalid (!):
619 // 0/0 because older QCad versions save the middle of the text as 0/0
620 // althought they didn't suport saving of the middle of the text.
621 if (fabs(data.mpx)<1.0e-6 && fabs(data.mpy)<1.0e-6) {
622 midP = Vector(false);
625 if (data.attachmentPoint<=3) {
626 valign=RS2::VAlignTop;
627 } else if (data.attachmentPoint<=6) {
628 valign=RS2::VAlignMiddle;
630 valign=RS2::VAlignBottom;
633 if (data.attachmentPoint%3==1) {
634 halign=RS2::HAlignLeft;
635 } else if (data.attachmentPoint%3==2) {
636 halign=RS2::HAlignCenter;
638 halign=RS2::HAlignRight;
641 if (data.lineSpacingStyle==1) {
647 t = toNativeString(data.text.c_str());
650 sty = variables.getString("$DIMSTYLE", "Standard");
653 DEBUG->print("Text as unicode:");
654 DEBUG->printUnicode(t);
656 // data needed to add the actual dimension entity
657 return DimensionData(defP, midP,
660 data.lineSpacingFactor,
667 * Implementation of the method which handles
668 * aligned dimensions (DIMENSION).
670 void FilterDXF::addDimAlign(const DL_DimensionData& data,
671 const DL_DimAlignedData& edata) {
672 DEBUG->print("FilterDXF::addDimAligned");
674 DimensionData dimensionData = convDimensionData(data);
676 Vector ext1(edata.epx1, edata.epy1);
677 Vector ext2(edata.epx2, edata.epy2);
679 DimAlignedData d(ext1, ext2);
681 DimAligned* entity = new DimAligned(currentContainer,
683 setEntityAttributes(entity, attributes);
685 currentContainer->addEntity(entity);
691 * Implementation of the method which handles
692 * linear dimensions (DIMENSION).
694 void FilterDXF::addDimLinear(const DL_DimensionData& data,
695 const DL_DimLinearData& edata) {
696 DEBUG->print("FilterDXF::addDimLinear");
698 DimensionData dimensionData = convDimensionData(data);
700 Vector dxt1(edata.dpx1, edata.dpy1);
701 Vector dxt2(edata.dpx2, edata.dpy2);
703 DimLinearData d(dxt1, dxt2, Math::deg2rad(edata.angle),
704 Math::deg2rad(edata.oblique));
706 DimLinear* entity = new DimLinear(currentContainer,
708 setEntityAttributes(entity, attributes);
710 currentContainer->addEntity(entity);
716 * Implementation of the method which handles
717 * radial dimensions (DIMENSION).
719 void FilterDXF::addDimRadial(const DL_DimensionData& data,
720 const DL_DimRadialData& edata) {
721 DEBUG->print("FilterDXF::addDimRadial");
723 DimensionData dimensionData = convDimensionData(data);
724 Vector dp(edata.dpx, edata.dpy);
726 DimRadialData d(dp, edata.leader);
728 DimRadial* entity = new DimRadial(currentContainer,
731 setEntityAttributes(entity, attributes);
733 currentContainer->addEntity(entity);
739 * Implementation of the method which handles
740 * diametric dimensions (DIMENSION).
742 void FilterDXF::addDimDiametric(const DL_DimensionData& data,
743 const DL_DimDiametricData& edata) {
744 DEBUG->print("FilterDXF::addDimDiametric");
746 DimensionData dimensionData = convDimensionData(data);
747 Vector dp(edata.dpx, edata.dpy);
749 DimDiametricData d(dp, edata.leader);
751 DimDiametric* entity = new DimDiametric(currentContainer,
754 setEntityAttributes(entity, attributes);
756 currentContainer->addEntity(entity);
762 * Implementation of the method which handles
763 * angular dimensions (DIMENSION).
765 void FilterDXF::addDimAngular(const DL_DimensionData& data,
766 const DL_DimAngularData& edata) {
767 DEBUG->print("FilterDXF::addDimAngular");
769 DimensionData dimensionData = convDimensionData(data);
770 Vector dp1(edata.dpx1, edata.dpy1);
771 Vector dp2(edata.dpx2, edata.dpy2);
772 Vector dp3(edata.dpx3, edata.dpy3);
773 Vector dp4(edata.dpx4, edata.dpy4);
775 DimAngularData d(dp1, dp2, dp3, dp4);
777 DimAngular* entity = new DimAngular(currentContainer,
780 setEntityAttributes(entity, attributes);
782 currentContainer->addEntity(entity);
788 * Implementation of the method which handles
789 * angular dimensions (DIMENSION).
791 void FilterDXF::addDimAngular3P(const DL_DimensionData& data,
792 const DL_DimAngular3PData& edata) {
793 DEBUG->print("FilterDXF::addDimAngular3P");
795 DimensionData dimensionData = convDimensionData(data);
796 Vector dp1(edata.dpx3, edata.dpy3);
797 Vector dp2(edata.dpx1, edata.dpy1);
798 Vector dp3(edata.dpx3, edata.dpy3);
799 Vector dp4 = dimensionData.definitionPoint;
800 dimensionData.definitionPoint = Vector(edata.dpx2, edata.dpy2);
802 DimAngularData d(dp1, dp2, dp3, dp4);
804 DimAngular* entity = new DimAngular(currentContainer,
807 setEntityAttributes(entity, attributes);
809 currentContainer->addEntity(entity);
815 * Implementation of the method which handles leader entities.
817 void FilterDXF::addLeader(const DL_LeaderData& data) {
818 DEBUG->print("FilterDXF::addDimLeader");
819 //DEBUG->print("FilterDXF::addPolyline()");
820 LeaderData d(data.arrowHeadFlag==1);
821 leader = new Leader(currentContainer, d);
822 setEntityAttributes(leader, attributes);
824 currentContainer->addEntity(leader);
830 * Implementation of the method which handles leader vertices.
832 void FilterDXF::addLeaderVertex(const DL_LeaderVertexData& data) {
833 DEBUG->print("FilterDXF::addLeaderVertex");
834 //DEBUG->print("FilterDXF::addVertex() bulge: %f", bulge);
836 Vector v(data.x, data.y);
839 leader->addVertex(v);
846 * Implementation of the method which handles hatch entities.
848 void FilterDXF::addHatch(const DL_HatchData& data) {
849 DEBUG->print("FilterDXF::addHatch()");
851 hatch = new Hatch(currentContainer,
852 HatchData(data.solid,
855 QString(data.pattern.c_str())));
856 setEntityAttributes(hatch, attributes);
858 currentContainer->addEntity(hatch);
864 * Implementation of the method which handles hatch loops.
866 void FilterDXF::addHatchLoop(const DL_HatchLoopData& /*data*/) {
867 DEBUG->print("FilterDXF::addHatchLoop()");
869 hatchLoop = new EntityContainer(hatch);
870 hatchLoop->setLayer(NULL);
871 hatch->addEntity(hatchLoop);
878 * Implementation of the method which handles hatch edge entities.
880 void FilterDXF::addHatchEdge(const DL_HatchEdgeData& data) {
881 DEBUG->print("FilterDXF::addHatchEdge()");
883 if (hatchLoop!=NULL) {
887 DEBUG->print("FilterDXF::addHatchEdge(): "
889 data.x1, data.y1, data.x2, data.y2);
890 e = new Line(hatchLoop,
891 LineData(Vector(data.x1, data.y1),
892 Vector(data.x2, data.y2)));
895 if (data.ccw && data.angle1<1.0e-6 && data.angle2>2*M_PI-1.0e-6) {
896 e = new Circle(hatchLoop,
897 CircleData(Vector(data.cx, data.cy),
903 ArcData(Vector(data.cx, data.cy),
905 Math::correctAngle(data.angle1),
906 Math::correctAngle(data.angle2),
911 ArcData(Vector(data.cx, data.cy),
913 Math::correctAngle(2*M_PI-data.angle1),
914 Math::correctAngle(2*M_PI-data.angle2),
925 hatchLoop->addEntity(e);
933 * Implementation of the method which handles image entities.
935 void FilterDXF::addImage(const DL_ImageData& data) {
936 DEBUG->print("FilterDXF::addImage");
938 Vector ip(data.ipx, data.ipy);
939 Vector uv(data.ux, data.uy);
940 Vector vv(data.vx, data.vy);
941 Vector size(data.width, data.height);
946 ImageData(QString(data.ref.c_str()).toInt(NULL, 16),
954 setEntityAttributes(image, attributes);
955 currentContainer->addEntity(image);
959 * Implementation of the method which links image entities to image files.
961 void FilterDXF::linkImage(const DL_ImageDefData & data)
963 DEBUG->print("FilterDXF::linkImage");
965 int handle = QString(data.ref.c_str()).toInt(NULL, 16);
966 QString sfile(data.file.c_str());
967 QFileInfo fiDxf(file);
968 QFileInfo fiBitmap(sfile);
970 // try to find the image file:
972 // first: absolute path:
973 if (!fiBitmap.exists())
975 DEBUG->print("File %s doesn't exist.", (const char *)QFile::encodeName(sfile));
976 // try relative path:
977 // QString f1 = fiDxf.dirPath(true) + "/" + sfile;
978 QString f1 = fiDxf.absolutePath() + "/" + sfile;
980 if (QFileInfo(f1).exists())
984 DEBUG->print("File %s doesn't exist.", (const char *)QFile::encodeName(f1));
986 // QString f2 = fiDxf.dirPath(true) + "/" + fiBitmap.fileName();
987 QString f2 = fiDxf.absolutePath() + "/" + fiBitmap.fileName();
989 if (QFileInfo(f2).exists())
995 DEBUG->print("File %s doesn't exist.", (const char *)QFile::encodeName(f2));
1000 // Also link images in subcontainers (e.g. inserts):
1001 for(Entity * e=graphic->firstEntity(RS2::ResolveNone); e!=NULL;
1002 e=graphic->nextEntity(RS2::ResolveNone))
1004 if (e->rtti() == RS2::EntityImage)
1006 Image * img = (Image *)e;
1008 if (img->getHandle() == handle)
1010 img->setFile(sfile);
1011 DEBUG->print("image found: %s", (const char *)QFile::encodeName(img->getFile()));
1017 // update images in blocks:
1018 for(uint i=0; i<graphic->countBlocks(); ++i)
1020 Block * b = graphic->blockAt(i);
1022 for(Entity * e=b->firstEntity(RS2::ResolveNone); e!=NULL; e=b->nextEntity(RS2::ResolveNone))
1024 if (e->rtti() == RS2::EntityImage)
1026 Image * img = (Image *)e;
1028 if (img->getHandle() == handle)
1030 img->setFile(sfile);
1031 DEBUG->print("image in block found: %s",
1032 (const char*)QFile::encodeName(img->getFile()));
1039 DEBUG->print("linking image: OK");
1043 * Finishes a hatch entity.
1045 void FilterDXF::endEntity()
1047 DEBUG->print("FilterDXF::endEntity");
1051 DEBUG->print("hatch->update()");
1053 if (hatch->validate())
1057 graphic->removeEntity(hatch);
1058 DEBUG->print(Debug::D_ERROR, "FilterDXF::endEntity(): updating hatch failed: invalid hatch area");
1065 /*virtual*/ void FilterDXF::endSequence()
1070 * Sets a vector variable from the DXF file.
1072 void FilterDXF::setVariableVector(const char * key, double v1, double v2, double v3, int code)
1074 DEBUG->print("FilterDXF::setVariableVector");
1076 // update document's variable list:
1077 if (currentContainer->rtti() == RS2::EntityGraphic)
1078 ((Drawing *)currentContainer)->addVariable(QString(key), Vector(v1, v2, v3), code);
1082 * Sets a string variable from the DXF file.
1084 void FilterDXF::setVariableString(const char * key, const char * value, int code)
1086 DEBUG->print("FilterDXF::setVariableString");
1088 // update local DXF variable list:
1089 variables.add(QString(key), QString(value), code);
1091 // update document's variable list:
1092 if (currentContainer->rtti()==RS2::EntityGraphic) {
1093 ((Drawing*)currentContainer)->addVariable(QString(key),
1094 QString(value), code);
1101 * Sets an int variable from the DXF file.
1103 void FilterDXF::setVariableInt(const char* key, int value, int code) {
1104 DEBUG->print("FilterDXF::setVariableInt");
1106 // update document's variable list:
1107 if (currentContainer->rtti()==RS2::EntityGraphic) {
1108 ((Drawing*)currentContainer)->addVariable(QString(key),
1116 * Sets a double variable from the DXF file.
1118 void FilterDXF::setVariableDouble(const char* key, double value, int code) {
1119 DEBUG->print("FilterDXF::setVariableDouble");
1121 // update document's variable list:
1122 if (currentContainer->rtti() == RS2::EntityGraphic)
1124 ((Drawing *)currentContainer)->addVariable(QString(key), value, code);
1129 * Implementation of the method used for RS_Export to communicate
1132 * @param file Full path to the DXF file that will be written.
1134 bool FilterDXF::fileExport(Drawing & g, const QString & file, RS2::FormatType type)
1136 DEBUG->print("FilterDXF::fileExport: exporting file '%s'...",
1137 (const char *)QFile::encodeName(file));
1138 DEBUG->print("FilterDXF::fileExport: file type '%d'", (int)type);
1143 // check if we can write to that directory:
1144 // QString path = QFileInfo(file).dirPath(true);
1145 QString path = QFileInfo(file).absolutePath();
1147 if (QFileInfo(path).isWritable() == false)
1149 DEBUG->print("FilterDXF::fileExport: can't write file: no permission");
1155 // set version for DXF filter:
1156 DL_Codes::version exportVersion;
1158 if (type == RS2::FormatDXF12)
1160 exportVersion = DL_Codes::AC1009;
1164 exportVersion = DL_Codes::AC1015;
1167 //DL_WriterA* dw = dxf.out(file, VER_R12);
1168 DL_WriterA * dw = dxf.out((const char *)QFile::encodeName(file), exportVersion);
1172 DEBUG->print("FilterDXF::fileExport: can't write file");
1177 DEBUG->print("writing headers...");
1178 dxf.writeHeader(*dw);
1181 DEBUG->print("writing variables...");
1182 writeVariables(*dw);
1185 DEBUG->print("writing tables...");
1186 dw->sectionTables();
1189 dxf.writeVPort(*dw);
1192 DEBUG->print("writing line types...");
1193 int numLT = (int)RS2::BorderLineX2 - (int)RS2::LineByBlock;
1195 if (type == RS2::FormatDXF12)
1198 dw->tableLineTypes(numLT);
1200 for(int t=(int)RS2::LineByBlock; t<=(int)RS2::BorderLineX2; ++t)
1202 if ((RS2::LineType)t != RS2::NoPen)
1203 writeLineType(*dw, (RS2::LineType)t);
1209 DEBUG->print("writing layers...");
1210 dw->tableLayers(graphic->countLayers());
1212 for(uint i=0; i<graphic->countLayers(); ++i)
1214 Layer * l = graphic->layerAt(i);
1221 DEBUG->print("writing styles...");
1222 dxf.writeStyle(*dw);
1225 DEBUG->print("writing views...");
1229 DEBUG->print("writing ucs...");
1233 DEBUG->print("writing appid...");
1235 writeAppid(*dw, "ACAD");
1239 DEBUG->print("writing dim styles...");
1240 dxf.writeDimStyle(*dw,
1241 graphic->getVariableDouble("$DIMASZ", 2.5),
1242 graphic->getVariableDouble("$DIMEXE", 1.25),
1243 graphic->getVariableDouble("$DIMEXO", 0.625),
1244 graphic->getVariableDouble("$DIMGAP", 0.625),
1245 graphic->getVariableDouble("$DIMTXT", 2.5));
1248 if (type == RS2::FormatDXF)
1250 DEBUG->print("writing block records...");
1251 dxf.writeBlockRecord(*dw);
1253 for(uint i=0; i<graphic->countBlocks(); ++i)
1255 Block * blk = graphic->blockAt(i);
1256 dxf.writeBlockRecord(*dw, std::string((const char *)blk->getName().toLocal8Bit()));
1259 //writeBlock(*dw, blk);
1260 dw->dxfString( 0, "BLOCK_RECORD");
1261 //dw.dxfHex(5, 0x1F);
1264 dw->dxfString(100, "AcDbSymbolTableRecord");
1265 dw->dxfString(100, "AcDbBlockTableRecord");
1266 dw->dxfString( 2, blk->getName().toLocal8Bit());
1275 DEBUG->print("writing end of section TABLES...");
1279 DEBUG->print("writing blocks...");
1280 dw->sectionBlocks();
1282 if (type == RS2::FormatDXF)
1284 Block b1(graphic, BlockData("*Model_Space", Vector(0.0, 0.0), false));
1285 writeBlock(*dw, &b1);
1286 Block b2(graphic, BlockData("*Paper_Space", Vector(0.0, 0.0), false));
1287 writeBlock(*dw, &b2);
1288 Block b3(graphic, BlockData("*Paper_Space0", Vector(0.0, 0.0), false));
1289 writeBlock(*dw, &b3);
1292 for(uint i=0; i<graphic->countBlocks(); ++i)
1294 Block * blk = graphic->blockAt(i);
1296 // Save block if it's not a model or paper space:
1297 // Careful: other blocks with * / $ exist
1298 //if (blk->getName().at(0)!='*' &&
1299 // blk->getName().at(0)!='$') {
1300 writeBlock(*dw, blk);
1306 // Section ENTITIES:
1307 DEBUG->print("writing section ENTITIES...");
1308 dw->sectionEntities();
1310 for(Entity * e=graphic->firstEntity(RS2::ResolveNone); e!=NULL;
1311 e=graphic->nextEntity(RS2::ResolveNone))
1313 writeEntity(*dw, e);
1316 DEBUG->print("writing end of section ENTITIES...");
1319 if (type == RS2::FormatDXF)
1321 DEBUG->print("writing section OBJECTS...");
1322 dxf.writeObjects(*dw);
1324 // IMAGEDEF's from images in entities and images in blocks
1325 QStringList written;
1327 for(uint i=0; i<graphic->countBlocks(); ++i)
1329 Block * block = graphic->blockAt(i);
1331 for(Entity * e=block->firstEntity(RS2::ResolveAll); e!=NULL;
1332 e=block->nextEntity(RS2::ResolveAll))
1334 if (e->rtti() == RS2::EntityImage)
1336 Image * img = ((Image *)e);
1338 if (written.contains(file) == 0 && img->getHandle() != 0)
1340 writeImageDef(*dw, img);
1341 written.append(img->getFile());
1347 for(Entity * e=graphic->firstEntity(RS2::ResolveNone); e!=NULL;
1348 e=graphic->nextEntity(RS2::ResolveNone))
1350 if (e->rtti() == RS2::EntityImage)
1352 Image * img = ((Image *)e);
1354 if (written.contains(file) == 0 && img->getHandle() != 0)
1356 writeImageDef(*dw, img);
1357 written.append(img->getFile());
1361 DEBUG->print("writing end of section OBJECTS...");
1362 dxf.writeObjectsEnd(*dw);
1365 DEBUG->print("writing EOF...");
1368 DEBUG->print("close..");
1373 // check if file was actually written (strange world of windoze xp):
1374 if (QFileInfo(file).exists() == false)
1376 DEBUG->print("FilterDXF::fileExport: file could not be written");
1384 * Writes all known variable settings to the DXF file.
1386 void FilterDXF::writeVariables(DL_WriterA & dw)
1388 // Q3DictIterator<Variable> it(graphic->getVariableDict());
1389 QHashIterator<QString, Variable *> it(graphic->getVariableDict());
1391 // for (; it.current(); ++it)
1392 while (it.hasNext())
1396 // exclude variables that are not known to DXF 12:
1397 if (!DL_Dxf::checkVariable(it.key().toLatin1(), dxf.getVersion()))
1400 if (it.key() != "$ACADVER" && it.key() != "$HANDSEED")
1402 dw.dxfString(9, (const char *)it.key().toAscii().data());
1404 switch (it.value()->getType())
1406 case RS2::VariableVoid:
1408 case RS2::VariableInt:
1409 dw.dxfInt(it.value()->getCode(), it.value()->getInt());
1411 case RS2::VariableDouble:
1412 dw.dxfReal(it.value()->getCode(), it.value()->getDouble());
1414 case RS2::VariableString:
1415 dw.dxfString(it.value()->getCode(), (const char *)it.value()->getString().toAscii().data());
1417 case RS2::VariableVector:
1418 dw.dxfReal(it.value()->getCode(), it.value()->getVector().x);
1419 dw.dxfReal(it.value()->getCode() + 10, it.value()->getVector().y);
1421 if (isVariableTwoDimensional(it.key()) == false)
1422 dw.dxfReal(it.value()->getCode() + 20, it.value()->getVector().z);
1433 * Writes one layer to the DXF file.
1435 * @todo Add support for unicode layer names
1437 void FilterDXF::writeLayer(DL_WriterA & dw, Layer * l)
1441 DEBUG->print(Debug::D_WARNING, "FilterDXF::writeLayer: layer is NULL");
1445 DEBUG->print("FilterDXF::writeLayer %s", l->getName().toLatin1().data());
1447 dxf.writeLayer(dw, DL_LayerData((const char *)l->getName().toLocal8Bit(),
1448 l->isFrozen() + (l->isLocked() << 2)), DL_Attributes(std::string(""),
1449 colorToNumber(l->getPen().getColor()), widthToNumber(l->getPen().getWidth()),
1450 (const char *)lineTypeToName(l->getPen().getLineType()).toLocal8Bit()));
1452 DEBUG->print("FilterDXF::writeLayer end");
1456 * Writes a line type to the DXF file.
1458 void FilterDXF::writeLineType(DL_WriterA & dw, RS2::LineType t)
1460 dxf.writeLineType(dw, DL_LineTypeData((const char *)lineTypeToName(t).toLocal8Bit(), 0));
1466 * Writes an application id to the DXF file.
1468 * @param appid Application ID (e.g. "QCad").
1470 void FilterDXF::writeAppid(DL_WriterA& dw, const char* appid) {
1471 dxf.writeAppid(dw, appid);
1477 * Writes a block (just the definition, not the entities in it).
1479 void FilterDXF::writeBlock(DL_WriterA& dw, Block* blk) {
1481 DEBUG->print(Debug::D_WARNING,
1482 "FilterDXF::writeBlock: Block is NULL");
1486 DEBUG->print("writing block: %s", (const char*)blk->getName().toLocal8Bit());
1489 DL_BlockData((const char*)blk->getName().toLocal8Bit(), 0,
1490 blk->getBasePoint().x,
1491 blk->getBasePoint().y,
1492 blk->getBasePoint().z));
1493 for (Entity* e=blk->firstEntity(RS2::ResolveNone);
1495 e=blk->nextEntity(RS2::ResolveNone)) {
1498 dxf.writeEndBlock(dw, (const char*)blk->getName().toLocal8Bit());
1504 * Writes the given entity to the DXF file.
1506 void FilterDXF::writeEntity(DL_WriterA& dw, Entity* e) {
1507 writeEntity(dw, e, getEntityAttributes(e));
1512 * Writes the given entity to the DXF file.
1514 void FilterDXF::writeEntity(DL_WriterA& dw, Entity* e,
1515 const DL_Attributes& attrib) {
1517 if (e==NULL || e->getFlag(RS2::FlagUndone)) {
1520 DEBUG->print("writing Entity");
1522 switch (e->rtti()) {
1523 case RS2::EntityPoint:
1524 writePoint(dw, (Point*)e, attrib);
1526 case RS2::EntityLine:
1527 writeLine(dw, (Line*)e, attrib);
1529 case RS2::EntityPolyline:
1530 writePolyline(dw, (Polyline*)e, attrib);
1532 case RS2::EntitySpline:
1533 writeSpline(dw, (Spline*)e, attrib);
1535 case RS2::EntityVertex:
1537 case RS2::EntityCircle:
1538 writeCircle(dw, (Circle*)e, attrib);
1540 case RS2::EntityArc:
1541 writeArc(dw, (Arc*)e, attrib);
1543 case RS2::EntityEllipse:
1544 writeEllipse(dw, (Ellipse*)e, attrib);
1546 case RS2::EntityInsert:
1547 writeInsert(dw, (Insert*)e, attrib);
1549 case RS2::EntityText:
1550 writeText(dw, (Text*)e, attrib);
1553 case RS2::EntityDimAligned:
1554 case RS2::EntityDimAngular:
1555 case RS2::EntityDimLinear:
1556 case RS2::EntityDimRadial:
1557 case RS2::EntityDimDiametric:
1558 writeDimension(dw, (Dimension*)e, attrib);
1560 case RS2::EntityDimLeader:
1561 writeLeader(dw, (Leader*)e, attrib);
1563 case RS2::EntityHatch:
1564 writeHatch(dw, (Hatch*)e, attrib);
1566 case RS2::EntityImage:
1567 writeImage(dw, (Image*)e, attrib);
1569 case RS2::EntitySolid:
1570 writeSolid(dw, (Solid*)e, attrib);
1573 #ifndef RS_NO_COMPLEX_ENTITIES
1575 case RS2::EntityContainer:
1576 writeEntityContainer(dw, (EntityContainer*)e, attrib);
1588 * Writes the given Point entity to the file.
1590 void FilterDXF::writePoint(DL_WriterA& dw, Point* p,
1591 const DL_Attributes& attrib) {
1594 DL_PointData(p->getPos().x,
1602 * Writes the given Line( entity to the file.
1604 void FilterDXF::writeLine(DL_WriterA& dw, Line* l,
1605 const DL_Attributes& attrib) {
1608 DL_LineData(l->getStartpoint().x,
1609 l->getStartpoint().y,
1620 * Writes the given polyline entity to the file.
1622 void FilterDXF::writePolyline(DL_WriterA& dw,
1624 const DL_Attributes& attrib) {
1626 int count = l->count();
1627 if (l->isClosed()==false) {
1633 DL_PolylineData(count,
1638 Entity* nextEntity = 0;
1639 AtomicEntity* ae = NULL;
1640 Entity* lastEntity = l->lastEntity(RS2::ResolveNone);
1641 for (Entity* v=l->firstEntity(RS2::ResolveNone);
1645 nextEntity = l->nextEntity(RS2::ResolveNone);
1647 if (!v->isAtomic()) {
1651 ae = (AtomicEntity*)v;
1656 if (v->rtti()==RS2::EntityArc) {
1657 bulge = ((Arc*)v)->getBulge();
1660 DL_VertexData(ae->getStartpoint().x,
1661 ae->getStartpoint().y,
1667 //if (dxf.getVersion()==VER_R12) {
1668 if (nextEntity!=NULL) {
1669 if (nextEntity->rtti()==RS2::EntityArc) {
1670 bulge = ((Arc*)nextEntity)->getBulge();
1677 if (v->rtti()==RS2::EntityArc) {
1678 bulge = ((Arc*)v)->getBulge();
1683 if (l->isClosed()==false || v!=lastEntity) {
1685 DL_VertexData(ae->getEndpoint().x,
1686 ae->getEndpoint().y,
1691 dxf.writePolylineEnd(dw);
1697 * Writes the given spline entity to the file.
1699 void FilterDXF::writeSpline(DL_WriterA & dw, Spline * s, const DL_Attributes & attrib)
1701 // split spline into atomic entities for DXF R12:
1702 if (dxf.getVersion() == VER_R12)
1704 writeAtomicEntities(dw, s, attrib, RS2::ResolveNone);
1708 if (s->getNumberOfControlPoints() < s->getDegree() + 1)
1710 DEBUG->print(Debug::D_ERROR, "FilterDXF::writeSpline: "
1711 "Discarding spline: not enough control points given.");
1715 // Number of control points:
1716 int numCtrl = s->getNumberOfControlPoints();
1718 // Number of knots (= number of control points + spline degree + 1)
1719 int numKnots = numCtrl + s->getDegree() + 1;
1728 // write spline header:
1729 dxf.writeSpline(dw, DL_SplineData(s->getDegree(), numKnots, numCtrl, flags), attrib);
1731 // write spline knots:
1732 QList<Vector> cp = s->getControlPoints();
1733 QList<Vector>::iterator it;
1735 int k = s->getDegree() + 1;
1738 for(int i=1; i<=numKnots; i++)
1741 kd = DL_KnotData(0.0);
1742 else if (i <= numKnots - k)
1743 kd = DL_KnotData(1.0 / (numKnots - 2 * k + 1) * (i - k));
1745 kd = DL_KnotData(1.0);
1747 dxf.writeKnot(dw, kd);
1750 // write spline control points:
1751 for(it=cp.begin(); it!=cp.end(); ++it)
1753 dxf.writeControlPoint(dw, DL_ControlPointData((*it).x, (*it).y, 0.0));
1758 * Writes the given circle entity to the file.
1760 void FilterDXF::writeCircle(DL_WriterA& dw, Circle* c,
1761 const DL_Attributes& attrib) {
1764 DL_CircleData(c->getCenter().x,
1774 void FilterDXF::writeArc(DL_WriterA& dw, Arc* a,
1775 const DL_Attributes& attrib) {
1777 if (a->isReversed()) {
1778 a1 = a->getAngle2()*ARAD;
1779 a2 = a->getAngle1()*ARAD;
1781 a1 = a->getAngle1()*ARAD;
1782 a2 = a->getAngle2()*ARAD;
1786 DL_ArcData(a->getCenter().x,
1795 void FilterDXF::writeEllipse(DL_WriterA& dw, Ellipse* s,
1796 const DL_Attributes& attrib) {
1797 if (s->isReversed()) {
1800 DL_EllipseData(s->getCenter().x,
1813 DL_EllipseData(s->getCenter().x,
1826 void FilterDXF::writeInsert(DL_WriterA & dw, Insert * i, const DL_Attributes & attrib)
1828 dxf.writeInsert(dw, DL_InsertData(i->getName().toLatin1().data(),
1829 i->getInsertionPoint().x, i->getInsertionPoint().y, 0.0,
1830 i->getScale().x, i->getScale().y, 0.0,
1831 i->getAngle() * ARAD, i->getCols(), i->getRows(),
1832 i->getSpacing().x, i->getSpacing().y),
1836 void FilterDXF::writeText(DL_WriterA & dw, Text * t, const DL_Attributes & attrib)
1838 if (dxf.getVersion()==VER_R12)
1843 if (t->getHAlign()==RS2::HAlignLeft) {
1845 } else if (t->getHAlign()==RS2::HAlignCenter) {
1847 } else if (t->getHAlign()==RS2::HAlignRight) {
1851 if (t->getVAlign()==RS2::VAlignTop) {
1853 } else if (t->getVAlign()==RS2::VAlignMiddle) {
1855 } else if (t->getVAlign()==RS2::VAlignBottom) {
1861 DL_TextData(t->getInsertionPoint().x,
1862 t->getInsertionPoint().y,
1864 t->getInsertionPoint().x,
1865 t->getInsertionPoint().y,
1871 (const char*)toDxfString(
1872 t->getText()).toLocal8Bit(),
1873 (const char*)t->getStyle().toLocal8Bit(),
1879 int attachmentPoint=1;
1881 if (t->getHAlign()==RS2::HAlignLeft) {
1883 } else if (t->getHAlign()==RS2::HAlignCenter) {
1885 } else if (t->getHAlign()==RS2::HAlignRight) {
1889 if (t->getVAlign()==RS2::VAlignTop) {
1891 } else if (t->getVAlign()==RS2::VAlignMiddle) {
1893 } else if (t->getVAlign()==RS2::VAlignBottom) {
1899 DL_MTextData(t->getInsertionPoint().x,
1900 t->getInsertionPoint().y,
1905 t->getDrawingDirection(),
1906 t->getLineSpacingStyle(),
1907 t->getLineSpacingFactor(),
1908 (const char*)toDxfString(
1909 t->getText()).toLocal8Bit(),
1910 (const char*)t->getStyle().toLocal8Bit(),
1918 void FilterDXF::writeDimension(DL_WriterA& dw, Dimension* d,
1919 const DL_Attributes& attrib) {
1921 // split hatch into atomic entities:
1922 if (dxf.getVersion()==VER_R12) {
1923 writeAtomicEntities(dw, d, attrib, RS2::ResolveNone);
1928 int attachmentPoint=1;
1929 if (d->getHAlign()==RS2::HAlignLeft) {
1931 } else if (d->getHAlign()==RS2::HAlignCenter) {
1933 } else if (d->getHAlign()==RS2::HAlignRight) {
1936 if (d->getVAlign()==RS2::VAlignTop) {
1938 } else if (d->getVAlign()==RS2::VAlignMiddle) {
1940 } else if (d->getVAlign()==RS2::VAlignBottom) {
1944 switch (d->rtti()) {
1945 case RS2::EntityDimAligned:
1948 case RS2::EntityDimLinear:
1951 case RS2::EntityDimRadial:
1954 case RS2::EntityDimDiametric:
1962 DL_DimensionData dimData(d->getDefinitionPoint().x,
1963 d->getDefinitionPoint().y,
1965 d->getMiddleOfText().x,
1966 d->getMiddleOfText().y,
1970 d->getLineSpacingStyle(),
1971 d->getLineSpacingFactor(),
1972 (const char*)toDxfString(
1973 d->getText()).toLocal8Bit(),
1974 (const char*)d->getStyle().toLocal8Bit(),
1977 if (d->rtti()==RS2::EntityDimAligned) {
1978 DimAligned* da = (DimAligned*)d;
1980 DL_DimAlignedData dimAlignedData(da->getExtensionPoint1().x,
1981 da->getExtensionPoint1().y,
1983 da->getExtensionPoint2().x,
1984 da->getExtensionPoint2().y,
1987 dxf.writeDimAligned(dw, dimData, dimAlignedData, attrib);
1988 } else if (d->rtti()==RS2::EntityDimLinear) {
1989 DimLinear* dl = (DimLinear*)d;
1991 DL_DimLinearData dimLinearData(dl->getExtensionPoint1().x,
1992 dl->getExtensionPoint1().y,
1994 dl->getExtensionPoint2().x,
1995 dl->getExtensionPoint2().y,
2000 dxf.writeDimLinear(dw, dimData, dimLinearData, attrib);
2001 } else if (d->rtti()==RS2::EntityDimRadial) {
2002 DimRadial* dr = (DimRadial*)d;
2004 DL_DimRadialData dimRadialData(dr->getDefinitionPoint().x,
2005 dr->getDefinitionPoint().y,
2009 dxf.writeDimRadial(dw, dimData, dimRadialData, attrib);
2010 } else if (d->rtti()==RS2::EntityDimDiametric) {
2011 DimDiametric* dr = (DimDiametric*)d;
2013 DL_DimDiametricData dimDiametricData(dr->getDefinitionPoint().x,
2014 dr->getDefinitionPoint().y,
2018 dxf.writeDimDiametric(dw, dimData, dimDiametricData, attrib);
2019 } else if (d->rtti()==RS2::EntityDimAngular) {
2020 DimAngular* da = (DimAngular*)d;
2022 DL_DimAngularData dimAngularData(da->getDefinitionPoint1().x,
2023 da->getDefinitionPoint1().y,
2025 da->getDefinitionPoint2().x,
2026 da->getDefinitionPoint2().y,
2028 da->getDefinitionPoint3().x,
2029 da->getDefinitionPoint3().y,
2031 da->getDefinitionPoint4().x,
2032 da->getDefinitionPoint4().y,
2035 dxf.writeDimAngular(dw, dimData, dimAngularData, attrib);
2041 void FilterDXF::writeLeader(DL_WriterA& dw, Leader* l,
2042 const DL_Attributes& attrib) {
2046 DL_LeaderData(l->hasArrowHead(),
2056 for (Entity* v=l->firstEntity(RS2::ResolveNone);
2058 v=l->nextEntity(RS2::ResolveNone)) {
2060 // Write line verties:
2061 if (v->rtti()==RS2::EntityLine) {
2064 dxf.writeLeaderVertex(
2066 DL_LeaderVertexData(l->getStartpoint().x,
2067 l->getStartpoint().y,
2071 dxf.writeLeaderVertex(
2073 DL_LeaderVertexData(l->getEndpoint().x,
2079 DEBUG->print(Debug::D_WARNING,
2080 "dropping leader with no vertices");
2085 void FilterDXF::writeHatch(DL_WriterA& dw, Hatch* h,
2086 const DL_Attributes& attrib) {
2088 // split hatch into atomic entities:
2089 if (dxf.getVersion()==VER_R12) {
2090 writeAtomicEntities(dw, h, attrib, RS2::ResolveAll);
2094 bool writeIt = true;
2095 if (h->countLoops()>0) {
2096 // check if all of the loops contain entities:
2097 for (Entity* l=h->firstEntity(RS2::ResolveNone);
2099 l=h->nextEntity(RS2::ResolveNone)) {
2101 if (l->isContainer() && !l->getFlag(RS2::FlagTemp)) {
2102 if (l->count()==0) {
2112 DEBUG->print(Debug::D_WARNING,
2113 "FilterDXF::writeHatch: Dropping Hatch");
2115 DL_HatchData data(h->countLoops(),
2119 (const char*)h->getPattern().toLocal8Bit());
2120 dxf.writeHatch1(dw, data, attrib);
2122 for (Entity* l=h->firstEntity(RS2::ResolveNone);
2124 l=h->nextEntity(RS2::ResolveNone)) {
2126 // Write hatch loops:
2127 if (l->isContainer() && !l->getFlag(RS2::FlagTemp)) {
2128 EntityContainer* loop = (EntityContainer*)l;
2129 DL_HatchLoopData lData(loop->count());
2130 dxf.writeHatchLoop1(dw, lData);
2132 for (Entity* ed=loop->firstEntity(RS2::ResolveNone);
2134 ed=loop->nextEntity(RS2::ResolveNone)) {
2136 // Write hatch loop edges:
2137 if (ed->rtti()==RS2::EntityLine) {
2138 Line* ln = (Line*)ed;
2141 DL_HatchEdgeData(ln->getStartpoint().x,
2142 ln->getStartpoint().y,
2143 ln->getEndpoint().x,
2144 ln->getEndpoint().y));
2145 } else if (ed->rtti()==RS2::EntityArc) {
2147 if (!ar->isReversed()) {
2150 DL_HatchEdgeData(ar->getCenter().x,
2159 DL_HatchEdgeData(ar->getCenter().x,
2162 2*M_PI-ar->getAngle1(),
2163 2*M_PI-ar->getAngle2(),
2166 } else if (ed->rtti()==RS2::EntityCircle) {
2167 Circle* ci = (Circle*)ed;
2170 DL_HatchEdgeData(ci->getCenter().x,
2178 dxf.writeHatchLoop2(dw, lData);
2181 dxf.writeHatch2(dw, data, attrib);
2188 void FilterDXF::writeSolid(DL_WriterA& dw, Solid* s,
2189 const DL_Attributes& attrib) {
2191 // split solid into line entities:
2192 //if (dxf.getVersion()==VER_R12) {
2193 for (int i=0; i<3; ++i) {
2196 DL_LineData(s->getCorner(i).x,
2199 s->getCorner((i+1)%3).x,
2200 s->getCorner((i+1)%3).y,
2209 void FilterDXF::writeImage(DL_WriterA& dw, Image* i,
2210 const DL_Attributes& attrib) {
2211 int handle = dxf.writeImage(
2213 DL_ImageData(std::string(""),
2214 i->getInsertionPoint().x,
2215 i->getInsertionPoint().y,
2229 i->setHandle(handle);
2234 void FilterDXF::writeEntityContainer(DL_WriterA& dw, EntityContainer* con,
2235 const DL_Attributes& /*attrib*/) {
2239 // Creating an unique ID from the element ID
2240 int tmp, c=1; // tmp = temporary var c = counter var
2245 blkName.append((char) tmp %10 + 48);
2254 dxf.writeBlockRecord(dw);
2255 dw.dxfString( 0, "BLOCK_RECORD");
2259 dw.dxfString(100, "AcDbSymbolTableRecord");
2260 dw.dxfString(100, "AcDbBlockTableRecord");
2261 dw.dxfString( 2, blkName.toLatin1());
2263 dw.dxfString(0, "ENDTAB");
2266 BlockData blkdata(blkName, Vector(0,0), false);
2268 Block* blk = new Block(graphic, blkdata);
2270 for (Entity* e1 = con->firstEntity(); e1 != NULL;
2271 e1 = con->nextEntity() ) {
2274 writeBlock(dw, blk);
2282 * Writes the atomic entities of the given cotnainer to the file.
2284 void FilterDXF::writeAtomicEntities(DL_WriterA& dw, EntityContainer* c,
2285 const DL_Attributes& attrib,
2286 RS2::ResolveLevel level) {
2288 for (Entity* e=c->firstEntity(level);
2290 e=c->nextEntity(level)) {
2292 writeEntity(dw, e, attrib);
2297 * Writes an IMAGEDEF object into an OBJECT section.
2299 void FilterDXF::writeImageDef(DL_WriterA& dw, Image* i) {
2300 if (i==NULL || i->getFlag(RS2::FlagUndone)) {
2307 DL_ImageData((const char*)i->getFile().toLocal8Bit(),
2308 i->getInsertionPoint().x,
2309 i->getInsertionPoint().y,
2327 * Sets the entities attributes according to the attributes
2328 * that come from a DXF file.
2330 void FilterDXF::setEntityAttributes(Entity* entity,
2331 const DL_Attributes& attrib) {
2332 DEBUG->print("FilterDXF::setEntityAttributes");
2335 pen.setColor(Qt::black);
2336 pen.setLineType(RS2::SolidLine);
2339 if (attrib.getLayer().empty()) {
2340 entity->setLayer("0");
2342 // add layer in case it doesn't exist:
2343 if (graphic->findLayer(attrib.getLayer().c_str())==NULL) {
2344 addLayer(DL_LayerData(attrib.getLayer(), 0));
2346 entity->setLayer(attrib.getLayer().c_str());
2350 pen.setColor(numberToColor(attrib.getColor()));
2353 pen.setLineType(nameToLineType(attrib.getLineType().c_str()));
2356 pen.setWidth(numberToWidth(attrib.getWidth()));
2358 entity->setPen(pen);
2359 DEBUG->print("FilterDXF::setEntityAttributes: OK");
2363 * Gets the entities attributes as a DL_Attributes object.
2365 DL_Attributes FilterDXF::getEntityAttributes(Entity * entity)
2368 Layer * layer = entity->getLayer();
2372 layerName = layer->getName();
2376 Pen pen = entity->getPen(false);
2379 int color = colorToNumber(pen.getColor());
2380 //printf("Color is: %s -> %d\n", pen.getColor().name().toLatin1(), color);
2383 QString lineType = lineTypeToName(pen.getLineType());
2386 int width = widthToNumber(pen.getWidth());
2388 DL_Attributes attrib(layerName.toLatin1().data(), color, width, lineType.toLatin1().data());
2394 * @return Pen with the same attributes as 'attrib'.
2396 Pen FilterDXF::attributesToPen(const DL_Attributes & attrib) const
2399 printf("converting Color %d to %s\n",
2400 attrib.getColor(), numberToColor(attrib.getColor()).name().toLatin1());
2403 Pen pen(numberToColor(attrib.getColor()),
2404 numberToWidth(attrib.getWidth()),
2405 nameToLineType(attrib.getLineType().c_str()));
2412 * Converts a color index (num) into a Color object.
2413 * Please refer to the dxflib documentation for details.
2415 * @param num Color number.
2416 * @param comp Compatibility with older QCad versions (1.5.3 and older)
2418 Color FilterDXF::numberToColor(int num, bool comp) {
2419 // Compatibility with QCad 1.5.3 and older:
2426 return Qt::darkBlue;
2429 return Qt::darkGreen;
2432 return Qt::darkCyan;
2438 return Qt::darkMagenta;
2441 return Qt::darkYellow;
2444 return Qt::lightGray;
2447 return Qt::darkGray;
2475 return Color(RS2::FlagByBlock);
2476 } else if (num==256) {
2477 return Color(RS2::FlagByLayer);
2478 } else if (num<=255 && num>=0) {
2479 return Color((int)(dxfColors[num][0]*255),
2480 (int)(dxfColors[num][1]*255),
2481 (int)(dxfColors[num][2]*255));
2483 DEBUG->print(Debug::D_WARNING,
2484 "FilterDXF::numberToColor: Invalid color number given.");
2485 return Color(RS2::FlagByLayer);
2494 * Converts a color into a color number in the DXF palette.
2495 * The color that fits best is chosen.
2497 int FilterDXF::colorToNumber(const Color& col) {
2499 //printf("Searching color for %s\n", col.name().toLatin1());
2501 // Special color BYBLOCK:
2502 if (col.getFlag(RS2::FlagByBlock)) {
2506 // Special color BYLAYER
2507 else if (col.getFlag(RS2::FlagByLayer)) {
2511 // Special color black is not in the table but white represents both
2513 else if (col.red()==0 && col.green()==0 && col.blue()==0) {
2520 int diff=255*3; // smallest difference to a color in the table found so far
2522 // Run through the whole table and compare
2523 for (int i=1; i<=255; i++) {
2524 int d = abs(col.red()-(int)(dxfColors[i][0]*255))
2525 + abs(col.green()-(int)(dxfColors[i][1]*255))
2526 + abs(col.blue()-(int)(dxfColors[i][2]*255));
2530 printf("color %f,%f,%f is closer\n",
2542 //printf(" Found: %d, diff: %d\n", num, diff);
2548 * Converts a line type name (e.g. "CONTINUOUS") into a RS2::LineType
2551 RS2::LineType FilterDXF::nameToLineType(const QString & name)
2553 QString uName = name.toUpper();
2555 // Standard linetypes for QCad II / AutoCAD
2556 if (uName.isEmpty() || uName == "BYLAYER")
2557 return RS2::LineByLayer;
2558 else if (uName == "BYBLOCK")
2559 return RS2::LineByBlock;
2560 else if (uName == "CONTINUOUS" || uName == "ACAD_ISO01W100")
2561 return RS2::SolidLine;
2562 else if (uName == "ACAD_ISO07W100" || uName == "DOT")
2563 return RS2::DotLine;
2564 else if (uName == "DOT2")
2565 return RS2::DotLine2;
2566 else if (uName == "DOTX2")
2567 return RS2::DotLineX2;
2568 else if (uName == "ACAD_ISO02W100" || uName == "ACAD_ISO03W100"
2569 || uName == "DASHED" || uName == "HIDDEN")
2570 return RS2::DashLine;
2571 else if (uName == "DASHED2" || uName == "HIDDEN2")
2572 return RS2::DashLine2;
2573 else if (uName == "DASHEDX2" || uName == "HIDDENX2")
2574 return RS2::DashLineX2;
2575 else if (uName == "ACAD_ISO10W100" || uName == "DASHDOT")
2576 return RS2::DashDotLine;
2577 else if (uName == "DASHDOT2")
2578 return RS2::DashDotLine2;
2579 else if (uName == "ACAD_ISO04W100" || uName == "DASHDOTX2")
2580 return RS2::DashDotLineX2;
2581 else if (uName == "ACAD_ISO12W100" || uName == "DIVIDE")
2582 return RS2::DivideLine;
2583 else if (uName == "DIVIDE2")
2584 return RS2::DivideLine2;
2585 else if (uName == "ACAD_ISO05W100" || uName == "DIVIDEX2")
2586 return RS2::DivideLineX2;
2587 else if (uName == "CENTER")
2588 return RS2::CenterLine;
2589 else if (uName == "CENTER2")
2590 return RS2::CenterLine2;
2591 else if (uName == "CENTERX2")
2592 return RS2::CenterLineX2;
2593 else if (uName == "BORDER")
2594 return RS2::BorderLine;
2595 else if (uName == "BORDER2")
2596 return RS2::BorderLine2;
2597 else if (uName == "BORDERX2")
2598 return RS2::BorderLineX2;
2600 return RS2::SolidLine;
2604 * Converts a LineType into a name for a line type.
2606 QString FilterDXF::lineTypeToName(RS2::LineType lineType)
2608 // Standard linetypes for QCad II / AutoCAD
2611 case RS2::SolidLine:
2612 return "CONTINUOUS";
2621 case RS2::DotLineX2:
2628 case RS2::DashLine2:
2631 case RS2::DashLineX2:
2635 case RS2::DashDotLine:
2638 case RS2::DashDotLine2:
2641 case RS2::DashDotLineX2:
2645 case RS2::DivideLine:
2648 case RS2::DivideLine2:
2651 case RS2::DivideLineX2:
2655 case RS2::CenterLine:
2658 case RS2::CenterLine2:
2661 case RS2::CenterLineX2:
2665 case RS2::BorderLine:
2668 case RS2::BorderLine2:
2671 case RS2::BorderLineX2:
2676 case RS2::LineByLayer:
2679 case RS2::LineByBlock:
2686 return "CONTINUOUS";
2692 * Converts a LineType into a name for a line type.
2694 /*QString FilterDXF::lineTypeToDescription(RS2::LineType lineType) {
2696 // Standard linetypes for QCad II / AutoCAD
2698 case RS2::SolidLine:
2699 return "Solid line";
2701 return "ISO Dashed __ __ __ __ __ __ __ __ __ __ _";
2703 return "ISO Dashed with Distance __ __ __ _";
2704 case RS2::DashDotLine:
2705 return "ISO Long Dashed Dotted ____ . ____ . __";
2706 case RS2::DashDotDotLine:
2707 return "ISO Long Dashed Double Dotted ____ .. __";
2708 case RS2::LineByLayer:
2710 case RS2::LineByBlock:
2716 return "CONTINUOUS";
2722 * Converts a line width number (e.g. 1) into a RS2::LineWidth.
2724 RS2::LineWidth FilterDXF::numberToWidth(int num) {
2727 return RS2::WidthByLayer;
2730 return RS2::WidthByBlock;
2733 return RS2::WidthDefault;
2737 return RS2::Width00;
2739 return RS2::Width01;
2740 } else if (num<11) {
2741 return RS2::Width02;
2742 } else if (num<14) {
2743 return RS2::Width03;
2744 } else if (num<16) {
2745 return RS2::Width04;
2746 } else if (num<19) {
2747 return RS2::Width05;
2748 } else if (num<22) {
2749 return RS2::Width06;
2750 } else if (num<27) {
2751 return RS2::Width07;
2752 } else if (num<32) {
2753 return RS2::Width08;
2754 } else if (num<37) {
2755 return RS2::Width09;
2756 } else if (num<45) {
2757 return RS2::Width10;
2758 } else if (num<52) {
2759 return RS2::Width11;
2760 } else if (num<57) {
2761 return RS2::Width12;
2762 } else if (num<65) {
2763 return RS2::Width13;
2764 } else if (num<75) {
2765 return RS2::Width14;
2766 } else if (num<85) {
2767 return RS2::Width15;
2768 } else if (num<95) {
2769 return RS2::Width16;
2770 } else if (num<103) {
2771 return RS2::Width17;
2772 } else if (num<112) {
2773 return RS2::Width18;
2774 } else if (num<130) {
2775 return RS2::Width19;
2776 } else if (num<149) {
2777 return RS2::Width20;
2778 } else if (num<180) {
2779 return RS2::Width21;
2780 } else if (num<205) {
2781 return RS2::Width22;
2783 return RS2::Width23;
2787 return (RS2::LineWidth)num;
2793 * Converts a RS2::LineWidth into an int width.
2795 int FilterDXF::widthToNumber(RS2::LineWidth width) {
2797 case RS2::WidthByLayer:
2800 case RS2::WidthByBlock:
2803 case RS2::WidthDefault:
2814 * Converts a native unicode string into a DXF encoded string.
2816 * DXF endoding includes the following special sequences:
2817 * - %%%c for a diameter sign
2818 * - %%%d for a degree sign
2819 * - %%%p for a plus/minus sign
2821 QString FilterDXF::toDxfString(const QString & string)
2824 QString res = string;
2826 res = res.replace(QRegExp("\\n"), "\\P");
2828 res = res.replace(QRegExp(" "), "\\~");
2830 res = res.replace(QChar(0x2205), "%%c");
2832 res = res.replace(QChar(0x00B0), "%%d");
2834 res = res.replace(QChar(0x00B1), "%%p");
2839 for(int i=0; i<string.length(); ++i)
2841 int c = string.at(i).unicode();
2866 hex = QString("%1").arg(c, 4, 16);
2867 hex = hex.replace(' ', '0');
2868 res += QString("\\U+%1").arg(hex);
2871 res += string.at(i);
2881 * Converts a DXF encoded string into a native Unicode string.
2883 QString FilterDXF::toNativeString(const QString & string)
2885 QString res = string;
2887 res = res.replace(QRegExp("\\\\P"), "\n");
2889 res = res.replace(QRegExp("\\\\~"), " ");
2891 res = res.replace(QRegExp("%%c"), QChar(0x2205));
2893 res = res.replace(QRegExp("%%d"), QChar(0x00B0));
2895 res = res.replace(QRegExp("%%p"), QChar(0x00B1));
2897 // Unicode characters:
2904 QRegExp regexp("\\\\U\\+[0-9A-Fa-f]{4,4}");
2905 // regexp.search(res);
2906 regexp.indexIn(res);
2911 uCode = cap.right(4).toInt(&ok, 16);
2912 // workaround for Qt 3.0.x:
2913 res.replace(QRegExp("\\\\U\\+" + cap.right(4)), QChar(uCode));
2915 //res.replace(cap, QChar(uCode));
2918 while (!cap.isNull());
2927 QRegExp regexp("%%[0-9]{3,3}");
2928 // regexp.search(res);
2929 regexp.indexIn(res);
2934 uCode = cap.right(3).toInt(&ok, 10);
2935 // workaround for Qt 3.0.x:
2936 res.replace(QRegExp("%%" + cap.right(3)), QChar(uCode));
2938 //res.replace(cap, QChar(uCode));
2941 while (!cap.isNull());
2943 // Ignore font tags:
2944 res = res.replace(QRegExp("\\\\f[0-9A-Za-z| ]{0,};"), "");
2947 res = res.replace("\\{", "#curly#");
2948 res = res.replace("{", "");
2949 res = res.replace("#curly#", "{");
2951 res = res.replace("\\}", "#curly#");
2952 res = res.replace("}", "");
2953 res = res.replace("#curly#", "}");
2955 DEBUG->print("FilterDXF::toNativeString:");
2956 DEBUG->printUnicode(res);
2961 * Converts the given number from a DXF file into an AngleFormat enum.
2963 * @param num $DIMAUNIT from DXF (0: decimal deg, 1: deg/min/sec, 2: gradians,
2964 * 3: radians, 4: surveyor's units)
2966 * @ret Matching AngleFormat enum value.
2968 RS2::AngleFormat FilterDXF::numberToAngleFormat(int num) {
2970 RS2::AngleFormat af;
2975 af = RS2::DegreesDecimal;
2978 af = RS2::DegreesMinutesSeconds;
2987 af = RS2::Surveyors;
2996 * Converts AngleFormat enum to DXF number.
2998 int FilterDXF::angleFormatToNumber(RS2::AngleFormat af) {
3004 case RS2::DegreesDecimal:
3007 case RS2::DegreesMinutesSeconds:
3016 case RS2::Surveyors:
3027 * converts a DXF unit setting (e.g. INSUNITS) to a unit enum.
3029 RS2::Unit FilterDXF::numberToUnit(int num) {
3045 return RS2::Millimeter;
3048 return RS2::Centimeter;
3054 return RS2::Kilometer;
3057 return RS2::Microinch;
3066 return RS2::Angstrom;
3069 return RS2::Nanometer;
3075 return RS2::Decimeter;
3078 return RS2::Decameter;
3081 return RS2::Hectometer;
3084 return RS2::Gigameter;
3090 return RS2::Lightyear;
3103 * Converst a unit enum into a DXF unit number e.g. for INSUNITS.
3105 int FilterDXF::unitToNumber(RS2::Unit unit) {
3120 case RS2::Millimeter:
3123 case RS2::Centimeter:
3129 case RS2::Kilometer:
3132 case RS2::Microinch:
3144 case RS2::Nanometer:
3150 case RS2::Decimeter:
3153 case RS2::Decameter:
3156 case RS2::Hectometer:
3159 case RS2::Gigameter:
3165 case RS2::Lightyear:
3179 * Checks if the given variable is two-dimensional (e.g. $LIMMIN).
3181 bool FilterDXF::isVariableTwoDimensional(const QString& var) {
3182 if (var=="$LIMMIN" ||