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::EntityDrawing)
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::EntityDrawing)
1094 ((Drawing *)currentContainer)->addVariable(QString(key), QString(value), code);
1101 * Sets an int variable from the DXF file.
1103 void FilterDXF::setVariableInt(const char* key, int value, int code)
1105 DEBUG->print("FilterDXF::setVariableInt");
1107 // update document's variable list:
1108 if (currentContainer->rtti()==RS2::EntityDrawing)
1110 ((Drawing *)currentContainer)->addVariable(QString(key), value, code);
1117 * Sets a double variable from the DXF file.
1119 void FilterDXF::setVariableDouble(const char* key, double value, int code)
1121 DEBUG->print("FilterDXF::setVariableDouble");
1123 // update document's variable list:
1124 if (currentContainer->rtti() == RS2::EntityDrawing)
1126 ((Drawing *)currentContainer)->addVariable(QString(key), value, code);
1131 * Implementation of the method used for RS_Export to communicate
1134 * @param file Full path to the DXF file that will be written.
1136 bool FilterDXF::fileExport(Drawing & g, const QString & file, RS2::FormatType type)
1138 DEBUG->print("FilterDXF::fileExport: exporting file '%s'...",
1139 (const char *)QFile::encodeName(file));
1140 DEBUG->print("FilterDXF::fileExport: file type '%d'", (int)type);
1145 // check if we can write to that directory:
1146 // QString path = QFileInfo(file).dirPath(true);
1147 QString path = QFileInfo(file).absolutePath();
1149 if (QFileInfo(path).isWritable() == false)
1151 DEBUG->print("FilterDXF::fileExport: can't write file: no permission");
1157 // set version for DXF filter:
1158 DL_Codes::version exportVersion;
1160 if (type == RS2::FormatDXF12)
1162 exportVersion = DL_Codes::AC1009;
1166 exportVersion = DL_Codes::AC1015;
1169 //DL_WriterA* dw = dxf.out(file, VER_R12);
1170 DL_WriterA * dw = dxf.out((const char *)QFile::encodeName(file), exportVersion);
1174 DEBUG->print("FilterDXF::fileExport: can't write file");
1179 DEBUG->print("writing headers...");
1180 dxf.writeHeader(*dw);
1183 DEBUG->print("writing variables...");
1184 writeVariables(*dw);
1187 DEBUG->print("writing tables...");
1188 dw->sectionTables();
1191 dxf.writeVPort(*dw);
1194 DEBUG->print("writing line types...");
1195 int numLT = (int)RS2::BorderLineX2 - (int)RS2::LineByBlock;
1197 if (type == RS2::FormatDXF12)
1200 dw->tableLineTypes(numLT);
1202 for(int t=(int)RS2::LineByBlock; t<=(int)RS2::BorderLineX2; ++t)
1204 if ((RS2::LineType)t != RS2::NoPen)
1205 writeLineType(*dw, (RS2::LineType)t);
1211 DEBUG->print("writing layers...");
1212 dw->tableLayers(graphic->countLayers());
1214 for(uint i=0; i<graphic->countLayers(); ++i)
1216 Layer * l = graphic->layerAt(i);
1223 DEBUG->print("writing styles...");
1224 dxf.writeStyle(*dw);
1227 DEBUG->print("writing views...");
1231 DEBUG->print("writing ucs...");
1235 DEBUG->print("writing appid...");
1237 writeAppid(*dw, "ACAD");
1241 DEBUG->print("writing dim styles...");
1242 dxf.writeDimStyle(*dw,
1243 graphic->getVariableDouble("$DIMASZ", 2.5),
1244 graphic->getVariableDouble("$DIMEXE", 1.25),
1245 graphic->getVariableDouble("$DIMEXO", 0.625),
1246 graphic->getVariableDouble("$DIMGAP", 0.625),
1247 graphic->getVariableDouble("$DIMTXT", 2.5));
1250 if (type == RS2::FormatDXF)
1252 DEBUG->print("writing block records...");
1253 dxf.writeBlockRecord(*dw);
1255 for(uint i=0; i<graphic->countBlocks(); ++i)
1257 Block * blk = graphic->blockAt(i);
1258 dxf.writeBlockRecord(*dw, std::string((const char *)blk->getName().toLocal8Bit()));
1261 //writeBlock(*dw, blk);
1262 dw->dxfString( 0, "BLOCK_RECORD");
1263 //dw.dxfHex(5, 0x1F);
1266 dw->dxfString(100, "AcDbSymbolTableRecord");
1267 dw->dxfString(100, "AcDbBlockTableRecord");
1268 dw->dxfString( 2, blk->getName().toLocal8Bit());
1277 DEBUG->print("writing end of section TABLES...");
1281 DEBUG->print("writing blocks...");
1282 dw->sectionBlocks();
1284 if (type == RS2::FormatDXF)
1286 Block b1(graphic, BlockData("*Model_Space", Vector(0.0, 0.0), false));
1287 writeBlock(*dw, &b1);
1288 Block b2(graphic, BlockData("*Paper_Space", Vector(0.0, 0.0), false));
1289 writeBlock(*dw, &b2);
1290 Block b3(graphic, BlockData("*Paper_Space0", Vector(0.0, 0.0), false));
1291 writeBlock(*dw, &b3);
1294 for(uint i=0; i<graphic->countBlocks(); ++i)
1296 Block * blk = graphic->blockAt(i);
1298 // Save block if it's not a model or paper space:
1299 // Careful: other blocks with * / $ exist
1300 //if (blk->getName().at(0)!='*' &&
1301 // blk->getName().at(0)!='$') {
1302 writeBlock(*dw, blk);
1308 // Section ENTITIES:
1309 DEBUG->print("writing section ENTITIES...");
1310 dw->sectionEntities();
1312 for(Entity * e=graphic->firstEntity(RS2::ResolveNone); e!=NULL;
1313 e=graphic->nextEntity(RS2::ResolveNone))
1315 writeEntity(*dw, e);
1318 DEBUG->print("writing end of section ENTITIES...");
1321 if (type == RS2::FormatDXF)
1323 DEBUG->print("writing section OBJECTS...");
1324 dxf.writeObjects(*dw);
1326 // IMAGEDEF's from images in entities and images in blocks
1327 QStringList written;
1329 for(uint i=0; i<graphic->countBlocks(); ++i)
1331 Block * block = graphic->blockAt(i);
1333 for(Entity * e=block->firstEntity(RS2::ResolveAll); e!=NULL;
1334 e=block->nextEntity(RS2::ResolveAll))
1336 if (e->rtti() == RS2::EntityImage)
1338 Image * img = ((Image *)e);
1340 if (written.contains(file) == 0 && img->getHandle() != 0)
1342 writeImageDef(*dw, img);
1343 written.append(img->getFile());
1349 for(Entity * e=graphic->firstEntity(RS2::ResolveNone); e!=NULL;
1350 e=graphic->nextEntity(RS2::ResolveNone))
1352 if (e->rtti() == RS2::EntityImage)
1354 Image * img = ((Image *)e);
1356 if (written.contains(file) == 0 && img->getHandle() != 0)
1358 writeImageDef(*dw, img);
1359 written.append(img->getFile());
1363 DEBUG->print("writing end of section OBJECTS...");
1364 dxf.writeObjectsEnd(*dw);
1367 DEBUG->print("writing EOF...");
1370 DEBUG->print("close..");
1375 // check if file was actually written (strange world of windoze xp):
1376 if (QFileInfo(file).exists() == false)
1378 DEBUG->print("FilterDXF::fileExport: file could not be written");
1386 * Writes all known variable settings to the DXF file.
1388 void FilterDXF::writeVariables(DL_WriterA & dw)
1390 // Q3DictIterator<Variable> it(graphic->getVariableDict());
1391 QHashIterator<QString, Variable *> it(graphic->getVariableDict());
1393 // for (; it.current(); ++it)
1394 while (it.hasNext())
1398 // exclude variables that are not known to DXF 12:
1399 if (!DL_Dxf::checkVariable(it.key().toLatin1(), dxf.getVersion()))
1402 if (it.key() != "$ACADVER" && it.key() != "$HANDSEED")
1404 dw.dxfString(9, (const char *)it.key().toAscii().data());
1406 switch (it.value()->getType())
1408 case RS2::VariableVoid:
1410 case RS2::VariableInt:
1411 dw.dxfInt(it.value()->getCode(), it.value()->getInt());
1413 case RS2::VariableDouble:
1414 dw.dxfReal(it.value()->getCode(), it.value()->getDouble());
1416 case RS2::VariableString:
1417 dw.dxfString(it.value()->getCode(), (const char *)it.value()->getString().toAscii().data());
1419 case RS2::VariableVector:
1420 dw.dxfReal(it.value()->getCode(), it.value()->getVector().x);
1421 dw.dxfReal(it.value()->getCode() + 10, it.value()->getVector().y);
1423 if (isVariableTwoDimensional(it.key()) == false)
1424 dw.dxfReal(it.value()->getCode() + 20, it.value()->getVector().z);
1435 * Writes one layer to the DXF file.
1437 * @todo Add support for unicode layer names
1439 void FilterDXF::writeLayer(DL_WriterA & dw, Layer * l)
1443 DEBUG->print(Debug::D_WARNING, "FilterDXF::writeLayer: layer is NULL");
1447 DEBUG->print("FilterDXF::writeLayer %s", l->getName().toLatin1().data());
1449 dxf.writeLayer(dw, DL_LayerData((const char *)l->getName().toLocal8Bit(),
1450 l->isFrozen() + (l->isLocked() << 2)), DL_Attributes(std::string(""),
1451 colorToNumber(l->getPen().getColor()), widthToNumber(l->getPen().getWidth()),
1452 (const char *)lineTypeToName(l->getPen().getLineType()).toLocal8Bit()));
1454 DEBUG->print("FilterDXF::writeLayer end");
1458 * Writes a line type to the DXF file.
1460 void FilterDXF::writeLineType(DL_WriterA & dw, RS2::LineType t)
1462 dxf.writeLineType(dw, DL_LineTypeData((const char *)lineTypeToName(t).toLocal8Bit(), 0));
1468 * Writes an application id to the DXF file.
1470 * @param appid Application ID (e.g. "QCad").
1472 void FilterDXF::writeAppid(DL_WriterA& dw, const char* appid) {
1473 dxf.writeAppid(dw, appid);
1479 * Writes a block (just the definition, not the entities in it).
1481 void FilterDXF::writeBlock(DL_WriterA& dw, Block* blk) {
1483 DEBUG->print(Debug::D_WARNING,
1484 "FilterDXF::writeBlock: Block is NULL");
1488 DEBUG->print("writing block: %s", (const char*)blk->getName().toLocal8Bit());
1491 DL_BlockData((const char*)blk->getName().toLocal8Bit(), 0,
1492 blk->getBasePoint().x,
1493 blk->getBasePoint().y,
1494 blk->getBasePoint().z));
1495 for (Entity* e=blk->firstEntity(RS2::ResolveNone);
1497 e=blk->nextEntity(RS2::ResolveNone)) {
1500 dxf.writeEndBlock(dw, (const char*)blk->getName().toLocal8Bit());
1506 * Writes the given entity to the DXF file.
1508 void FilterDXF::writeEntity(DL_WriterA& dw, Entity* e) {
1509 writeEntity(dw, e, getEntityAttributes(e));
1514 * Writes the given entity to the DXF file.
1516 void FilterDXF::writeEntity(DL_WriterA& dw, Entity* e,
1517 const DL_Attributes& attrib) {
1519 if (e==NULL || e->getFlag(RS2::FlagUndone)) {
1522 DEBUG->print("writing Entity");
1524 switch (e->rtti()) {
1525 case RS2::EntityPoint:
1526 writePoint(dw, (Point*)e, attrib);
1528 case RS2::EntityLine:
1529 writeLine(dw, (Line*)e, attrib);
1531 case RS2::EntityPolyline:
1532 writePolyline(dw, (Polyline*)e, attrib);
1534 case RS2::EntitySpline:
1535 writeSpline(dw, (Spline*)e, attrib);
1537 case RS2::EntityVertex:
1539 case RS2::EntityCircle:
1540 writeCircle(dw, (Circle*)e, attrib);
1542 case RS2::EntityArc:
1543 writeArc(dw, (Arc*)e, attrib);
1545 case RS2::EntityEllipse:
1546 writeEllipse(dw, (Ellipse*)e, attrib);
1548 case RS2::EntityInsert:
1549 writeInsert(dw, (Insert*)e, attrib);
1551 case RS2::EntityText:
1552 writeText(dw, (Text*)e, attrib);
1555 case RS2::EntityDimAligned:
1556 case RS2::EntityDimAngular:
1557 case RS2::EntityDimLinear:
1558 case RS2::EntityDimRadial:
1559 case RS2::EntityDimDiametric:
1560 writeDimension(dw, (Dimension*)e, attrib);
1562 case RS2::EntityDimLeader:
1563 writeLeader(dw, (Leader*)e, attrib);
1565 case RS2::EntityHatch:
1566 writeHatch(dw, (Hatch*)e, attrib);
1568 case RS2::EntityImage:
1569 writeImage(dw, (Image*)e, attrib);
1571 case RS2::EntitySolid:
1572 writeSolid(dw, (Solid*)e, attrib);
1575 #ifndef RS_NO_COMPLEX_ENTITIES
1577 case RS2::EntityContainer:
1578 writeEntityContainer(dw, (EntityContainer*)e, attrib);
1590 * Writes the given Point entity to the file.
1592 void FilterDXF::writePoint(DL_WriterA& dw, Point* p,
1593 const DL_Attributes& attrib) {
1596 DL_PointData(p->getPos().x,
1604 * Writes the given Line( entity to the file.
1606 void FilterDXF::writeLine(DL_WriterA& dw, Line* l,
1607 const DL_Attributes& attrib) {
1610 DL_LineData(l->getStartpoint().x,
1611 l->getStartpoint().y,
1622 * Writes the given polyline entity to the file.
1624 void FilterDXF::writePolyline(DL_WriterA& dw,
1626 const DL_Attributes& attrib) {
1628 int count = l->count();
1629 if (l->isClosed()==false) {
1635 DL_PolylineData(count,
1640 Entity* nextEntity = 0;
1641 AtomicEntity* ae = NULL;
1642 Entity* lastEntity = l->lastEntity(RS2::ResolveNone);
1643 for (Entity* v=l->firstEntity(RS2::ResolveNone);
1647 nextEntity = l->nextEntity(RS2::ResolveNone);
1649 if (!v->isAtomic()) {
1653 ae = (AtomicEntity*)v;
1658 if (v->rtti()==RS2::EntityArc) {
1659 bulge = ((Arc*)v)->getBulge();
1662 DL_VertexData(ae->getStartpoint().x,
1663 ae->getStartpoint().y,
1669 //if (dxf.getVersion()==VER_R12) {
1670 if (nextEntity!=NULL) {
1671 if (nextEntity->rtti()==RS2::EntityArc) {
1672 bulge = ((Arc*)nextEntity)->getBulge();
1679 if (v->rtti()==RS2::EntityArc) {
1680 bulge = ((Arc*)v)->getBulge();
1685 if (l->isClosed()==false || v!=lastEntity) {
1687 DL_VertexData(ae->getEndpoint().x,
1688 ae->getEndpoint().y,
1693 dxf.writePolylineEnd(dw);
1699 * Writes the given spline entity to the file.
1701 void FilterDXF::writeSpline(DL_WriterA & dw, Spline * s, const DL_Attributes & attrib)
1703 // split spline into atomic entities for DXF R12:
1704 if (dxf.getVersion() == VER_R12)
1706 writeAtomicEntities(dw, s, attrib, RS2::ResolveNone);
1710 if (s->getNumberOfControlPoints() < s->getDegree() + 1)
1712 DEBUG->print(Debug::D_ERROR, "FilterDXF::writeSpline: "
1713 "Discarding spline: not enough control points given.");
1717 // Number of control points:
1718 int numCtrl = s->getNumberOfControlPoints();
1720 // Number of knots (= number of control points + spline degree + 1)
1721 int numKnots = numCtrl + s->getDegree() + 1;
1730 // write spline header:
1731 dxf.writeSpline(dw, DL_SplineData(s->getDegree(), numKnots, numCtrl, flags), attrib);
1733 // write spline knots:
1734 QList<Vector> cp = s->getControlPoints();
1735 QList<Vector>::iterator it;
1737 int k = s->getDegree() + 1;
1740 for(int i=1; i<=numKnots; i++)
1743 kd = DL_KnotData(0.0);
1744 else if (i <= numKnots - k)
1745 kd = DL_KnotData(1.0 / (numKnots - 2 * k + 1) * (i - k));
1747 kd = DL_KnotData(1.0);
1749 dxf.writeKnot(dw, kd);
1752 // write spline control points:
1753 for(it=cp.begin(); it!=cp.end(); ++it)
1755 dxf.writeControlPoint(dw, DL_ControlPointData((*it).x, (*it).y, 0.0));
1760 * Writes the given circle entity to the file.
1762 void FilterDXF::writeCircle(DL_WriterA& dw, Circle* c,
1763 const DL_Attributes& attrib) {
1766 DL_CircleData(c->getCenter().x,
1776 void FilterDXF::writeArc(DL_WriterA& dw, Arc* a,
1777 const DL_Attributes& attrib) {
1779 if (a->isReversed()) {
1780 a1 = a->getAngle2()*ARAD;
1781 a2 = a->getAngle1()*ARAD;
1783 a1 = a->getAngle1()*ARAD;
1784 a2 = a->getAngle2()*ARAD;
1788 DL_ArcData(a->getCenter().x,
1797 void FilterDXF::writeEllipse(DL_WriterA& dw, Ellipse* s,
1798 const DL_Attributes& attrib) {
1799 if (s->isReversed()) {
1802 DL_EllipseData(s->getCenter().x,
1815 DL_EllipseData(s->getCenter().x,
1828 void FilterDXF::writeInsert(DL_WriterA & dw, Insert * i, const DL_Attributes & attrib)
1830 dxf.writeInsert(dw, DL_InsertData(i->getName().toLatin1().data(),
1831 i->getInsertionPoint().x, i->getInsertionPoint().y, 0.0,
1832 i->getScale().x, i->getScale().y, 0.0,
1833 i->getAngle() * ARAD, i->getCols(), i->getRows(),
1834 i->getSpacing().x, i->getSpacing().y),
1838 void FilterDXF::writeText(DL_WriterA & dw, Text * t, const DL_Attributes & attrib)
1840 if (dxf.getVersion()==VER_R12)
1845 if (t->getHAlign()==RS2::HAlignLeft) {
1847 } else if (t->getHAlign()==RS2::HAlignCenter) {
1849 } else if (t->getHAlign()==RS2::HAlignRight) {
1853 if (t->getVAlign()==RS2::VAlignTop) {
1855 } else if (t->getVAlign()==RS2::VAlignMiddle) {
1857 } else if (t->getVAlign()==RS2::VAlignBottom) {
1863 DL_TextData(t->getInsertionPoint().x,
1864 t->getInsertionPoint().y,
1866 t->getInsertionPoint().x,
1867 t->getInsertionPoint().y,
1873 (const char*)toDxfString(
1874 t->getText()).toLocal8Bit(),
1875 (const char*)t->getStyle().toLocal8Bit(),
1881 int attachmentPoint=1;
1883 if (t->getHAlign()==RS2::HAlignLeft) {
1885 } else if (t->getHAlign()==RS2::HAlignCenter) {
1887 } else if (t->getHAlign()==RS2::HAlignRight) {
1891 if (t->getVAlign()==RS2::VAlignTop) {
1893 } else if (t->getVAlign()==RS2::VAlignMiddle) {
1895 } else if (t->getVAlign()==RS2::VAlignBottom) {
1901 DL_MTextData(t->getInsertionPoint().x,
1902 t->getInsertionPoint().y,
1907 t->getDrawingDirection(),
1908 t->getLineSpacingStyle(),
1909 t->getLineSpacingFactor(),
1910 (const char*)toDxfString(
1911 t->getText()).toLocal8Bit(),
1912 (const char*)t->getStyle().toLocal8Bit(),
1920 void FilterDXF::writeDimension(DL_WriterA& dw, Dimension* d,
1921 const DL_Attributes& attrib) {
1923 // split hatch into atomic entities:
1924 if (dxf.getVersion()==VER_R12) {
1925 writeAtomicEntities(dw, d, attrib, RS2::ResolveNone);
1930 int attachmentPoint=1;
1931 if (d->getHAlign()==RS2::HAlignLeft) {
1933 } else if (d->getHAlign()==RS2::HAlignCenter) {
1935 } else if (d->getHAlign()==RS2::HAlignRight) {
1938 if (d->getVAlign()==RS2::VAlignTop) {
1940 } else if (d->getVAlign()==RS2::VAlignMiddle) {
1942 } else if (d->getVAlign()==RS2::VAlignBottom) {
1946 switch (d->rtti()) {
1947 case RS2::EntityDimAligned:
1950 case RS2::EntityDimLinear:
1953 case RS2::EntityDimRadial:
1956 case RS2::EntityDimDiametric:
1964 DL_DimensionData dimData(d->getDefinitionPoint().x,
1965 d->getDefinitionPoint().y,
1967 d->getMiddleOfText().x,
1968 d->getMiddleOfText().y,
1972 d->getLineSpacingStyle(),
1973 d->getLineSpacingFactor(),
1974 (const char*)toDxfString(
1975 d->getText()).toLocal8Bit(),
1976 (const char*)d->getStyle().toLocal8Bit(),
1979 if (d->rtti()==RS2::EntityDimAligned) {
1980 DimAligned* da = (DimAligned*)d;
1982 DL_DimAlignedData dimAlignedData(da->getExtensionPoint1().x,
1983 da->getExtensionPoint1().y,
1985 da->getExtensionPoint2().x,
1986 da->getExtensionPoint2().y,
1989 dxf.writeDimAligned(dw, dimData, dimAlignedData, attrib);
1990 } else if (d->rtti()==RS2::EntityDimLinear) {
1991 DimLinear* dl = (DimLinear*)d;
1993 DL_DimLinearData dimLinearData(dl->getExtensionPoint1().x,
1994 dl->getExtensionPoint1().y,
1996 dl->getExtensionPoint2().x,
1997 dl->getExtensionPoint2().y,
2002 dxf.writeDimLinear(dw, dimData, dimLinearData, attrib);
2003 } else if (d->rtti()==RS2::EntityDimRadial) {
2004 DimRadial* dr = (DimRadial*)d;
2006 DL_DimRadialData dimRadialData(dr->getDefinitionPoint().x,
2007 dr->getDefinitionPoint().y,
2011 dxf.writeDimRadial(dw, dimData, dimRadialData, attrib);
2012 } else if (d->rtti()==RS2::EntityDimDiametric) {
2013 DimDiametric* dr = (DimDiametric*)d;
2015 DL_DimDiametricData dimDiametricData(dr->getDefinitionPoint().x,
2016 dr->getDefinitionPoint().y,
2020 dxf.writeDimDiametric(dw, dimData, dimDiametricData, attrib);
2021 } else if (d->rtti()==RS2::EntityDimAngular) {
2022 DimAngular* da = (DimAngular*)d;
2024 DL_DimAngularData dimAngularData(da->getDefinitionPoint1().x,
2025 da->getDefinitionPoint1().y,
2027 da->getDefinitionPoint2().x,
2028 da->getDefinitionPoint2().y,
2030 da->getDefinitionPoint3().x,
2031 da->getDefinitionPoint3().y,
2033 da->getDefinitionPoint4().x,
2034 da->getDefinitionPoint4().y,
2037 dxf.writeDimAngular(dw, dimData, dimAngularData, attrib);
2043 void FilterDXF::writeLeader(DL_WriterA& dw, Leader* l,
2044 const DL_Attributes& attrib) {
2048 DL_LeaderData(l->hasArrowHead(),
2058 for (Entity* v=l->firstEntity(RS2::ResolveNone);
2060 v=l->nextEntity(RS2::ResolveNone)) {
2062 // Write line verties:
2063 if (v->rtti()==RS2::EntityLine) {
2066 dxf.writeLeaderVertex(
2068 DL_LeaderVertexData(l->getStartpoint().x,
2069 l->getStartpoint().y,
2073 dxf.writeLeaderVertex(
2075 DL_LeaderVertexData(l->getEndpoint().x,
2081 DEBUG->print(Debug::D_WARNING,
2082 "dropping leader with no vertices");
2087 void FilterDXF::writeHatch(DL_WriterA& dw, Hatch* h,
2088 const DL_Attributes& attrib) {
2090 // split hatch into atomic entities:
2091 if (dxf.getVersion()==VER_R12) {
2092 writeAtomicEntities(dw, h, attrib, RS2::ResolveAll);
2096 bool writeIt = true;
2097 if (h->countLoops()>0) {
2098 // check if all of the loops contain entities:
2099 for (Entity* l=h->firstEntity(RS2::ResolveNone);
2101 l=h->nextEntity(RS2::ResolveNone)) {
2103 if (l->isContainer() && !l->getFlag(RS2::FlagTemp)) {
2104 if (l->count()==0) {
2114 DEBUG->print(Debug::D_WARNING,
2115 "FilterDXF::writeHatch: Dropping Hatch");
2117 DL_HatchData data(h->countLoops(),
2121 (const char*)h->getPattern().toLocal8Bit());
2122 dxf.writeHatch1(dw, data, attrib);
2124 for (Entity* l=h->firstEntity(RS2::ResolveNone);
2126 l=h->nextEntity(RS2::ResolveNone)) {
2128 // Write hatch loops:
2129 if (l->isContainer() && !l->getFlag(RS2::FlagTemp)) {
2130 EntityContainer* loop = (EntityContainer*)l;
2131 DL_HatchLoopData lData(loop->count());
2132 dxf.writeHatchLoop1(dw, lData);
2134 for (Entity* ed=loop->firstEntity(RS2::ResolveNone);
2136 ed=loop->nextEntity(RS2::ResolveNone)) {
2138 // Write hatch loop edges:
2139 if (ed->rtti()==RS2::EntityLine) {
2140 Line* ln = (Line*)ed;
2143 DL_HatchEdgeData(ln->getStartpoint().x,
2144 ln->getStartpoint().y,
2145 ln->getEndpoint().x,
2146 ln->getEndpoint().y));
2147 } else if (ed->rtti()==RS2::EntityArc) {
2149 if (!ar->isReversed()) {
2152 DL_HatchEdgeData(ar->getCenter().x,
2161 DL_HatchEdgeData(ar->getCenter().x,
2164 2*M_PI-ar->getAngle1(),
2165 2*M_PI-ar->getAngle2(),
2168 } else if (ed->rtti()==RS2::EntityCircle) {
2169 Circle* ci = (Circle*)ed;
2172 DL_HatchEdgeData(ci->getCenter().x,
2180 dxf.writeHatchLoop2(dw, lData);
2183 dxf.writeHatch2(dw, data, attrib);
2190 void FilterDXF::writeSolid(DL_WriterA& dw, Solid* s,
2191 const DL_Attributes& attrib) {
2193 // split solid into line entities:
2194 //if (dxf.getVersion()==VER_R12) {
2195 for (int i=0; i<3; ++i) {
2198 DL_LineData(s->getCorner(i).x,
2201 s->getCorner((i+1)%3).x,
2202 s->getCorner((i+1)%3).y,
2211 void FilterDXF::writeImage(DL_WriterA& dw, Image* i,
2212 const DL_Attributes& attrib) {
2213 int handle = dxf.writeImage(
2215 DL_ImageData(std::string(""),
2216 i->getInsertionPoint().x,
2217 i->getInsertionPoint().y,
2231 i->setHandle(handle);
2236 void FilterDXF::writeEntityContainer(DL_WriterA& dw, EntityContainer* con,
2237 const DL_Attributes& /*attrib*/) {
2241 // Creating an unique ID from the element ID
2242 int tmp, c=1; // tmp = temporary var c = counter var
2247 blkName.append((char) tmp %10 + 48);
2256 dxf.writeBlockRecord(dw);
2257 dw.dxfString( 0, "BLOCK_RECORD");
2261 dw.dxfString(100, "AcDbSymbolTableRecord");
2262 dw.dxfString(100, "AcDbBlockTableRecord");
2263 dw.dxfString( 2, blkName.toLatin1());
2265 dw.dxfString(0, "ENDTAB");
2268 BlockData blkdata(blkName, Vector(0,0), false);
2270 Block* blk = new Block(graphic, blkdata);
2272 for (Entity* e1 = con->firstEntity(); e1 != NULL;
2273 e1 = con->nextEntity() ) {
2276 writeBlock(dw, blk);
2284 * Writes the atomic entities of the given cotnainer to the file.
2286 void FilterDXF::writeAtomicEntities(DL_WriterA& dw, EntityContainer* c,
2287 const DL_Attributes& attrib,
2288 RS2::ResolveLevel level) {
2290 for (Entity* e=c->firstEntity(level);
2292 e=c->nextEntity(level)) {
2294 writeEntity(dw, e, attrib);
2299 * Writes an IMAGEDEF object into an OBJECT section.
2301 void FilterDXF::writeImageDef(DL_WriterA& dw, Image* i) {
2302 if (i==NULL || i->getFlag(RS2::FlagUndone)) {
2309 DL_ImageData((const char*)i->getFile().toLocal8Bit(),
2310 i->getInsertionPoint().x,
2311 i->getInsertionPoint().y,
2329 * Sets the entities attributes according to the attributes
2330 * that come from a DXF file.
2332 void FilterDXF::setEntityAttributes(Entity* entity,
2333 const DL_Attributes& attrib) {
2334 DEBUG->print("FilterDXF::setEntityAttributes");
2337 pen.setColor(Qt::black);
2338 pen.setLineType(RS2::SolidLine);
2341 if (attrib.getLayer().empty()) {
2342 entity->setLayer("0");
2344 // add layer in case it doesn't exist:
2345 if (graphic->findLayer(attrib.getLayer().c_str())==NULL) {
2346 addLayer(DL_LayerData(attrib.getLayer(), 0));
2348 entity->setLayer(attrib.getLayer().c_str());
2352 pen.setColor(numberToColor(attrib.getColor()));
2355 pen.setLineType(nameToLineType(attrib.getLineType().c_str()));
2358 pen.setWidth(numberToWidth(attrib.getWidth()));
2360 entity->setPen(pen);
2361 DEBUG->print("FilterDXF::setEntityAttributes: OK");
2365 * Gets the entities attributes as a DL_Attributes object.
2367 DL_Attributes FilterDXF::getEntityAttributes(Entity * entity)
2370 Layer * layer = entity->getLayer();
2374 layerName = layer->getName();
2378 Pen pen = entity->getPen(false);
2381 int color = colorToNumber(pen.getColor());
2382 //printf("Color is: %s -> %d\n", pen.getColor().name().toLatin1(), color);
2385 QString lineType = lineTypeToName(pen.getLineType());
2388 int width = widthToNumber(pen.getWidth());
2390 DL_Attributes attrib(layerName.toLatin1().data(), color, width, lineType.toLatin1().data());
2396 * @return Pen with the same attributes as 'attrib'.
2398 Pen FilterDXF::attributesToPen(const DL_Attributes & attrib) const
2401 printf("converting Color %d to %s\n",
2402 attrib.getColor(), numberToColor(attrib.getColor()).name().toLatin1());
2405 Pen pen(numberToColor(attrib.getColor()),
2406 numberToWidth(attrib.getWidth()),
2407 nameToLineType(attrib.getLineType().c_str()));
2414 * Converts a color index (num) into a Color object.
2415 * Please refer to the dxflib documentation for details.
2417 * @param num Color number.
2418 * @param comp Compatibility with older QCad versions (1.5.3 and older)
2420 Color FilterDXF::numberToColor(int num, bool comp) {
2421 // Compatibility with QCad 1.5.3 and older:
2428 return Qt::darkBlue;
2431 return Qt::darkGreen;
2434 return Qt::darkCyan;
2440 return Qt::darkMagenta;
2443 return Qt::darkYellow;
2446 return Qt::lightGray;
2449 return Qt::darkGray;
2477 return Color(RS2::FlagByBlock);
2478 } else if (num==256) {
2479 return Color(RS2::FlagByLayer);
2480 } else if (num<=255 && num>=0) {
2481 return Color((int)(dxfColors[num][0]*255),
2482 (int)(dxfColors[num][1]*255),
2483 (int)(dxfColors[num][2]*255));
2485 DEBUG->print(Debug::D_WARNING,
2486 "FilterDXF::numberToColor: Invalid color number given.");
2487 return Color(RS2::FlagByLayer);
2496 * Converts a color into a color number in the DXF palette.
2497 * The color that fits best is chosen.
2499 int FilterDXF::colorToNumber(const Color& col) {
2501 //printf("Searching color for %s\n", col.name().toLatin1());
2503 // Special color BYBLOCK:
2504 if (col.getFlag(RS2::FlagByBlock)) {
2508 // Special color BYLAYER
2509 else if (col.getFlag(RS2::FlagByLayer)) {
2513 // Special color black is not in the table but white represents both
2515 else if (col.red()==0 && col.green()==0 && col.blue()==0) {
2522 int diff=255*3; // smallest difference to a color in the table found so far
2524 // Run through the whole table and compare
2525 for (int i=1; i<=255; i++) {
2526 int d = abs(col.red()-(int)(dxfColors[i][0]*255))
2527 + abs(col.green()-(int)(dxfColors[i][1]*255))
2528 + abs(col.blue()-(int)(dxfColors[i][2]*255));
2532 printf("color %f,%f,%f is closer\n",
2544 //printf(" Found: %d, diff: %d\n", num, diff);
2550 * Converts a line type name (e.g. "CONTINUOUS") into a RS2::LineType
2553 RS2::LineType FilterDXF::nameToLineType(const QString & name)
2555 QString uName = name.toUpper();
2557 // Standard linetypes for QCad II / AutoCAD
2558 if (uName.isEmpty() || uName == "BYLAYER")
2559 return RS2::LineByLayer;
2560 else if (uName == "BYBLOCK")
2561 return RS2::LineByBlock;
2562 else if (uName == "CONTINUOUS" || uName == "ACAD_ISO01W100")
2563 return RS2::SolidLine;
2564 else if (uName == "ACAD_ISO07W100" || uName == "DOT")
2565 return RS2::DotLine;
2566 else if (uName == "DOT2")
2567 return RS2::DotLine2;
2568 else if (uName == "DOTX2")
2569 return RS2::DotLineX2;
2570 else if (uName == "ACAD_ISO02W100" || uName == "ACAD_ISO03W100"
2571 || uName == "DASHED" || uName == "HIDDEN")
2572 return RS2::DashLine;
2573 else if (uName == "DASHED2" || uName == "HIDDEN2")
2574 return RS2::DashLine2;
2575 else if (uName == "DASHEDX2" || uName == "HIDDENX2")
2576 return RS2::DashLineX2;
2577 else if (uName == "ACAD_ISO10W100" || uName == "DASHDOT")
2578 return RS2::DashDotLine;
2579 else if (uName == "DASHDOT2")
2580 return RS2::DashDotLine2;
2581 else if (uName == "ACAD_ISO04W100" || uName == "DASHDOTX2")
2582 return RS2::DashDotLineX2;
2583 else if (uName == "ACAD_ISO12W100" || uName == "DIVIDE")
2584 return RS2::DivideLine;
2585 else if (uName == "DIVIDE2")
2586 return RS2::DivideLine2;
2587 else if (uName == "ACAD_ISO05W100" || uName == "DIVIDEX2")
2588 return RS2::DivideLineX2;
2589 else if (uName == "CENTER")
2590 return RS2::CenterLine;
2591 else if (uName == "CENTER2")
2592 return RS2::CenterLine2;
2593 else if (uName == "CENTERX2")
2594 return RS2::CenterLineX2;
2595 else if (uName == "BORDER")
2596 return RS2::BorderLine;
2597 else if (uName == "BORDER2")
2598 return RS2::BorderLine2;
2599 else if (uName == "BORDERX2")
2600 return RS2::BorderLineX2;
2602 return RS2::SolidLine;
2606 * Converts a LineType into a name for a line type.
2608 QString FilterDXF::lineTypeToName(RS2::LineType lineType)
2610 // Standard linetypes for QCad II / AutoCAD
2613 case RS2::SolidLine:
2614 return "CONTINUOUS";
2623 case RS2::DotLineX2:
2630 case RS2::DashLine2:
2633 case RS2::DashLineX2:
2637 case RS2::DashDotLine:
2640 case RS2::DashDotLine2:
2643 case RS2::DashDotLineX2:
2647 case RS2::DivideLine:
2650 case RS2::DivideLine2:
2653 case RS2::DivideLineX2:
2657 case RS2::CenterLine:
2660 case RS2::CenterLine2:
2663 case RS2::CenterLineX2:
2667 case RS2::BorderLine:
2670 case RS2::BorderLine2:
2673 case RS2::BorderLineX2:
2678 case RS2::LineByLayer:
2681 case RS2::LineByBlock:
2688 return "CONTINUOUS";
2694 * Converts a LineType into a name for a line type.
2696 /*QString FilterDXF::lineTypeToDescription(RS2::LineType lineType) {
2698 // Standard linetypes for QCad II / AutoCAD
2700 case RS2::SolidLine:
2701 return "Solid line";
2703 return "ISO Dashed __ __ __ __ __ __ __ __ __ __ _";
2705 return "ISO Dashed with Distance __ __ __ _";
2706 case RS2::DashDotLine:
2707 return "ISO Long Dashed Dotted ____ . ____ . __";
2708 case RS2::DashDotDotLine:
2709 return "ISO Long Dashed Double Dotted ____ .. __";
2710 case RS2::LineByLayer:
2712 case RS2::LineByBlock:
2718 return "CONTINUOUS";
2724 * Converts a line width number (e.g. 1) into a RS2::LineWidth.
2726 RS2::LineWidth FilterDXF::numberToWidth(int num) {
2729 return RS2::WidthByLayer;
2732 return RS2::WidthByBlock;
2735 return RS2::WidthDefault;
2739 return RS2::Width00;
2741 return RS2::Width01;
2742 } else if (num<11) {
2743 return RS2::Width02;
2744 } else if (num<14) {
2745 return RS2::Width03;
2746 } else if (num<16) {
2747 return RS2::Width04;
2748 } else if (num<19) {
2749 return RS2::Width05;
2750 } else if (num<22) {
2751 return RS2::Width06;
2752 } else if (num<27) {
2753 return RS2::Width07;
2754 } else if (num<32) {
2755 return RS2::Width08;
2756 } else if (num<37) {
2757 return RS2::Width09;
2758 } else if (num<45) {
2759 return RS2::Width10;
2760 } else if (num<52) {
2761 return RS2::Width11;
2762 } else if (num<57) {
2763 return RS2::Width12;
2764 } else if (num<65) {
2765 return RS2::Width13;
2766 } else if (num<75) {
2767 return RS2::Width14;
2768 } else if (num<85) {
2769 return RS2::Width15;
2770 } else if (num<95) {
2771 return RS2::Width16;
2772 } else if (num<103) {
2773 return RS2::Width17;
2774 } else if (num<112) {
2775 return RS2::Width18;
2776 } else if (num<130) {
2777 return RS2::Width19;
2778 } else if (num<149) {
2779 return RS2::Width20;
2780 } else if (num<180) {
2781 return RS2::Width21;
2782 } else if (num<205) {
2783 return RS2::Width22;
2785 return RS2::Width23;
2789 return (RS2::LineWidth)num;
2795 * Converts a RS2::LineWidth into an int width.
2797 int FilterDXF::widthToNumber(RS2::LineWidth width) {
2799 case RS2::WidthByLayer:
2802 case RS2::WidthByBlock:
2805 case RS2::WidthDefault:
2816 * Converts a native unicode string into a DXF encoded string.
2818 * DXF endoding includes the following special sequences:
2819 * - %%%c for a diameter sign
2820 * - %%%d for a degree sign
2821 * - %%%p for a plus/minus sign
2823 QString FilterDXF::toDxfString(const QString & string)
2826 QString res = string;
2828 res = res.replace(QRegExp("\\n"), "\\P");
2830 res = res.replace(QRegExp(" "), "\\~");
2832 res = res.replace(QChar(0x2205), "%%c");
2834 res = res.replace(QChar(0x00B0), "%%d");
2836 res = res.replace(QChar(0x00B1), "%%p");
2841 for(int i=0; i<string.length(); ++i)
2843 int c = string.at(i).unicode();
2868 hex = QString("%1").arg(c, 4, 16);
2869 hex = hex.replace(' ', '0');
2870 res += QString("\\U+%1").arg(hex);
2873 res += string.at(i);
2883 * Converts a DXF encoded string into a native Unicode string.
2885 QString FilterDXF::toNativeString(const QString & string)
2887 QString res = string;
2889 res = res.replace(QRegExp("\\\\P"), "\n");
2891 res = res.replace(QRegExp("\\\\~"), " ");
2893 res = res.replace(QRegExp("%%c"), QChar(0x2205));
2895 res = res.replace(QRegExp("%%d"), QChar(0x00B0));
2897 res = res.replace(QRegExp("%%p"), QChar(0x00B1));
2899 // Unicode characters:
2906 QRegExp regexp("\\\\U\\+[0-9A-Fa-f]{4,4}");
2907 // regexp.search(res);
2908 regexp.indexIn(res);
2913 uCode = cap.right(4).toInt(&ok, 16);
2914 // workaround for Qt 3.0.x:
2915 res.replace(QRegExp("\\\\U\\+" + cap.right(4)), QChar(uCode));
2917 //res.replace(cap, QChar(uCode));
2920 while (!cap.isNull());
2929 QRegExp regexp("%%[0-9]{3,3}");
2930 // regexp.search(res);
2931 regexp.indexIn(res);
2936 uCode = cap.right(3).toInt(&ok, 10);
2937 // workaround for Qt 3.0.x:
2938 res.replace(QRegExp("%%" + cap.right(3)), QChar(uCode));
2940 //res.replace(cap, QChar(uCode));
2943 while (!cap.isNull());
2945 // Ignore font tags:
2946 res = res.replace(QRegExp("\\\\f[0-9A-Za-z| ]{0,};"), "");
2949 res = res.replace("\\{", "#curly#");
2950 res = res.replace("{", "");
2951 res = res.replace("#curly#", "{");
2953 res = res.replace("\\}", "#curly#");
2954 res = res.replace("}", "");
2955 res = res.replace("#curly#", "}");
2957 DEBUG->print("FilterDXF::toNativeString:");
2958 DEBUG->printUnicode(res);
2963 * Converts the given number from a DXF file into an AngleFormat enum.
2965 * @param num $DIMAUNIT from DXF (0: decimal deg, 1: deg/min/sec, 2: gradians,
2966 * 3: radians, 4: surveyor's units)
2968 * @ret Matching AngleFormat enum value.
2970 RS2::AngleFormat FilterDXF::numberToAngleFormat(int num) {
2972 RS2::AngleFormat af;
2977 af = RS2::DegreesDecimal;
2980 af = RS2::DegreesMinutesSeconds;
2989 af = RS2::Surveyors;
2998 * Converts AngleFormat enum to DXF number.
3000 int FilterDXF::angleFormatToNumber(RS2::AngleFormat af) {
3006 case RS2::DegreesDecimal:
3009 case RS2::DegreesMinutesSeconds:
3018 case RS2::Surveyors:
3029 * converts a DXF unit setting (e.g. INSUNITS) to a unit enum.
3031 RS2::Unit FilterDXF::numberToUnit(int num) {
3047 return RS2::Millimeter;
3050 return RS2::Centimeter;
3056 return RS2::Kilometer;
3059 return RS2::Microinch;
3068 return RS2::Angstrom;
3071 return RS2::Nanometer;
3077 return RS2::Decimeter;
3080 return RS2::Decameter;
3083 return RS2::Hectometer;
3086 return RS2::Gigameter;
3092 return RS2::Lightyear;
3105 * Converst a unit enum into a DXF unit number e.g. for INSUNITS.
3107 int FilterDXF::unitToNumber(RS2::Unit unit) {
3122 case RS2::Millimeter:
3125 case RS2::Centimeter:
3131 case RS2::Kilometer:
3134 case RS2::Microinch:
3146 case RS2::Nanometer:
3152 case RS2::Decimeter:
3155 case RS2::Decameter:
3158 case RS2::Hectometer:
3161 case RS2::Gigameter:
3167 case RS2::Lightyear:
3181 * Checks if the given variable is two-dimensional (e.g. $LIMMIN).
3183 bool FilterDXF::isVariableTwoDimensional(const QString& var) {
3184 if (var=="$LIMMIN" ||