]> Shamusworld >> Repos - architektonas/blob - src/base/filterdxf.cpp
Fixed problem with MDI activation.
[architektonas] / src / base / filterdxf.cpp
1 // filterdxf.cpp
2 //
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
9 //
10 // JLH = James L. Hammons <jlhamm@acm.org>
11 //
12 // Who  When        What
13 // ---  ----------  -----------------------------------------------------------
14 // JLH  05/28/2010  Added this text. :-)
15 //
16
17 #include "filterdxf.h"
18
19 #include <stdio.h>
20 #include <QtCore>
21 #include "dl_attributes.h"
22 #include "dl_codes.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"
29 #include "hatch.h"
30 #include "image.h"
31 #include "leader.h"
32 #include "system.h"
33
34 /**
35  * Default constructor.
36  *
37  */
38 FilterDXF::FilterDXF(): FilterInterface()
39 {
40         DEBUG->print("FilterDXF::FilterDXF()");
41
42         addImportFormat(RS2::FormatDXF);
43         addExportFormat(RS2::FormatDXF);
44         addExportFormat(RS2::FormatDXF12);
45
46         mtext = "";
47         polyline = NULL;
48         leader = NULL;
49         hatch = NULL;
50         hatchLoop = NULL;
51         currentContainer = NULL;
52         graphic = NULL;
53         //exportVersion = DL_Codes::VER_2002;
54         //systemVariables.setAutoDelete(true);
55         DEBUG->print("FilterDXF::FilterDXF(): OK");
56 }
57
58 /**
59  * Destructor.
60  */
61 FilterDXF::~FilterDXF()
62 {
63         DEBUG->print("FilterDXF::~FilterDXF()");
64         DEBUG->print("FilterDXF::~FilterDXF(): OK");
65 }
66
67 /**
68  * Implementation of the method used for RS_Import to communicate
69  * with this filter.
70  *
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.
74  */
75 bool FilterDXF::fileImport(Drawing & g, const QString & file, RS2::FormatType /*type*/)
76 {
77         DEBUG->print("FilterDXF::fileImport");
78         //DEBUG->timestamp();
79
80         DEBUG->print("DXF Filter: importing file '%s'...", (const char *)QFile::encodeName(file));
81
82         graphic = &g;
83         currentContainer = graphic;
84         this->file = file;
85
86         DEBUG->print("graphic->countLayers(): %d", graphic->countLayers());
87
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);
93
94         if (!success)
95         {
96                 DEBUG->print(Debug::D_WARNING, "Cannot open DXF file '%s'.",
97                         (const char *)QFile::encodeName(file));
98                 return false;
99         }
100
101         DEBUG->print("FilterDXF::fileImport: adding variables");
102
103         // add some variables that need to be there for DXF drawings:
104         if (graphic->getVariableString("$DIMSTYLE", "").isEmpty())
105         {
106                 DEBUG->print("FilterDXF::fileImport: adding DIMSTYLE");
107                 graphic->addVariable("$DIMSTYLE", "Standard", 2);
108                 DEBUG->print("FilterDXF::fileImport: adding DIMSTYLE: OK");
109         }
110
111         DEBUG->print("FilterDXF::fileImport: adding variables: OK");
112
113         DEBUG->print("FilterDXF::fileImport: updating inserts");
114         graphic->updateInserts();
115         DEBUG->print("FilterDXF::fileImport: updating inserts: OK");
116
117         DEBUG->print("FilterDXF::fileImport OK");
118         //DEBUG->timestamp();
119
120         return true;
121 }
122
123 /**
124  * Implementation of the method which handles layers.
125  */
126 void FilterDXF::addLayer(const DL_LayerData& data) {
127     DEBUG->print("FilterDXF::addLayer");
128     DEBUG->print("  adding layer: %s", data.name.c_str());
129
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);
135
136     DEBUG->print("FilterDXF::addLayer: flags");
137     if (data.flags&0x01) {
138         layer->freeze(true);
139     }
140     if (data.flags&0x04) {
141         layer->lock(true);
142     }
143
144     DEBUG->print("FilterDXF::addLayer: add layer to graphic");
145     graphic->addLayer(layer);
146     DEBUG->print("FilterDXF::addLayer: OK");
147 }
148
149 /**
150  * Implementation of the method which handles blocks.
151  *
152  * @todo Adding blocks to blocks (stack for currentContainer)
153  */
154 void FilterDXF::addBlock(const DL_BlockData & data)
155 {
156         DEBUG->print("FilterDXF::addBlock");
157         DEBUG->print("  adding block: %s", data.name.c_str());
158
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")
166         {
167
168 #ifndef RS_NO_COMPLEX_ENTITIES
169                 if (QString(data.name.c_str()).startsWith("__CE"))
170                 {
171                         EntityContainer * ec = new EntityContainer();
172                         ec->setLayer("0");
173                         currentContainer = ec;
174                         graphic->addEntity(ec);
175                         //currentContainer->setLayer(graphic->findLayer("0"));
176                 }
177                 else
178                 {
179 #endif
180                         Vector bp(data.bpx, data.bpy);
181                         Block * block = new Block(graphic, BlockData(data.name.c_str(), bp, false));
182                         //block->setFlags(flags);
183
184                         if (graphic->addBlock(block))
185                                 currentContainer = block;
186 #ifndef RS_NO_COMPLEX_ENTITIES
187                 }
188 #endif
189         }
190 }
191
192 /**
193  * Implementation of the method which closes blocks.
194  */
195 void FilterDXF::endBlock()
196 {
197         currentContainer = graphic;
198 }
199
200 /**
201  * Implementation of the method which handles point entities.
202  */
203 void FilterDXF::addPoint(const DL_PointData & data)
204 {
205         Vector v(data.x, data.y);
206         Point * entity = new Point(currentContainer, PointData(v));
207         setEntityAttributes(entity, attributes);
208         currentContainer->addEntity(entity);
209 }
210
211 /**
212  * Implementation of the method which handles line entities.
213  */
214 void FilterDXF::addLine(const DL_LineData & data)
215 {
216         DEBUG->print("FilterDXF::addLine");
217
218         Vector v1(data.x1, data.y1);
219         Vector v2(data.x2, data.y2);
220
221         DEBUG->print("FilterDXF::addLine: create line");
222
223         if (currentContainer == NULL)
224                 DEBUG->print("FilterDXF::addLine: currentContainer is NULL");
225
226         Line * entity = new Line(currentContainer, LineData(v1, v2));
227         DEBUG->print("FilterDXF::addLine: set attributes");
228         setEntityAttributes(entity, attributes);
229
230         DEBUG->print("FilterDXF::addLine: add entity");
231
232         currentContainer->addEntity(entity);
233
234         DEBUG->print("FilterDXF::addLine: OK");
235 }
236
237 /**
238  * Implementation of the method which handles arc entities.
239  *
240  * @param angle1 Start angle in deg (!)
241  * @param angle2 End angle in deg (!)
242  */
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,
250                  data.angle1/ARAD,
251                  data.angle2/ARAD,
252                  false);
253     Arc* entity = new Arc(currentContainer, d);
254     setEntityAttributes(entity, attributes);
255
256     currentContainer->addEntity(entity);
257 }
258
259
260
261 /**
262  * Implementation of the method which handles ellipse entities.
263  *
264  * @param angle1 Start angle in rad (!)
265  * @param angle2 End angle in rad (!)
266  */
267 void FilterDXF::addEllipse(const DL_EllipseData& data) {
268     DEBUG->print("FilterDXF::addEllipse");
269
270     Vector v1(data.cx, data.cy);
271     Vector v2(data.mx, data.my);
272
273     EllipseData ed(v1, v2,
274                       data.ratio,
275                       data.angle1,
276                       data.angle2,
277                       false);
278     Ellipse* entity = new Ellipse(currentContainer, ed);
279     setEntityAttributes(entity, attributes);
280
281     currentContainer->addEntity(entity);
282 }
283
284
285
286 /**
287  * Implementation of the method which handles circle entities.
288  */
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]);
294
295     Vector v(data.cx, data.cy);
296     CircleData d(v, data.radius);
297     Circle* entity = new Circle(currentContainer, d);
298     setEntityAttributes(entity, attributes);
299
300     currentContainer->addEntity(entity);
301 }
302
303
304
305 /**
306  * Implementation of the method which handles polyline entities.
307  */
308 void FilterDXF::addPolyline(const DL_PolylineData& data) {
309     DEBUG->print("FilterDXF::addPolyline");
310     //DEBUG->print("FilterDXF::addPolyline()");
311     PolylineData d(Vector(false),
312                       Vector(false),
313                       data.flags&0x1);
314     polyline = new Polyline(currentContainer, d);
315     setEntityAttributes(polyline, attributes);
316
317     currentContainer->addEntity(polyline);
318 }
319
320
321
322 /**
323  * Implementation of the method which handles polyline vertices.
324  */
325 void FilterDXF::addVertex(const DL_VertexData& data) {
326     DEBUG->print("FilterDXF::addVertex(): %f/%f bulge: %f",
327                     data.x, data.y, data.bulge);
328
329     Vector v(data.x, data.y);
330
331     if (polyline!=NULL) {
332         polyline->addVertex(v, data.bulge);
333     }
334 }
335
336
337
338 /**
339  * Implementation of the method which handles splines.
340  */
341 void FilterDXF::addSpline(const DL_SplineData& data) {
342     DEBUG->print("FilterDXF::addSpline: degree: %d", data.degree);
343
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);
348
349         currentContainer->addEntity(spline);
350     } else {
351         DEBUG->print(Debug::D_WARNING,
352                         "FilterDXF::addSpline: Invalid degree for spline: %d. "
353                         "Accepted values are 1..3.", data.degree);
354     }
355 }
356
357 /*virtual*/ void FilterDXF::addKnot(const DL_KnotData &)
358 {
359 }
360
361 /**
362  * Implementation of the method which handles spline control points.
363  */
364 void FilterDXF::addControlPoint(const DL_ControlPointData & data)
365 {
366         DEBUG->print("FilterDXF::addControlPoint: %f/%f", data.x, data.y);
367
368         Vector v(data.x, data.y);
369
370         if (spline != NULL)
371         {
372                 spline->addControlPoint(v);
373                 spline->update();
374         }
375 }
376
377 /**
378  * Implementation of the method which handles inserts.
379  */
380 void FilterDXF::addInsert(const DL_InsertData & data)
381 {
382         DEBUG->print("FilterDXF::addInsert");
383
384         if (QString(data.name.c_str()).left(3) == "A$C")
385                 return;
386
387         Vector ip(data.ipx, data.ipy);
388         Vector sc(data.sx, data.sy);
389         Vector sp(data.colSp, data.rowSp);
390
391         //cout << "Insert: " << name << " " << ip << " " << cols << "/" << rows << endl;
392
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());
398         //entity->update();
399         currentContainer->addEntity(entity);
400 }
401
402 /*virtual*/ void FilterDXF::addTrace(const DL_TraceData &)
403 {
404 }
405
406 /*virtual*/ void FilterDXF::addSolid(const DL_SolidData &)
407 {
408 }
409
410 /**
411  * Implementation of the method which handles text
412  * chunks for MText entities.
413  */
414 void FilterDXF::addMTextChunk(const char * text)
415 {
416         DEBUG->print("FilterDXF::addMTextChunk: %s", text);
417         //mtext += text;
418         //mtext += QString::fromUtf8(text);
419
420         /*
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
424         if (codec!=NULL) {
425                 mtext += codec->toUnicode(toNativeString(locallyEncoded));
426 } else {
427                 mtext += toNativeString(text);
428 }
429         */
430         mtext += text;
431 }
432
433 /**
434  * Implementation of the method which handles
435  * multi texts (MTEXT).
436  */
437 void FilterDXF::addMText(const DL_MTextData & data)
438 {
439         DEBUG->print("FilterDXF::addMText: %s", data.text.c_str());
440
441         Vector ip(data.ipx, data.ipy);
442         RS2::VAlign valign;
443         RS2::HAlign halign;
444         RS2::TextDrawingDirection dir;
445         RS2::TextLineSpacingStyle lss;
446         QString sty = data.style.c_str();
447
448         if (data.attachmentPoint <= 3)
449                 valign = RS2::VAlignTop;
450         else if (data.attachmentPoint <= 6)
451                 valign = RS2::VAlignMiddle;
452         else
453                 valign = RS2::VAlignBottom;
454
455         if (data.attachmentPoint % 3 == 1)
456                 halign = RS2::HAlignLeft;
457         else if (data.attachmentPoint % 3 == 2)
458                 halign = RS2::HAlignCenter;
459         else
460                 halign = RS2::HAlignRight;
461
462         if (data.drawingDirection == 1)
463                 dir = RS2::LeftToRight;
464         else if (data.drawingDirection == 3)
465                 dir = RS2::TopToBottom;
466         else
467                 dir = RS2::ByStyle;
468
469         if (data.lineSpacingStyle == 1)
470                 lss = RS2::AtLeast;
471         else
472                 lss = RS2::Exact;
473
474         mtext += QString(data.text.c_str());
475
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());
480
481         if (codec != NULL)
482                 mtext = codec->toUnicode(toNativeString(locallyEncoded).toAscii());
483         else
484                 mtext = toNativeString(mtext);
485
486         // use default style for the drawing:
487         if (sty.isEmpty())
488         {
489                 // japanese, cyrillic:
490                 QString codepage = variables.getString("$DWGCODEPAGE", "ANSI_1252");
491
492                 if (codepage == "ANSI_932" || codepage == "ANSI_1251")
493                         sty = "Unicode";
494                 else
495                         sty = variables.getString("$TEXTSTYLE", "Standard");
496         }
497
498         DEBUG->print("Text as unicode:");
499         DEBUG->printUnicode(mtext);
500
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);
504
505         setEntityAttributes(entity, attributes);
506         entity->update();
507         currentContainer->addEntity(entity);
508
509         mtext = "";
510 }
511
512
513
514 /**
515  * Implementation of the method which handles
516  * texts (TEXT).
517  */
518 void FilterDXF::addText(const DL_TextData& data) {
519     DEBUG->print("FilterDXF::addText");
520     int attachmentPoint;
521     Vector refPoint;
522     double angle = data.angle;
523
524     // TODO: check, maybe implement a separate TEXT instead of using MTEXT
525
526     // baseline has 5 vertical alignment modes:
527     if (data.vJustification!=0 || data.hJustification!=0) {
528         switch (data.hJustification) {
529         default:
530         case 0: // left aligned
531             attachmentPoint = 1;
532             refPoint = Vector(data.apx, data.apy);
533             break;
534         case 1: // centered
535             attachmentPoint = 2;
536             refPoint = Vector(data.apx, data.apy);
537             break;
538         case 2: // right aligned
539             attachmentPoint = 3;
540             refPoint = Vector(data.apx, data.apy);
541             break;
542         case 3: // aligned (TODO)
543             attachmentPoint = 2;
544             refPoint = Vector((data.ipx+data.apx)/2.0,
545                                  (data.ipy+data.apy)/2.0);
546             angle =
547                 Vector(data.ipx, data.ipy).angleTo(
548                     Vector(data.apx, data.apy));
549             break;
550         case 4: // Middle (TODO)
551             attachmentPoint = 2;
552             refPoint = Vector(data.apx, data.apy);
553             break;
554         case 5: // fit (TODO)
555             attachmentPoint = 2;
556             refPoint = Vector((data.ipx+data.apx)/2.0,
557                                  (data.ipy+data.apy)/2.0);
558             angle =
559                 Vector(data.ipx, data.ipy).angleTo(
560                     Vector(data.apx, data.apy));
561             break;
562         }
563
564         switch (data.vJustification) {
565         default:
566         case 0: // baseline
567         case 1: // bottom
568             attachmentPoint += 6;
569             break;
570
571         case 2: // middle
572             attachmentPoint += 3;
573             break;
574
575         case 3: // top
576             break;
577         }
578     } else {
579         //attachmentPoint = (data.hJustification+1)+(3-data.vJustification)*3;
580         attachmentPoint = 7;
581         refPoint = Vector(data.ipx, data.ipy);
582     }
583
584     int drawingDirection = 5;
585     double width = 100.0;
586
587     mtext = "";
588     addMText(DL_MTextData(
589                  refPoint.x,
590                  refPoint.y,
591                  refPoint.z,
592                  data.height, width,
593                  attachmentPoint,
594                  drawingDirection,
595                  RS2::Exact,
596                  1.0,
597                  data.text.c_str(), data.style,
598                  angle));
599 }
600
601
602
603 /**
604  * Implementation of the method which handles
605  * dimensions (DIMENSION).
606  */
607 DimensionData FilterDXF::convDimensionData(
608     const DL_DimensionData& data) {
609
610     Vector defP(data.dpx, data.dpy);
611     Vector midP(data.mpx, data.mpy);
612     RS2::VAlign valign;
613     RS2::HAlign halign;
614     RS2::TextLineSpacingStyle lss;
615     QString sty = data.style.c_str();
616     QString t; //= data.text;
617
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);
623     }
624
625     if (data.attachmentPoint<=3) {
626         valign=RS2::VAlignTop;
627     } else if (data.attachmentPoint<=6) {
628         valign=RS2::VAlignMiddle;
629     } else {
630         valign=RS2::VAlignBottom;
631     }
632
633     if (data.attachmentPoint%3==1) {
634         halign=RS2::HAlignLeft;
635     } else if (data.attachmentPoint%3==2) {
636         halign=RS2::HAlignCenter;
637     } else {
638         halign=RS2::HAlignRight;
639     }
640
641     if (data.lineSpacingStyle==1) {
642         lss = RS2::AtLeast;
643     } else {
644         lss = RS2::Exact;
645     }
646
647     t = toNativeString(data.text.c_str());
648
649     if (sty.isEmpty()) {
650         sty = variables.getString("$DIMSTYLE", "Standard");
651     }
652
653     DEBUG->print("Text as unicode:");
654     DEBUG->printUnicode(t);
655
656     // data needed to add the actual dimension entity
657     return DimensionData(defP, midP,
658                             valign, halign,
659                             lss,
660                             data.lineSpacingFactor,
661                             t, sty, data.angle);
662 }
663
664
665
666 /**
667  * Implementation of the method which handles
668  * aligned dimensions (DIMENSION).
669  */
670 void FilterDXF::addDimAlign(const DL_DimensionData& data,
671                                const DL_DimAlignedData& edata) {
672     DEBUG->print("FilterDXF::addDimAligned");
673
674     DimensionData dimensionData = convDimensionData(data);
675
676     Vector ext1(edata.epx1, edata.epy1);
677     Vector ext2(edata.epx2, edata.epy2);
678
679     DimAlignedData d(ext1, ext2);
680
681     DimAligned* entity = new DimAligned(currentContainer,
682                             dimensionData, d);
683     setEntityAttributes(entity, attributes);
684     entity->update();
685     currentContainer->addEntity(entity);
686 }
687
688
689
690 /**
691  * Implementation of the method which handles
692  * linear dimensions (DIMENSION).
693  */
694 void FilterDXF::addDimLinear(const DL_DimensionData& data,
695                                 const DL_DimLinearData& edata) {
696     DEBUG->print("FilterDXF::addDimLinear");
697
698     DimensionData dimensionData = convDimensionData(data);
699
700     Vector dxt1(edata.dpx1, edata.dpy1);
701     Vector dxt2(edata.dpx2, edata.dpy2);
702
703     DimLinearData d(dxt1, dxt2, Math::deg2rad(edata.angle),
704                        Math::deg2rad(edata.oblique));
705
706     DimLinear* entity = new DimLinear(currentContainer,
707                                             dimensionData, d);
708     setEntityAttributes(entity, attributes);
709     entity->update();
710     currentContainer->addEntity(entity);
711 }
712
713
714
715 /**
716  * Implementation of the method which handles
717  * radial dimensions (DIMENSION).
718  */
719 void FilterDXF::addDimRadial(const DL_DimensionData& data,
720                                 const DL_DimRadialData& edata) {
721     DEBUG->print("FilterDXF::addDimRadial");
722
723     DimensionData dimensionData = convDimensionData(data);
724     Vector dp(edata.dpx, edata.dpy);
725
726     DimRadialData d(dp, edata.leader);
727
728     DimRadial* entity = new DimRadial(currentContainer,
729                                             dimensionData, d);
730
731     setEntityAttributes(entity, attributes);
732     entity->update();
733     currentContainer->addEntity(entity);
734 }
735
736
737
738 /**
739  * Implementation of the method which handles
740  * diametric dimensions (DIMENSION).
741  */
742 void FilterDXF::addDimDiametric(const DL_DimensionData& data,
743                                    const DL_DimDiametricData& edata) {
744     DEBUG->print("FilterDXF::addDimDiametric");
745
746     DimensionData dimensionData = convDimensionData(data);
747     Vector dp(edata.dpx, edata.dpy);
748
749     DimDiametricData d(dp, edata.leader);
750
751     DimDiametric* entity = new DimDiametric(currentContainer,
752                               dimensionData, d);
753
754     setEntityAttributes(entity, attributes);
755     entity->update();
756     currentContainer->addEntity(entity);
757 }
758
759
760
761 /**
762  * Implementation of the method which handles
763  * angular dimensions (DIMENSION).
764  */
765 void FilterDXF::addDimAngular(const DL_DimensionData& data,
766                                  const DL_DimAngularData& edata) {
767     DEBUG->print("FilterDXF::addDimAngular");
768
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);
774
775     DimAngularData d(dp1, dp2, dp3, dp4);
776
777     DimAngular* entity = new DimAngular(currentContainer,
778                             dimensionData, d);
779
780     setEntityAttributes(entity, attributes);
781     entity->update();
782     currentContainer->addEntity(entity);
783 }
784
785
786
787 /**
788  * Implementation of the method which handles
789  * angular dimensions (DIMENSION).
790  */
791 void FilterDXF::addDimAngular3P(const DL_DimensionData& data,
792                                    const DL_DimAngular3PData& edata) {
793     DEBUG->print("FilterDXF::addDimAngular3P");
794
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);
801
802     DimAngularData d(dp1, dp2, dp3, dp4);
803
804     DimAngular* entity = new DimAngular(currentContainer,
805                             dimensionData, d);
806
807     setEntityAttributes(entity, attributes);
808     entity->update();
809     currentContainer->addEntity(entity);
810 }
811
812
813
814 /**
815  * Implementation of the method which handles leader entities.
816  */
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);
823
824     currentContainer->addEntity(leader);
825 }
826
827
828
829 /**
830  * Implementation of the method which handles leader vertices.
831  */
832 void FilterDXF::addLeaderVertex(const DL_LeaderVertexData& data) {
833     DEBUG->print("FilterDXF::addLeaderVertex");
834     //DEBUG->print("FilterDXF::addVertex() bulge: %f", bulge);
835
836     Vector v(data.x, data.y);
837
838     if (leader!=NULL) {
839         leader->addVertex(v);
840     }
841 }
842
843
844
845 /**
846  * Implementation of the method which handles hatch entities.
847  */
848 void FilterDXF::addHatch(const DL_HatchData& data) {
849     DEBUG->print("FilterDXF::addHatch()");
850
851     hatch = new Hatch(currentContainer,
852                          HatchData(data.solid,
853                                       data.scale,
854                                       data.angle,
855                                       QString(data.pattern.c_str())));
856     setEntityAttributes(hatch, attributes);
857
858     currentContainer->addEntity(hatch);
859 }
860
861
862
863 /**
864  * Implementation of the method which handles hatch loops.
865  */
866 void FilterDXF::addHatchLoop(const DL_HatchLoopData& /*data*/) {
867     DEBUG->print("FilterDXF::addHatchLoop()");
868     if (hatch!=NULL) {
869         hatchLoop = new EntityContainer(hatch);
870         hatchLoop->setLayer(NULL);
871         hatch->addEntity(hatchLoop);
872     }
873 }
874
875
876
877 /**
878  * Implementation of the method which handles hatch edge entities.
879  */
880 void FilterDXF::addHatchEdge(const DL_HatchEdgeData& data) {
881     DEBUG->print("FilterDXF::addHatchEdge()");
882
883     if (hatchLoop!=NULL) {
884         Entity* e = NULL;
885         switch (data.type) {
886         case 1:
887             DEBUG->print("FilterDXF::addHatchEdge(): "
888                             "line: %f,%f %f,%f",
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)));
893             break;
894         case 2:
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),
898                                                 data.radius));
899             } else {
900                 if (data.ccw) {
901                     e = new Arc(
902                             hatchLoop,
903                             ArcData(Vector(data.cx, data.cy),
904                                        data.radius,
905                                        Math::correctAngle(data.angle1),
906                                        Math::correctAngle(data.angle2),
907                                        false));
908                 } else {
909                     e = new Arc(
910                             hatchLoop,
911                             ArcData(Vector(data.cx, data.cy),
912                                        data.radius,
913                                        Math::correctAngle(2*M_PI-data.angle1),
914                                        Math::correctAngle(2*M_PI-data.angle2),
915                                        true));
916                 }
917             }
918             break;
919         default:
920             break;
921         }
922
923         if (e!=NULL) {
924             e->setLayer(NULL);
925             hatchLoop->addEntity(e);
926         }
927     }
928 }
929
930
931
932 /**
933  * Implementation of the method which handles image entities.
934  */
935 void FilterDXF::addImage(const DL_ImageData& data) {
936     DEBUG->print("FilterDXF::addImage");
937
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);
942
943     Image* image =
944         new Image(
945             currentContainer,
946             ImageData(QString(data.ref.c_str()).toInt(NULL, 16),
947                          ip, uv, vv,
948                          size,
949                          QString(""),
950                          data.brightness,
951                          data.contrast,
952                          data.fade));
953
954     setEntityAttributes(image, attributes);
955     currentContainer->addEntity(image);
956 }
957
958 /**
959  * Implementation of the method which links image entities to image files.
960  */
961 void FilterDXF::linkImage(const DL_ImageDefData & data)
962 {
963         DEBUG->print("FilterDXF::linkImage");
964
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);
969
970         // try to find the image file:
971
972         // first: absolute path:
973         if (!fiBitmap.exists())
974         {
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;
979
980                 if (QFileInfo(f1).exists())
981                         sfile = f1;
982                 else
983                 {
984                         DEBUG->print("File %s doesn't exist.", (const char *)QFile::encodeName(f1));
985                         // try drawing path:
986 //                      QString f2 = fiDxf.dirPath(true) + "/" + fiBitmap.fileName();
987                         QString f2 = fiDxf.absolutePath() + "/" + fiBitmap.fileName();
988
989                         if (QFileInfo(f2).exists())
990                         {
991                                 sfile = f2;
992                         }
993                         else
994                         {
995                                 DEBUG->print("File %s doesn't exist.", (const char *)QFile::encodeName(f2));
996                         }
997                 }
998         }
999
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))
1003         {
1004                 if (e->rtti() == RS2::EntityImage)
1005                 {
1006                         Image * img = (Image *)e;
1007
1008                         if (img->getHandle() == handle)
1009                         {
1010                                 img->setFile(sfile);
1011                                 DEBUG->print("image found: %s", (const char *)QFile::encodeName(img->getFile()));
1012                                 img->update();
1013                         }
1014                 }
1015         }
1016
1017         // update images in blocks:
1018         for(uint i=0; i<graphic->countBlocks(); ++i)
1019         {
1020                 Block * b = graphic->blockAt(i);
1021
1022                 for(Entity * e=b->firstEntity(RS2::ResolveNone); e!=NULL; e=b->nextEntity(RS2::ResolveNone))
1023                 {
1024                         if (e->rtti() == RS2::EntityImage)
1025                         {
1026                                 Image * img = (Image *)e;
1027
1028                                 if (img->getHandle() == handle)
1029                                 {
1030                                         img->setFile(sfile);
1031                                         DEBUG->print("image in block found: %s",
1032                                                 (const char*)QFile::encodeName(img->getFile()));
1033                                         img->update();
1034                                 }
1035                         }
1036                 }
1037         }
1038
1039         DEBUG->print("linking image: OK");
1040 }
1041
1042 /**
1043  * Finishes a hatch entity.
1044  */
1045 void FilterDXF::endEntity()
1046 {
1047         DEBUG->print("FilterDXF::endEntity");
1048
1049         if (hatch != NULL)
1050         {
1051                 DEBUG->print("hatch->update()");
1052
1053                 if (hatch->validate())
1054                         hatch->update();
1055                 else
1056                 {
1057                         graphic->removeEntity(hatch);
1058                         DEBUG->print(Debug::D_ERROR, "FilterDXF::endEntity(): updating hatch failed: invalid hatch area");
1059                 }
1060
1061                 hatch = NULL;
1062         }
1063 }
1064
1065 /*virtual*/ void FilterDXF::endSequence()
1066 {
1067 }
1068
1069 /**
1070  * Sets a vector variable from the DXF file.
1071  */
1072 void FilterDXF::setVariableVector(const char * key, double v1, double v2, double v3, int code)
1073 {
1074         DEBUG->print("FilterDXF::setVariableVector");
1075
1076         // update document's variable list:
1077         if (currentContainer->rtti() == RS2::EntityDrawing)
1078                 ((Drawing *)currentContainer)->addVariable(QString(key), Vector(v1, v2, v3), code);
1079 }
1080
1081 /**
1082  * Sets a string variable from the DXF file.
1083  */
1084 void FilterDXF::setVariableString(const char * key, const char * value, int code)
1085 {
1086         DEBUG->print("FilterDXF::setVariableString");
1087
1088         // update local DXF variable list:
1089         variables.add(QString(key), QString(value), code);
1090
1091         // update document's variable list:
1092         if (currentContainer->rtti()==RS2::EntityDrawing)
1093         {
1094                 ((Drawing *)currentContainer)->addVariable(QString(key), QString(value), code);
1095         }
1096 }
1097
1098
1099
1100 /**
1101  * Sets an int variable from the DXF file.
1102  */
1103 void FilterDXF::setVariableInt(const char* key, int value, int code)
1104 {
1105         DEBUG->print("FilterDXF::setVariableInt");
1106
1107         // update document's variable list:
1108         if (currentContainer->rtti()==RS2::EntityDrawing)
1109         {
1110                 ((Drawing *)currentContainer)->addVariable(QString(key), value, code);
1111         }
1112 }
1113
1114
1115
1116 /**
1117  * Sets a double variable from the DXF file.
1118  */
1119 void FilterDXF::setVariableDouble(const char* key, double value, int code)
1120 {
1121         DEBUG->print("FilterDXF::setVariableDouble");
1122
1123         // update document's variable list:
1124         if (currentContainer->rtti() == RS2::EntityDrawing)
1125         {
1126                 ((Drawing *)currentContainer)->addVariable(QString(key), value, code);
1127         }
1128 }
1129
1130 /**
1131  * Implementation of the method used for RS_Export to communicate
1132  * with this filter.
1133  *
1134  * @param file Full path to the DXF file that will be written.
1135  */
1136 bool FilterDXF::fileExport(Drawing & g, const QString & file, RS2::FormatType type)
1137 {
1138         DEBUG->print("FilterDXF::fileExport: exporting file '%s'...",
1139                 (const char *)QFile::encodeName(file));
1140         DEBUG->print("FilterDXF::fileExport: file type '%d'", (int)type);
1141
1142         this->graphic = &g;
1143
1144 #ifndef Q_OS_WIN
1145         // check if we can write to that directory:
1146 //      QString path = QFileInfo(file).dirPath(true);
1147         QString path = QFileInfo(file).absolutePath();
1148
1149         if (QFileInfo(path).isWritable() == false)
1150         {
1151                 DEBUG->print("FilterDXF::fileExport: can't write file: no permission");
1152                 return false;
1153         }
1154         //
1155 #endif
1156
1157         // set version for DXF filter:
1158         DL_Codes::version exportVersion;
1159
1160         if (type == RS2::FormatDXF12)
1161         {
1162                 exportVersion = DL_Codes::AC1009;
1163         }
1164         else
1165         {
1166                 exportVersion = DL_Codes::AC1015;
1167         }
1168
1169         //DL_WriterA* dw = dxf.out(file, VER_R12);
1170         DL_WriterA * dw = dxf.out((const char *)QFile::encodeName(file), exportVersion);
1171
1172         if (dw == NULL)
1173         {
1174                 DEBUG->print("FilterDXF::fileExport: can't write file");
1175                 return false;
1176         }
1177
1178         // Header
1179         DEBUG->print("writing headers...");
1180         dxf.writeHeader(*dw);
1181
1182         // Variables
1183         DEBUG->print("writing variables...");
1184         writeVariables(*dw);
1185
1186         // Section TABLES
1187         DEBUG->print("writing tables...");
1188         dw->sectionTables();
1189
1190         // VPORT:
1191         dxf.writeVPort(*dw);
1192
1193         // Line types:
1194         DEBUG->print("writing line types...");
1195         int numLT = (int)RS2::BorderLineX2 - (int)RS2::LineByBlock;
1196
1197         if (type == RS2::FormatDXF12)
1198                 numLT -= 2;
1199
1200         dw->tableLineTypes(numLT);
1201
1202         for(int t=(int)RS2::LineByBlock; t<=(int)RS2::BorderLineX2; ++t)
1203         {
1204                 if ((RS2::LineType)t != RS2::NoPen)
1205                         writeLineType(*dw, (RS2::LineType)t);
1206         }
1207
1208         dw->tableEnd();
1209
1210         // Layers:
1211         DEBUG->print("writing layers...");
1212         dw->tableLayers(graphic->countLayers());
1213
1214         for(uint i=0; i<graphic->countLayers(); ++i)
1215         {
1216                 Layer * l = graphic->layerAt(i);
1217                 writeLayer(*dw, l);
1218         }
1219
1220         dw->tableEnd();
1221
1222         // STYLE:
1223         DEBUG->print("writing styles...");
1224         dxf.writeStyle(*dw);
1225
1226         // VIEW:
1227         DEBUG->print("writing views...");
1228         dxf.writeView(*dw);
1229
1230         // UCS:
1231         DEBUG->print("writing ucs...");
1232         dxf.writeUcs(*dw);
1233
1234         // Appid:
1235         DEBUG->print("writing appid...");
1236         dw->tableAppid(1);
1237         writeAppid(*dw, "ACAD");
1238         dw->tableEnd();
1239
1240         // DIMSTYLE:
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));
1248
1249         // BLOCK_RECORD:
1250         if (type == RS2::FormatDXF)
1251         {
1252                 DEBUG->print("writing block records...");
1253                 dxf.writeBlockRecord(*dw);
1254
1255                 for(uint i=0; i<graphic->countBlocks(); ++i)
1256                 {
1257                         Block * blk = graphic->blockAt(i);
1258                         dxf.writeBlockRecord(*dw, std::string((const char *)blk->getName().toLocal8Bit()));
1259                         /*
1260                         // v2.0.4.9..:
1261                         //writeBlock(*dw, blk);
1262                         dw->dxfString(  0, "BLOCK_RECORD");
1263                         //dw.dxfHex(5, 0x1F);
1264                         dw->handle();
1265                         dw->dxfHex(330, 1);
1266                         dw->dxfString(100, "AcDbSymbolTableRecord");
1267                         dw->dxfString(100, "AcDbBlockTableRecord");
1268                         dw->dxfString(  2, blk->getName().toLocal8Bit());
1269                         dw->dxfHex(340, 0);
1270                         */
1271                 }
1272
1273                 dw->tableEnd();
1274         }
1275
1276         // end of tables:
1277         DEBUG->print("writing end of section TABLES...");
1278         dw->sectionEnd();
1279
1280         // Section BLOCKS:
1281         DEBUG->print("writing blocks...");
1282         dw->sectionBlocks();
1283
1284         if (type == RS2::FormatDXF)
1285         {
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);
1292         }
1293
1294         for(uint i=0; i<graphic->countBlocks(); ++i)
1295         {
1296                 Block * blk = graphic->blockAt(i);
1297
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);
1303                 //}
1304         }
1305
1306         dw->sectionEnd();
1307
1308         // Section ENTITIES:
1309         DEBUG->print("writing section ENTITIES...");
1310         dw->sectionEntities();
1311
1312         for(Entity * e=graphic->firstEntity(RS2::ResolveNone); e!=NULL;
1313                 e=graphic->nextEntity(RS2::ResolveNone))
1314         {
1315                 writeEntity(*dw, e);
1316         }
1317
1318         DEBUG->print("writing end of section ENTITIES...");
1319         dw->sectionEnd();
1320
1321         if (type == RS2::FormatDXF)
1322         {
1323                 DEBUG->print("writing section OBJECTS...");
1324                 dxf.writeObjects(*dw);
1325
1326                 // IMAGEDEF's from images in entities and images in blocks
1327                 QStringList written;
1328
1329                 for(uint i=0; i<graphic->countBlocks(); ++i)
1330                 {
1331                         Block * block = graphic->blockAt(i);
1332
1333                         for(Entity * e=block->firstEntity(RS2::ResolveAll); e!=NULL;
1334                                 e=block->nextEntity(RS2::ResolveAll))
1335                         {
1336                                 if (e->rtti() == RS2::EntityImage)
1337                                 {
1338                                         Image * img = ((Image *)e);
1339
1340                                         if (written.contains(file) == 0 && img->getHandle() != 0)
1341                                         {
1342                                                 writeImageDef(*dw, img);
1343                                                 written.append(img->getFile());
1344                                         }
1345                                 }
1346                         }
1347                 }
1348
1349                 for(Entity * e=graphic->firstEntity(RS2::ResolveNone); e!=NULL;
1350                         e=graphic->nextEntity(RS2::ResolveNone))
1351                 {
1352                         if (e->rtti() == RS2::EntityImage)
1353                         {
1354                                 Image * img = ((Image *)e);
1355
1356                                 if (written.contains(file) == 0 && img->getHandle() != 0)
1357                                 {
1358                                         writeImageDef(*dw, img);
1359                                         written.append(img->getFile());
1360                                 }
1361                         }
1362                 }
1363                 DEBUG->print("writing end of section OBJECTS...");
1364                 dxf.writeObjectsEnd(*dw);
1365         }
1366
1367         DEBUG->print("writing EOF...");
1368         dw->dxfEOF();
1369
1370         DEBUG->print("close..");
1371         dw->close();
1372
1373         delete dw;
1374
1375         // check if file was actually written (strange world of windoze xp):
1376         if (QFileInfo(file).exists() == false)
1377         {
1378                 DEBUG->print("FilterDXF::fileExport: file could not be written");
1379                 return false;
1380         }
1381
1382         return true;
1383 }
1384
1385 /**
1386  * Writes all known variable settings to the DXF file.
1387  */
1388 void FilterDXF::writeVariables(DL_WriterA & dw)
1389 {
1390 //    Q3DictIterator<Variable> it(graphic->getVariableDict());
1391         QHashIterator<QString, Variable *> it(graphic->getVariableDict());
1392
1393 //      for (; it.current(); ++it)
1394         while (it.hasNext())
1395         {
1396                 it.next();
1397
1398                 // exclude variables that are not known to DXF 12:
1399                 if (!DL_Dxf::checkVariable(it.key().toLatin1(), dxf.getVersion()))
1400                         continue;
1401
1402                 if (it.key() != "$ACADVER" && it.key() != "$HANDSEED")
1403                 {
1404                         dw.dxfString(9, (const char *)it.key().toAscii().data());
1405
1406                         switch (it.value()->getType())
1407                         {
1408                         case RS2::VariableVoid:
1409                                 break;
1410                         case RS2::VariableInt:
1411                                 dw.dxfInt(it.value()->getCode(), it.value()->getInt());
1412                                 break;
1413                         case RS2::VariableDouble:
1414                                 dw.dxfReal(it.value()->getCode(), it.value()->getDouble());
1415                                 break;
1416                         case RS2::VariableString:
1417                                 dw.dxfString(it.value()->getCode(), (const char *)it.value()->getString().toAscii().data());
1418                                 break;
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);
1422
1423                                 if (isVariableTwoDimensional(it.key()) == false)
1424                                         dw.dxfReal(it.value()->getCode() + 20, it.value()->getVector().z);
1425
1426                                 break;
1427                         }
1428                 }
1429         }
1430
1431         dw.sectionEnd();
1432 }
1433
1434 /**
1435  * Writes one layer to the DXF file.
1436  *
1437  * @todo Add support for unicode layer names
1438  */
1439 void FilterDXF::writeLayer(DL_WriterA & dw, Layer * l)
1440 {
1441         if (l == NULL)
1442         {
1443                 DEBUG->print(Debug::D_WARNING, "FilterDXF::writeLayer: layer is NULL");
1444                 return;
1445         }
1446
1447         DEBUG->print("FilterDXF::writeLayer %s", l->getName().toLatin1().data());
1448
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()));
1453
1454         DEBUG->print("FilterDXF::writeLayer end");
1455 }
1456
1457 /**
1458  * Writes a line type to the DXF file.
1459  */
1460 void FilterDXF::writeLineType(DL_WriterA & dw, RS2::LineType t)
1461 {
1462     dxf.writeLineType(dw, DL_LineTypeData((const char *)lineTypeToName(t).toLocal8Bit(), 0));
1463 }
1464
1465
1466
1467 /**
1468  * Writes an application id to the DXF file.
1469  *
1470  * @param appid Application ID (e.g. "QCad").
1471  */
1472 void FilterDXF::writeAppid(DL_WriterA& dw, const char* appid) {
1473     dxf.writeAppid(dw, appid);
1474 }
1475
1476
1477
1478 /**
1479  * Writes a block (just the definition, not the entities in it).
1480  */
1481 void FilterDXF::writeBlock(DL_WriterA& dw, Block* blk) {
1482     if (blk==NULL) {
1483         DEBUG->print(Debug::D_WARNING,
1484                         "FilterDXF::writeBlock: Block is NULL");
1485         return;
1486     }
1487
1488     DEBUG->print("writing block: %s", (const char*)blk->getName().toLocal8Bit());
1489
1490     dxf.writeBlock(dw,
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);
1496             e!=NULL;
1497             e=blk->nextEntity(RS2::ResolveNone)) {
1498         writeEntity(dw, e);
1499     }
1500     dxf.writeEndBlock(dw, (const char*)blk->getName().toLocal8Bit());
1501 }
1502
1503
1504
1505 /**
1506  * Writes the given entity to the DXF file.
1507  */
1508 void FilterDXF::writeEntity(DL_WriterA& dw, Entity* e) {
1509     writeEntity(dw, e, getEntityAttributes(e));
1510 }
1511
1512
1513 /**
1514  * Writes the given entity to the DXF file.
1515  */
1516 void FilterDXF::writeEntity(DL_WriterA& dw, Entity* e,
1517                                const DL_Attributes& attrib) {
1518
1519     if (e==NULL || e->getFlag(RS2::FlagUndone)) {
1520         return;
1521     }
1522     DEBUG->print("writing Entity");
1523
1524     switch (e->rtti()) {
1525     case RS2::EntityPoint:
1526         writePoint(dw, (Point*)e, attrib);
1527         break;
1528     case RS2::EntityLine:
1529         writeLine(dw, (Line*)e, attrib);
1530         break;
1531     case RS2::EntityPolyline:
1532         writePolyline(dw, (Polyline*)e, attrib);
1533         break;
1534     case RS2::EntitySpline:
1535         writeSpline(dw, (Spline*)e, attrib);
1536         break;
1537     case RS2::EntityVertex:
1538         break;
1539     case RS2::EntityCircle:
1540         writeCircle(dw, (Circle*)e, attrib);
1541         break;
1542     case RS2::EntityArc:
1543         writeArc(dw, (Arc*)e, attrib);
1544         break;
1545     case RS2::EntityEllipse:
1546         writeEllipse(dw, (Ellipse*)e, attrib);
1547         break;
1548     case RS2::EntityInsert:
1549         writeInsert(dw, (Insert*)e, attrib);
1550         break;
1551     case RS2::EntityText:
1552         writeText(dw, (Text*)e, attrib);
1553         break;
1554
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);
1561         break;
1562     case RS2::EntityDimLeader:
1563         writeLeader(dw, (Leader*)e, attrib);
1564         break;
1565     case RS2::EntityHatch:
1566         writeHatch(dw, (Hatch*)e, attrib);
1567         break;
1568     case RS2::EntityImage:
1569         writeImage(dw, (Image*)e, attrib);
1570         break;
1571     case RS2::EntitySolid:
1572         writeSolid(dw, (Solid*)e, attrib);
1573         break;
1574
1575 #ifndef RS_NO_COMPLEX_ENTITIES
1576
1577     case RS2::EntityContainer:
1578         writeEntityContainer(dw, (EntityContainer*)e, attrib);
1579         break;
1580 #endif
1581
1582     default:
1583         break;
1584     }
1585 }
1586
1587
1588
1589 /**
1590  * Writes the given Point entity to the file.
1591  */
1592 void FilterDXF::writePoint(DL_WriterA& dw, Point* p,
1593                               const DL_Attributes& attrib) {
1594     dxf.writePoint(
1595         dw,
1596         DL_PointData(p->getPos().x,
1597                      p->getPos().y,
1598                      0.0),
1599         attrib);
1600 }
1601
1602
1603 /**
1604  * Writes the given Line( entity to the file.
1605  */
1606 void FilterDXF::writeLine(DL_WriterA& dw, Line* l,
1607                              const DL_Attributes& attrib) {
1608     dxf.writeLine(
1609         dw,
1610         DL_LineData(l->getStartpoint().x,
1611                     l->getStartpoint().y,
1612                     0.0,
1613                     l->getEndpoint().x,
1614                     l->getEndpoint().y,
1615                     0.0),
1616         attrib);
1617 }
1618
1619
1620
1621 /**
1622  * Writes the given polyline entity to the file.
1623  */
1624 void FilterDXF::writePolyline(DL_WriterA& dw,
1625                                  Polyline* l,
1626                                  const DL_Attributes& attrib) {
1627
1628         int count = l->count();
1629         if (l->isClosed()==false) {
1630                 count++;
1631         }
1632
1633         dxf.writePolyline(
1634         dw,
1635         DL_PolylineData(count,
1636                         0, 0,
1637                         l->isClosed()*0x1),
1638         attrib);
1639     bool first = true;
1640     Entity* nextEntity = 0;
1641     AtomicEntity* ae = NULL;
1642         Entity* lastEntity = l->lastEntity(RS2::ResolveNone);
1643     for (Entity* v=l->firstEntity(RS2::ResolveNone);
1644             v!=NULL;
1645             v=nextEntity) {
1646
1647         nextEntity = l->nextEntity(RS2::ResolveNone);
1648
1649         if (!v->isAtomic()) {
1650             continue;
1651         }
1652
1653         ae = (AtomicEntity*)v;
1654         double bulge=0.0;
1655
1656                 // Write vertex:
1657         if (first) {
1658             if (v->rtti()==RS2::EntityArc) {
1659                 bulge = ((Arc*)v)->getBulge();
1660             }
1661             dxf.writeVertex(dw,
1662                             DL_VertexData(ae->getStartpoint().x,
1663                                           ae->getStartpoint().y,
1664                                           0.0,
1665                                                                                   bulge));
1666             first = false;
1667         }
1668
1669         //if (dxf.getVersion()==VER_R12) {
1670             if (nextEntity!=NULL) {
1671                 if (nextEntity->rtti()==RS2::EntityArc) {
1672                     bulge = ((Arc*)nextEntity)->getBulge();
1673                 }
1674                                 else {
1675                                         bulge = 0.0;
1676                                 }
1677             }
1678         /*} else {
1679             if (v->rtti()==RS2::EntityArc) {
1680                 bulge = ((Arc*)v)->getBulge();
1681             }
1682         }*/
1683
1684
1685                 if (l->isClosed()==false || v!=lastEntity) {
1686                 dxf.writeVertex(dw,
1687                         DL_VertexData(ae->getEndpoint().x,
1688                                       ae->getEndpoint().y,
1689                                       0.0,
1690                                       bulge));
1691                 }
1692     }
1693     dxf.writePolylineEnd(dw);
1694 }
1695
1696
1697
1698 /**
1699  * Writes the given spline entity to the file.
1700  */
1701 void FilterDXF::writeSpline(DL_WriterA & dw, Spline * s, const DL_Attributes & attrib)
1702 {
1703         // split spline into atomic entities for DXF R12:
1704         if (dxf.getVersion() == VER_R12)
1705         {
1706                 writeAtomicEntities(dw, s, attrib, RS2::ResolveNone);
1707                 return;
1708         }
1709
1710         if (s->getNumberOfControlPoints() < s->getDegree() + 1)
1711         {
1712                 DEBUG->print(Debug::D_ERROR, "FilterDXF::writeSpline: "
1713                         "Discarding spline: not enough control points given.");
1714                 return;
1715         }
1716
1717         // Number of control points:
1718         int numCtrl = s->getNumberOfControlPoints();
1719
1720         // Number of knots (= number of control points + spline degree + 1)
1721         int numKnots = numCtrl + s->getDegree() + 1;
1722
1723         int flags;
1724
1725         if (s->isClosed())
1726                 flags = 11;
1727         else
1728                 flags = 8;
1729
1730         // write spline header:
1731         dxf.writeSpline(dw, DL_SplineData(s->getDegree(), numKnots, numCtrl, flags), attrib);
1732
1733         // write spline knots:
1734         QList<Vector> cp = s->getControlPoints();
1735         QList<Vector>::iterator it;
1736
1737         int k = s->getDegree() + 1;
1738         DL_KnotData kd;
1739
1740         for(int i=1; i<=numKnots; i++)
1741         {
1742                 if (i <= k)
1743                         kd = DL_KnotData(0.0);
1744                 else if (i <= numKnots - k)
1745                         kd = DL_KnotData(1.0 / (numKnots - 2 * k + 1) * (i - k));
1746                 else
1747                         kd = DL_KnotData(1.0);
1748
1749                 dxf.writeKnot(dw, kd);
1750         }
1751
1752         // write spline control points:
1753         for(it=cp.begin(); it!=cp.end(); ++it)
1754         {
1755                 dxf.writeControlPoint(dw, DL_ControlPointData((*it).x, (*it).y, 0.0));
1756         }
1757 }
1758
1759 /**
1760  * Writes the given circle entity to the file.
1761  */
1762 void FilterDXF::writeCircle(DL_WriterA& dw, Circle* c,
1763                                const DL_Attributes& attrib) {
1764     dxf.writeCircle(
1765         dw,
1766         DL_CircleData(c->getCenter().x,
1767                       c->getCenter().y,
1768                       0.0,
1769                       c->getRadius()),
1770         attrib);
1771
1772 }
1773
1774
1775
1776 void FilterDXF::writeArc(DL_WriterA& dw, Arc* a,
1777                             const DL_Attributes& attrib) {
1778     double a1, a2;
1779     if (a->isReversed()) {
1780         a1 = a->getAngle2()*ARAD;
1781         a2 = a->getAngle1()*ARAD;
1782     } else {
1783         a1 = a->getAngle1()*ARAD;
1784         a2 = a->getAngle2()*ARAD;
1785     }
1786     dxf.writeArc(
1787         dw,
1788         DL_ArcData(a->getCenter().x,
1789                    a->getCenter().y,
1790                    0.0,
1791                    a->getRadius(),
1792                    a1, a2),
1793         attrib);
1794 }
1795
1796
1797 void FilterDXF::writeEllipse(DL_WriterA& dw, Ellipse* s,
1798                                 const DL_Attributes& attrib) {
1799     if (s->isReversed()) {
1800         dxf.writeEllipse(
1801             dw,
1802             DL_EllipseData(s->getCenter().x,
1803                            s->getCenter().y,
1804                            0.0,
1805                            s->getMajorP().x,
1806                            s->getMajorP().y,
1807                            0.0,
1808                            s->getRatio(),
1809                            s->getAngle2(),
1810                            s->getAngle1()),
1811             attrib);
1812     } else {
1813         dxf.writeEllipse(
1814             dw,
1815             DL_EllipseData(s->getCenter().x,
1816                            s->getCenter().y,
1817                            0.0,
1818                            s->getMajorP().x,
1819                            s->getMajorP().y,
1820                            0.0,
1821                            s->getRatio(),
1822                            s->getAngle1(),
1823                            s->getAngle2()),
1824             attrib);
1825     }
1826 }
1827
1828 void FilterDXF::writeInsert(DL_WriterA & dw, Insert * i, const DL_Attributes & attrib)
1829 {
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),
1835                 attrib);
1836 }
1837
1838 void FilterDXF::writeText(DL_WriterA & dw, Text * t, const DL_Attributes & attrib)
1839 {
1840     if (dxf.getVersion()==VER_R12)
1841         {
1842         int hJust=0;
1843         int vJust=0;
1844
1845                 if (t->getHAlign()==RS2::HAlignLeft) {
1846             hJust=0;
1847         } else if (t->getHAlign()==RS2::HAlignCenter) {
1848             hJust=1;
1849         } else if (t->getHAlign()==RS2::HAlignRight) {
1850             hJust=2;
1851         }
1852
1853                 if (t->getVAlign()==RS2::VAlignTop) {
1854             vJust=3;
1855         } else if (t->getVAlign()==RS2::VAlignMiddle) {
1856             vJust=2;
1857         } else if (t->getVAlign()==RS2::VAlignBottom) {
1858             vJust=1;
1859         }
1860
1861                 dxf.writeText(
1862             dw,
1863             DL_TextData(t->getInsertionPoint().x,
1864                         t->getInsertionPoint().y,
1865                         0.0,
1866                         t->getInsertionPoint().x,
1867                         t->getInsertionPoint().y,
1868                         0.0,
1869                         t->getHeight(),
1870                         1.0,
1871                         0,
1872                         hJust, vJust,
1873                         (const char*)toDxfString(
1874                             t->getText()).toLocal8Bit(),
1875                         (const char*)t->getStyle().toLocal8Bit(),
1876                         t->getAngle()),
1877             attrib);
1878     }
1879     else
1880         {
1881         int attachmentPoint=1;
1882
1883                 if (t->getHAlign()==RS2::HAlignLeft) {
1884             attachmentPoint=1;
1885         } else if (t->getHAlign()==RS2::HAlignCenter) {
1886             attachmentPoint=2;
1887         } else if (t->getHAlign()==RS2::HAlignRight) {
1888             attachmentPoint=3;
1889         }
1890
1891                 if (t->getVAlign()==RS2::VAlignTop) {
1892             attachmentPoint+=0;
1893         } else if (t->getVAlign()==RS2::VAlignMiddle) {
1894             attachmentPoint+=3;
1895         } else if (t->getVAlign()==RS2::VAlignBottom) {
1896             attachmentPoint+=6;
1897         }
1898
1899         dxf.writeMText(
1900             dw,
1901             DL_MTextData(t->getInsertionPoint().x,
1902                          t->getInsertionPoint().y,
1903                          0.0,
1904                          t->getHeight(),
1905                          t->getWidth(),
1906                          attachmentPoint,
1907                          t->getDrawingDirection(),
1908                          t->getLineSpacingStyle(),
1909                          t->getLineSpacingFactor(),
1910                          (const char*)toDxfString(
1911                              t->getText()).toLocal8Bit(),
1912                          (const char*)t->getStyle().toLocal8Bit(),
1913                          t->getAngle()),
1914             attrib);
1915     }
1916 }
1917
1918
1919
1920 void FilterDXF::writeDimension(DL_WriterA& dw, Dimension* d,
1921                                   const DL_Attributes& attrib) {
1922
1923     // split hatch into atomic entities:
1924     if (dxf.getVersion()==VER_R12) {
1925         writeAtomicEntities(dw, d, attrib, RS2::ResolveNone);
1926         return;
1927     }
1928
1929     int type;
1930     int attachmentPoint=1;
1931     if (d->getHAlign()==RS2::HAlignLeft) {
1932         attachmentPoint=1;
1933     } else if (d->getHAlign()==RS2::HAlignCenter) {
1934         attachmentPoint=2;
1935     } else if (d->getHAlign()==RS2::HAlignRight) {
1936         attachmentPoint=3;
1937     }
1938     if (d->getVAlign()==RS2::VAlignTop) {
1939         attachmentPoint+=0;
1940     } else if (d->getVAlign()==RS2::VAlignMiddle) {
1941         attachmentPoint+=3;
1942     } else if (d->getVAlign()==RS2::VAlignBottom) {
1943         attachmentPoint+=6;
1944     }
1945
1946     switch (d->rtti()) {
1947     case RS2::EntityDimAligned:
1948         type = 1;
1949         break;
1950     case RS2::EntityDimLinear:
1951         type = 0;
1952         break;
1953     case RS2::EntityDimRadial:
1954         type = 4;
1955         break;
1956     case RS2::EntityDimDiametric:
1957         type = 3;
1958         break;
1959     default:
1960         type = 0;
1961         break;
1962     }
1963
1964     DL_DimensionData dimData(d->getDefinitionPoint().x,
1965                              d->getDefinitionPoint().y,
1966                              0.0,
1967                              d->getMiddleOfText().x,
1968                              d->getMiddleOfText().y,
1969                              0.0,
1970                              type,
1971                              attachmentPoint,
1972                              d->getLineSpacingStyle(),
1973                              d->getLineSpacingFactor(),
1974                              (const char*)toDxfString(
1975                                  d->getText()).toLocal8Bit(),
1976                              (const char*)d->getStyle().toLocal8Bit(),
1977                              d->getAngle());
1978
1979     if (d->rtti()==RS2::EntityDimAligned) {
1980         DimAligned* da = (DimAligned*)d;
1981
1982         DL_DimAlignedData dimAlignedData(da->getExtensionPoint1().x,
1983                                          da->getExtensionPoint1().y,
1984                                          0.0,
1985                                          da->getExtensionPoint2().x,
1986                                          da->getExtensionPoint2().y,
1987                                          0.0);
1988
1989         dxf.writeDimAligned(dw, dimData, dimAlignedData, attrib);
1990     } else if (d->rtti()==RS2::EntityDimLinear) {
1991         DimLinear* dl = (DimLinear*)d;
1992
1993         DL_DimLinearData dimLinearData(dl->getExtensionPoint1().x,
1994                                        dl->getExtensionPoint1().y,
1995                                        0.0,
1996                                        dl->getExtensionPoint2().x,
1997                                        dl->getExtensionPoint2().y,
1998                                        0.0,
1999                                        dl->getAngle(),
2000                                        dl->getOblique());
2001
2002         dxf.writeDimLinear(dw, dimData, dimLinearData, attrib);
2003     } else if (d->rtti()==RS2::EntityDimRadial) {
2004         DimRadial* dr = (DimRadial*)d;
2005
2006         DL_DimRadialData dimRadialData(dr->getDefinitionPoint().x,
2007                                        dr->getDefinitionPoint().y,
2008                                        0.0,
2009                                        dr->getLeader());
2010
2011         dxf.writeDimRadial(dw, dimData, dimRadialData, attrib);
2012     } else if (d->rtti()==RS2::EntityDimDiametric) {
2013         DimDiametric* dr = (DimDiametric*)d;
2014
2015         DL_DimDiametricData dimDiametricData(dr->getDefinitionPoint().x,
2016                                              dr->getDefinitionPoint().y,
2017                                              0.0,
2018                                              dr->getLeader());
2019
2020         dxf.writeDimDiametric(dw, dimData, dimDiametricData, attrib);
2021     } else if (d->rtti()==RS2::EntityDimAngular) {
2022         DimAngular* da = (DimAngular*)d;
2023
2024         DL_DimAngularData dimAngularData(da->getDefinitionPoint1().x,
2025                                          da->getDefinitionPoint1().y,
2026                                          0.0,
2027                                          da->getDefinitionPoint2().x,
2028                                          da->getDefinitionPoint2().y,
2029                                          0.0,
2030                                          da->getDefinitionPoint3().x,
2031                                          da->getDefinitionPoint3().y,
2032                                          0.0,
2033                                          da->getDefinitionPoint4().x,
2034                                          da->getDefinitionPoint4().y,
2035                                          0.0);
2036
2037         dxf.writeDimAngular(dw, dimData, dimAngularData, attrib);
2038     }
2039
2040 }
2041
2042
2043 void FilterDXF::writeLeader(DL_WriterA& dw, Leader* l,
2044                                const DL_Attributes& attrib) {
2045     if (l->count()>0) {
2046         dxf.writeLeader(
2047             dw,
2048             DL_LeaderData(l->hasArrowHead(),
2049                           0,
2050                           3,
2051                           0,
2052                           0,
2053                           1.0,
2054                           10.0,
2055                           l->count()),
2056             attrib);
2057         bool first = true;
2058         for (Entity* v=l->firstEntity(RS2::ResolveNone);
2059                 v!=NULL;
2060                 v=l->nextEntity(RS2::ResolveNone)) {
2061
2062             // Write line verties:
2063             if (v->rtti()==RS2::EntityLine) {
2064                 Line* l = (Line*)v;
2065                 if (first) {
2066                     dxf.writeLeaderVertex(
2067                         dw,
2068                         DL_LeaderVertexData(l->getStartpoint().x,
2069                                             l->getStartpoint().y,
2070                                             0.0));
2071                     first = false;
2072                 }
2073                 dxf.writeLeaderVertex(
2074                     dw,
2075                     DL_LeaderVertexData(l->getEndpoint().x,
2076                                         l->getEndpoint().y,
2077                                         0.0));
2078             }
2079         }
2080     } else {
2081         DEBUG->print(Debug::D_WARNING,
2082                         "dropping leader with no vertices");
2083     }
2084 }
2085
2086
2087 void FilterDXF::writeHatch(DL_WriterA& dw, Hatch* h,
2088                               const DL_Attributes& attrib) {
2089
2090     // split hatch into atomic entities:
2091     if (dxf.getVersion()==VER_R12) {
2092         writeAtomicEntities(dw, h, attrib, RS2::ResolveAll);
2093         return;
2094     }
2095
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);
2100                 l!=NULL;
2101                 l=h->nextEntity(RS2::ResolveNone)) {
2102
2103             if (l->isContainer() && !l->getFlag(RS2::FlagTemp)) {
2104                 if (l->count()==0) {
2105                     writeIt = false;
2106                 }
2107             }
2108         }
2109     } else {
2110         writeIt = false;
2111     }
2112
2113     if (!writeIt) {
2114         DEBUG->print(Debug::D_WARNING,
2115                         "FilterDXF::writeHatch: Dropping Hatch");
2116     } else {
2117         DL_HatchData data(h->countLoops(),
2118                           h->isSolid(),
2119                           h->getScale(),
2120                           h->getAngle(),
2121                           (const char*)h->getPattern().toLocal8Bit());
2122         dxf.writeHatch1(dw, data, attrib);
2123
2124         for (Entity* l=h->firstEntity(RS2::ResolveNone);
2125                 l!=NULL;
2126                 l=h->nextEntity(RS2::ResolveNone)) {
2127
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);
2133
2134                 for (Entity* ed=loop->firstEntity(RS2::ResolveNone);
2135                         ed!=NULL;
2136                         ed=loop->nextEntity(RS2::ResolveNone)) {
2137
2138                     // Write hatch loop edges:
2139                     if (ed->rtti()==RS2::EntityLine) {
2140                         Line* ln = (Line*)ed;
2141                         dxf.writeHatchEdge(
2142                             dw,
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) {
2148                         Arc* ar = (Arc*)ed;
2149                         if (!ar->isReversed()) {
2150                             dxf.writeHatchEdge(
2151                                 dw,
2152                                 DL_HatchEdgeData(ar->getCenter().x,
2153                                                  ar->getCenter().y,
2154                                                  ar->getRadius(),
2155                                                  ar->getAngle1(),
2156                                                  ar->getAngle2(),
2157                                                  true));
2158                         } else {
2159                             dxf.writeHatchEdge(
2160                                 dw,
2161                                 DL_HatchEdgeData(ar->getCenter().x,
2162                                                  ar->getCenter().y,
2163                                                  ar->getRadius(),
2164                                                  2*M_PI-ar->getAngle1(),
2165                                                  2*M_PI-ar->getAngle2(),
2166                                                  false));
2167                         }
2168                     } else if (ed->rtti()==RS2::EntityCircle) {
2169                         Circle* ci = (Circle*)ed;
2170                         dxf.writeHatchEdge(
2171                             dw,
2172                             DL_HatchEdgeData(ci->getCenter().x,
2173                                              ci->getCenter().y,
2174                                              ci->getRadius(),
2175                                              0.0,
2176                                              2*M_PI,
2177                                              true));
2178                     }
2179                 }
2180                 dxf.writeHatchLoop2(dw, lData);
2181             }
2182         }
2183         dxf.writeHatch2(dw, data, attrib);
2184     }
2185
2186 }
2187
2188
2189
2190 void FilterDXF::writeSolid(DL_WriterA& dw, Solid* s,
2191                               const DL_Attributes& attrib) {
2192
2193     // split solid into line entities:
2194     //if (dxf.getVersion()==VER_R12) {
2195         for (int i=0; i<3; ++i) {
2196             dxf.writeLine(
2197                 dw,
2198                 DL_LineData(s->getCorner(i).x,
2199                             s->getCorner(i).y,
2200                             0.0,
2201                             s->getCorner((i+1)%3).x,
2202                             s->getCorner((i+1)%3).y,
2203                             0.0),
2204                 attrib);
2205         }
2206         //return;
2207     //}
2208 }
2209
2210
2211 void FilterDXF::writeImage(DL_WriterA& dw, Image* i,
2212                               const DL_Attributes& attrib) {
2213     int handle = dxf.writeImage(
2214                      dw,
2215                      DL_ImageData(std::string(""),
2216                                   i->getInsertionPoint().x,
2217                                   i->getInsertionPoint().y,
2218                                   0.0,
2219                                   i->getUVector().x,
2220                                   i->getUVector().y,
2221                                   0.0,
2222                                   i->getVVector().x,
2223                                   i->getVVector().y,
2224                                   0.0,
2225                                   i->getWidth(),
2226                                   i->getHeight(),
2227                                   i->getBrightness(),
2228                                   i->getContrast(),
2229                                   i->getFade()),
2230                      attrib);
2231     i->setHandle(handle);
2232 }
2233
2234
2235
2236 void FilterDXF::writeEntityContainer(DL_WriterA& dw, EntityContainer* con,
2237                                         const DL_Attributes& /*attrib*/) {
2238     QString blkName;
2239     blkName = "__CE";
2240
2241     // Creating an unique ID from the element ID
2242     int tmp, c=1; // tmp = temporary var c = counter var
2243     tmp = con->getId();
2244
2245     while (true) {
2246         tmp = tmp/c;
2247         blkName.append((char) tmp %10 + 48);
2248         c *= 10;
2249         if (tmp < 10) {
2250             break;
2251         }
2252     }
2253
2254     //Block definition
2255     dw.sectionTables();
2256     dxf.writeBlockRecord(dw);
2257     dw.dxfString(  0, "BLOCK_RECORD");
2258
2259     dw.handle();
2260     dw.dxfHex(330, 1);
2261     dw.dxfString(100, "AcDbSymbolTableRecord");
2262     dw.dxfString(100, "AcDbBlockTableRecord");
2263     dw.dxfString(  2, blkName.toLatin1());
2264     dw.dxfHex(340, 0);
2265     dw.dxfString(0, "ENDTAB");
2266
2267     //Block creation
2268     BlockData blkdata(blkName, Vector(0,0), false);
2269
2270     Block* blk = new Block(graphic, blkdata);
2271
2272     for (Entity* e1 = con->firstEntity(); e1 != NULL;
2273             e1 = con->nextEntity() ) {
2274         blk->addEntity(e1);
2275     }
2276     writeBlock(dw, blk);
2277     //delete e1;
2278
2279 }
2280
2281
2282
2283 /**
2284  * Writes the atomic entities of the given cotnainer to the file.
2285  */
2286 void FilterDXF::writeAtomicEntities(DL_WriterA& dw, EntityContainer* c,
2287                                        const DL_Attributes& attrib,
2288                                        RS2::ResolveLevel level) {
2289
2290     for (Entity* e=c->firstEntity(level);
2291             e!=NULL;
2292             e=c->nextEntity(level)) {
2293
2294         writeEntity(dw, e, attrib);
2295     }
2296 }
2297
2298 /**
2299  * Writes an IMAGEDEF object into an OBJECT section.
2300  */
2301 void FilterDXF::writeImageDef(DL_WriterA& dw, Image* i) {
2302     if (i==NULL || i->getFlag(RS2::FlagUndone)) {
2303         return;
2304     }
2305
2306     dxf.writeImageDef(
2307         dw,
2308         i->getHandle(),
2309         DL_ImageData((const char*)i->getFile().toLocal8Bit(),
2310                      i->getInsertionPoint().x,
2311                      i->getInsertionPoint().y,
2312                      0.0,
2313                      i->getUVector().x,
2314                      i->getUVector().y,
2315                      0.0,
2316                      i->getVVector().x,
2317                      i->getVVector().y,
2318                      0.0,
2319                      i->getWidth(),
2320                      i->getHeight(),
2321                      i->getBrightness(),
2322                      i->getContrast(),
2323                      i->getFade()));
2324 }
2325
2326
2327
2328 /**
2329  * Sets the entities attributes according to the attributes
2330  * that come from a DXF file.
2331  */
2332 void FilterDXF::setEntityAttributes(Entity* entity,
2333                                        const DL_Attributes& attrib) {
2334     DEBUG->print("FilterDXF::setEntityAttributes");
2335
2336     Pen pen;
2337     pen.setColor(Qt::black);
2338     pen.setLineType(RS2::SolidLine);
2339
2340     // Layer:
2341     if (attrib.getLayer().empty()) {
2342         entity->setLayer("0");
2343     } else {
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));
2347         }
2348         entity->setLayer(attrib.getLayer().c_str());
2349     }
2350
2351     // Color:
2352     pen.setColor(numberToColor(attrib.getColor()));
2353
2354     // Linetype:
2355     pen.setLineType(nameToLineType(attrib.getLineType().c_str()));
2356
2357     // Width:
2358     pen.setWidth(numberToWidth(attrib.getWidth()));
2359
2360     entity->setPen(pen);
2361     DEBUG->print("FilterDXF::setEntityAttributes: OK");
2362 }
2363
2364 /**
2365  * Gets the entities attributes as a DL_Attributes object.
2366  */
2367 DL_Attributes FilterDXF::getEntityAttributes(Entity * entity)
2368 {
2369         // Layer:
2370         Layer * layer = entity->getLayer();
2371         QString layerName;
2372
2373         if (layer != NULL)
2374                 layerName = layer->getName();
2375         else
2376                 layerName = "NULL";
2377
2378         Pen pen = entity->getPen(false);
2379
2380         // Color:
2381         int color = colorToNumber(pen.getColor());
2382         //printf("Color is: %s -> %d\n", pen.getColor().name().toLatin1(), color);
2383
2384         // Linetype:
2385         QString lineType = lineTypeToName(pen.getLineType());
2386
2387         // Width:
2388         int width = widthToNumber(pen.getWidth());
2389
2390         DL_Attributes attrib(layerName.toLatin1().data(), color, width, lineType.toLatin1().data());
2391
2392         return attrib;
2393 }
2394
2395 /**
2396  * @return Pen with the same attributes as 'attrib'.
2397  */
2398 Pen FilterDXF::attributesToPen(const DL_Attributes & attrib) const
2399 {
2400     /*
2401     printf("converting Color %d to %s\n",
2402        attrib.getColor(), numberToColor(attrib.getColor()).name().toLatin1());
2403     */
2404
2405     Pen pen(numberToColor(attrib.getColor()),
2406                numberToWidth(attrib.getWidth()),
2407                nameToLineType(attrib.getLineType().c_str()));
2408     return pen;
2409 }
2410
2411
2412
2413 /**
2414  * Converts a color index (num) into a Color object.
2415  * Please refer to the dxflib documentation for details.
2416  *
2417  * @param num Color number.
2418  * @param comp Compatibility with older QCad versions (1.5.3 and older)
2419  */
2420 Color FilterDXF::numberToColor(int num, bool comp) {
2421     // Compatibility with QCad 1.5.3 and older:
2422     if (comp) {
2423         switch(num) {
2424         case 0:
2425             return Qt::black;
2426             break;
2427         case 1:
2428             return Qt::darkBlue;
2429             break;
2430         case 2:
2431             return Qt::darkGreen;
2432             break;
2433         case 3:
2434             return Qt::darkCyan;
2435             break;
2436         case 4:
2437             return Qt::darkRed;
2438             break;
2439         case 5:
2440             return Qt::darkMagenta;
2441             break;
2442         case 6:
2443             return Qt::darkYellow;
2444             break;
2445         case 7:
2446             return Qt::lightGray;
2447             break;
2448         case 8:
2449             return Qt::darkGray;
2450             break;
2451         case 9:
2452             return Qt::blue;
2453             break;
2454         case 10:
2455             return Qt::green;
2456             break;
2457         case 11:
2458             return Qt::cyan;
2459             break;
2460         case 12:
2461             return Qt::red;
2462             break;
2463         case 13:
2464             return Qt::magenta;
2465             break;
2466         case 14:
2467             return Qt::yellow;
2468             break;
2469         case 15:
2470             return Qt::black;
2471             break;
2472         default:
2473             break;
2474         }
2475     } else {
2476         if (num==0) {
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));
2484         } else {
2485             DEBUG->print(Debug::D_WARNING,
2486                                 "FilterDXF::numberToColor: Invalid color number given.");
2487             return Color(RS2::FlagByLayer);
2488         }
2489     }
2490     return Color();
2491 }
2492
2493
2494
2495 /**
2496  * Converts a color into a color number in the DXF palette.
2497  * The color that fits best is chosen.
2498  */
2499 int FilterDXF::colorToNumber(const Color& col) {
2500
2501     //printf("Searching color for %s\n", col.name().toLatin1());
2502
2503     // Special color BYBLOCK:
2504     if (col.getFlag(RS2::FlagByBlock)) {
2505         return 0;
2506     }
2507
2508     // Special color BYLAYER
2509     else if (col.getFlag(RS2::FlagByLayer)) {
2510         return 256;
2511     }
2512
2513     // Special color black is not in the table but white represents both
2514     // black and white
2515     else if (col.red()==0 && col.green()==0 && col.blue()==0) {
2516         return 7;
2517     }
2518
2519     // All other colors
2520     else {
2521         int num=0;
2522         int diff=255*3;  // smallest difference to a color in the table found so far
2523
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));
2529
2530             if (d<diff) {
2531                 /*
2532                 printf("color %f,%f,%f is closer\n",
2533                        dxfColors[i][0],
2534                        dxfColors[i][1],
2535                        dxfColors[i][2]);
2536                 */
2537                 diff = d;
2538                 num = i;
2539                 if (d==0) {
2540                     break;
2541                 }
2542             }
2543         }
2544         //printf("  Found: %d, diff: %d\n", num, diff);
2545         return num;
2546     }
2547 }
2548
2549 /**
2550  * Converts a line type name (e.g. "CONTINUOUS") into a RS2::LineType
2551  * object.
2552  */
2553 RS2::LineType FilterDXF::nameToLineType(const QString & name)
2554 {
2555         QString uName = name.toUpper();
2556
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;
2601
2602         return RS2::SolidLine;
2603 }
2604
2605 /**
2606  * Converts a LineType into a name for a line type.
2607  */
2608 QString FilterDXF::lineTypeToName(RS2::LineType lineType)
2609 {
2610     // Standard linetypes for QCad II / AutoCAD
2611     switch (lineType)
2612         {
2613     case RS2::SolidLine:
2614         return "CONTINUOUS";
2615         break;
2616
2617     case RS2::DotLine:
2618         return "DOT";
2619         break;
2620     case RS2::DotLine2:
2621         return "DOT2";
2622         break;
2623     case RS2::DotLineX2:
2624         return "DOTX2";
2625         break;
2626
2627     case RS2::DashLine:
2628         return "DASHED";
2629         break;
2630     case RS2::DashLine2:
2631         return "DASHED2";
2632         break;
2633     case RS2::DashLineX2:
2634         return "DASHEDX2";
2635         break;
2636
2637     case RS2::DashDotLine:
2638         return "DASHDOT";
2639         break;
2640     case RS2::DashDotLine2:
2641         return "DASHDOT2";
2642         break;
2643     case RS2::DashDotLineX2:
2644         return "DASHDOTX2";
2645         break;
2646
2647     case RS2::DivideLine:
2648         return "DIVIDE";
2649         break;
2650     case RS2::DivideLine2:
2651         return "DIVIDE2";
2652         break;
2653     case RS2::DivideLineX2:
2654         return "DIVIDEX2";
2655         break;
2656
2657     case RS2::CenterLine:
2658         return "CENTER";
2659         break;
2660     case RS2::CenterLine2:
2661         return "CENTER2";
2662         break;
2663     case RS2::CenterLineX2:
2664         return "CENTERX2";
2665         break;
2666
2667     case RS2::BorderLine:
2668         return "BORDER";
2669         break;
2670     case RS2::BorderLine2:
2671         return "BORDER2";
2672         break;
2673     case RS2::BorderLineX2:
2674         return "BORDERX2";
2675         break;
2676
2677
2678     case RS2::LineByLayer:
2679         return "ByLayer";
2680         break;
2681     case RS2::LineByBlock:
2682         return "ByBlock";
2683         break;
2684     default:
2685         break;
2686     }
2687
2688     return "CONTINUOUS";
2689 }
2690
2691
2692
2693 /**
2694  * Converts a LineType into a name for a line type.
2695  */
2696 /*QString FilterDXF::lineTypeToDescription(RS2::LineType lineType) {
2697
2698     // Standard linetypes for QCad II / AutoCAD
2699     switch (lineType) {
2700     case RS2::SolidLine:
2701         return "Solid line";
2702     case RS2::DotLine:
2703         return "ISO Dashed __ __ __ __ __ __ __ __ __ __ _";
2704     case RS2::DashLine:
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:
2711         return "";
2712     case RS2::LineByBlock:
2713         return "";
2714     default:
2715         break;
2716     }
2717
2718     return "CONTINUOUS";
2719 }*/
2720
2721
2722
2723 /**
2724  * Converts a line width number (e.g. 1) into a RS2::LineWidth.
2725  */
2726 RS2::LineWidth FilterDXF::numberToWidth(int num) {
2727     switch (num) {
2728     case -1:
2729         return RS2::WidthByLayer;
2730         break;
2731     case -2:
2732         return RS2::WidthByBlock;
2733         break;
2734     case -3:
2735         return RS2::WidthDefault;
2736         break;
2737     default:
2738         if (num<3) {
2739             return RS2::Width00;
2740         } else if (num<7) {
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;
2784         } else {
2785             return RS2::Width23;
2786         }
2787         break;
2788     }
2789     return (RS2::LineWidth)num;
2790 }
2791
2792
2793
2794 /**
2795  * Converts a RS2::LineWidth into an int width.
2796  */
2797 int FilterDXF::widthToNumber(RS2::LineWidth width) {
2798     switch (width) {
2799     case RS2::WidthByLayer:
2800         return -1;
2801         break;
2802     case RS2::WidthByBlock:
2803         return -2;
2804         break;
2805     case RS2::WidthDefault:
2806         return -3;
2807         break;
2808     default:
2809         return (int)width;
2810         break;
2811     }
2812     return (int)width;
2813 }
2814
2815 /**
2816  * Converts a native unicode string into a DXF encoded string.
2817  *
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
2822  */
2823 QString FilterDXF::toDxfString(const QString & string)
2824 {
2825         /*
2826         QString res = string;
2827         // Line feed:
2828         res = res.replace(QRegExp("\\n"), "\\P");
2829         // Space:
2830         res = res.replace(QRegExp(" "), "\\~");
2831         // diameter:
2832         res = res.replace(QChar(0x2205), "%%c");
2833         // degree:
2834         res = res.replace(QChar(0x00B0), "%%d");
2835         // plus/minus
2836         res = res.replace(QChar(0x00B1), "%%p");
2837         */
2838
2839         QString res = "";
2840
2841         for(int i=0; i<string.length(); ++i)
2842         {
2843                 int c = string.at(i).unicode();
2844                 switch (c)
2845                 {
2846                 case 0x0A:
2847                         res += "\\P";
2848                         break;
2849                 case 0x20:
2850                         res += "\\~";
2851                         break;
2852                         // diameter:
2853                 case 0x2205:
2854                         res += "%%c";
2855                         break;
2856                         // degree:
2857                 case 0x00B0:
2858                         res += "%%d";
2859                         break;
2860                         // plus/minus
2861                 case 0x00B1:
2862                         res += "%%p";
2863                         break;
2864                 default:
2865                         if (c > 127)
2866                         {
2867                                 QString hex;
2868                                 hex = QString("%1").arg(c, 4, 16);
2869                                 hex = hex.replace(' ', '0');
2870                                 res += QString("\\U+%1").arg(hex);
2871                         }
2872                         else
2873                                 res += string.at(i);
2874
2875                         break;
2876                 }
2877         }
2878
2879         return res;
2880 }
2881
2882 /**
2883  * Converts a DXF encoded string into a native Unicode string.
2884  */
2885 QString FilterDXF::toNativeString(const QString & string)
2886 {
2887         QString res = string;
2888         // Line feed:
2889         res = res.replace(QRegExp("\\\\P"), "\n");
2890         // Space:
2891         res = res.replace(QRegExp("\\\\~"), " ");
2892         // diameter:
2893         res = res.replace(QRegExp("%%c"), QChar(0x2205));
2894         // degree:
2895         res = res.replace(QRegExp("%%d"), QChar(0x00B0));
2896         // plus/minus
2897         res = res.replace(QRegExp("%%p"), QChar(0x00B1));
2898
2899         // Unicode characters:
2900         QString cap = "";
2901         int uCode = 0;
2902         bool ok = false;
2903
2904         do
2905         {
2906                 QRegExp regexp("\\\\U\\+[0-9A-Fa-f]{4,4}");
2907 //              regexp.search(res);
2908                 regexp.indexIn(res);
2909                 cap = regexp.cap();
2910
2911                 if (!cap.isNull())
2912                 {
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));
2916                         // for Qt 3.1:
2917                         //res.replace(cap, QChar(uCode));
2918                 }
2919         }
2920         while (!cap.isNull());
2921
2922         // ASCII code:
2923         cap = "";
2924         uCode = 0;
2925         ok = false;
2926
2927         do
2928         {
2929                 QRegExp regexp("%%[0-9]{3,3}");
2930 //              regexp.search(res);
2931                 regexp.indexIn(res);
2932                 cap = regexp.cap();
2933
2934                 if (!cap.isNull())
2935                 {
2936                         uCode = cap.right(3).toInt(&ok, 10);
2937                         // workaround for Qt 3.0.x:
2938                         res.replace(QRegExp("%%" + cap.right(3)), QChar(uCode));
2939                         // for Qt 3.1:
2940                         //res.replace(cap, QChar(uCode));
2941                 }
2942         }
2943         while (!cap.isNull());
2944
2945         // Ignore font tags:
2946         res = res.replace(QRegExp("\\\\f[0-9A-Za-z| ]{0,};"), "");
2947
2948         // Ignore {}
2949         res = res.replace("\\{", "#curly#");
2950         res = res.replace("{", "");
2951         res = res.replace("#curly#", "{");
2952
2953         res = res.replace("\\}", "#curly#");
2954         res = res.replace("}", "");
2955         res = res.replace("#curly#", "}");
2956
2957         DEBUG->print("FilterDXF::toNativeString:");
2958         DEBUG->printUnicode(res);
2959         return res;
2960 }
2961
2962 /**
2963  * Converts the given number from a DXF file into an AngleFormat enum.
2964  *
2965  * @param num $DIMAUNIT from DXF (0: decimal deg, 1: deg/min/sec, 2: gradians,
2966  *                                3: radians, 4: surveyor's units)
2967  *
2968  * @ret Matching AngleFormat enum value.
2969  */
2970 RS2::AngleFormat FilterDXF::numberToAngleFormat(int num) {
2971
2972     RS2::AngleFormat af;
2973
2974     switch (num) {
2975     default:
2976     case 0:
2977         af = RS2::DegreesDecimal;
2978         break;
2979     case 1:
2980         af = RS2::DegreesMinutesSeconds;
2981         break;
2982     case 2:
2983         af = RS2::Gradians;
2984         break;
2985     case 3:
2986         af = RS2::Radians;
2987         break;
2988     case 4:
2989         af = RS2::Surveyors;
2990         break;
2991     }
2992
2993     return af;
2994 }
2995
2996
2997 /**
2998  * Converts AngleFormat enum to DXF number.
2999  */
3000 int FilterDXF::angleFormatToNumber(RS2::AngleFormat af) {
3001
3002     int num;
3003
3004     switch (af) {
3005     default:
3006     case RS2::DegreesDecimal:
3007         num = 0;
3008         break;
3009     case RS2::DegreesMinutesSeconds:
3010         num = 1;
3011         break;
3012     case RS2::Gradians:
3013         num = 2;
3014         break;
3015     case RS2::Radians:
3016         num = 3;
3017         break;
3018     case RS2::Surveyors:
3019         num = 4;
3020         break;
3021     }
3022
3023     return num;
3024 }
3025
3026
3027
3028 /**
3029  * converts a DXF unit setting (e.g. INSUNITS) to a unit enum.
3030  */
3031 RS2::Unit FilterDXF::numberToUnit(int num) {
3032     switch (num) {
3033     default:
3034     case  0:
3035         return RS2::None;
3036         break;
3037     case  1:
3038         return RS2::Inch;
3039         break;
3040     case  2:
3041         return RS2::Foot;
3042         break;
3043     case  3:
3044         return RS2::Mile;
3045         break;
3046     case  4:
3047         return RS2::Millimeter;
3048         break;
3049     case  5:
3050         return RS2::Centimeter;
3051         break;
3052     case  6:
3053         return RS2::Meter;
3054         break;
3055     case  7:
3056         return RS2::Kilometer;
3057         break;
3058     case  8:
3059         return RS2::Microinch;
3060         break;
3061     case  9:
3062         return RS2::Mil;
3063         break;
3064     case 10:
3065         return RS2::Yard;
3066         break;
3067     case 11:
3068         return RS2::Angstrom;
3069         break;
3070     case 12:
3071         return RS2::Nanometer;
3072         break;
3073     case 13:
3074         return RS2::Micron;
3075         break;
3076     case 14:
3077         return RS2::Decimeter;
3078         break;
3079     case 15:
3080         return RS2::Decameter;
3081         break;
3082     case 16:
3083         return RS2::Hectometer;
3084         break;
3085     case 17:
3086         return RS2::Gigameter;
3087         break;
3088     case 18:
3089         return RS2::Astro;
3090         break;
3091     case 19:
3092         return RS2::Lightyear;
3093         break;
3094     case 20:
3095         return RS2::Parsec;
3096         break;
3097     }
3098
3099     return RS2::None;
3100 }
3101
3102
3103
3104 /**
3105  * Converst a unit enum into a DXF unit number e.g. for INSUNITS.
3106  */
3107 int FilterDXF::unitToNumber(RS2::Unit unit) {
3108     switch (unit) {
3109     default:
3110     case RS2::None:
3111         return  0;
3112         break;
3113     case RS2::Inch:
3114         return  1;
3115         break;
3116     case RS2::Foot:
3117         return  2;
3118         break;
3119     case RS2::Mile:
3120         return  3;
3121         break;
3122     case RS2::Millimeter:
3123         return  4;
3124         break;
3125     case RS2::Centimeter:
3126         return  5;
3127         break;
3128     case RS2::Meter:
3129         return  6;
3130         break;
3131     case RS2::Kilometer:
3132         return  7;
3133         break;
3134     case RS2::Microinch:
3135         return  8;
3136         break;
3137     case RS2::Mil:
3138         return  9;
3139         break;
3140     case RS2::Yard:
3141         return 10;
3142         break;
3143     case RS2::Angstrom:
3144         return 11;
3145         break;
3146     case RS2::Nanometer:
3147         return 12;
3148         break;
3149     case RS2::Micron:
3150         return 13;
3151         break;
3152     case RS2::Decimeter:
3153         return 14;
3154         break;
3155     case RS2::Decameter:
3156         return 15;
3157         break;
3158     case RS2::Hectometer:
3159         return 16;
3160         break;
3161     case RS2::Gigameter:
3162         return 17;
3163         break;
3164     case RS2::Astro:
3165         return 18;
3166         break;
3167     case RS2::Lightyear:
3168         return 19;
3169         break;
3170     case RS2::Parsec:
3171         return 20;
3172         break;
3173     }
3174
3175     return 0;
3176 }
3177
3178
3179
3180 /**
3181  * Checks if the given variable is two-dimensional (e.g. $LIMMIN).
3182  */
3183 bool FilterDXF::isVariableTwoDimensional(const QString& var) {
3184     if (var=="$LIMMIN" ||
3185             var=="$LIMMAX" ||
3186             var=="$PLIMMIN" ||
3187             var=="$PLIMMAX" ||
3188             var=="$GRIDUNIT" ||
3189             var=="$VIEWCTR") {
3190
3191         return true;
3192     } else {
3193         return false;
3194     }
3195 }
3196
3197 // EOF
3198