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