]> Shamusworld >> Repos - architektonas/blob - src/base/filterdxf.cpp
5bc10588c7704b4ac09fd6255ac548cd93580277
[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::EntityGraphic)
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::EntityGraphic) {
1093         ((Drawing*)currentContainer)->addVariable(QString(key),
1094                 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     DEBUG->print("FilterDXF::setVariableInt");
1105
1106     // update document's variable list:
1107     if (currentContainer->rtti()==RS2::EntityGraphic) {
1108         ((Drawing*)currentContainer)->addVariable(QString(key),
1109                 value, code);
1110     }
1111 }
1112
1113
1114
1115 /**
1116  * Sets a double variable from the DXF file.
1117  */
1118 void FilterDXF::setVariableDouble(const char* key, double value, int code) {
1119     DEBUG->print("FilterDXF::setVariableDouble");
1120
1121     // update document's variable list:
1122     if (currentContainer->rtti() == RS2::EntityGraphic)
1123         {
1124         ((Drawing *)currentContainer)->addVariable(QString(key), value, code);
1125     }
1126 }
1127
1128 /**
1129  * Implementation of the method used for RS_Export to communicate
1130  * with this filter.
1131  *
1132  * @param file Full path to the DXF file that will be written.
1133  */
1134 bool FilterDXF::fileExport(Drawing & g, const QString & file, RS2::FormatType type)
1135 {
1136         DEBUG->print("FilterDXF::fileExport: exporting file '%s'...",
1137                 (const char *)QFile::encodeName(file));
1138         DEBUG->print("FilterDXF::fileExport: file type '%d'", (int)type);
1139
1140         this->graphic = &g;
1141
1142 #ifndef Q_OS_WIN
1143         // check if we can write to that directory:
1144 //      QString path = QFileInfo(file).dirPath(true);
1145         QString path = QFileInfo(file).absolutePath();
1146
1147         if (QFileInfo(path).isWritable() == false)
1148         {
1149                 DEBUG->print("FilterDXF::fileExport: can't write file: no permission");
1150                 return false;
1151         }
1152         //
1153 #endif
1154
1155         // set version for DXF filter:
1156         DL_Codes::version exportVersion;
1157
1158         if (type == RS2::FormatDXF12)
1159         {
1160                 exportVersion = DL_Codes::AC1009;
1161         }
1162         else
1163         {
1164                 exportVersion = DL_Codes::AC1015;
1165         }
1166
1167         //DL_WriterA* dw = dxf.out(file, VER_R12);
1168         DL_WriterA * dw = dxf.out((const char *)QFile::encodeName(file), exportVersion);
1169
1170         if (dw == NULL)
1171         {
1172                 DEBUG->print("FilterDXF::fileExport: can't write file");
1173                 return false;
1174         }
1175
1176         // Header
1177         DEBUG->print("writing headers...");
1178         dxf.writeHeader(*dw);
1179
1180         // Variables
1181         DEBUG->print("writing variables...");
1182         writeVariables(*dw);
1183
1184         // Section TABLES
1185         DEBUG->print("writing tables...");
1186         dw->sectionTables();
1187
1188         // VPORT:
1189         dxf.writeVPort(*dw);
1190
1191         // Line types:
1192         DEBUG->print("writing line types...");
1193         int numLT = (int)RS2::BorderLineX2 - (int)RS2::LineByBlock;
1194
1195         if (type == RS2::FormatDXF12)
1196                 numLT -= 2;
1197
1198         dw->tableLineTypes(numLT);
1199
1200         for(int t=(int)RS2::LineByBlock; t<=(int)RS2::BorderLineX2; ++t)
1201         {
1202                 if ((RS2::LineType)t != RS2::NoPen)
1203                         writeLineType(*dw, (RS2::LineType)t);
1204         }
1205
1206         dw->tableEnd();
1207
1208         // Layers:
1209         DEBUG->print("writing layers...");
1210         dw->tableLayers(graphic->countLayers());
1211
1212         for(uint i=0; i<graphic->countLayers(); ++i)
1213         {
1214                 Layer * l = graphic->layerAt(i);
1215                 writeLayer(*dw, l);
1216         }
1217
1218         dw->tableEnd();
1219
1220         // STYLE:
1221         DEBUG->print("writing styles...");
1222         dxf.writeStyle(*dw);
1223
1224         // VIEW:
1225         DEBUG->print("writing views...");
1226         dxf.writeView(*dw);
1227
1228         // UCS:
1229         DEBUG->print("writing ucs...");
1230         dxf.writeUcs(*dw);
1231
1232         // Appid:
1233         DEBUG->print("writing appid...");
1234         dw->tableAppid(1);
1235         writeAppid(*dw, "ACAD");
1236         dw->tableEnd();
1237
1238         // DIMSTYLE:
1239         DEBUG->print("writing dim styles...");
1240         dxf.writeDimStyle(*dw,
1241                 graphic->getVariableDouble("$DIMASZ", 2.5),
1242                 graphic->getVariableDouble("$DIMEXE", 1.25),
1243                 graphic->getVariableDouble("$DIMEXO", 0.625),
1244                 graphic->getVariableDouble("$DIMGAP", 0.625),
1245                 graphic->getVariableDouble("$DIMTXT", 2.5));
1246
1247         // BLOCK_RECORD:
1248         if (type == RS2::FormatDXF)
1249         {
1250                 DEBUG->print("writing block records...");
1251                 dxf.writeBlockRecord(*dw);
1252
1253                 for(uint i=0; i<graphic->countBlocks(); ++i)
1254                 {
1255                         Block * blk = graphic->blockAt(i);
1256                         dxf.writeBlockRecord(*dw, std::string((const char *)blk->getName().toLocal8Bit()));
1257                         /*
1258                         // v2.0.4.9..:
1259                         //writeBlock(*dw, blk);
1260                         dw->dxfString(  0, "BLOCK_RECORD");
1261                         //dw.dxfHex(5, 0x1F);
1262                         dw->handle();
1263                         dw->dxfHex(330, 1);
1264                         dw->dxfString(100, "AcDbSymbolTableRecord");
1265                         dw->dxfString(100, "AcDbBlockTableRecord");
1266                         dw->dxfString(  2, blk->getName().toLocal8Bit());
1267                         dw->dxfHex(340, 0);
1268                         */
1269                 }
1270
1271                 dw->tableEnd();
1272         }
1273
1274         // end of tables:
1275         DEBUG->print("writing end of section TABLES...");
1276         dw->sectionEnd();
1277
1278         // Section BLOCKS:
1279         DEBUG->print("writing blocks...");
1280         dw->sectionBlocks();
1281
1282         if (type == RS2::FormatDXF)
1283         {
1284                 Block b1(graphic, BlockData("*Model_Space", Vector(0.0, 0.0), false));
1285                 writeBlock(*dw, &b1);
1286                 Block b2(graphic, BlockData("*Paper_Space", Vector(0.0, 0.0), false));
1287                 writeBlock(*dw, &b2);
1288                 Block b3(graphic, BlockData("*Paper_Space0", Vector(0.0, 0.0), false));
1289                 writeBlock(*dw, &b3);
1290         }
1291
1292         for(uint i=0; i<graphic->countBlocks(); ++i)
1293         {
1294                 Block * blk = graphic->blockAt(i);
1295
1296                 // Save block if it's not a model or paper space:
1297                 // Careful: other blocks with * / $ exist
1298                 //if (blk->getName().at(0)!='*' &&
1299                 //        blk->getName().at(0)!='$') {
1300                 writeBlock(*dw, blk);
1301                 //}
1302         }
1303
1304         dw->sectionEnd();
1305
1306         // Section ENTITIES:
1307         DEBUG->print("writing section ENTITIES...");
1308         dw->sectionEntities();
1309
1310         for(Entity * e=graphic->firstEntity(RS2::ResolveNone); e!=NULL;
1311                 e=graphic->nextEntity(RS2::ResolveNone))
1312         {
1313                 writeEntity(*dw, e);
1314         }
1315
1316         DEBUG->print("writing end of section ENTITIES...");
1317         dw->sectionEnd();
1318
1319         if (type == RS2::FormatDXF)
1320         {
1321                 DEBUG->print("writing section OBJECTS...");
1322                 dxf.writeObjects(*dw);
1323
1324                 // IMAGEDEF's from images in entities and images in blocks
1325                 QStringList written;
1326
1327                 for(uint i=0; i<graphic->countBlocks(); ++i)
1328                 {
1329                         Block * block = graphic->blockAt(i);
1330
1331                         for(Entity * e=block->firstEntity(RS2::ResolveAll); e!=NULL;
1332                                 e=block->nextEntity(RS2::ResolveAll))
1333                         {
1334                                 if (e->rtti() == RS2::EntityImage)
1335                                 {
1336                                         Image * img = ((Image *)e);
1337
1338                                         if (written.contains(file) == 0 && img->getHandle() != 0)
1339                                         {
1340                                                 writeImageDef(*dw, img);
1341                                                 written.append(img->getFile());
1342                                         }
1343                                 }
1344                         }
1345                 }
1346
1347                 for(Entity * e=graphic->firstEntity(RS2::ResolveNone); e!=NULL;
1348                         e=graphic->nextEntity(RS2::ResolveNone))
1349                 {
1350                         if (e->rtti() == RS2::EntityImage)
1351                         {
1352                                 Image * img = ((Image *)e);
1353
1354                                 if (written.contains(file) == 0 && img->getHandle() != 0)
1355                                 {
1356                                         writeImageDef(*dw, img);
1357                                         written.append(img->getFile());
1358                                 }
1359                         }
1360                 }
1361                 DEBUG->print("writing end of section OBJECTS...");
1362                 dxf.writeObjectsEnd(*dw);
1363         }
1364
1365         DEBUG->print("writing EOF...");
1366         dw->dxfEOF();
1367
1368         DEBUG->print("close..");
1369         dw->close();
1370
1371         delete dw;
1372
1373         // check if file was actually written (strange world of windoze xp):
1374         if (QFileInfo(file).exists() == false)
1375         {
1376                 DEBUG->print("FilterDXF::fileExport: file could not be written");
1377                 return false;
1378         }
1379
1380         return true;
1381 }
1382
1383 /**
1384  * Writes all known variable settings to the DXF file.
1385  */
1386 void FilterDXF::writeVariables(DL_WriterA & dw)
1387 {
1388 //    Q3DictIterator<Variable> it(graphic->getVariableDict());
1389         QHashIterator<QString, Variable *> it(graphic->getVariableDict());
1390
1391 //      for (; it.current(); ++it)
1392         while (it.hasNext())
1393         {
1394                 it.next();
1395
1396                 // exclude variables that are not known to DXF 12:
1397                 if (!DL_Dxf::checkVariable(it.key().toLatin1(), dxf.getVersion()))
1398                         continue;
1399
1400                 if (it.key() != "$ACADVER" && it.key() != "$HANDSEED")
1401                 {
1402                         dw.dxfString(9, (const char *)it.key().toAscii().data());
1403
1404                         switch (it.value()->getType())
1405                         {
1406                         case RS2::VariableVoid:
1407                                 break;
1408                         case RS2::VariableInt:
1409                                 dw.dxfInt(it.value()->getCode(), it.value()->getInt());
1410                                 break;
1411                         case RS2::VariableDouble:
1412                                 dw.dxfReal(it.value()->getCode(), it.value()->getDouble());
1413                                 break;
1414                         case RS2::VariableString:
1415                                 dw.dxfString(it.value()->getCode(), (const char *)it.value()->getString().toAscii().data());
1416                                 break;
1417                         case RS2::VariableVector:
1418                                 dw.dxfReal(it.value()->getCode(), it.value()->getVector().x);
1419                                 dw.dxfReal(it.value()->getCode() + 10, it.value()->getVector().y);
1420
1421                                 if (isVariableTwoDimensional(it.key()) == false)
1422                                         dw.dxfReal(it.value()->getCode() + 20, it.value()->getVector().z);
1423
1424                                 break;
1425                         }
1426                 }
1427         }
1428
1429         dw.sectionEnd();
1430 }
1431
1432 /**
1433  * Writes one layer to the DXF file.
1434  *
1435  * @todo Add support for unicode layer names
1436  */
1437 void FilterDXF::writeLayer(DL_WriterA & dw, Layer * l)
1438 {
1439         if (l == NULL)
1440         {
1441                 DEBUG->print(Debug::D_WARNING, "FilterDXF::writeLayer: layer is NULL");
1442                 return;
1443         }
1444
1445         DEBUG->print("FilterDXF::writeLayer %s", l->getName().toLatin1().data());
1446
1447         dxf.writeLayer(dw, DL_LayerData((const char *)l->getName().toLocal8Bit(),
1448                 l->isFrozen() + (l->isLocked() << 2)), DL_Attributes(std::string(""),
1449                 colorToNumber(l->getPen().getColor()), widthToNumber(l->getPen().getWidth()),
1450                 (const char *)lineTypeToName(l->getPen().getLineType()).toLocal8Bit()));
1451
1452         DEBUG->print("FilterDXF::writeLayer end");
1453 }
1454
1455 /**
1456  * Writes a line type to the DXF file.
1457  */
1458 void FilterDXF::writeLineType(DL_WriterA & dw, RS2::LineType t)
1459 {
1460     dxf.writeLineType(dw, DL_LineTypeData((const char *)lineTypeToName(t).toLocal8Bit(), 0));
1461 }
1462
1463
1464
1465 /**
1466  * Writes an application id to the DXF file.
1467  *
1468  * @param appid Application ID (e.g. "QCad").
1469  */
1470 void FilterDXF::writeAppid(DL_WriterA& dw, const char* appid) {
1471     dxf.writeAppid(dw, appid);
1472 }
1473
1474
1475
1476 /**
1477  * Writes a block (just the definition, not the entities in it).
1478  */
1479 void FilterDXF::writeBlock(DL_WriterA& dw, Block* blk) {
1480     if (blk==NULL) {
1481         DEBUG->print(Debug::D_WARNING,
1482                         "FilterDXF::writeBlock: Block is NULL");
1483         return;
1484     }
1485
1486     DEBUG->print("writing block: %s", (const char*)blk->getName().toLocal8Bit());
1487
1488     dxf.writeBlock(dw,
1489                    DL_BlockData((const char*)blk->getName().toLocal8Bit(), 0,
1490                                 blk->getBasePoint().x,
1491                                 blk->getBasePoint().y,
1492                                 blk->getBasePoint().z));
1493     for (Entity* e=blk->firstEntity(RS2::ResolveNone);
1494             e!=NULL;
1495             e=blk->nextEntity(RS2::ResolveNone)) {
1496         writeEntity(dw, e);
1497     }
1498     dxf.writeEndBlock(dw, (const char*)blk->getName().toLocal8Bit());
1499 }
1500
1501
1502
1503 /**
1504  * Writes the given entity to the DXF file.
1505  */
1506 void FilterDXF::writeEntity(DL_WriterA& dw, Entity* e) {
1507     writeEntity(dw, e, getEntityAttributes(e));
1508 }
1509
1510
1511 /**
1512  * Writes the given entity to the DXF file.
1513  */
1514 void FilterDXF::writeEntity(DL_WriterA& dw, Entity* e,
1515                                const DL_Attributes& attrib) {
1516
1517     if (e==NULL || e->getFlag(RS2::FlagUndone)) {
1518         return;
1519     }
1520     DEBUG->print("writing Entity");
1521
1522     switch (e->rtti()) {
1523     case RS2::EntityPoint:
1524         writePoint(dw, (Point*)e, attrib);
1525         break;
1526     case RS2::EntityLine:
1527         writeLine(dw, (Line*)e, attrib);
1528         break;
1529     case RS2::EntityPolyline:
1530         writePolyline(dw, (Polyline*)e, attrib);
1531         break;
1532     case RS2::EntitySpline:
1533         writeSpline(dw, (Spline*)e, attrib);
1534         break;
1535     case RS2::EntityVertex:
1536         break;
1537     case RS2::EntityCircle:
1538         writeCircle(dw, (Circle*)e, attrib);
1539         break;
1540     case RS2::EntityArc:
1541         writeArc(dw, (Arc*)e, attrib);
1542         break;
1543     case RS2::EntityEllipse:
1544         writeEllipse(dw, (Ellipse*)e, attrib);
1545         break;
1546     case RS2::EntityInsert:
1547         writeInsert(dw, (Insert*)e, attrib);
1548         break;
1549     case RS2::EntityText:
1550         writeText(dw, (Text*)e, attrib);
1551         break;
1552
1553     case RS2::EntityDimAligned:
1554     case RS2::EntityDimAngular:
1555     case RS2::EntityDimLinear:
1556     case RS2::EntityDimRadial:
1557     case RS2::EntityDimDiametric:
1558         writeDimension(dw, (Dimension*)e, attrib);
1559         break;
1560     case RS2::EntityDimLeader:
1561         writeLeader(dw, (Leader*)e, attrib);
1562         break;
1563     case RS2::EntityHatch:
1564         writeHatch(dw, (Hatch*)e, attrib);
1565         break;
1566     case RS2::EntityImage:
1567         writeImage(dw, (Image*)e, attrib);
1568         break;
1569     case RS2::EntitySolid:
1570         writeSolid(dw, (Solid*)e, attrib);
1571         break;
1572
1573 #ifndef RS_NO_COMPLEX_ENTITIES
1574
1575     case RS2::EntityContainer:
1576         writeEntityContainer(dw, (EntityContainer*)e, attrib);
1577         break;
1578 #endif
1579
1580     default:
1581         break;
1582     }
1583 }
1584
1585
1586
1587 /**
1588  * Writes the given Point entity to the file.
1589  */
1590 void FilterDXF::writePoint(DL_WriterA& dw, Point* p,
1591                               const DL_Attributes& attrib) {
1592     dxf.writePoint(
1593         dw,
1594         DL_PointData(p->getPos().x,
1595                      p->getPos().y,
1596                      0.0),
1597         attrib);
1598 }
1599
1600
1601 /**
1602  * Writes the given Line( entity to the file.
1603  */
1604 void FilterDXF::writeLine(DL_WriterA& dw, Line* l,
1605                              const DL_Attributes& attrib) {
1606     dxf.writeLine(
1607         dw,
1608         DL_LineData(l->getStartpoint().x,
1609                     l->getStartpoint().y,
1610                     0.0,
1611                     l->getEndpoint().x,
1612                     l->getEndpoint().y,
1613                     0.0),
1614         attrib);
1615 }
1616
1617
1618
1619 /**
1620  * Writes the given polyline entity to the file.
1621  */
1622 void FilterDXF::writePolyline(DL_WriterA& dw,
1623                                  Polyline* l,
1624                                  const DL_Attributes& attrib) {
1625
1626         int count = l->count();
1627         if (l->isClosed()==false) {
1628                 count++;
1629         }
1630
1631         dxf.writePolyline(
1632         dw,
1633         DL_PolylineData(count,
1634                         0, 0,
1635                         l->isClosed()*0x1),
1636         attrib);
1637     bool first = true;
1638     Entity* nextEntity = 0;
1639     AtomicEntity* ae = NULL;
1640         Entity* lastEntity = l->lastEntity(RS2::ResolveNone);
1641     for (Entity* v=l->firstEntity(RS2::ResolveNone);
1642             v!=NULL;
1643             v=nextEntity) {
1644
1645         nextEntity = l->nextEntity(RS2::ResolveNone);
1646
1647         if (!v->isAtomic()) {
1648             continue;
1649         }
1650
1651         ae = (AtomicEntity*)v;
1652         double bulge=0.0;
1653
1654                 // Write vertex:
1655         if (first) {
1656             if (v->rtti()==RS2::EntityArc) {
1657                 bulge = ((Arc*)v)->getBulge();
1658             }
1659             dxf.writeVertex(dw,
1660                             DL_VertexData(ae->getStartpoint().x,
1661                                           ae->getStartpoint().y,
1662                                           0.0,
1663                                                                                   bulge));
1664             first = false;
1665         }
1666
1667         //if (dxf.getVersion()==VER_R12) {
1668             if (nextEntity!=NULL) {
1669                 if (nextEntity->rtti()==RS2::EntityArc) {
1670                     bulge = ((Arc*)nextEntity)->getBulge();
1671                 }
1672                                 else {
1673                                         bulge = 0.0;
1674                                 }
1675             }
1676         /*} else {
1677             if (v->rtti()==RS2::EntityArc) {
1678                 bulge = ((Arc*)v)->getBulge();
1679             }
1680         }*/
1681
1682
1683                 if (l->isClosed()==false || v!=lastEntity) {
1684                 dxf.writeVertex(dw,
1685                         DL_VertexData(ae->getEndpoint().x,
1686                                       ae->getEndpoint().y,
1687                                       0.0,
1688                                       bulge));
1689                 }
1690     }
1691     dxf.writePolylineEnd(dw);
1692 }
1693
1694
1695
1696 /**
1697  * Writes the given spline entity to the file.
1698  */
1699 void FilterDXF::writeSpline(DL_WriterA & dw, Spline * s, const DL_Attributes & attrib)
1700 {
1701         // split spline into atomic entities for DXF R12:
1702         if (dxf.getVersion() == VER_R12)
1703         {
1704                 writeAtomicEntities(dw, s, attrib, RS2::ResolveNone);
1705                 return;
1706         }
1707
1708         if (s->getNumberOfControlPoints() < s->getDegree() + 1)
1709         {
1710                 DEBUG->print(Debug::D_ERROR, "FilterDXF::writeSpline: "
1711                         "Discarding spline: not enough control points given.");
1712                 return;
1713         }
1714
1715         // Number of control points:
1716         int numCtrl = s->getNumberOfControlPoints();
1717
1718         // Number of knots (= number of control points + spline degree + 1)
1719         int numKnots = numCtrl + s->getDegree() + 1;
1720
1721         int flags;
1722
1723         if (s->isClosed())
1724                 flags = 11;
1725         else
1726                 flags = 8;
1727
1728         // write spline header:
1729         dxf.writeSpline(dw, DL_SplineData(s->getDegree(), numKnots, numCtrl, flags), attrib);
1730
1731         // write spline knots:
1732         QList<Vector> cp = s->getControlPoints();
1733         QList<Vector>::iterator it;
1734
1735         int k = s->getDegree() + 1;
1736         DL_KnotData kd;
1737
1738         for(int i=1; i<=numKnots; i++)
1739         {
1740                 if (i <= k)
1741                         kd = DL_KnotData(0.0);
1742                 else if (i <= numKnots - k)
1743                         kd = DL_KnotData(1.0 / (numKnots - 2 * k + 1) * (i - k));
1744                 else
1745                         kd = DL_KnotData(1.0);
1746
1747                 dxf.writeKnot(dw, kd);
1748         }
1749
1750         // write spline control points:
1751         for(it=cp.begin(); it!=cp.end(); ++it)
1752         {
1753                 dxf.writeControlPoint(dw, DL_ControlPointData((*it).x, (*it).y, 0.0));
1754         }
1755 }
1756
1757 /**
1758  * Writes the given circle entity to the file.
1759  */
1760 void FilterDXF::writeCircle(DL_WriterA& dw, Circle* c,
1761                                const DL_Attributes& attrib) {
1762     dxf.writeCircle(
1763         dw,
1764         DL_CircleData(c->getCenter().x,
1765                       c->getCenter().y,
1766                       0.0,
1767                       c->getRadius()),
1768         attrib);
1769
1770 }
1771
1772
1773
1774 void FilterDXF::writeArc(DL_WriterA& dw, Arc* a,
1775                             const DL_Attributes& attrib) {
1776     double a1, a2;
1777     if (a->isReversed()) {
1778         a1 = a->getAngle2()*ARAD;
1779         a2 = a->getAngle1()*ARAD;
1780     } else {
1781         a1 = a->getAngle1()*ARAD;
1782         a2 = a->getAngle2()*ARAD;
1783     }
1784     dxf.writeArc(
1785         dw,
1786         DL_ArcData(a->getCenter().x,
1787                    a->getCenter().y,
1788                    0.0,
1789                    a->getRadius(),
1790                    a1, a2),
1791         attrib);
1792 }
1793
1794
1795 void FilterDXF::writeEllipse(DL_WriterA& dw, Ellipse* s,
1796                                 const DL_Attributes& attrib) {
1797     if (s->isReversed()) {
1798         dxf.writeEllipse(
1799             dw,
1800             DL_EllipseData(s->getCenter().x,
1801                            s->getCenter().y,
1802                            0.0,
1803                            s->getMajorP().x,
1804                            s->getMajorP().y,
1805                            0.0,
1806                            s->getRatio(),
1807                            s->getAngle2(),
1808                            s->getAngle1()),
1809             attrib);
1810     } else {
1811         dxf.writeEllipse(
1812             dw,
1813             DL_EllipseData(s->getCenter().x,
1814                            s->getCenter().y,
1815                            0.0,
1816                            s->getMajorP().x,
1817                            s->getMajorP().y,
1818                            0.0,
1819                            s->getRatio(),
1820                            s->getAngle1(),
1821                            s->getAngle2()),
1822             attrib);
1823     }
1824 }
1825
1826 void FilterDXF::writeInsert(DL_WriterA & dw, Insert * i, const DL_Attributes & attrib)
1827 {
1828         dxf.writeInsert(dw, DL_InsertData(i->getName().toLatin1().data(),
1829                 i->getInsertionPoint().x, i->getInsertionPoint().y, 0.0,
1830                 i->getScale().x, i->getScale().y, 0.0,
1831                 i->getAngle() * ARAD, i->getCols(), i->getRows(),
1832                 i->getSpacing().x, i->getSpacing().y),
1833                 attrib);
1834 }
1835
1836 void FilterDXF::writeText(DL_WriterA & dw, Text * t, const DL_Attributes & attrib)
1837 {
1838     if (dxf.getVersion()==VER_R12)
1839         {
1840         int hJust=0;
1841         int vJust=0;
1842
1843                 if (t->getHAlign()==RS2::HAlignLeft) {
1844             hJust=0;
1845         } else if (t->getHAlign()==RS2::HAlignCenter) {
1846             hJust=1;
1847         } else if (t->getHAlign()==RS2::HAlignRight) {
1848             hJust=2;
1849         }
1850
1851                 if (t->getVAlign()==RS2::VAlignTop) {
1852             vJust=3;
1853         } else if (t->getVAlign()==RS2::VAlignMiddle) {
1854             vJust=2;
1855         } else if (t->getVAlign()==RS2::VAlignBottom) {
1856             vJust=1;
1857         }
1858
1859                 dxf.writeText(
1860             dw,
1861             DL_TextData(t->getInsertionPoint().x,
1862                         t->getInsertionPoint().y,
1863                         0.0,
1864                         t->getInsertionPoint().x,
1865                         t->getInsertionPoint().y,
1866                         0.0,
1867                         t->getHeight(),
1868                         1.0,
1869                         0,
1870                         hJust, vJust,
1871                         (const char*)toDxfString(
1872                             t->getText()).toLocal8Bit(),
1873                         (const char*)t->getStyle().toLocal8Bit(),
1874                         t->getAngle()),
1875             attrib);
1876     }
1877     else
1878         {
1879         int attachmentPoint=1;
1880
1881                 if (t->getHAlign()==RS2::HAlignLeft) {
1882             attachmentPoint=1;
1883         } else if (t->getHAlign()==RS2::HAlignCenter) {
1884             attachmentPoint=2;
1885         } else if (t->getHAlign()==RS2::HAlignRight) {
1886             attachmentPoint=3;
1887         }
1888
1889                 if (t->getVAlign()==RS2::VAlignTop) {
1890             attachmentPoint+=0;
1891         } else if (t->getVAlign()==RS2::VAlignMiddle) {
1892             attachmentPoint+=3;
1893         } else if (t->getVAlign()==RS2::VAlignBottom) {
1894             attachmentPoint+=6;
1895         }
1896
1897         dxf.writeMText(
1898             dw,
1899             DL_MTextData(t->getInsertionPoint().x,
1900                          t->getInsertionPoint().y,
1901                          0.0,
1902                          t->getHeight(),
1903                          t->getWidth(),
1904                          attachmentPoint,
1905                          t->getDrawingDirection(),
1906                          t->getLineSpacingStyle(),
1907                          t->getLineSpacingFactor(),
1908                          (const char*)toDxfString(
1909                              t->getText()).toLocal8Bit(),
1910                          (const char*)t->getStyle().toLocal8Bit(),
1911                          t->getAngle()),
1912             attrib);
1913     }
1914 }
1915
1916
1917
1918 void FilterDXF::writeDimension(DL_WriterA& dw, Dimension* d,
1919                                   const DL_Attributes& attrib) {
1920
1921     // split hatch into atomic entities:
1922     if (dxf.getVersion()==VER_R12) {
1923         writeAtomicEntities(dw, d, attrib, RS2::ResolveNone);
1924         return;
1925     }
1926
1927     int type;
1928     int attachmentPoint=1;
1929     if (d->getHAlign()==RS2::HAlignLeft) {
1930         attachmentPoint=1;
1931     } else if (d->getHAlign()==RS2::HAlignCenter) {
1932         attachmentPoint=2;
1933     } else if (d->getHAlign()==RS2::HAlignRight) {
1934         attachmentPoint=3;
1935     }
1936     if (d->getVAlign()==RS2::VAlignTop) {
1937         attachmentPoint+=0;
1938     } else if (d->getVAlign()==RS2::VAlignMiddle) {
1939         attachmentPoint+=3;
1940     } else if (d->getVAlign()==RS2::VAlignBottom) {
1941         attachmentPoint+=6;
1942     }
1943
1944     switch (d->rtti()) {
1945     case RS2::EntityDimAligned:
1946         type = 1;
1947         break;
1948     case RS2::EntityDimLinear:
1949         type = 0;
1950         break;
1951     case RS2::EntityDimRadial:
1952         type = 4;
1953         break;
1954     case RS2::EntityDimDiametric:
1955         type = 3;
1956         break;
1957     default:
1958         type = 0;
1959         break;
1960     }
1961
1962     DL_DimensionData dimData(d->getDefinitionPoint().x,
1963                              d->getDefinitionPoint().y,
1964                              0.0,
1965                              d->getMiddleOfText().x,
1966                              d->getMiddleOfText().y,
1967                              0.0,
1968                              type,
1969                              attachmentPoint,
1970                              d->getLineSpacingStyle(),
1971                              d->getLineSpacingFactor(),
1972                              (const char*)toDxfString(
1973                                  d->getText()).toLocal8Bit(),
1974                              (const char*)d->getStyle().toLocal8Bit(),
1975                              d->getAngle());
1976
1977     if (d->rtti()==RS2::EntityDimAligned) {
1978         DimAligned* da = (DimAligned*)d;
1979
1980         DL_DimAlignedData dimAlignedData(da->getExtensionPoint1().x,
1981                                          da->getExtensionPoint1().y,
1982                                          0.0,
1983                                          da->getExtensionPoint2().x,
1984                                          da->getExtensionPoint2().y,
1985                                          0.0);
1986
1987         dxf.writeDimAligned(dw, dimData, dimAlignedData, attrib);
1988     } else if (d->rtti()==RS2::EntityDimLinear) {
1989         DimLinear* dl = (DimLinear*)d;
1990
1991         DL_DimLinearData dimLinearData(dl->getExtensionPoint1().x,
1992                                        dl->getExtensionPoint1().y,
1993                                        0.0,
1994                                        dl->getExtensionPoint2().x,
1995                                        dl->getExtensionPoint2().y,
1996                                        0.0,
1997                                        dl->getAngle(),
1998                                        dl->getOblique());
1999
2000         dxf.writeDimLinear(dw, dimData, dimLinearData, attrib);
2001     } else if (d->rtti()==RS2::EntityDimRadial) {
2002         DimRadial* dr = (DimRadial*)d;
2003
2004         DL_DimRadialData dimRadialData(dr->getDefinitionPoint().x,
2005                                        dr->getDefinitionPoint().y,
2006                                        0.0,
2007                                        dr->getLeader());
2008
2009         dxf.writeDimRadial(dw, dimData, dimRadialData, attrib);
2010     } else if (d->rtti()==RS2::EntityDimDiametric) {
2011         DimDiametric* dr = (DimDiametric*)d;
2012
2013         DL_DimDiametricData dimDiametricData(dr->getDefinitionPoint().x,
2014                                              dr->getDefinitionPoint().y,
2015                                              0.0,
2016                                              dr->getLeader());
2017
2018         dxf.writeDimDiametric(dw, dimData, dimDiametricData, attrib);
2019     } else if (d->rtti()==RS2::EntityDimAngular) {
2020         DimAngular* da = (DimAngular*)d;
2021
2022         DL_DimAngularData dimAngularData(da->getDefinitionPoint1().x,
2023                                          da->getDefinitionPoint1().y,
2024                                          0.0,
2025                                          da->getDefinitionPoint2().x,
2026                                          da->getDefinitionPoint2().y,
2027                                          0.0,
2028                                          da->getDefinitionPoint3().x,
2029                                          da->getDefinitionPoint3().y,
2030                                          0.0,
2031                                          da->getDefinitionPoint4().x,
2032                                          da->getDefinitionPoint4().y,
2033                                          0.0);
2034
2035         dxf.writeDimAngular(dw, dimData, dimAngularData, attrib);
2036     }
2037
2038 }
2039
2040
2041 void FilterDXF::writeLeader(DL_WriterA& dw, Leader* l,
2042                                const DL_Attributes& attrib) {
2043     if (l->count()>0) {
2044         dxf.writeLeader(
2045             dw,
2046             DL_LeaderData(l->hasArrowHead(),
2047                           0,
2048                           3,
2049                           0,
2050                           0,
2051                           1.0,
2052                           10.0,
2053                           l->count()),
2054             attrib);
2055         bool first = true;
2056         for (Entity* v=l->firstEntity(RS2::ResolveNone);
2057                 v!=NULL;
2058                 v=l->nextEntity(RS2::ResolveNone)) {
2059
2060             // Write line verties:
2061             if (v->rtti()==RS2::EntityLine) {
2062                 Line* l = (Line*)v;
2063                 if (first) {
2064                     dxf.writeLeaderVertex(
2065                         dw,
2066                         DL_LeaderVertexData(l->getStartpoint().x,
2067                                             l->getStartpoint().y,
2068                                             0.0));
2069                     first = false;
2070                 }
2071                 dxf.writeLeaderVertex(
2072                     dw,
2073                     DL_LeaderVertexData(l->getEndpoint().x,
2074                                         l->getEndpoint().y,
2075                                         0.0));
2076             }
2077         }
2078     } else {
2079         DEBUG->print(Debug::D_WARNING,
2080                         "dropping leader with no vertices");
2081     }
2082 }
2083
2084
2085 void FilterDXF::writeHatch(DL_WriterA& dw, Hatch* h,
2086                               const DL_Attributes& attrib) {
2087
2088     // split hatch into atomic entities:
2089     if (dxf.getVersion()==VER_R12) {
2090         writeAtomicEntities(dw, h, attrib, RS2::ResolveAll);
2091         return;
2092     }
2093
2094     bool writeIt = true;
2095     if (h->countLoops()>0) {
2096         // check if all of the loops contain entities:
2097         for (Entity* l=h->firstEntity(RS2::ResolveNone);
2098                 l!=NULL;
2099                 l=h->nextEntity(RS2::ResolveNone)) {
2100
2101             if (l->isContainer() && !l->getFlag(RS2::FlagTemp)) {
2102                 if (l->count()==0) {
2103                     writeIt = false;
2104                 }
2105             }
2106         }
2107     } else {
2108         writeIt = false;
2109     }
2110
2111     if (!writeIt) {
2112         DEBUG->print(Debug::D_WARNING,
2113                         "FilterDXF::writeHatch: Dropping Hatch");
2114     } else {
2115         DL_HatchData data(h->countLoops(),
2116                           h->isSolid(),
2117                           h->getScale(),
2118                           h->getAngle(),
2119                           (const char*)h->getPattern().toLocal8Bit());
2120         dxf.writeHatch1(dw, data, attrib);
2121
2122         for (Entity* l=h->firstEntity(RS2::ResolveNone);
2123                 l!=NULL;
2124                 l=h->nextEntity(RS2::ResolveNone)) {
2125
2126             // Write hatch loops:
2127             if (l->isContainer() && !l->getFlag(RS2::FlagTemp)) {
2128                 EntityContainer* loop = (EntityContainer*)l;
2129                 DL_HatchLoopData lData(loop->count());
2130                 dxf.writeHatchLoop1(dw, lData);
2131
2132                 for (Entity* ed=loop->firstEntity(RS2::ResolveNone);
2133                         ed!=NULL;
2134                         ed=loop->nextEntity(RS2::ResolveNone)) {
2135
2136                     // Write hatch loop edges:
2137                     if (ed->rtti()==RS2::EntityLine) {
2138                         Line* ln = (Line*)ed;
2139                         dxf.writeHatchEdge(
2140                             dw,
2141                             DL_HatchEdgeData(ln->getStartpoint().x,
2142                                              ln->getStartpoint().y,
2143                                              ln->getEndpoint().x,
2144                                              ln->getEndpoint().y));
2145                     } else if (ed->rtti()==RS2::EntityArc) {
2146                         Arc* ar = (Arc*)ed;
2147                         if (!ar->isReversed()) {
2148                             dxf.writeHatchEdge(
2149                                 dw,
2150                                 DL_HatchEdgeData(ar->getCenter().x,
2151                                                  ar->getCenter().y,
2152                                                  ar->getRadius(),
2153                                                  ar->getAngle1(),
2154                                                  ar->getAngle2(),
2155                                                  true));
2156                         } else {
2157                             dxf.writeHatchEdge(
2158                                 dw,
2159                                 DL_HatchEdgeData(ar->getCenter().x,
2160                                                  ar->getCenter().y,
2161                                                  ar->getRadius(),
2162                                                  2*M_PI-ar->getAngle1(),
2163                                                  2*M_PI-ar->getAngle2(),
2164                                                  false));
2165                         }
2166                     } else if (ed->rtti()==RS2::EntityCircle) {
2167                         Circle* ci = (Circle*)ed;
2168                         dxf.writeHatchEdge(
2169                             dw,
2170                             DL_HatchEdgeData(ci->getCenter().x,
2171                                              ci->getCenter().y,
2172                                              ci->getRadius(),
2173                                              0.0,
2174                                              2*M_PI,
2175                                              true));
2176                     }
2177                 }
2178                 dxf.writeHatchLoop2(dw, lData);
2179             }
2180         }
2181         dxf.writeHatch2(dw, data, attrib);
2182     }
2183
2184 }
2185
2186
2187
2188 void FilterDXF::writeSolid(DL_WriterA& dw, Solid* s,
2189                               const DL_Attributes& attrib) {
2190
2191     // split solid into line entities:
2192     //if (dxf.getVersion()==VER_R12) {
2193         for (int i=0; i<3; ++i) {
2194             dxf.writeLine(
2195                 dw,
2196                 DL_LineData(s->getCorner(i).x,
2197                             s->getCorner(i).y,
2198                             0.0,
2199                             s->getCorner((i+1)%3).x,
2200                             s->getCorner((i+1)%3).y,
2201                             0.0),
2202                 attrib);
2203         }
2204         //return;
2205     //}
2206 }
2207
2208
2209 void FilterDXF::writeImage(DL_WriterA& dw, Image* i,
2210                               const DL_Attributes& attrib) {
2211     int handle = dxf.writeImage(
2212                      dw,
2213                      DL_ImageData(std::string(""),
2214                                   i->getInsertionPoint().x,
2215                                   i->getInsertionPoint().y,
2216                                   0.0,
2217                                   i->getUVector().x,
2218                                   i->getUVector().y,
2219                                   0.0,
2220                                   i->getVVector().x,
2221                                   i->getVVector().y,
2222                                   0.0,
2223                                   i->getWidth(),
2224                                   i->getHeight(),
2225                                   i->getBrightness(),
2226                                   i->getContrast(),
2227                                   i->getFade()),
2228                      attrib);
2229     i->setHandle(handle);
2230 }
2231
2232
2233
2234 void FilterDXF::writeEntityContainer(DL_WriterA& dw, EntityContainer* con,
2235                                         const DL_Attributes& /*attrib*/) {
2236     QString blkName;
2237     blkName = "__CE";
2238
2239     // Creating an unique ID from the element ID
2240     int tmp, c=1; // tmp = temporary var c = counter var
2241     tmp = con->getId();
2242
2243     while (true) {
2244         tmp = tmp/c;
2245         blkName.append((char) tmp %10 + 48);
2246         c *= 10;
2247         if (tmp < 10) {
2248             break;
2249         }
2250     }
2251
2252     //Block definition
2253     dw.sectionTables();
2254     dxf.writeBlockRecord(dw);
2255     dw.dxfString(  0, "BLOCK_RECORD");
2256
2257     dw.handle();
2258     dw.dxfHex(330, 1);
2259     dw.dxfString(100, "AcDbSymbolTableRecord");
2260     dw.dxfString(100, "AcDbBlockTableRecord");
2261     dw.dxfString(  2, blkName.toLatin1());
2262     dw.dxfHex(340, 0);
2263     dw.dxfString(0, "ENDTAB");
2264
2265     //Block creation
2266     BlockData blkdata(blkName, Vector(0,0), false);
2267
2268     Block* blk = new Block(graphic, blkdata);
2269
2270     for (Entity* e1 = con->firstEntity(); e1 != NULL;
2271             e1 = con->nextEntity() ) {
2272         blk->addEntity(e1);
2273     }
2274     writeBlock(dw, blk);
2275     //delete e1;
2276
2277 }
2278
2279
2280
2281 /**
2282  * Writes the atomic entities of the given cotnainer to the file.
2283  */
2284 void FilterDXF::writeAtomicEntities(DL_WriterA& dw, EntityContainer* c,
2285                                        const DL_Attributes& attrib,
2286                                        RS2::ResolveLevel level) {
2287
2288     for (Entity* e=c->firstEntity(level);
2289             e!=NULL;
2290             e=c->nextEntity(level)) {
2291
2292         writeEntity(dw, e, attrib);
2293     }
2294 }
2295
2296 /**
2297  * Writes an IMAGEDEF object into an OBJECT section.
2298  */
2299 void FilterDXF::writeImageDef(DL_WriterA& dw, Image* i) {
2300     if (i==NULL || i->getFlag(RS2::FlagUndone)) {
2301         return;
2302     }
2303
2304     dxf.writeImageDef(
2305         dw,
2306         i->getHandle(),
2307         DL_ImageData((const char*)i->getFile().toLocal8Bit(),
2308                      i->getInsertionPoint().x,
2309                      i->getInsertionPoint().y,
2310                      0.0,
2311                      i->getUVector().x,
2312                      i->getUVector().y,
2313                      0.0,
2314                      i->getVVector().x,
2315                      i->getVVector().y,
2316                      0.0,
2317                      i->getWidth(),
2318                      i->getHeight(),
2319                      i->getBrightness(),
2320                      i->getContrast(),
2321                      i->getFade()));
2322 }
2323
2324
2325
2326 /**
2327  * Sets the entities attributes according to the attributes
2328  * that come from a DXF file.
2329  */
2330 void FilterDXF::setEntityAttributes(Entity* entity,
2331                                        const DL_Attributes& attrib) {
2332     DEBUG->print("FilterDXF::setEntityAttributes");
2333
2334     Pen pen;
2335     pen.setColor(Qt::black);
2336     pen.setLineType(RS2::SolidLine);
2337
2338     // Layer:
2339     if (attrib.getLayer().empty()) {
2340         entity->setLayer("0");
2341     } else {
2342         // add layer in case it doesn't exist:
2343         if (graphic->findLayer(attrib.getLayer().c_str())==NULL) {
2344             addLayer(DL_LayerData(attrib.getLayer(), 0));
2345         }
2346         entity->setLayer(attrib.getLayer().c_str());
2347     }
2348
2349     // Color:
2350     pen.setColor(numberToColor(attrib.getColor()));
2351
2352     // Linetype:
2353     pen.setLineType(nameToLineType(attrib.getLineType().c_str()));
2354
2355     // Width:
2356     pen.setWidth(numberToWidth(attrib.getWidth()));
2357
2358     entity->setPen(pen);
2359     DEBUG->print("FilterDXF::setEntityAttributes: OK");
2360 }
2361
2362 /**
2363  * Gets the entities attributes as a DL_Attributes object.
2364  */
2365 DL_Attributes FilterDXF::getEntityAttributes(Entity * entity)
2366 {
2367         // Layer:
2368         Layer * layer = entity->getLayer();
2369         QString layerName;
2370
2371         if (layer != NULL)
2372                 layerName = layer->getName();
2373         else
2374                 layerName = "NULL";
2375
2376         Pen pen = entity->getPen(false);
2377
2378         // Color:
2379         int color = colorToNumber(pen.getColor());
2380         //printf("Color is: %s -> %d\n", pen.getColor().name().toLatin1(), color);
2381
2382         // Linetype:
2383         QString lineType = lineTypeToName(pen.getLineType());
2384
2385         // Width:
2386         int width = widthToNumber(pen.getWidth());
2387
2388         DL_Attributes attrib(layerName.toLatin1().data(), color, width, lineType.toLatin1().data());
2389
2390         return attrib;
2391 }
2392
2393 /**
2394  * @return Pen with the same attributes as 'attrib'.
2395  */
2396 Pen FilterDXF::attributesToPen(const DL_Attributes & attrib) const
2397 {
2398     /*
2399     printf("converting Color %d to %s\n",
2400        attrib.getColor(), numberToColor(attrib.getColor()).name().toLatin1());
2401     */
2402
2403     Pen pen(numberToColor(attrib.getColor()),
2404                numberToWidth(attrib.getWidth()),
2405                nameToLineType(attrib.getLineType().c_str()));
2406     return pen;
2407 }
2408
2409
2410
2411 /**
2412  * Converts a color index (num) into a Color object.
2413  * Please refer to the dxflib documentation for details.
2414  *
2415  * @param num Color number.
2416  * @param comp Compatibility with older QCad versions (1.5.3 and older)
2417  */
2418 Color FilterDXF::numberToColor(int num, bool comp) {
2419     // Compatibility with QCad 1.5.3 and older:
2420     if (comp) {
2421         switch(num) {
2422         case 0:
2423             return Qt::black;
2424             break;
2425         case 1:
2426             return Qt::darkBlue;
2427             break;
2428         case 2:
2429             return Qt::darkGreen;
2430             break;
2431         case 3:
2432             return Qt::darkCyan;
2433             break;
2434         case 4:
2435             return Qt::darkRed;
2436             break;
2437         case 5:
2438             return Qt::darkMagenta;
2439             break;
2440         case 6:
2441             return Qt::darkYellow;
2442             break;
2443         case 7:
2444             return Qt::lightGray;
2445             break;
2446         case 8:
2447             return Qt::darkGray;
2448             break;
2449         case 9:
2450             return Qt::blue;
2451             break;
2452         case 10:
2453             return Qt::green;
2454             break;
2455         case 11:
2456             return Qt::cyan;
2457             break;
2458         case 12:
2459             return Qt::red;
2460             break;
2461         case 13:
2462             return Qt::magenta;
2463             break;
2464         case 14:
2465             return Qt::yellow;
2466             break;
2467         case 15:
2468             return Qt::black;
2469             break;
2470         default:
2471             break;
2472         }
2473     } else {
2474         if (num==0) {
2475             return Color(RS2::FlagByBlock);
2476         } else if (num==256) {
2477             return Color(RS2::FlagByLayer);
2478         } else if (num<=255 && num>=0) {
2479             return Color((int)(dxfColors[num][0]*255),
2480                             (int)(dxfColors[num][1]*255),
2481                             (int)(dxfColors[num][2]*255));
2482         } else {
2483             DEBUG->print(Debug::D_WARNING,
2484                                 "FilterDXF::numberToColor: Invalid color number given.");
2485             return Color(RS2::FlagByLayer);
2486         }
2487     }
2488     return Color();
2489 }
2490
2491
2492
2493 /**
2494  * Converts a color into a color number in the DXF palette.
2495  * The color that fits best is chosen.
2496  */
2497 int FilterDXF::colorToNumber(const Color& col) {
2498
2499     //printf("Searching color for %s\n", col.name().toLatin1());
2500
2501     // Special color BYBLOCK:
2502     if (col.getFlag(RS2::FlagByBlock)) {
2503         return 0;
2504     }
2505
2506     // Special color BYLAYER
2507     else if (col.getFlag(RS2::FlagByLayer)) {
2508         return 256;
2509     }
2510
2511     // Special color black is not in the table but white represents both
2512     // black and white
2513     else if (col.red()==0 && col.green()==0 && col.blue()==0) {
2514         return 7;
2515     }
2516
2517     // All other colors
2518     else {
2519         int num=0;
2520         int diff=255*3;  // smallest difference to a color in the table found so far
2521
2522         // Run through the whole table and compare
2523         for (int i=1; i<=255; i++) {
2524             int d = abs(col.red()-(int)(dxfColors[i][0]*255))
2525                     + abs(col.green()-(int)(dxfColors[i][1]*255))
2526                     + abs(col.blue()-(int)(dxfColors[i][2]*255));
2527
2528             if (d<diff) {
2529                 /*
2530                 printf("color %f,%f,%f is closer\n",
2531                        dxfColors[i][0],
2532                        dxfColors[i][1],
2533                        dxfColors[i][2]);
2534                 */
2535                 diff = d;
2536                 num = i;
2537                 if (d==0) {
2538                     break;
2539                 }
2540             }
2541         }
2542         //printf("  Found: %d, diff: %d\n", num, diff);
2543         return num;
2544     }
2545 }
2546
2547 /**
2548  * Converts a line type name (e.g. "CONTINUOUS") into a RS2::LineType
2549  * object.
2550  */
2551 RS2::LineType FilterDXF::nameToLineType(const QString & name)
2552 {
2553         QString uName = name.toUpper();
2554
2555         // Standard linetypes for QCad II / AutoCAD
2556         if (uName.isEmpty() || uName == "BYLAYER")
2557                 return RS2::LineByLayer;
2558         else if (uName == "BYBLOCK")
2559                 return RS2::LineByBlock;
2560         else if (uName == "CONTINUOUS" || uName == "ACAD_ISO01W100")
2561                 return RS2::SolidLine;
2562         else if (uName == "ACAD_ISO07W100" || uName == "DOT")
2563                 return RS2::DotLine;
2564         else if (uName == "DOT2")
2565                 return RS2::DotLine2;
2566         else if (uName == "DOTX2")
2567                 return RS2::DotLineX2;
2568         else if (uName == "ACAD_ISO02W100" || uName == "ACAD_ISO03W100"
2569                 || uName == "DASHED" || uName == "HIDDEN")
2570                 return RS2::DashLine;
2571         else if (uName == "DASHED2" || uName == "HIDDEN2")
2572                 return RS2::DashLine2;
2573         else if (uName == "DASHEDX2" || uName == "HIDDENX2")
2574                 return RS2::DashLineX2;
2575         else if (uName == "ACAD_ISO10W100" || uName == "DASHDOT")
2576                 return RS2::DashDotLine;
2577         else if (uName == "DASHDOT2")
2578                 return RS2::DashDotLine2;
2579         else if (uName == "ACAD_ISO04W100" || uName == "DASHDOTX2")
2580                 return RS2::DashDotLineX2;
2581         else if (uName == "ACAD_ISO12W100" || uName == "DIVIDE")
2582                 return RS2::DivideLine;
2583         else if (uName == "DIVIDE2")
2584                 return RS2::DivideLine2;
2585         else if (uName == "ACAD_ISO05W100" || uName == "DIVIDEX2")
2586                 return RS2::DivideLineX2;
2587         else if (uName == "CENTER")
2588                 return RS2::CenterLine;
2589         else if (uName == "CENTER2")
2590                 return RS2::CenterLine2;
2591         else if (uName == "CENTERX2")
2592                 return RS2::CenterLineX2;
2593         else if (uName == "BORDER")
2594                 return RS2::BorderLine;
2595         else if (uName == "BORDER2")
2596                 return RS2::BorderLine2;
2597         else if (uName == "BORDERX2")
2598                 return RS2::BorderLineX2;
2599
2600         return RS2::SolidLine;
2601 }
2602
2603 /**
2604  * Converts a LineType into a name for a line type.
2605  */
2606 QString FilterDXF::lineTypeToName(RS2::LineType lineType)
2607 {
2608     // Standard linetypes for QCad II / AutoCAD
2609     switch (lineType)
2610         {
2611     case RS2::SolidLine:
2612         return "CONTINUOUS";
2613         break;
2614
2615     case RS2::DotLine:
2616         return "DOT";
2617         break;
2618     case RS2::DotLine2:
2619         return "DOT2";
2620         break;
2621     case RS2::DotLineX2:
2622         return "DOTX2";
2623         break;
2624
2625     case RS2::DashLine:
2626         return "DASHED";
2627         break;
2628     case RS2::DashLine2:
2629         return "DASHED2";
2630         break;
2631     case RS2::DashLineX2:
2632         return "DASHEDX2";
2633         break;
2634
2635     case RS2::DashDotLine:
2636         return "DASHDOT";
2637         break;
2638     case RS2::DashDotLine2:
2639         return "DASHDOT2";
2640         break;
2641     case RS2::DashDotLineX2:
2642         return "DASHDOTX2";
2643         break;
2644
2645     case RS2::DivideLine:
2646         return "DIVIDE";
2647         break;
2648     case RS2::DivideLine2:
2649         return "DIVIDE2";
2650         break;
2651     case RS2::DivideLineX2:
2652         return "DIVIDEX2";
2653         break;
2654
2655     case RS2::CenterLine:
2656         return "CENTER";
2657         break;
2658     case RS2::CenterLine2:
2659         return "CENTER2";
2660         break;
2661     case RS2::CenterLineX2:
2662         return "CENTERX2";
2663         break;
2664
2665     case RS2::BorderLine:
2666         return "BORDER";
2667         break;
2668     case RS2::BorderLine2:
2669         return "BORDER2";
2670         break;
2671     case RS2::BorderLineX2:
2672         return "BORDERX2";
2673         break;
2674
2675
2676     case RS2::LineByLayer:
2677         return "ByLayer";
2678         break;
2679     case RS2::LineByBlock:
2680         return "ByBlock";
2681         break;
2682     default:
2683         break;
2684     }
2685
2686     return "CONTINUOUS";
2687 }
2688
2689
2690
2691 /**
2692  * Converts a LineType into a name for a line type.
2693  */
2694 /*QString FilterDXF::lineTypeToDescription(RS2::LineType lineType) {
2695
2696     // Standard linetypes for QCad II / AutoCAD
2697     switch (lineType) {
2698     case RS2::SolidLine:
2699         return "Solid line";
2700     case RS2::DotLine:
2701         return "ISO Dashed __ __ __ __ __ __ __ __ __ __ _";
2702     case RS2::DashLine:
2703         return "ISO Dashed with Distance __    __    __    _";
2704     case RS2::DashDotLine:
2705         return "ISO Long Dashed Dotted ____ . ____ . __";
2706     case RS2::DashDotDotLine:
2707         return "ISO Long Dashed Double Dotted ____ .. __";
2708     case RS2::LineByLayer:
2709         return "";
2710     case RS2::LineByBlock:
2711         return "";
2712     default:
2713         break;
2714     }
2715
2716     return "CONTINUOUS";
2717 }*/
2718
2719
2720
2721 /**
2722  * Converts a line width number (e.g. 1) into a RS2::LineWidth.
2723  */
2724 RS2::LineWidth FilterDXF::numberToWidth(int num) {
2725     switch (num) {
2726     case -1:
2727         return RS2::WidthByLayer;
2728         break;
2729     case -2:
2730         return RS2::WidthByBlock;
2731         break;
2732     case -3:
2733         return RS2::WidthDefault;
2734         break;
2735     default:
2736         if (num<3) {
2737             return RS2::Width00;
2738         } else if (num<7) {
2739             return RS2::Width01;
2740         } else if (num<11) {
2741             return RS2::Width02;
2742         } else if (num<14) {
2743             return RS2::Width03;
2744         } else if (num<16) {
2745             return RS2::Width04;
2746         } else if (num<19) {
2747             return RS2::Width05;
2748         } else if (num<22) {
2749             return RS2::Width06;
2750         } else if (num<27) {
2751             return RS2::Width07;
2752         } else if (num<32) {
2753             return RS2::Width08;
2754         } else if (num<37) {
2755             return RS2::Width09;
2756         } else if (num<45) {
2757             return RS2::Width10;
2758         } else if (num<52) {
2759             return RS2::Width11;
2760         } else if (num<57) {
2761             return RS2::Width12;
2762         } else if (num<65) {
2763             return RS2::Width13;
2764         } else if (num<75) {
2765             return RS2::Width14;
2766         } else if (num<85) {
2767             return RS2::Width15;
2768         } else if (num<95) {
2769             return RS2::Width16;
2770         } else if (num<103) {
2771             return RS2::Width17;
2772         } else if (num<112) {
2773             return RS2::Width18;
2774         } else if (num<130) {
2775             return RS2::Width19;
2776         } else if (num<149) {
2777             return RS2::Width20;
2778         } else if (num<180) {
2779             return RS2::Width21;
2780         } else if (num<205) {
2781             return RS2::Width22;
2782         } else {
2783             return RS2::Width23;
2784         }
2785         break;
2786     }
2787     return (RS2::LineWidth)num;
2788 }
2789
2790
2791
2792 /**
2793  * Converts a RS2::LineWidth into an int width.
2794  */
2795 int FilterDXF::widthToNumber(RS2::LineWidth width) {
2796     switch (width) {
2797     case RS2::WidthByLayer:
2798         return -1;
2799         break;
2800     case RS2::WidthByBlock:
2801         return -2;
2802         break;
2803     case RS2::WidthDefault:
2804         return -3;
2805         break;
2806     default:
2807         return (int)width;
2808         break;
2809     }
2810     return (int)width;
2811 }
2812
2813 /**
2814  * Converts a native unicode string into a DXF encoded string.
2815  *
2816  * DXF endoding includes the following special sequences:
2817  * - %%%c for a diameter sign
2818  * - %%%d for a degree sign
2819  * - %%%p for a plus/minus sign
2820  */
2821 QString FilterDXF::toDxfString(const QString & string)
2822 {
2823         /*
2824         QString res = string;
2825         // Line feed:
2826         res = res.replace(QRegExp("\\n"), "\\P");
2827         // Space:
2828         res = res.replace(QRegExp(" "), "\\~");
2829         // diameter:
2830         res = res.replace(QChar(0x2205), "%%c");
2831         // degree:
2832         res = res.replace(QChar(0x00B0), "%%d");
2833         // plus/minus
2834         res = res.replace(QChar(0x00B1), "%%p");
2835         */
2836
2837         QString res = "";
2838
2839         for(int i=0; i<string.length(); ++i)
2840         {
2841                 int c = string.at(i).unicode();
2842                 switch (c)
2843                 {
2844                 case 0x0A:
2845                         res += "\\P";
2846                         break;
2847                 case 0x20:
2848                         res += "\\~";
2849                         break;
2850                         // diameter:
2851                 case 0x2205:
2852                         res += "%%c";
2853                         break;
2854                         // degree:
2855                 case 0x00B0:
2856                         res += "%%d";
2857                         break;
2858                         // plus/minus
2859                 case 0x00B1:
2860                         res += "%%p";
2861                         break;
2862                 default:
2863                         if (c > 127)
2864                         {
2865                                 QString hex;
2866                                 hex = QString("%1").arg(c, 4, 16);
2867                                 hex = hex.replace(' ', '0');
2868                                 res += QString("\\U+%1").arg(hex);
2869                         }
2870                         else
2871                                 res += string.at(i);
2872
2873                         break;
2874                 }
2875         }
2876
2877         return res;
2878 }
2879
2880 /**
2881  * Converts a DXF encoded string into a native Unicode string.
2882  */
2883 QString FilterDXF::toNativeString(const QString & string)
2884 {
2885         QString res = string;
2886         // Line feed:
2887         res = res.replace(QRegExp("\\\\P"), "\n");
2888         // Space:
2889         res = res.replace(QRegExp("\\\\~"), " ");
2890         // diameter:
2891         res = res.replace(QRegExp("%%c"), QChar(0x2205));
2892         // degree:
2893         res = res.replace(QRegExp("%%d"), QChar(0x00B0));
2894         // plus/minus
2895         res = res.replace(QRegExp("%%p"), QChar(0x00B1));
2896
2897         // Unicode characters:
2898         QString cap = "";
2899         int uCode = 0;
2900         bool ok = false;
2901
2902         do
2903         {
2904                 QRegExp regexp("\\\\U\\+[0-9A-Fa-f]{4,4}");
2905 //              regexp.search(res);
2906                 regexp.indexIn(res);
2907                 cap = regexp.cap();
2908
2909                 if (!cap.isNull())
2910                 {
2911                         uCode = cap.right(4).toInt(&ok, 16);
2912                         // workaround for Qt 3.0.x:
2913                         res.replace(QRegExp("\\\\U\\+" + cap.right(4)), QChar(uCode));
2914                         // for Qt 3.1:
2915                         //res.replace(cap, QChar(uCode));
2916                 }
2917         }
2918         while (!cap.isNull());
2919
2920         // ASCII code:
2921         cap = "";
2922         uCode = 0;
2923         ok = false;
2924
2925         do
2926         {
2927                 QRegExp regexp("%%[0-9]{3,3}");
2928 //              regexp.search(res);
2929                 regexp.indexIn(res);
2930                 cap = regexp.cap();
2931
2932                 if (!cap.isNull())
2933                 {
2934                         uCode = cap.right(3).toInt(&ok, 10);
2935                         // workaround for Qt 3.0.x:
2936                         res.replace(QRegExp("%%" + cap.right(3)), QChar(uCode));
2937                         // for Qt 3.1:
2938                         //res.replace(cap, QChar(uCode));
2939                 }
2940         }
2941         while (!cap.isNull());
2942
2943         // Ignore font tags:
2944         res = res.replace(QRegExp("\\\\f[0-9A-Za-z| ]{0,};"), "");
2945
2946         // Ignore {}
2947         res = res.replace("\\{", "#curly#");
2948         res = res.replace("{", "");
2949         res = res.replace("#curly#", "{");
2950
2951         res = res.replace("\\}", "#curly#");
2952         res = res.replace("}", "");
2953         res = res.replace("#curly#", "}");
2954
2955         DEBUG->print("FilterDXF::toNativeString:");
2956         DEBUG->printUnicode(res);
2957         return res;
2958 }
2959
2960 /**
2961  * Converts the given number from a DXF file into an AngleFormat enum.
2962  *
2963  * @param num $DIMAUNIT from DXF (0: decimal deg, 1: deg/min/sec, 2: gradians,
2964  *                                3: radians, 4: surveyor's units)
2965  *
2966  * @ret Matching AngleFormat enum value.
2967  */
2968 RS2::AngleFormat FilterDXF::numberToAngleFormat(int num) {
2969
2970     RS2::AngleFormat af;
2971
2972     switch (num) {
2973     default:
2974     case 0:
2975         af = RS2::DegreesDecimal;
2976         break;
2977     case 1:
2978         af = RS2::DegreesMinutesSeconds;
2979         break;
2980     case 2:
2981         af = RS2::Gradians;
2982         break;
2983     case 3:
2984         af = RS2::Radians;
2985         break;
2986     case 4:
2987         af = RS2::Surveyors;
2988         break;
2989     }
2990
2991     return af;
2992 }
2993
2994
2995 /**
2996  * Converts AngleFormat enum to DXF number.
2997  */
2998 int FilterDXF::angleFormatToNumber(RS2::AngleFormat af) {
2999
3000     int num;
3001
3002     switch (af) {
3003     default:
3004     case RS2::DegreesDecimal:
3005         num = 0;
3006         break;
3007     case RS2::DegreesMinutesSeconds:
3008         num = 1;
3009         break;
3010     case RS2::Gradians:
3011         num = 2;
3012         break;
3013     case RS2::Radians:
3014         num = 3;
3015         break;
3016     case RS2::Surveyors:
3017         num = 4;
3018         break;
3019     }
3020
3021     return num;
3022 }
3023
3024
3025
3026 /**
3027  * converts a DXF unit setting (e.g. INSUNITS) to a unit enum.
3028  */
3029 RS2::Unit FilterDXF::numberToUnit(int num) {
3030     switch (num) {
3031     default:
3032     case  0:
3033         return RS2::None;
3034         break;
3035     case  1:
3036         return RS2::Inch;
3037         break;
3038     case  2:
3039         return RS2::Foot;
3040         break;
3041     case  3:
3042         return RS2::Mile;
3043         break;
3044     case  4:
3045         return RS2::Millimeter;
3046         break;
3047     case  5:
3048         return RS2::Centimeter;
3049         break;
3050     case  6:
3051         return RS2::Meter;
3052         break;
3053     case  7:
3054         return RS2::Kilometer;
3055         break;
3056     case  8:
3057         return RS2::Microinch;
3058         break;
3059     case  9:
3060         return RS2::Mil;
3061         break;
3062     case 10:
3063         return RS2::Yard;
3064         break;
3065     case 11:
3066         return RS2::Angstrom;
3067         break;
3068     case 12:
3069         return RS2::Nanometer;
3070         break;
3071     case 13:
3072         return RS2::Micron;
3073         break;
3074     case 14:
3075         return RS2::Decimeter;
3076         break;
3077     case 15:
3078         return RS2::Decameter;
3079         break;
3080     case 16:
3081         return RS2::Hectometer;
3082         break;
3083     case 17:
3084         return RS2::Gigameter;
3085         break;
3086     case 18:
3087         return RS2::Astro;
3088         break;
3089     case 19:
3090         return RS2::Lightyear;
3091         break;
3092     case 20:
3093         return RS2::Parsec;
3094         break;
3095     }
3096
3097     return RS2::None;
3098 }
3099
3100
3101
3102 /**
3103  * Converst a unit enum into a DXF unit number e.g. for INSUNITS.
3104  */
3105 int FilterDXF::unitToNumber(RS2::Unit unit) {
3106     switch (unit) {
3107     default:
3108     case RS2::None:
3109         return  0;
3110         break;
3111     case RS2::Inch:
3112         return  1;
3113         break;
3114     case RS2::Foot:
3115         return  2;
3116         break;
3117     case RS2::Mile:
3118         return  3;
3119         break;
3120     case RS2::Millimeter:
3121         return  4;
3122         break;
3123     case RS2::Centimeter:
3124         return  5;
3125         break;
3126     case RS2::Meter:
3127         return  6;
3128         break;
3129     case RS2::Kilometer:
3130         return  7;
3131         break;
3132     case RS2::Microinch:
3133         return  8;
3134         break;
3135     case RS2::Mil:
3136         return  9;
3137         break;
3138     case RS2::Yard:
3139         return 10;
3140         break;
3141     case RS2::Angstrom:
3142         return 11;
3143         break;
3144     case RS2::Nanometer:
3145         return 12;
3146         break;
3147     case RS2::Micron:
3148         return 13;
3149         break;
3150     case RS2::Decimeter:
3151         return 14;
3152         break;
3153     case RS2::Decameter:
3154         return 15;
3155         break;
3156     case RS2::Hectometer:
3157         return 16;
3158         break;
3159     case RS2::Gigameter:
3160         return 17;
3161         break;
3162     case RS2::Astro:
3163         return 18;
3164         break;
3165     case RS2::Lightyear:
3166         return 19;
3167         break;
3168     case RS2::Parsec:
3169         return 20;
3170         break;
3171     }
3172
3173     return 0;
3174 }
3175
3176
3177
3178 /**
3179  * Checks if the given variable is two-dimensional (e.g. $LIMMIN).
3180  */
3181 bool FilterDXF::isVariableTwoDimensional(const QString& var) {
3182     if (var=="$LIMMIN" ||
3183             var=="$LIMMAX" ||
3184             var=="$PLIMMIN" ||
3185             var=="$PLIMMAX" ||
3186             var=="$GRIDUNIT" ||
3187             var=="$VIEWCTR") {
3188
3189         return true;
3190     } else {
3191         return false;
3192     }
3193 }
3194
3195 // EOF
3196