1 /****************************************************************************
2 ** Copyright (C) 2001-2013 RibbonSoft, GmbH. All rights reserved.
3 **
4 ** This file is part of the dxflib project.
5 **
6 ** This file is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
10 **
11 ** Licensees holding valid dxflib Professional Edition licenses may use
12 ** this file in accordance with the dxflib Commercial License
13 ** Agreement provided with the Software.
14 **
15 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 **
18 ** See http://www.ribbonsoft.com for further details.
19 **
20 ** Contact info@ribbonsoft.com if any conditions of this licensing are
21 ** not clear to you.
22 **
23 **********************************************************************/
24 
25 #include "dl_dxf.h"
26 
27 #include <algorithm>
28 #include <string>
29 #include <cstdio>
30 #include <cassert>
31 #include <cmath>
32 
33 #include "dl_attributes.h"
34 #include "dl_codes.h"
35 #include "dl_creationadapter.h"
36 #include "dl_writer_ascii.h"
37 
38 #include "iostream"
39 
40 /**
41  * Default constructor.
42  */
DL_Dxf()43 DL_Dxf::DL_Dxf() {
44     version = DL_VERSION_2000;
45 
46     vertices = NULL;
47     maxVertices = 0;
48     vertexIndex = 0;
49 
50     knots = NULL;
51     maxKnots = 0;
52     knotIndex = 0;
53 
54     weights = NULL;
55     weightIndex = 0;
56 
57     controlPoints = NULL;
58     maxControlPoints = 0;
59     controlPointIndex = 0;
60 
61     fitPoints = NULL;
62     maxFitPoints = 0;
63     fitPointIndex = 0;
64 
65     leaderVertices = NULL;
66     maxLeaderVertices = 0;
67     leaderVertexIndex = 0;
68 }
69 
70 
71 
72 /**
73  * Destructor.
74  */
~DL_Dxf()75 DL_Dxf::~DL_Dxf() {
76     if (vertices!=NULL) {
77         delete[] vertices;
78     }
79     if (knots!=NULL) {
80         delete[] knots;
81     }
82     if (controlPoints!=NULL) {
83         delete[] controlPoints;
84     }
85     if (fitPoints!=NULL) {
86         delete[] fitPoints;
87     }
88     if (weights!=NULL) {
89         delete[] weights;
90     }
91     if (leaderVertices!=NULL) {
92         delete[] leaderVertices;
93     }
94 }
95 
96 
97 
98 /**
99  * @brief Reads the given file and calls the appropriate functions in
100  * the given creation interface for every entity found in the file.
101  *
102  * @param file Input
103  *      Path and name of file to read
104  * @param creationInterface
105  *      Pointer to the class which takes care of the entities in the file.
106  *
107  * @retval true If \p file could be opened.
108  * @retval false If \p file could not be opened.
109  */
in(const std::string & file,DL_CreationInterface * creationInterface)110 bool DL_Dxf::in(const std::string& file, DL_CreationInterface* creationInterface) {
111     FILE *fp;
112     firstCall = true;
113     currentObjectType = DL_UNKNOWN;
114 
115     fp = fopen(file.c_str(), "rt");
116     if (fp) {
117         std::locale oldLocale = std::locale::global(std::locale("C"));	// use dot in numbers
118         while (readDxfGroups(fp, creationInterface)) {}
119         std::locale::global(oldLocale);
120         fclose(fp);
121         return true;
122     }
123 
124     return false;
125 }
126 
127 
128 
129 /**
130  * Reads a DXF file from an existing stream.
131  *
132  * @param stream The string stream.
133  * @param creationInterface
134  *      Pointer to the class which takes care of the entities in the file.
135  *
136  * @retval true If \p file could be opened.
137  * @retval false If \p file could not be opened.
138  */
in(std::stringstream & stream,DL_CreationInterface * creationInterface)139 bool DL_Dxf::in(std::stringstream& stream,
140                 DL_CreationInterface* creationInterface) {
141 
142     if (stream.good()) {
143         firstCall=true;
144         currentObjectType = DL_UNKNOWN;
145         while (readDxfGroups(stream, creationInterface)) {}
146         return true;
147     }
148     return false;
149 }
150 
151 
152 
153 /**
154  * @brief Reads a group couplet from a DXF file.  Calls another function
155  * to process it.
156  *
157  * A group couplet consists of two lines that represent a single
158  * piece of data.  An integer constant on the first line indicates
159  * the type of data.  The value is on the next line.\n
160  *
161  * This function reads a couplet, determines the type of data, and
162  * passes the value to the the appropriate handler function of
163  * \p creationInterface.\n
164  *
165  * \p fp is advanced so that the next call to \p readDXFGroups() reads
166  * the next couplet in the file.
167  *
168  * @param fp Handle of input file
169  * @param creationInterface Handle of class which processes entities
170  *      in the file
171  *
172  * @retval true If EOF not reached.
173  * @retval false If EOF reached.
174  */
readDxfGroups(FILE * fp,DL_CreationInterface * creationInterface)175 bool DL_Dxf::readDxfGroups(FILE *fp, DL_CreationInterface* creationInterface) {
176 
177     static int line = 1;
178 
179     // Read one group of the DXF file and strip the lines:
180     if (DL_Dxf::getStrippedLine(groupCodeTmp, DL_DXF_MAXLINE, fp) &&
181             DL_Dxf::getStrippedLine(groupValue, DL_DXF_MAXLINE, fp, false) ) {
182 
183         groupCode = (unsigned int)toInt(groupCodeTmp);
184 
185         creationInterface->processCodeValuePair(groupCode, groupValue);
186         line+=2;
187         processDXFGroup(creationInterface, groupCode, groupValue);
188     }
189 
190     return !feof(fp);
191 }
192 
193 
194 
195 /**
196  * Same as above but for stringstreams.
197  */
readDxfGroups(std::stringstream & stream,DL_CreationInterface * creationInterface)198 bool DL_Dxf::readDxfGroups(std::stringstream& stream,
199                            DL_CreationInterface* creationInterface) {
200 
201     static int line = 1;
202 
203     // Read one group of the DXF file and chop the lines:
204     if (DL_Dxf::getStrippedLine(groupCodeTmp, DL_DXF_MAXLINE, stream) &&
205             DL_Dxf::getStrippedLine(groupValue, DL_DXF_MAXLINE, stream, false) ) {
206 
207         groupCode = (unsigned int)toInt(groupCodeTmp);
208 
209         line+=2;
210         processDXFGroup(creationInterface, groupCode, groupValue);
211     }
212     return !stream.eof();
213 }
214 
215 
216 
217 /**
218  * @brief Reads line from file & strips whitespace at start and newline
219  * at end.
220  *
221  * @param s Output\n
222  *      Pointer to character array that chopped line will be returned in.
223  * @param size Size of \p s.  (Including space for NULL.)
224  * @param fp Input\n
225  *      Handle of input file.
226  *
227  * @retval true if line could be read
228  * @retval false if \p fp is already at end of file
229  *
230  * @todo Change function to use safer FreeBSD strl* functions
231  * @todo Is it a problem if line is blank (i.e., newline only)?
232  *      Then, when function returns, (s==NULL).
233  */
getStrippedLine(std::string & s,unsigned int size,FILE * fp,bool stripSpace)234 bool DL_Dxf::getStrippedLine(std::string& s, unsigned int size, FILE *fp, bool stripSpace) {
235     if (!feof(fp)) {
236         // The whole line in the file.  Includes space for NULL.
237         char* wholeLine = new char[size];
238         // Only the useful part of the line
239         char* line;
240 
241         line = fgets(wholeLine, size, fp);
242 
243         if (line!=NULL && line[0] != '\0') { // Evaluates to fgets() retval
244             // line == wholeLine at this point.
245             // Both guaranteed to be NULL terminated.
246 
247             // Strip leading whitespace and trailing CR/LF.
248             stripWhiteSpace(&line, stripSpace);
249 
250             s = line;
251             assert(size > s.length());
252         }
253 
254         delete[] wholeLine; // Done with wholeLine
255 
256         return true;
257     } else {
258         s = "";
259         return false;
260     }
261 }
262 
263 
264 
265 /**
266  * Same as above but for stringstreams.
267  */
getStrippedLine(std::string & s,unsigned int size,std::stringstream & stream,bool stripSpace)268 bool DL_Dxf::getStrippedLine(std::string &s, unsigned int size,
269                             std::stringstream& stream, bool stripSpace) {
270 
271     if (!stream.eof()) {
272         // Only the useful part of the line
273         char* line = new char[size+1];
274         char* oriLine = line;
275         stream.getline(line, size);
276         stripWhiteSpace(&line, stripSpace);
277         s = line;
278         assert(size > s.length());
279         delete[] oriLine;
280         return true;
281     } else {
282         s[0] = '\0';
283         return false;
284     }
285 }
286 
287 
288 
289 /**
290  * @brief Strips leading whitespace and trailing Carriage Return (CR)
291  * and Line Feed (LF) from NULL terminated string.
292  *
293  * @param s Input and output.
294  *      NULL terminates string.
295  *
296  * @retval true if \p s is non-NULL
297  * @retval false if \p s is NULL
298  */
stripWhiteSpace(char ** s,bool stripSpace)299 bool DL_Dxf::stripWhiteSpace(char** s, bool stripSpace) {
300     // last non-NULL char:
301     int lastChar = strlen(*s) - 1;
302 
303     // Is last character CR or LF?
304     while ( (lastChar >= 0) &&
305             (((*s)[lastChar] == 10) || ((*s)[lastChar] == 13) ||
306              (stripSpace && ((*s)[lastChar] == ' ' || ((*s)[lastChar] == '\t')))) ) {
307         (*s)[lastChar] = '\0';
308         lastChar--;
309     }
310 
311     // Skip whitespace, excluding \n, at beginning of line
312     if (stripSpace) {
313         while ((*s)[0]==' ' || (*s)[0]=='\t') {
314             ++(*s);
315         }
316     }
317 
318     return ((*s) ? true : false);
319 }
320 
321 
322 
323 /**
324  * Processes a group (pair of group code and value).
325  *
326  * @param creationInterface Handle to class that creates entities and
327  * other CAD data from DXF group codes
328  *
329  * @param groupCode Constant indicating the data type of the group.
330  * @param groupValue The data value.
331  *
332  * @retval true if done processing current entity and new entity begun
333  * @retval false if not done processing current entity
334 */
processDXFGroup(DL_CreationInterface * creationInterface,int groupCode,const std::string & groupValue)335 bool DL_Dxf::processDXFGroup(DL_CreationInterface* creationInterface,
336                              int groupCode, const std::string& groupValue) {
337 
338     //printf("%d\n", groupCode);
339     //printf("%s\n", groupValue.c_str());
340 
341     // Init values on first call
342     if (firstCall) {
343         settingValue[0] = '\0';
344         firstCall=false;
345     }
346 
347     // Indicates comment or dxflib version:
348     if (groupCode==999) {
349         if (!groupValue.empty()) {
350             if (groupValue.substr(0, 6)=="dxflib") {
351                 libVersion = getLibVersion(groupValue.substr(7));
352             }
353 
354             addComment(creationInterface, groupValue);
355         }
356     }
357 
358     // Indicates start of new entity or variable:
359     else if (groupCode==0 || groupCode==9) {
360         // If new entity is encountered, the last one is complete.
361         // Prepare default attributes for next entity:
362         std::string layer = getStringValue(8, "0");
363 
364         int width;
365         // Compatibility with qcad1:
366         if (hasValue(39) && !hasValue(370)) {
367             width = getIntValue(39, -1);
368         }
369         // since autocad 2002:
370         else if (hasValue(370)) {
371             width = getIntValue(370, -1);
372         }
373         // default to BYLAYER:
374         else {
375             width = -1;
376         }
377 
378         int color;
379         color = getIntValue(62, 256);
380         int color24;
381         color24 = getIntValue(420, -1);
382         int handle;
383         handle = getInt16Value(5, -1);
384 
385         std::string linetype = getStringValue(6, "BYLAYER");
386 
387         attrib = DL_Attributes(layer,                   // layer
388                                color,                   // color
389                                color24,                 // 24 bit color
390                                width,                   // width
391                                linetype,                // linetype
392                                handle);                 // handle
393         attrib.setInPaperSpace((bool)getIntValue(67, 0));
394         attrib.setLinetypeScale(getRealValue(48, 1.0));
395         creationInterface->setAttributes(attrib);
396 
397         int elevationGroupCode=30;
398         if (currentObjectType==DL_ENTITY_LWPOLYLINE ) {
399             // see lwpolyline group codes reference
400             elevationGroupCode=38;
401         }
402         else {
403             // see polyline group codes reference
404             elevationGroupCode=30;
405         }
406 
407         creationInterface->setExtrusion(getRealValue(210, 0.0),
408                                         getRealValue(220, 0.0),
409                                         getRealValue(230, 1.0),
410                                         getRealValue(elevationGroupCode, 0.0));
411 
412         // Add the previously parsed entity via creationInterface
413         switch (currentObjectType) {
414         case DL_SETTING:
415             addSetting(creationInterface);
416             break;
417 
418         case DL_LAYER:
419             addLayer(creationInterface);
420             break;
421 
422         case DL_LINETYPE:
423             addLinetype(creationInterface);
424             break;
425 
426         case DL_BLOCK:
427             addBlock(creationInterface);
428             break;
429 
430         case DL_ENDBLK:
431             endBlock(creationInterface);
432             break;
433 
434         case DL_STYLE:
435             addTextStyle(creationInterface);
436             break;
437 
438         case DL_ENTITY_POINT:
439             addPoint(creationInterface);
440             break;
441 
442         case DL_ENTITY_LINE:
443             addLine(creationInterface);
444             break;
445 
446         case DL_ENTITY_XLINE:
447             addXLine(creationInterface);
448             break;
449 
450         case DL_ENTITY_RAY:
451             addRay(creationInterface);
452             break;
453 
454         case DL_ENTITY_POLYLINE:
455         case DL_ENTITY_LWPOLYLINE:
456             addPolyline(creationInterface);
457             break;
458 
459         case DL_ENTITY_VERTEX:
460             addVertex(creationInterface);
461             break;
462 
463         case DL_ENTITY_SPLINE:
464             addSpline(creationInterface);
465             break;
466 
467         case DL_ENTITY_ARC:
468             addArc(creationInterface);
469             break;
470 
471         case DL_ENTITY_CIRCLE:
472             addCircle(creationInterface);
473             break;
474 
475         case DL_ENTITY_ELLIPSE:
476             addEllipse(creationInterface);
477             break;
478 
479         case DL_ENTITY_INSERT:
480             addInsert(creationInterface);
481             break;
482 
483         case DL_ENTITY_MTEXT:
484             addMText(creationInterface);
485             break;
486 
487         case DL_ENTITY_TEXT:
488             addText(creationInterface);
489             break;
490 
491         case DL_ENTITY_ARCALIGNEDTEXT:
492             addArcAlignedText(creationInterface);
493             break;
494 
495         case DL_ENTITY_ATTRIB:
496             addAttribute(creationInterface);
497             break;
498 
499         case DL_ENTITY_DIMENSION: {
500                 int type = (getIntValue(70, 0)&0x07);
501 
502                 switch (type) {
503                 case 0:
504                     addDimLinear(creationInterface);
505                     break;
506 
507                 case 1:
508                     addDimAligned(creationInterface);
509                     break;
510 
511                 case 2:
512                     addDimAngular(creationInterface);
513                     break;
514 
515                 case 3:
516                     addDimDiametric(creationInterface);
517                     break;
518 
519                 case 4:
520                     addDimRadial(creationInterface);
521                     break;
522 
523                 case 5:
524                     addDimAngular3P(creationInterface);
525                     break;
526 
527                 case 6:
528                     addDimOrdinate(creationInterface);
529                     break;
530 
531                 default:
532                     break;
533                 }
534             }
535             break;
536 
537         case DL_ENTITY_LEADER:
538             addLeader(creationInterface);
539             break;
540 
541         case DL_ENTITY_HATCH:
542             //addHatch(creationInterface);
543             handleHatchData(creationInterface);
544             break;
545 
546         case DL_ENTITY_IMAGE:
547             addImage(creationInterface);
548             break;
549 
550         case DL_ENTITY_IMAGEDEF:
551             addImageDef(creationInterface);
552             break;
553 
554         case DL_ENTITY_TRACE:
555             addTrace(creationInterface);
556             break;
557 
558         case DL_ENTITY_3DFACE:
559             add3dFace(creationInterface);
560             break;
561 
562         case DL_ENTITY_SOLID:
563             addSolid(creationInterface);
564             break;
565 
566         case DL_ENTITY_SEQEND:
567             endSequence(creationInterface);
568             break;
569 
570         default:
571             break;
572         }
573 
574         creationInterface->endSection();
575 
576         // reset all values (they are not persistent and only this
577         //  way we can set defaults for omitted values)
578 //        for (int i=0; i<DL_DXF_MAXGROUPCODE; ++i) {
579 //            values[i][0] = '\0';
580 //        }
581         values.clear();
582         settingValue[0] = '\0';
583         settingKey = "";
584         firstHatchLoop = true;
585         //firstHatchEdge = true;
586         hatchEdge = DL_HatchEdgeData();
587         //xRecordHandle = "";
588         xRecordValues = false;
589 
590         // Last DXF entity or setting has been handled
591         // Now determine what the next entity or setting type is
592 
593         int prevEntity = currentObjectType;
594 
595         // Read DXF variable:
596         if (groupValue[0]=='$') {
597             currentObjectType = DL_SETTING;
598             settingKey = groupValue;
599         }
600 
601         // Read Layers:
602         else if (groupValue=="LAYER") {
603             currentObjectType = DL_LAYER;
604         }
605 
606         // Read Linetypes:
607         else if (groupValue=="LTYPE") {
608             currentObjectType = DL_LINETYPE;
609         }
610 
611         // Read Blocks:
612         else if (groupValue=="BLOCK") {
613             currentObjectType = DL_BLOCK;
614         } else if (groupValue=="ENDBLK") {
615             currentObjectType = DL_ENDBLK;
616         }
617 
618         // Read text styles:
619         else if (groupValue=="STYLE") {
620             currentObjectType = DL_STYLE;
621         }
622 
623         // Read entities:
624         else if (groupValue=="POINT") {
625             currentObjectType = DL_ENTITY_POINT;
626         } else if (groupValue=="LINE") {
627             currentObjectType = DL_ENTITY_LINE;
628         } else if (groupValue=="XLINE") {
629             currentObjectType = DL_ENTITY_XLINE;
630         } else if (groupValue=="RAY") {
631             currentObjectType = DL_ENTITY_RAY;
632         } else if (groupValue=="POLYLINE") {
633             currentObjectType = DL_ENTITY_POLYLINE;
634         } else if (groupValue=="LWPOLYLINE") {
635             currentObjectType = DL_ENTITY_LWPOLYLINE;
636         } else if (groupValue=="VERTEX") {
637             currentObjectType = DL_ENTITY_VERTEX;
638         } else if (groupValue=="SPLINE") {
639             currentObjectType = DL_ENTITY_SPLINE;
640         } else if (groupValue=="ARC") {
641             currentObjectType = DL_ENTITY_ARC;
642         } else if (groupValue=="ELLIPSE") {
643             currentObjectType = DL_ENTITY_ELLIPSE;
644         } else if (groupValue=="CIRCLE") {
645             currentObjectType = DL_ENTITY_CIRCLE;
646         } else if (groupValue=="INSERT") {
647             currentObjectType = DL_ENTITY_INSERT;
648         } else if (groupValue=="TEXT") {
649             currentObjectType = DL_ENTITY_TEXT;
650         } else if (groupValue=="MTEXT") {
651             currentObjectType = DL_ENTITY_MTEXT;
652         } else if (groupValue=="ARCALIGNEDTEXT") {
653             currentObjectType = DL_ENTITY_ARCALIGNEDTEXT;
654         } else if (groupValue=="ATTRIB") {
655             currentObjectType = DL_ENTITY_ATTRIB;
656         } else if (groupValue=="DIMENSION") {
657             currentObjectType = DL_ENTITY_DIMENSION;
658         } else if (groupValue=="LEADER") {
659             currentObjectType = DL_ENTITY_LEADER;
660         } else if (groupValue=="HATCH") {
661             currentObjectType = DL_ENTITY_HATCH;
662         } else if (groupValue=="IMAGE") {
663             currentObjectType = DL_ENTITY_IMAGE;
664         } else if (groupValue=="IMAGEDEF") {
665             currentObjectType = DL_ENTITY_IMAGEDEF;
666         } else if (groupValue=="TRACE") {
667            currentObjectType = DL_ENTITY_TRACE;
668         } else if (groupValue=="SOLID") {
669            currentObjectType = DL_ENTITY_SOLID;
670         } else if (groupValue=="3DFACE") {
671            currentObjectType = DL_ENTITY_3DFACE;
672         } else if (groupValue=="SEQEND") {
673             currentObjectType = DL_ENTITY_SEQEND;
674         } else if (groupValue=="XRECORD") {
675             currentObjectType = DL_XRECORD;
676         } else if (groupValue=="DICTIONARY") {
677             currentObjectType = DL_DICTIONARY;
678         } else {
679             currentObjectType = DL_UNKNOWN;
680         }
681 
682         // end of old style POLYLINE entity
683         if (prevEntity==DL_ENTITY_VERTEX && currentObjectType!=DL_ENTITY_VERTEX) {
684             endEntity(creationInterface);
685         }
686 
687         // TODO: end of SPLINE entity
688         //if (prevEntity==DL_ENTITY_CONTROLPOINT && currentEntity!=DL_ENTITY_CONTROLPOINT) {
689         //    endEntity(creationInterface);
690         //}
691 
692         return true;
693 
694     } else {
695         // Group code does not indicate start of new entity or setting,
696         // so this group must be continuation of data for the current
697         // one.
698         if (groupCode<DL_DXF_MAXGROUPCODE) {
699 
700             bool handled = false;
701 
702             switch (currentObjectType) {
703             case DL_ENTITY_MTEXT:
704                 handled = handleMTextData(creationInterface);
705                 break;
706 
707             case DL_ENTITY_LWPOLYLINE:
708                 handled = handleLWPolylineData(creationInterface);
709                 break;
710 
711             case DL_ENTITY_SPLINE:
712                 handled = handleSplineData(creationInterface);
713                 break;
714 
715             case DL_ENTITY_LEADER:
716                 handled = handleLeaderData(creationInterface);
717                 break;
718 
719             case DL_ENTITY_HATCH:
720                 handled = handleHatchData(creationInterface);
721                 break;
722 
723             case DL_XRECORD:
724                 handled = handleXRecordData(creationInterface);
725                 break;
726 
727             case DL_DICTIONARY:
728                 handled = handleDictionaryData(creationInterface);
729                 break;
730 
731             case DL_LINETYPE:
732                 handled = handleLinetypeData(creationInterface);
733                 break;
734 
735             default:
736                 break;
737             }
738 
739             // Always try to handle XData, unless we're in an XData record:
740             if (currentObjectType!=DL_XRECORD) {
741                 handled = handleXData(creationInterface);
742             }
743 
744             if (!handled) {
745                 // Normal group / value pair:
746                 values[groupCode] = groupValue;
747             }
748         }
749 
750         return false;
751     }
752     return false;
753 }
754 
755 
756 
757 /**
758  * Adds a comment from the DXF file.
759  */
addComment(DL_CreationInterface * creationInterface,const std::string & comment)760 void DL_Dxf::addComment(DL_CreationInterface* creationInterface, const std::string& comment) {
761     creationInterface->addComment(comment);
762 }
763 
addDictionary(DL_CreationInterface * creationInterface)764 void DL_Dxf::addDictionary(DL_CreationInterface* creationInterface) {
765     creationInterface->addDictionary(DL_DictionaryData(getStringValue(5, "")));
766 }
767 
addDictionaryEntry(DL_CreationInterface * creationInterface)768 void DL_Dxf::addDictionaryEntry(DL_CreationInterface* creationInterface) {
769     creationInterface->addDictionaryEntry(DL_DictionaryEntryData(getStringValue(3, ""), getStringValue(350, "")));
770 }
771 
772 
773 
774 /**
775  * Adds a variable from the DXF file.
776  */
addSetting(DL_CreationInterface * creationInterface)777 void DL_Dxf::addSetting(DL_CreationInterface* creationInterface) {
778     int c = -1;
779     std::map<int,std::string>::iterator it = values.begin();
780     if (it!=values.end()) {
781         c = it->first;
782     }
783 //    for (int i=0; i<=380; ++i) {
784 //        if (values[i][0]!='\0') {
785 //            c = i;
786 //            break;
787 //        }
788 //    }
789 
790     // string
791     if (c>=0 && c<=9) {
792         creationInterface->setVariableString(settingKey, values[c], c);
793  #ifdef DL_COMPAT
794         // backwards compatibility:
795         creationInterface->setVariableString(settingKey.c_str(), values[c].c_str(), c);
796  #endif
797     }
798     // vector
799     else if (c>=10 && c<=39) {
800         if (c==10) {
801             creationInterface->setVariableVector(
802                 settingKey,
803                 getRealValue(c, 0.0),
804                 getRealValue(c+10, 0.0),
805                 getRealValue(c+20, 0.0),
806                 c);
807         }
808     }
809     // double
810     else if (c>=40 && c<=59) {
811         creationInterface->setVariableDouble(settingKey, getRealValue(c, 0.0), c);
812     }
813     // int
814     else if (c>=60 && c<=99) {
815         creationInterface->setVariableInt(settingKey, getIntValue(c, 0), c);
816     }
817     // misc
818     else if (c>=0) {
819         creationInterface->setVariableString(settingKey, getStringValue(c, ""), c);
820     }
821 }
822 
823 
824 
825 /**
826  * Adds a layer that was read from the file via the creation interface.
827  */
addLayer(DL_CreationInterface * creationInterface)828 void DL_Dxf::addLayer(DL_CreationInterface* creationInterface) {
829     // correct some invalid attributes for layers:
830     attrib = creationInterface->getAttributes();
831     if (attrib.getColor()==256 || attrib.getColor()==0) {
832         attrib.setColor(7);
833     }
834     if (attrib.getWidth()<0) {
835         attrib.setWidth(1);
836     }
837 
838     std::string linetype = attrib.getLinetype();
839     std::transform(linetype.begin(), linetype.end(), linetype.begin(), ::toupper);
840     if (linetype=="BYLAYER" || linetype=="BYBLOCK") {
841         attrib.setLinetype("CONTINUOUS");
842     }
843 
844     // add layer
845     std::string name = getStringValue(2, "");
846     if (name.length()==0) {
847         return;
848     }
849 
850     creationInterface->addLayer(DL_LayerData(name, getIntValue(70, 0)));
851 }
852 
853 /**
854  * Adds a linetype that was read from the file via the creation interface.
855  */
addLinetype(DL_CreationInterface * creationInterface)856 void DL_Dxf::addLinetype(DL_CreationInterface* creationInterface) {
857     std::string name = getStringValue(2, "");
858     if (name.length()==0) {
859         return;
860     }
861     int numDashes = getIntValue(73, 0);
862     //double dashes[numDashes];
863 
864     DL_LinetypeData d(
865         // name:
866         name,
867         // description:
868         getStringValue(3, ""),
869         // flags
870         getIntValue(70, 0),
871         // number of dashes:
872         numDashes,
873         // pattern length:
874         getRealValue(40, 0.0)
875         // pattern:
876         //dashes
877     );
878 
879     if (name != "By Layer" && name != "By Block" && name != "BYLAYER" && name != "BYBLOCK") {
880         creationInterface->addLinetype(d);
881     }
882 }
883 
884 /**
885  * Handles all dashes in linetype pattern.
886  */
handleLinetypeData(DL_CreationInterface * creationInterface)887 bool DL_Dxf::handleLinetypeData(DL_CreationInterface* creationInterface) {
888     if (groupCode == 49) {
889         creationInterface->addLinetypeDash(toReal(groupValue));
890         return true;
891     }
892 
893     return false;
894 }
895 
896 
897 /**
898  * Adds a block that was read from the file via the creation interface.
899  */
addBlock(DL_CreationInterface * creationInterface)900 void DL_Dxf::addBlock(DL_CreationInterface* creationInterface) {
901     std::string name = getStringValue(2, "");
902     if (name.length()==0) {
903         return;
904     }
905 
906     DL_BlockData d(
907         // Name:
908         name,
909         // flags:
910         getIntValue(70, 0),
911         // base point:
912         getRealValue(10, 0.0),
913         getRealValue(20, 0.0),
914         getRealValue(30, 0.0));
915 
916     creationInterface->addBlock(d);
917 }
918 
919 
920 
921 /**
922  * Ends a block that was read from the file via the creation interface.
923  */
endBlock(DL_CreationInterface * creationInterface)924 void DL_Dxf::endBlock(DL_CreationInterface* creationInterface) {
925     creationInterface->endBlock();
926 }
927 
928 
929 
addTextStyle(DL_CreationInterface * creationInterface)930 void DL_Dxf::addTextStyle(DL_CreationInterface* creationInterface) {
931     std::string name = getStringValue(2, "");
932     if (name.length()==0) {
933         return;
934     }
935 
936     DL_StyleData d(
937         // name:
938         name,
939         // flags
940         getIntValue(70, 0),
941         // fixed text heigth:
942         getRealValue(40, 0.0),
943         // width factor:
944         getRealValue(41, 0.0),
945         // oblique angle:
946         getRealValue(50, 0.0),
947         // text generation flags:
948         getIntValue(71, 0),
949         // last height used:
950         getRealValue(42, 0.0),
951         // primart font file:
952         getStringValue(3, ""),
953         // big font file:
954         getStringValue(4, "")
955         );
956     creationInterface->addTextStyle(d);
957 }
958 
959 
960 /**
961  * Adds a point entity that was read from the file via the creation interface.
962  */
addPoint(DL_CreationInterface * creationInterface)963 void DL_Dxf::addPoint(DL_CreationInterface* creationInterface) {
964     DL_PointData d(getRealValue(10, 0.0),
965                    getRealValue(20, 0.0),
966                    getRealValue(30, 0.0));
967     creationInterface->addPoint(d);
968 }
969 
970 
971 
972 /**
973  * Adds a line entity that was read from the file via the creation interface.
974  */
addLine(DL_CreationInterface * creationInterface)975 void DL_Dxf::addLine(DL_CreationInterface* creationInterface) {
976     DL_LineData d(getRealValue(10, 0.0),
977                   getRealValue(20, 0.0),
978                   getRealValue(30, 0.0),
979                   getRealValue(11, 0.0),
980                   getRealValue(21, 0.0),
981                   getRealValue(31, 0.0));
982 
983     creationInterface->addLine(d);
984 }
985 
986 /**
987  * Adds an xline entity that was read from the file via the creation interface.
988  */
addXLine(DL_CreationInterface * creationInterface)989 void DL_Dxf::addXLine(DL_CreationInterface* creationInterface) {
990     DL_XLineData d(getRealValue(10, 0.0),
991                    getRealValue(20, 0.0),
992                    getRealValue(30, 0.0),
993                    getRealValue(11, 0.0),
994                    getRealValue(21, 0.0),
995                    getRealValue(31, 0.0));
996 
997     creationInterface->addXLine(d);
998 }
999 
1000 /**
1001  * Adds a ray entity that was read from the file via the creation interface.
1002  */
addRay(DL_CreationInterface * creationInterface)1003 void DL_Dxf::addRay(DL_CreationInterface* creationInterface) {
1004     DL_RayData d(getRealValue(10, 0.0),
1005                  getRealValue(20, 0.0),
1006                  getRealValue(30, 0.0),
1007                  getRealValue(11, 0.0),
1008                  getRealValue(21, 0.0),
1009                  getRealValue(31, 0.0));
1010 
1011     creationInterface->addRay(d);
1012 }
1013 
1014 
1015 
1016 /**
1017  * Adds a polyline entity that was read from the file via the creation interface.
1018  */
addPolyline(DL_CreationInterface * creationInterface)1019 void DL_Dxf::addPolyline(DL_CreationInterface* creationInterface) {
1020     DL_PolylineData pd(maxVertices, getIntValue(71, 0), getIntValue(72, 0), getIntValue(70, 0), getRealValue(38, 0));
1021     creationInterface->addPolyline(pd);
1022 
1023     maxVertices = std::min(maxVertices, vertexIndex+1);
1024 
1025     if (currentObjectType==DL_ENTITY_LWPOLYLINE) {
1026         for (int i=0; i<maxVertices; i++) {
1027             DL_VertexData d(vertices[i*4],
1028                             vertices[i*4+1],
1029                             vertices[i*4+2],
1030                             vertices[i*4+3]);
1031 
1032             creationInterface->addVertex(d);
1033         }
1034         creationInterface->endEntity();
1035     }
1036 }
1037 
1038 
1039 
1040 /**
1041  * Adds a polyline vertex entity that was read from the file
1042  * via the creation interface.
1043  */
addVertex(DL_CreationInterface * creationInterface)1044 void DL_Dxf::addVertex(DL_CreationInterface* creationInterface) {
1045 
1046     // vertex defines a face of the mesh if its vertex flags group has the
1047     // 128 bit set but not the 64 bit. 10, 20, 30 are irrelevant and set to
1048     // 0 in this case
1049     if ((getIntValue(70, 0)&128) && !(getIntValue(70, 0)&64)) {
1050         return;
1051     }
1052 
1053     DL_VertexData d(getRealValue(10, 0.0),
1054                     getRealValue(20, 0.0),
1055                     getRealValue(30, 0.0),
1056                     getRealValue(42, 0.0));
1057 
1058     creationInterface->addVertex(d);
1059 }
1060 
1061 
1062 /**
1063  * Adds a spline entity that was read from the file via the creation interface.
1064  */
addSpline(DL_CreationInterface * creationInterface)1065 void DL_Dxf::addSpline(DL_CreationInterface* creationInterface) {
1066     DL_SplineData sd(getIntValue(71, 3),
1067                      maxKnots,
1068                      maxControlPoints,
1069                      maxFitPoints,
1070                      getIntValue(70, 4));
1071 
1072     sd.tangentStartX = getRealValue(12, 0.0);
1073     sd.tangentStartY = getRealValue(22, 0.0);
1074     sd.tangentStartZ = getRealValue(32, 0.0);
1075     sd.tangentEndX = getRealValue(13, 0.0);
1076     sd.tangentEndY = getRealValue(23, 0.0);
1077     sd.tangentEndZ = getRealValue(33, 0.0);
1078 
1079     creationInterface->addSpline(sd);
1080 
1081     int i;
1082     for (i=0; i<maxControlPoints; i++) {
1083         DL_ControlPointData d(controlPoints[i*3],
1084                               controlPoints[i*3+1],
1085                               controlPoints[i*3+2],
1086                               weights[i]);
1087 
1088         creationInterface->addControlPoint(d);
1089     }
1090     for (i=0; i<maxFitPoints; i++) {
1091         DL_FitPointData d(fitPoints[i*3],
1092                               fitPoints[i*3+1],
1093                               fitPoints[i*3+2]);
1094 
1095         creationInterface->addFitPoint(d);
1096     }
1097     for (i=0; i<maxKnots; i++) {
1098         DL_KnotData k(knots[i]);
1099 
1100         creationInterface->addKnot(k);
1101     }
1102     creationInterface->endEntity();
1103 }
1104 
1105 
1106 
1107 /**
1108  * Adds an arc entity that was read from the file via the creation interface.
1109  */
addArc(DL_CreationInterface * creationInterface)1110 void DL_Dxf::addArc(DL_CreationInterface* creationInterface) {
1111     DL_ArcData d(getRealValue(10, 0.0),
1112                  getRealValue(20, 0.0),
1113                  getRealValue(30, 0.0),
1114                  getRealValue(40, 0.0),
1115                  getRealValue(50, 0.0),
1116                  getRealValue(51, 0.0));
1117 
1118     creationInterface->addArc(d);
1119 }
1120 
1121 
1122 
1123 /**
1124  * Adds a circle entity that was read from the file via the creation interface.
1125  */
addCircle(DL_CreationInterface * creationInterface)1126 void DL_Dxf::addCircle(DL_CreationInterface* creationInterface) {
1127     DL_CircleData d(getRealValue(10, 0.0),
1128                     getRealValue(20, 0.0),
1129                     getRealValue(30, 0.0),
1130                     getRealValue(40, 0.0));
1131 
1132     creationInterface->addCircle(d);
1133 }
1134 
1135 
1136 
1137 /**
1138  * Adds an ellipse entity that was read from the file via the creation interface.
1139  */
addEllipse(DL_CreationInterface * creationInterface)1140 void DL_Dxf::addEllipse(DL_CreationInterface* creationInterface) {
1141     DL_EllipseData d(getRealValue(10, 0.0),
1142                      getRealValue(20, 0.0),
1143                      getRealValue(30, 0.0),
1144                      getRealValue(11, 0.0),
1145                      getRealValue(21, 0.0),
1146                      getRealValue(31, 0.0),
1147                      getRealValue(40, 1.0),
1148                      getRealValue(41, 0.0),
1149                      getRealValue(42, 2*M_PI));
1150 
1151     creationInterface->addEllipse(d);
1152 }
1153 
1154 
1155 
1156 /**
1157  * Adds an insert entity that was read from the file via the creation interface.
1158  */
addInsert(DL_CreationInterface * creationInterface)1159 void DL_Dxf::addInsert(DL_CreationInterface* creationInterface) {
1160     //printf("addInsert\n");
1161     //printf("code 50: %s\n", values[50]);
1162     //printf("code 50 length: %d\n", strlen(values[50]));
1163     //printf("code 50:\n");
1164     //getRealValue(50, 0.0);
1165 
1166     std::string name = getStringValue(2, "");
1167     if (name.length()==0) {
1168         return;
1169     }
1170 
1171     DL_InsertData d(name,
1172                     // insertion point
1173                     getRealValue(10, 0.0),
1174                     getRealValue(20, 0.0),
1175                     getRealValue(30, 0.0),
1176                     // scale:
1177                     getRealValue(41, 1.0),
1178                     getRealValue(42, 1.0),
1179                     getRealValue(43, 1.0),
1180                     // angle (deg):
1181                     getRealValue(50, 0.0),
1182                     // cols / rows:
1183                     getIntValue(70, 1),
1184                     getIntValue(71, 1),
1185                     // spacing:
1186                     getRealValue(44, 0.0),
1187                     getRealValue(45, 0.0));
1188 
1189     creationInterface->addInsert(d);
1190 }
1191 
1192 
1193 
1194 /**
1195  * Adds a trace entity (4 edge closed polyline) that was read from the file via the creation interface.
1196  *
1197  * @author AHM
1198  */
addTrace(DL_CreationInterface * creationInterface)1199 void DL_Dxf::addTrace(DL_CreationInterface* creationInterface) {
1200     DL_TraceData td;
1201 
1202     for (int k = 0; k < 4; k++) {
1203        td.x[k] = getRealValue(10 + k, 0.0);
1204        td.y[k] = getRealValue(20 + k, 0.0);
1205        td.z[k] = getRealValue(30 + k, 0.0);
1206     }
1207     creationInterface->addTrace(td);
1208 }
1209 
1210 
1211 
1212 /**
1213  * Adds a 3dface entity that was read from the file via the creation interface.
1214  */
add3dFace(DL_CreationInterface * creationInterface)1215 void DL_Dxf::add3dFace(DL_CreationInterface* creationInterface) {
1216     DL_3dFaceData td;
1217 
1218     for (int k = 0; k < 4; k++) {
1219        td.x[k] = getRealValue(10 + k, 0.0);
1220        td.y[k] = getRealValue(20 + k, 0.0);
1221        td.z[k] = getRealValue(30 + k, 0.0);
1222     }
1223     creationInterface->add3dFace(td);
1224 }
1225 
1226 
1227 
1228 /**
1229  * Adds a solid entity (filled trace) that was read from the file via the creation interface.
1230  *
1231  * @author AHM
1232  */
addSolid(DL_CreationInterface * creationInterface)1233 void DL_Dxf::addSolid(DL_CreationInterface* creationInterface) {
1234     DL_SolidData sd;
1235 
1236     for (int k = 0; k < 4; k++) {
1237        sd.x[k] = getRealValue(10 + k, 0.0);
1238        sd.y[k] = getRealValue(20 + k, 0.0);
1239        sd.z[k] = getRealValue(30 + k, 0.0);
1240     }
1241     creationInterface->addSolid(sd);
1242 }
1243 
1244 
1245 /**
1246  * Adds an MText entity that was read from the file via the creation interface.
1247  */
addMText(DL_CreationInterface * creationInterface)1248 void DL_Dxf::addMText(DL_CreationInterface* creationInterface) {
1249     double angle = 0.0;
1250 
1251     if (hasValue(50)) {
1252         if (libVersion<=0x02000200) {
1253             // wrong but compatible with dxflib <=2.0.2.0 (angle stored in rad):
1254             angle = getRealValue(50, 0.0);
1255         } else {
1256             angle = (getRealValue(50, 0.0)*2*M_PI)/360.0;
1257         }
1258     } else if (hasValue(11) && hasValue(21)) {
1259         double x = getRealValue(11, 0.0);
1260         double y = getRealValue(21, 0.0);
1261 
1262         if (fabs(x)<1.0e-6) {
1263             if (y>0.0) {
1264                 angle = M_PI/2.0;
1265             } else {
1266                 angle = M_PI/2.0*3.0;
1267             }
1268         } else {
1269             angle = atan(y/x);
1270         }
1271     }
1272 
1273     DL_MTextData d(
1274         // insertion point
1275         getRealValue(10, 0.0),
1276         getRealValue(20, 0.0),
1277         getRealValue(30, 0.0),
1278         // X direction vector
1279         getRealValue(11, 0.0),
1280         getRealValue(21, 0.0),
1281         getRealValue(31, 0.0),
1282         // height
1283         getRealValue(40, 2.5),
1284         // width
1285         getRealValue(41, 0.0),
1286         // attachment point
1287         getIntValue(71, 1),
1288         // drawing direction
1289         getIntValue(72, 1),
1290         // line spacing style
1291         getIntValue(73, 1),
1292         // line spacing factor
1293         getRealValue(44, 1.0),
1294         // text
1295         getStringValue(1, ""),
1296         // style
1297         getStringValue(7, ""),
1298         // angle
1299         angle);
1300     creationInterface->addMText(d);
1301 }
1302 
1303 /**
1304  * Handles all XRecord data.
1305  */
handleXRecordData(DL_CreationInterface * creationInterface)1306 bool DL_Dxf::handleXRecordData(DL_CreationInterface* creationInterface) {
1307     if (groupCode==105) {
1308         return false;
1309     }
1310 
1311     if (groupCode==5) {
1312         creationInterface->addXRecord(groupValue);
1313         return true;
1314     }
1315 
1316     if (groupCode==280) {
1317         xRecordValues = true;
1318         return true;
1319     }
1320 
1321     if (!xRecordValues) {
1322         return false;
1323     }
1324 
1325     // string:
1326     if (groupCode<=9 ||
1327         groupCode==100 || groupCode==102 || groupCode==105 ||
1328         (groupCode>=300 && groupCode<=369) ||
1329         (groupCode>=1000 && groupCode<=1009)) {
1330 
1331         creationInterface->addXRecordString(groupCode, groupValue);
1332         return true;
1333     }
1334 
1335     // int:
1336     else if ((groupCode>=60 && groupCode<=99) || (groupCode>=160 && groupCode<=179) || (groupCode>=270 && groupCode<=289)) {
1337         creationInterface->addXRecordInt(groupCode, toInt(groupValue));
1338         return true;
1339     }
1340 
1341     // bool:
1342     else if (groupCode>=290 && groupCode<=299) {
1343         creationInterface->addXRecordBool(groupCode, toBool(groupValue));
1344         return true;
1345     }
1346 
1347     // double:
1348     else if ((groupCode>=10 && groupCode<=59) || (groupCode>=110 && groupCode<=149) || (groupCode>=210 && groupCode<=239)) {
1349         creationInterface->addXRecordReal(groupCode, toReal(groupValue));
1350         return true;
1351     }
1352 
1353     return false;
1354 }
1355 
1356 /**
1357  * Handles all dictionary data.
1358  */
handleDictionaryData(DL_CreationInterface * creationInterface)1359 bool DL_Dxf::handleDictionaryData(DL_CreationInterface* creationInterface) {
1360     if (groupCode==3) {
1361         return true;
1362     }
1363 
1364     if (groupCode==5) {
1365         creationInterface->addDictionary(DL_DictionaryData(groupValue));
1366         return true;
1367     }
1368 
1369     if (groupCode==350) {
1370         creationInterface->addDictionaryEntry(DL_DictionaryEntryData(getStringValue(3, ""), groupValue));
1371         return true;
1372     }
1373     return false;
1374 }
1375 
1376 
1377 
1378 /**
1379  * Handles XData for all object types.
1380  */
handleXData(DL_CreationInterface * creationInterface)1381 bool DL_Dxf::handleXData(DL_CreationInterface* creationInterface) {
1382     if (groupCode==1001) {
1383         creationInterface->addXDataApp(groupValue);
1384         return true;
1385     }
1386     else if (groupCode>=1000 && groupCode<=1009) {
1387         creationInterface->addXDataString(groupCode, groupValue);
1388         return true;
1389     }
1390     else if (groupCode>=1010 && groupCode<=1059) {
1391         creationInterface->addXDataReal(groupCode, toReal(groupValue));
1392         return true;
1393     }
1394     else if (groupCode>=1060 && groupCode<=1070) {
1395         creationInterface->addXDataInt(groupCode, toInt(groupValue));
1396         return true;
1397     }
1398     else if (groupCode==1071) {
1399         creationInterface->addXDataInt(groupCode, toInt(groupValue));
1400         return true;
1401     }
1402 
1403     return false;
1404 }
1405 
1406 /**
1407  * Handles additional MText data.
1408  */
handleMTextData(DL_CreationInterface * creationInterface)1409 bool DL_Dxf::handleMTextData(DL_CreationInterface* creationInterface) {
1410     // Special handling of text chunks for MTEXT entities:
1411     if (groupCode==3) {
1412         creationInterface->addMTextChunk(groupValue);
1413         return true;
1414     }
1415 
1416     return false;
1417 }
1418 
1419 /**
1420  * Handles additional polyline data.
1421  */
handleLWPolylineData(DL_CreationInterface *)1422 bool DL_Dxf::handleLWPolylineData(DL_CreationInterface* /*creationInterface*/) {
1423     // Allocate LWPolyline vertices (group code 90):
1424     if (groupCode==90) {
1425         maxVertices = toInt(groupValue);
1426         if (maxVertices>0) {
1427             if (vertices!=NULL) {
1428                 delete[] vertices;
1429             }
1430             vertices = new double[4*maxVertices];
1431             for (int i=0; i<maxVertices; ++i) {
1432                 vertices[i*4] = 0.0;
1433                 vertices[i*4+1] = 0.0;
1434                 vertices[i*4+2] = 0.0;
1435                 vertices[i*4+3] = 0.0;
1436             }
1437         }
1438         vertexIndex=-1;
1439         return true;
1440     }
1441 
1442     // Process LWPolylines vertices (group codes 10/20/30/42):
1443     else if (groupCode==10 || groupCode==20 ||
1444              groupCode==30 || groupCode==42) {
1445 
1446         if (vertexIndex<maxVertices-1 && groupCode==10) {
1447             vertexIndex++;
1448         }
1449 
1450         if (groupCode<=30) {
1451             if (vertexIndex>=0 && vertexIndex<maxVertices) {
1452                 vertices[4*vertexIndex + (groupCode/10-1)] = toReal(groupValue);
1453             }
1454         } else if (groupCode==42 && vertexIndex<maxVertices) {
1455             vertices[4*vertexIndex + 3] = toReal(groupValue);
1456         }
1457         return true;
1458     }
1459     return false;
1460 }
1461 
1462 
1463 
1464 /**
1465  * Handles additional spline data.
1466  */
handleSplineData(DL_CreationInterface *)1467 bool DL_Dxf::handleSplineData(DL_CreationInterface* /*creationInterface*/) {
1468     // Allocate Spline knots (group code 72):
1469     if (groupCode==72) {
1470         maxKnots = toInt(groupValue);
1471         if (maxKnots>0) {
1472             if (knots!=NULL) {
1473                 delete[] knots;
1474             }
1475             knots = new double[maxKnots];
1476             for (int i=0; i<maxKnots; ++i) {
1477                 knots[i] = 0.0;
1478             }
1479         }
1480         knotIndex=-1;
1481         return true;
1482     }
1483 
1484     // Allocate Spline control points / weights (group code 73):
1485     else if (groupCode==73) {
1486         maxControlPoints = toInt(groupValue);
1487         if (maxControlPoints>0) {
1488             if (controlPoints!=NULL) {
1489                 delete[] controlPoints;
1490             }
1491             if (weights!=NULL) {
1492                 delete[] weights;
1493             }
1494             controlPoints = new double[3*maxControlPoints];
1495             weights = new double[maxControlPoints];
1496             for (int i=0; i<maxControlPoints; ++i) {
1497                 controlPoints[i*3] = 0.0;
1498                 controlPoints[i*3+1] = 0.0;
1499                 controlPoints[i*3+2] = 0.0;
1500                 weights[i] = 1.0;
1501             }
1502         }
1503         controlPointIndex=-1;
1504         weightIndex=-1;
1505         return true;
1506     }
1507 
1508     // Allocate Spline fit points (group code 74):
1509     else if (groupCode==74) {
1510         maxFitPoints = toInt(groupValue);
1511         if (maxFitPoints>0) {
1512             if (fitPoints!=NULL) {
1513                 delete[] fitPoints;
1514             }
1515             fitPoints = new double[3*maxFitPoints];
1516             for (int i=0; i<maxFitPoints; ++i) {
1517                 fitPoints[i*3] = 0.0;
1518                 fitPoints[i*3+1] = 0.0;
1519                 fitPoints[i*3+2] = 0.0;
1520             }
1521         }
1522         fitPointIndex=-1;
1523         return true;
1524     }
1525 
1526     // Process spline knot vertices (group code 40):
1527     else if (groupCode==40) {
1528         if (knotIndex<maxKnots-1) {
1529             knotIndex++;
1530             knots[knotIndex] = toReal(groupValue);
1531         }
1532         return true;
1533     }
1534 
1535     // Process spline control points (group codes 10/20/30):
1536     else if (groupCode==10 || groupCode==20 ||
1537              groupCode==30) {
1538 
1539         if (controlPointIndex<maxControlPoints-1 && groupCode==10) {
1540             controlPointIndex++;
1541         }
1542 
1543         if (controlPointIndex>=0 && controlPointIndex<maxControlPoints) {
1544             controlPoints[3*controlPointIndex + (groupCode/10-1)] = toReal(groupValue);
1545         }
1546         return true;
1547     }
1548 
1549     // Process spline fit points (group codes 11/21/31):
1550     else if (groupCode==11 || groupCode==21 || groupCode==31) {
1551         if (fitPointIndex<maxFitPoints-1 && groupCode==11) {
1552             fitPointIndex++;
1553         }
1554 
1555         if (fitPointIndex>=0 && fitPointIndex<maxFitPoints) {
1556             fitPoints[3*fitPointIndex + ((groupCode-1)/10-1)] = toReal(groupValue);
1557         }
1558         return true;
1559     }
1560 
1561     // Process spline weights (group code 41)
1562     else if (groupCode==41) {
1563 
1564         if (weightIndex<maxControlPoints-1) {
1565             weightIndex++;
1566         }
1567 
1568         if (weightIndex>=0 && weightIndex<maxControlPoints) {
1569             weights[weightIndex] = toReal(groupValue);
1570         }
1571         return true;
1572     }
1573     return false;
1574 }
1575 
1576 
1577 
1578 /**
1579  * Handles additional leader data.
1580  */
handleLeaderData(DL_CreationInterface *)1581 bool DL_Dxf::handleLeaderData(DL_CreationInterface* /*creationInterface*/) {
1582     // Allocate Leader vertices (group code 76):
1583     if (groupCode==76) {
1584         maxLeaderVertices = toInt(groupValue);
1585         if (maxLeaderVertices>0) {
1586             if (leaderVertices!=NULL) {
1587                 delete[] leaderVertices;
1588             }
1589             leaderVertices = new double[3*maxLeaderVertices];
1590             for (int i=0; i<maxLeaderVertices; ++i) {
1591                 leaderVertices[i*3] = 0.0;
1592                 leaderVertices[i*3+1] = 0.0;
1593                 leaderVertices[i*3+2] = 0.0;
1594             }
1595         }
1596         leaderVertexIndex=-1;
1597         return true;
1598     }
1599 
1600     // Process Leader vertices (group codes 10/20/30):
1601     else if (groupCode==10 || groupCode==20 || groupCode==30) {
1602 
1603         if (leaderVertexIndex<maxLeaderVertices-1 && groupCode==10) {
1604             leaderVertexIndex++;
1605         }
1606 
1607         if (groupCode<=30) {
1608             if (leaderVertexIndex>=0 &&
1609                     leaderVertexIndex<maxLeaderVertices) {
1610                 leaderVertices[3*leaderVertexIndex + (groupCode/10-1)]
1611                 = toReal(groupValue);
1612             }
1613         }
1614         return true;
1615     }
1616 
1617     return false;
1618 }
1619 
1620 
1621 
1622 
1623 /**
1624  * Adds an text entity that was read from the file via the creation interface.
1625  */
addText(DL_CreationInterface * creationInterface)1626 void DL_Dxf::addText(DL_CreationInterface* creationInterface) {
1627     DL_TextData d(
1628         // insertion point
1629         getRealValue(10, 0.0),
1630         getRealValue(20, 0.0),
1631         getRealValue(30, 0.0),
1632         // alignment point
1633         getRealValue(11, DL_NANDOUBLE),
1634         getRealValue(21, DL_NANDOUBLE),
1635         getRealValue(31, DL_NANDOUBLE),
1636         // height
1637         getRealValue(40, 2.5),
1638         // x scale
1639         getRealValue(41, 1.0),
1640         // generation flags
1641         getIntValue(71, 0),
1642         // h just
1643         getIntValue(72, 0),
1644         // v just
1645         getIntValue(73, 0),
1646         // text
1647         getStringValue(1, ""),
1648         // style
1649         getStringValue(7, ""),
1650         // angle
1651         (getRealValue(50, 0.0)*2*M_PI)/360.0);
1652 
1653     creationInterface->addText(d);
1654 }
1655 
1656 
1657 /**
1658  * Adds an arc aligned text entity that was read from the file via the creation interface.
1659  */
addArcAlignedText(DL_CreationInterface * creationInterface)1660 void DL_Dxf::addArcAlignedText(DL_CreationInterface* creationInterface) {
1661     DL_ArcAlignedTextData d;
1662     d.text = getStringValue(1, "");
1663     d.font = getStringValue(2, "");
1664     d.style = getStringValue(7, "");
1665     d.cx = getRealValue(10, 0.0);
1666     d.cy = getRealValue(20, 0.0);
1667     d.cz = getRealValue(30, 0.0);
1668     d.radius = getRealValue(40, 0.0);
1669     d.xScaleFactor = getRealValue(41, 0.0);
1670     d.height = getRealValue(42, 0.0);
1671     d.spacing = getRealValue(43, 0.0);
1672     d.offset = getRealValue(44, 0.0);
1673     d.rightOffset = getRealValue(45, 0.0);
1674     d.leftOffset = getRealValue(46, 0.0);
1675     d.startAngle = getRealValue(50, 0.0);
1676     d.endAngle = getRealValue(51, 0.0);
1677     d.reversedCharacterOrder = getIntValue(70, 0);
1678     d.direction = getIntValue(71, 0);
1679     d.alignment = getIntValue(72, 0);
1680     d.side = getIntValue(73, 0);
1681     d.bold = getIntValue(74, 0);
1682     d.italic = getIntValue(75, 0);
1683     d.underline = getIntValue(76, 0);
1684     d.characerSet = getIntValue(77, 0);
1685     d.pitch = getIntValue(78, 0);
1686     d.shxFont = getIntValue(79, 0);
1687     d.wizard = getIntValue(280, 0);
1688     d.arcHandle = getIntValue(330, 0);
1689 
1690     creationInterface->addArcAlignedText(d);
1691 }
1692 
1693 
1694 
1695 /**
1696  * Adds an attrib entity that was read from the file via the creation interface.
1697  * @todo add attrib instead of normal text
1698  */
addAttribute(DL_CreationInterface * creationInterface)1699 void DL_Dxf::addAttribute(DL_CreationInterface* creationInterface) {
1700     DL_AttributeData d(
1701         // insertion point
1702         getRealValue(10, 0.0),
1703         getRealValue(20, 0.0),
1704         getRealValue(30, 0.0),
1705         // alignment point
1706         getRealValue(11, 0.0),
1707         getRealValue(21, 0.0),
1708         getRealValue(31, 0.0),
1709         // height
1710         getRealValue(40, 2.5),
1711         // x scale
1712         getRealValue(41, 1.0),
1713         // generation flags
1714         getIntValue(71, 0),
1715         // h just
1716         getIntValue(72, 0),
1717         // v just
1718         getIntValue(74, 0),
1719         // tag
1720         getStringValue(2, ""),
1721         // text
1722         getStringValue(1, ""),
1723         // style
1724         getStringValue(7, ""),
1725         // angle
1726         (getRealValue(50, 0.0)*2*M_PI)/360.0);
1727 
1728     creationInterface->addAttribute(d);
1729 }
1730 
1731 
1732 
1733 /**
1734  * @return dimension data from current values.
1735  */
getDimData()1736 DL_DimensionData DL_Dxf::getDimData() {
1737     // generic dimension data:
1738     return DL_DimensionData(
1739                // def point
1740                getRealValue(10, 0.0),
1741                getRealValue(20, 0.0),
1742                getRealValue(30, 0.0),
1743                // text middle point
1744                getRealValue(11, 0.0),
1745                getRealValue(21, 0.0),
1746                getRealValue(31, 0.0),
1747                // type
1748                getIntValue(70, 0),
1749                // attachment point
1750                getIntValue(71, 5),
1751                // line sp. style
1752                getIntValue(72, 1),
1753                // line sp. factor
1754                getRealValue(41, 1.0),
1755                // text
1756                getStringValue(1, ""),
1757                // style
1758                getStringValue(3, ""),
1759                // angle
1760                getRealValue(53, 0.0));
1761 }
1762 
1763 
1764 
1765 /**
1766  * Adds a linear dimension entity that was read from the file via the creation interface.
1767  */
addDimLinear(DL_CreationInterface * creationInterface)1768 void DL_Dxf::addDimLinear(DL_CreationInterface* creationInterface) {
1769     DL_DimensionData d = getDimData();
1770 
1771     // horizontal / vertical / rotated dimension:
1772     DL_DimLinearData dl(
1773         // definition point 1
1774         getRealValue(13, 0.0),
1775         getRealValue(23, 0.0),
1776         getRealValue(33, 0.0),
1777         // definition point 2
1778         getRealValue(14, 0.0),
1779         getRealValue(24, 0.0),
1780         getRealValue(34, 0.0),
1781         // angle
1782         getRealValue(50, 0.0),
1783         // oblique
1784         getRealValue(52, 0.0));
1785     creationInterface->addDimLinear(d, dl);
1786 }
1787 
1788 
1789 
1790 /**
1791  * Adds an aligned dimension entity that was read from the file via the creation interface.
1792  */
addDimAligned(DL_CreationInterface * creationInterface)1793 void DL_Dxf::addDimAligned(DL_CreationInterface* creationInterface) {
1794     DL_DimensionData d = getDimData();
1795 
1796     // aligned dimension:
1797     DL_DimAlignedData da(
1798         // extension point 1
1799         getRealValue(13, 0.0),
1800         getRealValue(23, 0.0),
1801         getRealValue(33, 0.0),
1802         // extension point 2
1803         getRealValue(14, 0.0),
1804         getRealValue(24, 0.0),
1805         getRealValue(34, 0.0));
1806     creationInterface->addDimAlign(d, da);
1807 }
1808 
1809 
1810 
1811 /**
1812  * Adds a radial dimension entity that was read from the file via the creation interface.
1813  */
addDimRadial(DL_CreationInterface * creationInterface)1814 void DL_Dxf::addDimRadial(DL_CreationInterface* creationInterface) {
1815     DL_DimensionData d = getDimData();
1816 
1817     DL_DimRadialData dr(
1818         // definition point
1819         getRealValue(15, 0.0),
1820         getRealValue(25, 0.0),
1821         getRealValue(35, 0.0),
1822         // leader length:
1823         getRealValue(40, 0.0));
1824     creationInterface->addDimRadial(d, dr);
1825 }
1826 
1827 
1828 
1829 /**
1830  * Adds a diametric dimension entity that was read from the file via the creation interface.
1831  */
addDimDiametric(DL_CreationInterface * creationInterface)1832 void DL_Dxf::addDimDiametric(DL_CreationInterface* creationInterface) {
1833     DL_DimensionData d = getDimData();
1834 
1835     // diametric dimension:
1836     DL_DimDiametricData dr(
1837         // definition point
1838         getRealValue(15, 0.0),
1839         getRealValue(25, 0.0),
1840         getRealValue(35, 0.0),
1841         // leader length:
1842         getRealValue(40, 0.0));
1843     creationInterface->addDimDiametric(d, dr);
1844 }
1845 
1846 
1847 
1848 /**
1849  * Adds an angular dimension entity that was read from the file via the creation interface.
1850  */
addDimAngular(DL_CreationInterface * creationInterface)1851 void DL_Dxf::addDimAngular(DL_CreationInterface* creationInterface) {
1852     DL_DimensionData d = getDimData();
1853 
1854     // angular dimension:
1855     DL_DimAngularData da(
1856         // definition point 1
1857         getRealValue(13, 0.0),
1858         getRealValue(23, 0.0),
1859         getRealValue(33, 0.0),
1860         // definition point 2
1861         getRealValue(14, 0.0),
1862         getRealValue(24, 0.0),
1863         getRealValue(34, 0.0),
1864         // definition point 3
1865         getRealValue(15, 0.0),
1866         getRealValue(25, 0.0),
1867         getRealValue(35, 0.0),
1868         // definition point 4
1869         getRealValue(16, 0.0),
1870         getRealValue(26, 0.0),
1871         getRealValue(36, 0.0));
1872     creationInterface->addDimAngular(d, da);
1873 }
1874 
1875 
1876 /**
1877  * Adds an angular dimension entity that was read from the file via the creation interface.
1878  */
addDimAngular3P(DL_CreationInterface * creationInterface)1879 void DL_Dxf::addDimAngular3P(DL_CreationInterface* creationInterface) {
1880     DL_DimensionData d = getDimData();
1881 
1882     // angular dimension (3P):
1883     DL_DimAngular3PData da(
1884         // definition point 1
1885         getRealValue(13, 0.0),
1886         getRealValue(23, 0.0),
1887         getRealValue(33, 0.0),
1888         // definition point 2
1889         getRealValue(14, 0.0),
1890         getRealValue(24, 0.0),
1891         getRealValue(34, 0.0),
1892         // definition point 3
1893         getRealValue(15, 0.0),
1894         getRealValue(25, 0.0),
1895         getRealValue(35, 0.0));
1896     creationInterface->addDimAngular3P(d, da);
1897 }
1898 
1899 
1900 
1901 /**
1902  * Adds an ordinate dimension entity that was read from the file via the creation interface.
1903  */
addDimOrdinate(DL_CreationInterface * creationInterface)1904 void DL_Dxf::addDimOrdinate(DL_CreationInterface* creationInterface) {
1905     DL_DimensionData d = getDimData();
1906 
1907     // ordinate dimension:
1908     DL_DimOrdinateData dl(
1909         // definition point 1
1910         getRealValue(13, 0.0),
1911         getRealValue(23, 0.0),
1912         getRealValue(33, 0.0),
1913         // definition point 2
1914         getRealValue(14, 0.0),
1915         getRealValue(24, 0.0),
1916         getRealValue(34, 0.0),
1917         (getIntValue(70, 0)&64)==64         // true: X-type, false: Y-type
1918     );
1919     creationInterface->addDimOrdinate(d, dl);
1920 }
1921 
1922 
1923 
1924 /**
1925  * Adds a leader entity that was read from the file via the creation interface.
1926  */
addLeader(DL_CreationInterface * creationInterface)1927 void DL_Dxf::addLeader(DL_CreationInterface* creationInterface) {
1928     // leader (arrow)
1929     DL_LeaderData le(
1930         // arrow head flag
1931         getIntValue(71, 1),
1932         // leader path type
1933         getIntValue(72, 0),
1934         // Leader creation flag
1935         getIntValue(73, 3),
1936         // Hookline direction flag
1937         getIntValue(74, 1),
1938         // Hookline flag
1939         getIntValue(75, 0),
1940         // Text annotation height
1941         getRealValue(40, 1.0),
1942         // Text annotation width
1943         getRealValue(41, 1.0),
1944         // Number of vertices in leader
1945         getIntValue(76, 0)
1946     );
1947     creationInterface->addLeader(le);
1948 
1949     for (int i=0; i<maxLeaderVertices; i++) {
1950         DL_LeaderVertexData d(leaderVertices[i*3],
1951                               leaderVertices[i*3+1],
1952                               leaderVertices[i*3+2]);
1953 
1954         creationInterface->addLeaderVertex(d);
1955     }
1956     creationInterface->endEntity();
1957 }
1958 
1959 /**
1960  * Adds a hatch entity that was read from the file via the creation interface.
1961  */
addHatch(DL_CreationInterface * creationInterface)1962 void DL_Dxf::addHatch(DL_CreationInterface* creationInterface) {
1963     DL_HatchData hd(getIntValue(91, 1),
1964                     getIntValue(70, 0),
1965                     getRealValue(41, 1.0),
1966                     getRealValue(52, 0.0),
1967                     getStringValue(2, ""));
1968 
1969     creationInterface->addHatch(hd);
1970 
1971     for (unsigned int i=0; i<hatchEdges.size(); i++) {
1972         creationInterface->addHatchLoop(DL_HatchLoopData(hatchEdges[i].size()));
1973         for (unsigned int k=0; k<hatchEdges[i].size(); k++) {
1974             creationInterface->addHatchEdge(DL_HatchEdgeData(hatchEdges[i][k]));
1975         }
1976     }
1977 
1978     creationInterface->endEntity();
1979 }
1980 
addHatchLoop()1981 void DL_Dxf::addHatchLoop() {
1982     addHatchEdge();
1983     hatchEdges.push_back(std::vector<DL_HatchEdgeData>());
1984 }
1985 
addHatchEdge()1986 void DL_Dxf::addHatchEdge() {
1987     if (hatchEdge.defined) {
1988         if (hatchEdges.size()>0) {
1989             hatchEdges.back().push_back(hatchEdge);
1990         }
1991         hatchEdge = DL_HatchEdgeData();
1992     }
1993 }
1994 
1995 /**
1996  * Handles all hatch data.
1997  */
handleHatchData(DL_CreationInterface * creationInterface)1998 bool DL_Dxf::handleHatchData(DL_CreationInterface* creationInterface) {
1999     // New polyline loop, group code 92
2000     // or new loop with individual edges, group code 93
2001     if (groupCode==92 || groupCode==93) {
2002         if (firstHatchLoop) {
2003             hatchEdges.clear();
2004             firstHatchLoop = false;
2005         }
2006         if (groupCode==92 && (toInt(groupValue)&2)==2) {
2007             addHatchLoop();
2008         }
2009         if (groupCode==93) {
2010             addHatchLoop();
2011         }
2012         return true;
2013     }
2014 
2015     // New hatch edge or new section / entity: add last hatch edge:
2016     if (groupCode==72 || groupCode==0 || groupCode==78 || groupCode==98) {
2017         // polyline boundaries use code 72 for bulge flag:
2018         if (groupCode!=72 || (getIntValue(92, 0)&2)==0) {
2019             addHatchEdge();
2020         }
2021 
2022         if (groupCode==0 /*|| groupCode==78*/) {
2023             addHatch(creationInterface);
2024         }
2025         else {
2026             hatchEdge.type = toInt(groupValue);
2027         }
2028         return true;
2029     }
2030 
2031     // polyline boundary:
2032     if ((getIntValue(92, 0)&2)==2) {
2033         switch (groupCode) {
2034         case 10:
2035             hatchEdge.type = 0;
2036             hatchEdge.vertices.push_back(std::vector<double>());
2037             hatchEdge.vertices.back().push_back(toReal(groupValue));
2038             return true;
2039         case 20:
2040             if (!hatchEdge.vertices.empty()) {
2041                 hatchEdge.vertices.back().push_back(toReal(groupValue));
2042                 hatchEdge.defined = true;
2043             }
2044             return true;
2045         case 42:
2046             if (!hatchEdge.vertices.empty()) {
2047                 hatchEdge.vertices.back().push_back(toReal(groupValue));
2048                 hatchEdge.defined = true;
2049             }
2050             return true;
2051         }
2052     }
2053     else {
2054         // Line edge:
2055         if (hatchEdge.type==1) {
2056             switch (groupCode) {
2057             case 10:
2058                 hatchEdge.x1 = toReal(groupValue);
2059                 return true;
2060             case 20:
2061                 hatchEdge.y1 = toReal(groupValue);
2062                 return true;
2063             case 11:
2064                 hatchEdge.x2 = toReal(groupValue);
2065                 return true;
2066             case 21:
2067                 hatchEdge.y2 = toReal(groupValue);
2068                 hatchEdge.defined = true;
2069                 return true;
2070             }
2071         }
2072 
2073         // Arc edge:
2074         if (hatchEdge.type==2) {
2075             switch(groupCode) {
2076             case 10:
2077                 hatchEdge.cx = toReal(groupValue);
2078                 return true;
2079             case 20:
2080                 hatchEdge.cy = toReal(groupValue);
2081                 return true;
2082             case 40:
2083                 hatchEdge.radius = toReal(groupValue);
2084                 return true;
2085             case 50:
2086                 hatchEdge.angle1 = toReal(groupValue)/360.0*2*M_PI;
2087                 return true;
2088             case 51:
2089                 hatchEdge.angle2 = toReal(groupValue)/360.0*2*M_PI;
2090                 return true;
2091             case 73:
2092                 hatchEdge.ccw = (bool)toInt(groupValue);
2093                 hatchEdge.defined = true;
2094                 return true;
2095             }
2096         }
2097 
2098         // Ellipse arc edge:
2099         if (hatchEdge.type==3) {
2100             switch (groupCode) {
2101             case 10:
2102                 hatchEdge.cx = toReal(groupValue);
2103                 return true;
2104             case 20:
2105                 hatchEdge.cy = toReal(groupValue);
2106                 return true;
2107             case 11:
2108                 hatchEdge.mx = toReal(groupValue);
2109                 return true;
2110             case 21:
2111                 hatchEdge.my = toReal(groupValue);
2112                 return true;
2113             case 40:
2114                 hatchEdge.ratio = toReal(groupValue);
2115                 return true;
2116             case 50:
2117                 hatchEdge.angle1 = toReal(groupValue)/360.0*2*M_PI;
2118                 return true;
2119             case 51:
2120                 hatchEdge.angle2 = toReal(groupValue)/360.0*2*M_PI;
2121                 return true;
2122             case 73:
2123                 hatchEdge.ccw = (bool)toInt(groupValue);
2124                 hatchEdge.defined = true;
2125                 return true;
2126             }
2127         }
2128 
2129         // Spline edge:
2130         if (hatchEdge.type==4) {
2131             switch (groupCode) {
2132             case 94:
2133                 hatchEdge.degree = toInt(groupValue);
2134                 return true;
2135             case 73:
2136                 hatchEdge.rational = toBool(groupValue);
2137                 return true;
2138             case 74:
2139                 hatchEdge.periodic = toBool(groupValue);
2140                 return true;
2141             case 95:
2142                 hatchEdge.nKnots = toInt(groupValue);
2143                 return true;
2144             case 96:
2145                 hatchEdge.nControl = toInt(groupValue);
2146                 return true;
2147             case 97:
2148                 hatchEdge.nFit = toInt(groupValue);
2149                 return true;
2150             case 40:
2151                 if (hatchEdge.knots.size() < hatchEdge.nKnots) {
2152                     hatchEdge.knots.push_back(toReal(groupValue));
2153                 }
2154                 return true;
2155             case 10:
2156                 if (hatchEdge.controlPoints.size() < hatchEdge.nControl) {
2157                     std::vector<double> v;
2158                     v.push_back(toReal(groupValue));
2159                     hatchEdge.controlPoints.push_back(v);
2160                 }
2161                 return true;
2162             case 20:
2163                 if (!hatchEdge.controlPoints.empty() && hatchEdge.controlPoints.back().size()==1) {
2164                     hatchEdge.controlPoints.back().push_back(toReal(groupValue));
2165                 }
2166                 hatchEdge.defined = true;
2167                 return true;
2168             case 42:
2169                 if (hatchEdge.weights.size() < hatchEdge.nControl) {
2170                     hatchEdge.weights.push_back(toReal(groupValue));
2171                 }
2172                 return true;
2173             case 11:
2174                 if (hatchEdge.fitPoints.size() < hatchEdge.nFit) {
2175                     std::vector<double> v;
2176                     v.push_back(toReal(groupValue));
2177                     hatchEdge.fitPoints.push_back(v);
2178                 }
2179                 return true;
2180             case 21:
2181                 if (!hatchEdge.fitPoints.empty() && hatchEdge.fitPoints.back().size()==1) {
2182                     hatchEdge.fitPoints.back().push_back(toReal(groupValue));
2183                 }
2184                 hatchEdge.defined = true;
2185                 return true;
2186             case 12:
2187                 hatchEdge.startTangentX = toReal(groupValue);
2188                 return true;
2189             case 22:
2190                 hatchEdge.startTangentY = toReal(groupValue);
2191                 return true;
2192             case 13:
2193                 hatchEdge.endTangentX = toReal(groupValue);
2194                 return true;
2195             case 23:
2196                 hatchEdge.endTangentY = toReal(groupValue);
2197                 return true;
2198             }
2199         }
2200     }
2201 
2202     return false;
2203 }
2204 
2205 
2206 /**
2207  * Adds an image entity that was read from the file via the creation interface.
2208  */
addImage(DL_CreationInterface * creationInterface)2209 void DL_Dxf::addImage(DL_CreationInterface* creationInterface) {
2210     DL_ImageData id(// pass ref insead of name we don't have yet
2211         getStringValue(340, ""),
2212         // ins point:
2213         getRealValue(10, 0.0),
2214         getRealValue(20, 0.0),
2215         getRealValue(30, 0.0),
2216         // u vector:
2217         getRealValue(11, 1.0),
2218         getRealValue(21, 0.0),
2219         getRealValue(31, 0.0),
2220         // v vector:
2221         getRealValue(12, 0.0),
2222         getRealValue(22, 1.0),
2223         getRealValue(32, 0.0),
2224         // image size (pixel):
2225         getIntValue(13, 1),
2226         getIntValue(23, 1),
2227         // brightness, contrast, fade
2228         getIntValue(281, 50),
2229         getIntValue(282, 50),
2230         getIntValue(283, 0));
2231 
2232     creationInterface->addImage(id);
2233     creationInterface->endEntity();
2234     currentObjectType = DL_UNKNOWN;
2235 }
2236 
2237 
2238 
2239 /**
2240  * Adds an image definition that was read from the file via the creation interface.
2241  */
addImageDef(DL_CreationInterface * creationInterface)2242 void DL_Dxf::addImageDef(DL_CreationInterface* creationInterface) {
2243     DL_ImageDefData id(// handle
2244         getStringValue(5, ""),
2245         getStringValue(1, ""));
2246 
2247     creationInterface->linkImage(id);
2248     creationInterface->endEntity();
2249     currentObjectType = DL_UNKNOWN;
2250 }
2251 
2252 
2253 
2254 /**
2255  * Ends some special entities like hatches or old style polylines.
2256  */
endEntity(DL_CreationInterface * creationInterface)2257 void DL_Dxf::endEntity(DL_CreationInterface* creationInterface) {
2258     creationInterface->endEntity();
2259 }
2260 
2261 
2262 /**
2263  * Ends a sequence and notifies the creation interface.
2264  */
endSequence(DL_CreationInterface * creationInterface)2265 void DL_Dxf::endSequence(DL_CreationInterface* creationInterface) {
2266     creationInterface->endSequence();
2267 }
2268 
2269 
2270 /**
2271  * Converts the given string into an int.
2272  * ok is set to false if there was an error.
2273  */
2274 //int DL_Dxf::stringToInt(const char* s, bool* ok) {
2275 //    if (ok!=NULL) {
2276 //        // check string:
2277 //        *ok = true;
2278 //        int i=0;
2279 //        bool dot = false;
2280 //        do {
2281 //            if (s[i]=='\0') {
2282 //                break;
2283 //            } else if (s[i]=='.') {
2284 //                if (dot==true) {
2285 //                    //std::cerr << "two dots\n";
2286 //                    *ok = false;
2287 //                } else {
2288 //                    dot = true;
2289 //                }
2290 //            } else if (s[i]<'0' || s[i]>'9') {
2291 //                //std::cerr << "NaN: '" << s[i] << "'\n";
2292 //                *ok = false;
2293 //            }
2294 //            i++;
2295 //        } while(s[i]!='\0' && *ok==true);
2296 //    }
2297 
2298 //    return atoi(s);
2299 //}
2300 
2301 
2302 /**
2303  * @brief Opens the given file for writing and returns a pointer
2304  * to the dxf writer. This pointer needs to be passed on to other
2305  * writing functions.
2306  *
2307  * @param file Full path of the file to open.
2308  *
2309  * @return Pointer to an ascii dxf writer object.
2310  */
out(const char * file,DL_Codes::version version)2311 DL_WriterA* DL_Dxf::out(const char* file, DL_Codes::version version) {
2312     char* f = new char[strlen(file)+1];
2313     strcpy(f, file);
2314     this->version = version;
2315 
2316     DL_WriterA* dw = new DL_WriterA(f, version);
2317     if (dw->openFailed()) {
2318         delete dw;
2319         delete[] f;
2320         return NULL;
2321     } else {
2322         delete[] f;
2323         return dw;
2324     }
2325 }
2326 
2327 
2328 
2329 /**
2330  * @brief Writes a DXF header to the file currently opened
2331  * by the given DXF writer object.
2332  */
writeHeader(DL_WriterA & dw)2333 void DL_Dxf::writeHeader(DL_WriterA& dw) {
2334     dw.comment("dxflib " DL_VERSION);
2335     dw.sectionHeader();
2336 
2337     dw.dxfString(9, "$ACADVER");
2338     switch (version) {
2339     case DL_Codes::AC1009:
2340         dw.dxfString(1, "AC1009");
2341         break;
2342     case DL_Codes::AC1012:
2343         dw.dxfString(1, "AC1012");
2344         break;
2345     case DL_Codes::AC1014:
2346         dw.dxfString(1, "AC1014");
2347         break;
2348     case DL_Codes::AC1015:
2349         dw.dxfString(1, "AC1015");
2350         break;
2351     case DL_Codes::AC1009_MIN:
2352         // minimalistic DXF version is unidentified in file:
2353         break;
2354     }
2355 
2356     // Newer version require that (otherwise a*cad crashes..)
2357     if (version==DL_VERSION_2000) {
2358         dw.dxfString(9, "$HANDSEED");
2359         dw.dxfHex(5, 0xFFFF);
2360     }
2361 
2362     // commented out: more variables can be added after that by caller:
2363     //dw.sectionEnd();
2364 }
2365 
2366 
2367 
2368 
2369 /**
2370  * Writes a point entity to the file.
2371  *
2372  * @param dw DXF writer
2373  * @param data Entity data from the file
2374  * @param attrib Attributes
2375  */
writePoint(DL_WriterA & dw,const DL_PointData & data,const DL_Attributes & attrib)2376 void DL_Dxf::writePoint(DL_WriterA& dw,
2377                         const DL_PointData& data,
2378                         const DL_Attributes& attrib) {
2379     dw.entity("POINT");
2380     if (version==DL_VERSION_2000) {
2381         dw.dxfString(100, "AcDbEntity");
2382     }
2383     dw.entityAttributes(attrib);
2384     if (version==DL_VERSION_2000) {
2385         dw.dxfString(100, "AcDbPoint");
2386     }
2387     dw.coord(DL_POINT_COORD_CODE, data.x, data.y, data.z);
2388 }
2389 
2390 
2391 
2392 /**
2393  * Writes a line entity to the file.
2394  *
2395  * @param dw DXF writer
2396  * @param data Entity data from the file
2397  * @param attrib Attributes
2398  */
writeLine(DL_WriterA & dw,const DL_LineData & data,const DL_Attributes & attrib)2399 void DL_Dxf::writeLine(DL_WriterA& dw,
2400                        const DL_LineData& data,
2401                        const DL_Attributes& attrib) {
2402     dw.entity("LINE");
2403     if (version==DL_VERSION_2000) {
2404         dw.dxfString(100, "AcDbEntity");
2405     }
2406     dw.entityAttributes(attrib);
2407     if (version==DL_VERSION_2000) {
2408         dw.dxfString(100, "AcDbLine");
2409     }
2410     dw.coord(DL_LINE_START_CODE, data.x1, data.y1, data.z1);
2411     dw.coord(DL_LINE_END_CODE, data.x2, data.y2, data.z2);
2412 }
2413 
2414 
2415 
2416 /**
2417  * Writes an x line entity to the file.
2418  *
2419  * @param dw DXF writer
2420  * @param data Entity data from the file
2421  * @param attrib Attributes
2422  */
writeXLine(DL_WriterA & dw,const DL_XLineData & data,const DL_Attributes & attrib)2423 void DL_Dxf::writeXLine(DL_WriterA& dw,
2424                        const DL_XLineData& data,
2425                        const DL_Attributes& attrib) {
2426     dw.entity("XLINE");
2427     if (version==DL_VERSION_2000) {
2428         dw.dxfString(100, "AcDbEntity");
2429     }
2430     dw.entityAttributes(attrib);
2431     if (version==DL_VERSION_2000) {
2432         dw.dxfString(100, "AcDbLine");
2433     }
2434     dw.coord(DL_LINE_START_CODE, data.bx, data.by, data.bz);
2435     dw.coord(DL_LINE_END_CODE, data.dx, data.dy, data.dz);
2436 }
2437 
2438 
2439 
2440 /**
2441  * Writes a ray entity to the file.
2442  *
2443  * @param dw DXF writer
2444  * @param data Entity data from the file
2445  * @param attrib Attributes
2446  */
writeRay(DL_WriterA & dw,const DL_RayData & data,const DL_Attributes & attrib)2447 void DL_Dxf::writeRay(DL_WriterA& dw,
2448                         const DL_RayData& data,
2449                         const DL_Attributes& attrib) {
2450     dw.entity("RAY");
2451     if (version==DL_VERSION_2000) {
2452         dw.dxfString(100, "AcDbEntity");
2453     }
2454     dw.entityAttributes(attrib);
2455     if (version==DL_VERSION_2000) {
2456         dw.dxfString(100, "AcDbLine");
2457     }
2458     dw.coord(DL_LINE_START_CODE, data.bx, data.by, data.bz);
2459     dw.coord(DL_LINE_END_CODE, data.dx, data.dy, data.dz);
2460 }
2461 
2462 
2463 
2464 /**
2465  * Writes a polyline entity to the file.
2466  *
2467  * @param dw DXF writer
2468  * @param data Entity data from the file
2469  * @param attrib Attributes
2470  * @see writeVertex
2471  */
writePolyline(DL_WriterA & dw,const DL_PolylineData & data,const DL_Attributes & attrib)2472 void DL_Dxf::writePolyline(DL_WriterA& dw,
2473                            const DL_PolylineData& data,
2474                            const DL_Attributes& attrib) {
2475     if (version==DL_VERSION_2000) {
2476         dw.entity("LWPOLYLINE");
2477         dw.dxfString(100, "AcDbEntity");
2478         dw.entityAttributes(attrib);
2479         dw.dxfString(100, "AcDbPolyline");
2480         dw.dxfInt(90, (int)data.number);
2481         dw.dxfInt(70, data.flags);
2482     } else {
2483         dw.entity("POLYLINE");
2484         dw.entityAttributes(attrib);
2485         polylineLayer = attrib.getLayer();
2486         dw.dxfInt(66, 1);
2487         dw.dxfInt(70, data.flags);
2488         dw.coord(DL_VERTEX_COORD_CODE, 0.0, 0.0, 0.0);
2489     }
2490 }
2491 
2492 
2493 
2494 /**
2495  * Writes a single vertex of a polyline to the file.
2496  *
2497  * @param dw DXF writer
2498  * @param data Entity data from the file
2499  * @param attrib Attributes
2500  */
writeVertex(DL_WriterA & dw,const DL_VertexData & data)2501 void DL_Dxf::writeVertex(DL_WriterA& dw,
2502                          const DL_VertexData& data) {
2503 
2504 
2505     if (version==DL_VERSION_2000) {
2506         dw.dxfReal(10, data.x);
2507         dw.dxfReal(20, data.y);
2508         dw.dxfReal(30, data.z);
2509         if (fabs(data.bulge)>1.0e-10) {
2510             dw.dxfReal(42, data.bulge);
2511         }
2512     } else {
2513         dw.entity("VERTEX");
2514         //dw.entityAttributes(attrib);
2515         dw.dxfString(8, polylineLayer);
2516         dw.coord(DL_VERTEX_COORD_CODE, data.x, data.y, data.z);
2517         if (fabs(data.bulge)>1.0e-10) {
2518             dw.dxfReal(42, data.bulge);
2519         }
2520     }
2521 }
2522 
2523 
2524 
2525 /**
2526  * Writes the polyline end. Only needed for DXF R12.
2527  */
writePolylineEnd(DL_WriterA & dw)2528 void DL_Dxf::writePolylineEnd(DL_WriterA& dw) {
2529     if (version==DL_VERSION_2000) {
2530     } else {
2531         dw.entity("SEQEND");
2532     }
2533 }
2534 
2535 
2536 /**
2537  * Writes a spline entity to the file.
2538  *
2539  * @param dw DXF writer
2540  * @param data Entity data from the file
2541  * @param attrib Attributes
2542  * @see writeControlPoint
2543  */
writeSpline(DL_WriterA & dw,const DL_SplineData & data,const DL_Attributes & attrib)2544 void DL_Dxf::writeSpline(DL_WriterA& dw,
2545                          const DL_SplineData& data,
2546                          const DL_Attributes& attrib) {
2547 
2548     dw.entity("SPLINE");
2549     if (version==DL_VERSION_2000) {
2550         dw.dxfString(100, "AcDbEntity");
2551     }
2552     dw.entityAttributes(attrib);
2553     if (version==DL_VERSION_2000) {
2554         dw.dxfString(100, "AcDbSpline");
2555     }
2556     dw.dxfInt(70, data.flags);
2557     dw.dxfInt(71, data.degree);
2558     dw.dxfInt(72, data.nKnots);            // number of knots
2559     dw.dxfInt(73, data.nControl);          // number of control points
2560     dw.dxfInt(74, data.nFit);              // number of fit points
2561 }
2562 
2563 
2564 
2565 /**
2566  * Writes a single control point of a spline to the file.
2567  *
2568  * @param dw DXF writer
2569  * @param data Entity data from the file
2570  * @param attrib Attributes
2571  */
writeControlPoint(DL_WriterA & dw,const DL_ControlPointData & data)2572 void DL_Dxf::writeControlPoint(DL_WriterA& dw,
2573                                const DL_ControlPointData& data) {
2574 
2575     dw.dxfReal(10, data.x);
2576     dw.dxfReal(20, data.y);
2577     dw.dxfReal(30, data.z);
2578 }
2579 
2580 
2581 
2582 /**
2583  * Writes a single fit point of a spline to the file.
2584  *
2585  * @param dw DXF writer
2586  * @param data Entity data from the file
2587  * @param attrib Attributes
2588  */
writeFitPoint(DL_WriterA & dw,const DL_FitPointData & data)2589 void DL_Dxf::writeFitPoint(DL_WriterA& dw,
2590                            const DL_FitPointData& data) {
2591 
2592     dw.dxfReal(11, data.x);
2593     dw.dxfReal(21, data.y);
2594     dw.dxfReal(31, data.z);
2595 }
2596 
2597 
2598 
2599 /**
2600  * Writes a single knot of a spline to the file.
2601  *
2602  * @param dw DXF writer
2603  * @param data Entity data from the file
2604  * @param attrib Attributes
2605  */
writeKnot(DL_WriterA & dw,const DL_KnotData & data)2606 void DL_Dxf::writeKnot(DL_WriterA& dw,
2607                        const DL_KnotData& data) {
2608 
2609     dw.dxfReal(40, data.k);
2610 }
2611 
2612 
2613 
2614 /**
2615  * Writes a circle entity to the file.
2616  *
2617  * @param dw DXF writer
2618  * @param data Entity data from the file
2619  * @param attrib Attributes
2620  */
writeCircle(DL_WriterA & dw,const DL_CircleData & data,const DL_Attributes & attrib)2621 void DL_Dxf::writeCircle(DL_WriterA& dw,
2622                          const DL_CircleData& data,
2623                          const DL_Attributes& attrib) {
2624     dw.entity("CIRCLE");
2625     if (version==DL_VERSION_2000) {
2626         dw.dxfString(100, "AcDbEntity");
2627     }
2628     dw.entityAttributes(attrib);
2629     if (version==DL_VERSION_2000) {
2630         dw.dxfString(100, "AcDbCircle");
2631     }
2632     dw.coord(10, data.cx, data.cy, data.cz);
2633     dw.dxfReal(40, data.radius);
2634 }
2635 
2636 
2637 
2638 /**
2639  * Writes an arc entity to the file.
2640  *
2641  * @param dw DXF writer
2642  * @param data Entity data from the file
2643  * @param attrib Attributes
2644  */
writeArc(DL_WriterA & dw,const DL_ArcData & data,const DL_Attributes & attrib)2645 void DL_Dxf::writeArc(DL_WriterA& dw,
2646                       const DL_ArcData& data,
2647                       const DL_Attributes& attrib) {
2648     dw.entity("ARC");
2649     if (version==DL_VERSION_2000) {
2650         dw.dxfString(100, "AcDbEntity");
2651     }
2652     dw.entityAttributes(attrib);
2653     if (version==DL_VERSION_2000) {
2654         dw.dxfString(100, "AcDbCircle");
2655     }
2656     dw.coord(10, data.cx, data.cy, data.cz);
2657     dw.dxfReal(40, data.radius);
2658     if (version==DL_VERSION_2000) {
2659         dw.dxfString(100, "AcDbArc");
2660     }
2661     dw.dxfReal(50, data.angle1);
2662     dw.dxfReal(51, data.angle2);
2663 }
2664 
2665 
2666 
2667 /**
2668  * Writes an ellipse entity to the file.
2669  *
2670  * @param dw DXF writer
2671  * @param data Entity data from the file
2672  * @param attrib Attributes
2673  */
writeEllipse(DL_WriterA & dw,const DL_EllipseData & data,const DL_Attributes & attrib)2674 void DL_Dxf::writeEllipse(DL_WriterA& dw,
2675                           const DL_EllipseData& data,
2676                           const DL_Attributes& attrib) {
2677 
2678     if (version>DL_VERSION_R12) {
2679         dw.entity("ELLIPSE");
2680         if (version==DL_VERSION_2000) {
2681             dw.dxfString(100, "AcDbEntity");
2682         }
2683         dw.entityAttributes(attrib);
2684         if (version==DL_VERSION_2000) {
2685             dw.dxfString(100, "AcDbEllipse");
2686         }
2687         dw.coord(10, data.cx, data.cy, data.cz);
2688         dw.coord(11, data.mx, data.my, data.mz);
2689         dw.dxfReal(40, data.ratio);
2690         dw.dxfReal(41, data.angle1);
2691         dw.dxfReal(42, data.angle2);
2692     }
2693 }
2694 
2695 
2696 
2697 /**
2698  * Writes a solid entity to the file.
2699  *
2700  * @param dw DXF writer
2701  * @param data Entity data from the file
2702  * @param attrib Attributes
2703  */
writeSolid(DL_WriterA & dw,const DL_SolidData & data,const DL_Attributes & attrib)2704 void DL_Dxf::writeSolid(DL_WriterA& dw,
2705                    const DL_SolidData& data,
2706                    const DL_Attributes& attrib) {
2707     dw.entity("SOLID");
2708     if (version==DL_VERSION_2000) {
2709         dw.dxfString(100, "AcDbEntity");
2710     }
2711     dw.entityAttributes(attrib);
2712     if (version==DL_VERSION_2000) {
2713         dw.dxfString(100, "AcDbTrace");
2714     }
2715     dw.coord(10, data.x[0], data.y[0], data.z[0]);
2716     dw.coord(11, data.x[1], data.y[1], data.z[1]);
2717     dw.coord(12, data.x[2], data.y[2], data.z[2]);
2718     dw.coord(13, data.x[3], data.y[3], data.z[3]);
2719     dw.dxfReal(39, data.thickness);
2720 }
2721 
2722 /**
2723  * Writes a trace entity to the file.
2724  *
2725  * @param dw DXF writer
2726  * @param data Entity data from the file
2727  * @param attrib Attributes
2728  */
writeTrace(DL_WriterA & dw,const DL_TraceData & data,const DL_Attributes & attrib)2729 void DL_Dxf::writeTrace(DL_WriterA& dw,
2730                         const DL_TraceData& data,
2731                         const DL_Attributes& attrib) {
2732     dw.entity("TRACE");
2733     if (version==DL_VERSION_2000) {
2734         dw.dxfString(100, "AcDbEntity");
2735     }
2736     dw.entityAttributes(attrib);
2737     if (version==DL_VERSION_2000) {
2738         dw.dxfString(100, "AcDbTrace");
2739     }
2740     dw.coord(10, data.x[0], data.y[0], data.z[0]);
2741     dw.coord(11, data.x[1], data.y[1], data.z[1]);
2742     dw.coord(12, data.x[2], data.y[2], data.z[2]);
2743     dw.coord(13, data.x[3], data.y[3], data.z[3]);
2744     dw.dxfReal(39, data.thickness);
2745 }
2746 
2747 
2748 
2749 /**
2750  * Writes a 3d face entity to the file.
2751  *
2752  * @param dw DXF writer
2753  * @param data Entity data from the file
2754  * @param attrib Attributes
2755  */
write3dFace(DL_WriterA & dw,const DL_3dFaceData & data,const DL_Attributes & attrib)2756 void DL_Dxf::write3dFace(DL_WriterA& dw,
2757                    const DL_3dFaceData& data,
2758                    const DL_Attributes& attrib) {
2759     dw.entity("3DFACE");
2760     if (version==DL_VERSION_2000) {
2761         dw.dxfString(100, "AcDbEntity");
2762     }
2763     dw.entityAttributes(attrib);
2764     if (version==DL_VERSION_2000) {
2765         dw.dxfString(100, "AcDbFace");
2766     }
2767     dw.coord(10, data.x[0], data.y[0], data.z[0]);
2768     dw.coord(11, data.x[1], data.y[1], data.z[1]);
2769     dw.coord(12, data.x[2], data.y[2], data.z[2]);
2770     dw.coord(13, data.x[3], data.y[3], data.z[3]);
2771 }
2772 
2773 
2774 
2775 /**
2776  * Writes an insert to the file.
2777  *
2778  * @param dw DXF writer
2779  * @param data Entity data from the file
2780  * @param attrib Attributes
2781  */
writeInsert(DL_WriterA & dw,const DL_InsertData & data,const DL_Attributes & attrib)2782 void DL_Dxf::writeInsert(DL_WriterA& dw,
2783                          const DL_InsertData& data,
2784                          const DL_Attributes& attrib) {
2785 
2786     if (data.name.empty()) {
2787         std::cerr << "DL_Dxf::writeInsert: "
2788         << "Block name must not be empty\n";
2789         return;
2790     }
2791 
2792     dw.entity("INSERT");
2793     if (version==DL_VERSION_2000) {
2794         dw.dxfString(100, "AcDbEntity");
2795     }
2796     dw.entityAttributes(attrib);
2797     if (version==DL_VERSION_2000) {
2798         if (data.cols!=1 || data.rows!=1) {
2799             dw.dxfString(100, "AcDbMInsertBlock");
2800         }
2801         else {
2802             dw.dxfString(100, "AcDbBlockReference");
2803         }
2804     }
2805     dw.dxfString(2, data.name);
2806     dw.dxfReal(10, data.ipx);
2807     dw.dxfReal(20, data.ipy);
2808     dw.dxfReal(30, data.ipz);
2809     if (data.sx!=1.0 || data.sy!=1.0) {
2810         dw.dxfReal(41, data.sx);
2811         dw.dxfReal(42, data.sy);
2812         dw.dxfReal(43, 1.0);
2813     }
2814     if (data.angle!=0.0) {
2815         dw.dxfReal(50, data.angle);
2816     }
2817     if (data.cols!=1 || data.rows!=1) {
2818         dw.dxfInt(70, data.cols);
2819         dw.dxfInt(71, data.rows);
2820     }
2821     if (data.colSp!=0.0 || data.rowSp!=0.0) {
2822         dw.dxfReal(44, data.colSp);
2823         dw.dxfReal(45, data.rowSp);
2824     }
2825 }
2826 
2827 
2828 
2829 /**
2830  * Writes a multi text entity to the file.
2831  *
2832  * @param dw DXF writer
2833  * @param data Entity data from the file
2834  * @param attrib Attributes
2835  */
writeMText(DL_WriterA & dw,const DL_MTextData & data,const DL_Attributes & attrib)2836 void DL_Dxf::writeMText(DL_WriterA& dw,
2837                         const DL_MTextData& data,
2838                         const DL_Attributes& attrib) {
2839 
2840     dw.entity("MTEXT");
2841     if (version==DL_VERSION_2000) {
2842         dw.dxfString(100, "AcDbEntity");
2843     }
2844     dw.entityAttributes(attrib);
2845     if (version==DL_VERSION_2000) {
2846         dw.dxfString(100, "AcDbMText");
2847     }
2848     dw.dxfReal(10, data.ipx);
2849     dw.dxfReal(20, data.ipy);
2850     dw.dxfReal(30, data.ipz);
2851     dw.dxfReal(40, data.height);
2852     dw.dxfReal(41, data.width);
2853 
2854     dw.dxfInt(71, data.attachmentPoint);
2855     dw.dxfInt(72, data.drawingDirection);
2856 
2857     // Creare text chunks of 250 characters each:
2858     int length = data.text.length();
2859     char chunk[251];
2860     int i;
2861     for (i=250; i<length; i+=250) {
2862         strncpy(chunk, &data.text.c_str()[i-250], 250);
2863         chunk[250]='\0';
2864         dw.dxfString(3, chunk);
2865     }
2866     strncpy(chunk, &data.text.c_str()[i-250], 250);
2867     chunk[250]='\0';
2868     dw.dxfString(1, chunk);
2869 
2870     dw.dxfString(7, data.style);
2871 
2872     // since dxflib 2.0.2.1: degrees not rad (error in autodesk dxf doc)
2873     dw.dxfReal(50, data.angle/(2.0*M_PI)*360.0);
2874 
2875     dw.dxfInt(73, data.lineSpacingStyle);
2876     dw.dxfReal(44, data.lineSpacingFactor);
2877 }
2878 
2879 
2880 
2881 /**
2882  * Writes a text entity to the file.
2883  *
2884  * @param dw DXF writer
2885  * @param data Entity data from the file
2886  * @param attrib Attributes
2887  */
writeText(DL_WriterA & dw,const DL_TextData & data,const DL_Attributes & attrib)2888 void DL_Dxf::writeText(DL_WriterA& dw,
2889                        const DL_TextData& data,
2890                        const DL_Attributes& attrib) {
2891 
2892     dw.entity("TEXT");
2893     if (version==DL_VERSION_2000) {
2894         dw.dxfString(100, "AcDbEntity");
2895     }
2896     dw.entityAttributes(attrib);
2897     if (version==DL_VERSION_2000) {
2898         dw.dxfString(100, "AcDbText");
2899     }
2900     dw.dxfReal(10, data.ipx);
2901     dw.dxfReal(20, data.ipy);
2902     dw.dxfReal(30, data.ipz);
2903     dw.dxfReal(40, data.height);
2904     dw.dxfString(1, data.text);
2905     dw.dxfReal(50, data.angle/(2*M_PI)*360.0);
2906     dw.dxfReal(41, data.xScaleFactor);
2907     dw.dxfString(7, data.style);
2908 
2909     dw.dxfInt(71, data.textGenerationFlags);
2910     dw.dxfInt(72, data.hJustification);
2911 
2912     dw.dxfReal(11, data.apx);
2913     dw.dxfReal(21, data.apy);
2914     dw.dxfReal(31, data.apz);
2915 
2916     if (version==DL_VERSION_2000) {
2917         // required twice for some reason:
2918         dw.dxfString(100, "AcDbText");
2919     }
2920 
2921     dw.dxfInt(73, data.vJustification);
2922 }
2923 
writeAttribute(DL_WriterA & dw,const DL_AttributeData & data,const DL_Attributes & attrib)2924 void DL_Dxf::writeAttribute(DL_WriterA& dw,
2925                    const DL_AttributeData& data,
2926                    const DL_Attributes& attrib) {
2927 
2928     dw.entity("ATTRIB");
2929     if (version==DL_VERSION_2000) {
2930         dw.dxfString(100, "AcDbEntity");
2931     }
2932     dw.entityAttributes(attrib);
2933     if (version==DL_VERSION_2000) {
2934         dw.dxfString(100, "AcDbText");
2935     }
2936     dw.dxfReal(10, data.ipx);
2937     dw.dxfReal(20, data.ipy);
2938     dw.dxfReal(30, data.ipz);
2939     dw.dxfReal(40, data.height);
2940     dw.dxfString(1, data.text);
2941     dw.dxfReal(50, data.angle/(2*M_PI)*360.0);
2942     dw.dxfReal(41, data.xScaleFactor);
2943     dw.dxfString(7, data.style);
2944 
2945     dw.dxfInt(71, data.textGenerationFlags);
2946     dw.dxfInt(72, data.hJustification);
2947 
2948     dw.dxfReal(11, data.apx);
2949     dw.dxfReal(21, data.apy);
2950     dw.dxfReal(31, data.apz);
2951 
2952     if (version==DL_VERSION_2000) {
2953         dw.dxfString(100, "AcDbAttribute");
2954     }
2955 
2956     dw.dxfString(2, data.tag);
2957     dw.dxfInt(74, data.vJustification);
2958 }
2959 
writeDimStyleOverrides(DL_WriterA & dw,const DL_DimensionData & data)2960 void DL_Dxf::writeDimStyleOverrides(DL_WriterA& dw,
2961                              const DL_DimensionData& data) {
2962 
2963     if (version==DL_VERSION_2000) {
2964         dw.dxfString(1001, "ACAD");
2965         dw.dxfString(1000, "DSTYLE");
2966         dw.dxfString(1002, "{");
2967         dw.dxfInt(1070, 144);
2968         dw.dxfReal(1040, data.linearFactor);
2969         dw.dxfInt(1070,40);
2970         dw.dxfReal(1040, data.dimScale);
2971         dw.dxfString(1002, "}");
2972     }
2973 }
2974 
2975 
2976 /**
2977  * Writes an aligned dimension entity to the file.
2978  *
2979  * @param dw DXF writer
2980  * @param data Generic dimension data for from the file
2981  * @param data Specific aligned dimension data from the file
2982  * @param attrib Attributes
2983  */
writeDimAligned(DL_WriterA & dw,const DL_DimensionData & data,const DL_DimAlignedData & edata,const DL_Attributes & attrib)2984 void DL_Dxf::writeDimAligned(DL_WriterA& dw,
2985                              const DL_DimensionData& data,
2986                              const DL_DimAlignedData& edata,
2987                              const DL_Attributes& attrib) {
2988 
2989     dw.entity("DIMENSION");
2990 
2991     if (version==DL_VERSION_2000) {
2992         dw.dxfString(100, "AcDbEntity");
2993     }
2994     dw.entityAttributes(attrib);
2995     if (version==DL_VERSION_2000) {
2996         dw.dxfString(100, "AcDbDimension");
2997     }
2998 
2999     dw.dxfReal(10, data.dpx);
3000     dw.dxfReal(20, data.dpy);
3001     dw.dxfReal(30, data.dpz);
3002 
3003     dw.dxfReal(11, data.mpx);
3004     dw.dxfReal(21, data.mpy);
3005     dw.dxfReal(31, 0.0);
3006 
3007     dw.dxfInt(70, data.type);
3008     if (version>DL_VERSION_R12) {
3009         dw.dxfInt(71, data.attachmentPoint);
3010         dw.dxfInt(72, data.lineSpacingStyle); // opt
3011         dw.dxfReal(41, data.lineSpacingFactor); // opt
3012     }
3013 
3014     dw.dxfReal(42, data.angle);
3015 
3016     dw.dxfString(1, data.text);   // opt
3017     //dw.dxfString(3, data.style);
3018     dw.dxfString(3, "Standard");
3019 
3020     if (version==DL_VERSION_2000) {
3021         dw.dxfString(100, "AcDbAlignedDimension");
3022     }
3023 
3024     dw.dxfReal(13, edata.epx1);
3025     dw.dxfReal(23, edata.epy1);
3026     dw.dxfReal(33, 0.0);
3027 
3028     dw.dxfReal(14, edata.epx2);
3029     dw.dxfReal(24, edata.epy2);
3030     dw.dxfReal(34, 0.0);
3031 
3032     writeDimStyleOverrides(dw, data);
3033 }
3034 
3035 
3036 
3037 /**
3038  * Writes a linear dimension entity to the file.
3039  *
3040  * @param dw DXF writer
3041  * @param data Generic dimension data for from the file
3042  * @param data Specific linear dimension data from the file
3043  * @param attrib Attributes
3044  */
writeDimLinear(DL_WriterA & dw,const DL_DimensionData & data,const DL_DimLinearData & edata,const DL_Attributes & attrib)3045 void DL_Dxf::writeDimLinear(DL_WriterA& dw,
3046                             const DL_DimensionData& data,
3047                             const DL_DimLinearData& edata,
3048                             const DL_Attributes& attrib) {
3049 
3050     dw.entity("DIMENSION");
3051 
3052     if (version==DL_VERSION_2000) {
3053         dw.dxfString(100, "AcDbEntity");
3054     }
3055     dw.entityAttributes(attrib);
3056     if (version==DL_VERSION_2000) {
3057         dw.dxfString(100, "AcDbDimension");
3058     }
3059 
3060     dw.dxfReal(10, data.dpx);
3061     dw.dxfReal(20, data.dpy);
3062     dw.dxfReal(30, data.dpz);
3063 
3064     dw.dxfReal(11, data.mpx);
3065     dw.dxfReal(21, data.mpy);
3066     dw.dxfReal(31, 0.0);
3067 
3068     dw.dxfInt(70, data.type);
3069     if (version>DL_VERSION_R12) {
3070         dw.dxfInt(71, data.attachmentPoint);
3071         dw.dxfInt(72, data.lineSpacingStyle); // opt
3072         dw.dxfReal(41, data.lineSpacingFactor); // opt
3073     }
3074 
3075     dw.dxfReal(42, data.angle);
3076 
3077     dw.dxfString(1, data.text);   // opt
3078     //dw.dxfString(3, data.style);
3079     dw.dxfString(3, "Standard");
3080 
3081     if (version==DL_VERSION_2000) {
3082         dw.dxfString(100, "AcDbAlignedDimension");
3083     }
3084 
3085     dw.dxfReal(13, edata.dpx1);
3086     dw.dxfReal(23, edata.dpy1);
3087     dw.dxfReal(33, 0.0);
3088 
3089     dw.dxfReal(14, edata.dpx2);
3090     dw.dxfReal(24, edata.dpy2);
3091     dw.dxfReal(34, 0.0);
3092 
3093     dw.dxfReal(50, edata.angle/(2.0*M_PI)*360.0);
3094 
3095     if (version==DL_VERSION_2000) {
3096         dw.dxfString(100, "AcDbRotatedDimension");
3097     }
3098 
3099     writeDimStyleOverrides(dw, data);
3100 }
3101 
3102 
3103 
3104 /**
3105  * Writes a radial dimension entity to the file.
3106  *
3107  * @param dw DXF writer
3108  * @param data Generic dimension data for from the file
3109  * @param data Specific radial dimension data from the file
3110  * @param attrib Attributes
3111  */
writeDimRadial(DL_WriterA & dw,const DL_DimensionData & data,const DL_DimRadialData & edata,const DL_Attributes & attrib)3112 void DL_Dxf::writeDimRadial(DL_WriterA& dw,
3113                             const DL_DimensionData& data,
3114                             const DL_DimRadialData& edata,
3115                             const DL_Attributes& attrib) {
3116 
3117     dw.entity("DIMENSION");
3118 
3119     if (version==DL_VERSION_2000) {
3120         dw.dxfString(100, "AcDbEntity");
3121     }
3122     dw.entityAttributes(attrib);
3123     if (version==DL_VERSION_2000) {
3124         dw.dxfString(100, "AcDbDimension");
3125     }
3126 
3127     dw.dxfReal(10, data.dpx);
3128     dw.dxfReal(20, data.dpy);
3129     dw.dxfReal(30, data.dpz);
3130 
3131     dw.dxfReal(11, data.mpx);
3132     dw.dxfReal(21, data.mpy);
3133     dw.dxfReal(31, 0.0);
3134 
3135     dw.dxfInt(70, data.type);
3136     if (version>DL_VERSION_R12) {
3137         dw.dxfInt(71, data.attachmentPoint);
3138         dw.dxfInt(72, data.lineSpacingStyle); // opt
3139         dw.dxfReal(41, data.lineSpacingFactor); // opt
3140     }
3141 
3142     dw.dxfReal(42, data.angle);
3143 
3144     dw.dxfString(1, data.text);   // opt
3145     //dw.dxfString(3, data.style);
3146     dw.dxfString(3, "Standard");
3147 
3148     if (version==DL_VERSION_2000) {
3149         dw.dxfString(100, "AcDbRadialDimension");
3150     }
3151 
3152     dw.dxfReal(15, edata.dpx);
3153     dw.dxfReal(25, edata.dpy);
3154     dw.dxfReal(35, 0.0);
3155 
3156     dw.dxfReal(40, edata.leader);
3157 
3158     writeDimStyleOverrides(dw, data);
3159 }
3160 
3161 
3162 
3163 /**
3164  * Writes a diametric dimension entity to the file.
3165  *
3166  * @param dw DXF writer
3167  * @param data Generic dimension data for from the file
3168  * @param data Specific diametric dimension data from the file
3169  * @param attrib Attributes
3170  */
writeDimDiametric(DL_WriterA & dw,const DL_DimensionData & data,const DL_DimDiametricData & edata,const DL_Attributes & attrib)3171 void DL_Dxf::writeDimDiametric(DL_WriterA& dw,
3172                                const DL_DimensionData& data,
3173                                const DL_DimDiametricData& edata,
3174                                const DL_Attributes& attrib) {
3175 
3176     dw.entity("DIMENSION");
3177 
3178     if (version==DL_VERSION_2000) {
3179         dw.dxfString(100, "AcDbEntity");
3180     }
3181     dw.entityAttributes(attrib);
3182     if (version==DL_VERSION_2000) {
3183         dw.dxfString(100, "AcDbDimension");
3184     }
3185 
3186     dw.dxfReal(10, data.dpx);
3187     dw.dxfReal(20, data.dpy);
3188     dw.dxfReal(30, data.dpz);
3189 
3190     dw.dxfReal(11, data.mpx);
3191     dw.dxfReal(21, data.mpy);
3192     dw.dxfReal(31, 0.0);
3193 
3194     dw.dxfInt(70, data.type);
3195     if (version>DL_VERSION_R12) {
3196         dw.dxfInt(71, data.attachmentPoint);
3197         dw.dxfInt(72, data.lineSpacingStyle); // opt
3198         dw.dxfReal(41, data.lineSpacingFactor); // opt
3199     }
3200 
3201     dw.dxfReal(42, data.angle);
3202 
3203     dw.dxfString(1, data.text);   // opt
3204     //dw.dxfString(3, data.style);
3205     dw.dxfString(3, "Standard");
3206 
3207     if (version==DL_VERSION_2000) {
3208         dw.dxfString(100, "AcDbDiametricDimension");
3209     }
3210 
3211     dw.dxfReal(15, edata.dpx);
3212     dw.dxfReal(25, edata.dpy);
3213     dw.dxfReal(35, 0.0);
3214 
3215     dw.dxfReal(40, edata.leader);
3216 
3217     writeDimStyleOverrides(dw, data);
3218 }
3219 
3220 
3221 
3222 /**
3223  * Writes an angular dimension entity to the file.
3224  *
3225  * @param dw DXF writer
3226  * @param data Generic dimension data for from the file
3227  * @param data Specific angular dimension data from the file
3228  * @param attrib Attributes
3229  */
writeDimAngular(DL_WriterA & dw,const DL_DimensionData & data,const DL_DimAngularData & edata,const DL_Attributes & attrib)3230 void DL_Dxf::writeDimAngular(DL_WriterA& dw,
3231                              const DL_DimensionData& data,
3232                              const DL_DimAngularData& edata,
3233                              const DL_Attributes& attrib) {
3234 
3235     dw.entity("DIMENSION");
3236 
3237     if (version==DL_VERSION_2000) {
3238         dw.dxfString(100, "AcDbEntity");
3239     }
3240     dw.entityAttributes(attrib);
3241     if (version==DL_VERSION_2000) {
3242         dw.dxfString(100, "AcDbDimension");
3243     }
3244 
3245     dw.dxfReal(10, data.dpx);
3246     dw.dxfReal(20, data.dpy);
3247     dw.dxfReal(30, data.dpz);
3248 
3249     dw.dxfReal(11, data.mpx);
3250     dw.dxfReal(21, data.mpy);
3251     dw.dxfReal(31, 0.0);
3252 
3253     dw.dxfInt(70, data.type);
3254     if (version>DL_VERSION_R12) {
3255         dw.dxfInt(71, data.attachmentPoint);
3256         dw.dxfInt(72, data.lineSpacingStyle); // opt
3257         dw.dxfReal(41, data.lineSpacingFactor); // opt
3258     }
3259 
3260     dw.dxfReal(42, data.angle);
3261 
3262     dw.dxfString(1, data.text);   // opt
3263     //dw.dxfString(3, data.style);
3264     dw.dxfString(3, "Standard");
3265 
3266     if (version==DL_VERSION_2000) {
3267         dw.dxfString(100, "AcDb2LineAngularDimension");
3268     }
3269 
3270     dw.dxfReal(13, edata.dpx1);
3271     dw.dxfReal(23, edata.dpy1);
3272     dw.dxfReal(33, 0.0);
3273 
3274     dw.dxfReal(14, edata.dpx2);
3275     dw.dxfReal(24, edata.dpy2);
3276     dw.dxfReal(34, 0.0);
3277 
3278     dw.dxfReal(15, edata.dpx3);
3279     dw.dxfReal(25, edata.dpy3);
3280     dw.dxfReal(35, 0.0);
3281 
3282     dw.dxfReal(16, edata.dpx4);
3283     dw.dxfReal(26, edata.dpy4);
3284     dw.dxfReal(36, 0.0);
3285 }
3286 
3287 
3288 
3289 /**
3290  * Writes an angular dimension entity (3 points version) to the file.
3291  *
3292  * @param dw DXF writer
3293  * @param data Generic dimension data for from the file
3294  * @param data Specific angular dimension data from the file
3295  * @param attrib Attributes
3296  */
writeDimAngular3P(DL_WriterA & dw,const DL_DimensionData & data,const DL_DimAngular3PData & edata,const DL_Attributes & attrib)3297 void DL_Dxf::writeDimAngular3P(DL_WriterA& dw,
3298                                const DL_DimensionData& data,
3299                                const DL_DimAngular3PData& edata,
3300                                const DL_Attributes& attrib) {
3301 
3302     dw.entity("DIMENSION");
3303 
3304     if (version==DL_VERSION_2000) {
3305         dw.dxfString(100, "AcDbEntity");
3306     }
3307     dw.entityAttributes(attrib);
3308     if (version==DL_VERSION_2000) {
3309         dw.dxfString(100, "AcDbDimension");
3310     }
3311 
3312     dw.dxfReal(10, data.dpx);
3313     dw.dxfReal(20, data.dpy);
3314     dw.dxfReal(30, data.dpz);
3315 
3316     dw.dxfReal(11, data.mpx);
3317     dw.dxfReal(21, data.mpy);
3318     dw.dxfReal(31, 0.0);
3319 
3320     dw.dxfInt(70, data.type);
3321     if (version>DL_VERSION_R12) {
3322         dw.dxfInt(71, data.attachmentPoint);
3323         dw.dxfInt(72, data.lineSpacingStyle); // opt
3324         dw.dxfReal(41, data.lineSpacingFactor); // opt
3325     }
3326 
3327     dw.dxfReal(42, data.angle);
3328 
3329     dw.dxfString(1, data.text);   // opt
3330     //dw.dxfString(3, data.style);
3331     dw.dxfString(3, "Standard");
3332 
3333     if (version==DL_VERSION_2000) {
3334         dw.dxfString(100, "AcDb3PointAngularDimension");
3335     }
3336 
3337     dw.dxfReal(13, edata.dpx1);
3338     dw.dxfReal(23, edata.dpy1);
3339     dw.dxfReal(33, 0.0);
3340 
3341     dw.dxfReal(14, edata.dpx2);
3342     dw.dxfReal(24, edata.dpy2);
3343     dw.dxfReal(34, 0.0);
3344 
3345     dw.dxfReal(15, edata.dpx3);
3346     dw.dxfReal(25, edata.dpy3);
3347     dw.dxfReal(35, 0.0);
3348 }
3349 
3350 
3351 
3352 
3353 /**
3354  * Writes an ordinate dimension entity to the file.
3355  *
3356  * @param dw DXF writer
3357  * @param data Generic dimension data for from the file
3358  * @param data Specific ordinate dimension data from the file
3359  * @param attrib Attributes
3360  */
writeDimOrdinate(DL_WriterA & dw,const DL_DimensionData & data,const DL_DimOrdinateData & edata,const DL_Attributes & attrib)3361 void DL_Dxf::writeDimOrdinate(DL_WriterA& dw,
3362                              const DL_DimensionData& data,
3363                              const DL_DimOrdinateData& edata,
3364                              const DL_Attributes& attrib) {
3365 
3366     dw.entity("DIMENSION");
3367 
3368     if (version==DL_VERSION_2000) {
3369         dw.dxfString(100, "AcDbEntity");
3370     }
3371     dw.entityAttributes(attrib);
3372     if (version==DL_VERSION_2000) {
3373         dw.dxfString(100, "AcDbDimension");
3374     }
3375 
3376     dw.dxfReal(10, data.dpx);
3377     dw.dxfReal(20, data.dpy);
3378     dw.dxfReal(30, data.dpz);
3379 
3380     dw.dxfReal(11, data.mpx);
3381     dw.dxfReal(21, data.mpy);
3382     dw.dxfReal(31, 0.0);
3383 
3384     int type = data.type;
3385     if (edata.xtype) {
3386         type|=0x40;
3387     }
3388 
3389     dw.dxfInt(70, type);
3390     if (version>DL_VERSION_R12) {
3391         dw.dxfInt(71, data.attachmentPoint);
3392         dw.dxfInt(72, data.lineSpacingStyle); // opt
3393         dw.dxfReal(41, data.lineSpacingFactor); // opt
3394     }
3395 
3396     dw.dxfString(1, data.text);   // opt
3397     //dw.dxfString(3, data.style);
3398     dw.dxfString(3, "Standard");
3399 
3400     if (version==DL_VERSION_2000) {
3401         dw.dxfString(100, "AcDbOrdinateDimension");
3402     }
3403 
3404     dw.dxfReal(13, edata.dpx1);
3405     dw.dxfReal(23, edata.dpy1);
3406     dw.dxfReal(33, 0.0);
3407 
3408     dw.dxfReal(14, edata.dpx2);
3409     dw.dxfReal(24, edata.dpy2);
3410     dw.dxfReal(34, 0.0);
3411 }
3412 
3413 
3414 
3415 /**
3416  * Writes a leader entity to the file.
3417  *
3418  * @param dw DXF writer
3419  * @param data Entity data from the file
3420  * @param attrib Attributes
3421  * @see writeVertex
3422  */
writeLeader(DL_WriterA & dw,const DL_LeaderData & data,const DL_Attributes & attrib)3423 void DL_Dxf::writeLeader(DL_WriterA& dw,
3424                          const DL_LeaderData& data,
3425                          const DL_Attributes& attrib) {
3426     if (version>DL_VERSION_R12) {
3427         dw.entity("LEADER");
3428         if (version==DL_VERSION_2000) {
3429             dw.dxfString(100, "AcDbEntity");
3430         }
3431         dw.entityAttributes(attrib);
3432         if (version==DL_VERSION_2000) {
3433             dw.dxfString(100, "AcDbLeader");
3434         }
3435         dw.dxfString(3, "Standard");
3436         dw.dxfInt(71, data.arrowHeadFlag);
3437         dw.dxfInt(72, data.leaderPathType);
3438         dw.dxfInt(73, data.leaderCreationFlag);
3439         dw.dxfInt(74, data.hooklineDirectionFlag);
3440         dw.dxfInt(75, data.hooklineFlag);
3441         dw.dxfReal(40, data.textAnnotationHeight);
3442         dw.dxfReal(41, data.textAnnotationWidth);
3443         dw.dxfInt(76, data.number);
3444     }
3445 }
3446 
3447 
3448 
3449 /**
3450  * Writes a single vertex of a leader to the file.
3451  *
3452  * @param dw DXF writer
3453  * @param data Entity data
3454  */
writeLeaderVertex(DL_WriterA & dw,const DL_LeaderVertexData & data)3455 void DL_Dxf::writeLeaderVertex(DL_WriterA& dw,
3456                                const DL_LeaderVertexData& data) {
3457     if (version>DL_VERSION_R12) {
3458         dw.dxfReal(10, data.x);
3459         dw.dxfReal(20, data.y);
3460     }
3461 }
3462 
3463 
3464 
3465 /**
3466  * Writes the beginning of a hatch entity to the file.
3467  * This must be followed by one or more writeHatchLoop()
3468  * calls and a writeHatch2() call.
3469  *
3470  * @param dw DXF writer
3471  * @param data Entity data.
3472  * @param attrib Attributes
3473  */
writeHatch1(DL_WriterA & dw,const DL_HatchData & data,const DL_Attributes & attrib)3474 void DL_Dxf::writeHatch1(DL_WriterA& dw,
3475                          const DL_HatchData& data,
3476                          const DL_Attributes& attrib) {
3477 
3478     dw.entity("HATCH");
3479     if (version==DL_VERSION_2000) {
3480         dw.dxfString(100, "AcDbEntity");
3481     }
3482     dw.entityAttributes(attrib);
3483     if (version==DL_VERSION_2000) {
3484         dw.dxfString(100, "AcDbHatch");
3485     }
3486     dw.dxfReal(10, 0.0);             // elevation
3487     dw.dxfReal(20, 0.0);
3488     dw.dxfReal(30, 0.0);
3489     dw.dxfReal(210, 0.0);             // extrusion dir.
3490     dw.dxfReal(220, 0.0);
3491     dw.dxfReal(230, 1.0);
3492     if (data.solid==false) {
3493         dw.dxfString(2, data.pattern);
3494     } else {
3495         dw.dxfString(2, "SOLID");
3496     }
3497     dw.dxfInt(70, (int)data.solid);
3498     dw.dxfInt(71, 0);                // non-associative
3499     dw.dxfInt(91, data.numLoops);
3500 }
3501 
3502 
3503 
3504 /**
3505  * Writes the end of a hatch entity to the file.
3506  *
3507  * @param dw DXF writer
3508  * @param data Entity data.
3509  * @param attrib Attributes
3510  */
writeHatch2(DL_WriterA & dw,const DL_HatchData & data,const DL_Attributes &)3511 void DL_Dxf::writeHatch2(DL_WriterA& dw,
3512                          const DL_HatchData& data,
3513                          const DL_Attributes& /*attrib*/) {
3514 
3515     dw.dxfInt(75, 0);                // odd parity
3516     dw.dxfInt(76, 1);                // pattern type
3517     if (data.solid==false) {
3518         dw.dxfReal(52, data.angle);
3519         dw.dxfReal(41, data.scale);
3520         dw.dxfInt(77, 0);            // not double
3521         //dw.dxfInt(78, 0);
3522         dw.dxfInt(78, 1);
3523         dw.dxfReal(53, 45.0);
3524         dw.dxfReal(43, 0.0);
3525         dw.dxfReal(44, 0.0);
3526         dw.dxfReal(45, -0.0883883476483184);
3527         dw.dxfReal(46, 0.0883883476483185);
3528         dw.dxfInt(79, 0);
3529     }
3530     dw.dxfInt(98, 0);
3531 
3532     if (version==DL_VERSION_2000) {
3533         dw.dxfString(1001, "ACAD");
3534         dw.dxfReal(1010, data.originX);
3535         dw.dxfReal(1020, data.originY);
3536         dw.dxfInt(1030, 0.0);
3537     }
3538 }
3539 
3540 
3541 
3542 /**
3543  * Writes the beginning of a hatch loop to the file. This
3544  * must happen after writing the beginning of a hatch entity.
3545  *
3546  * @param dw DXF writer
3547  * @param data Entity data.
3548  * @param attrib Attributes
3549  */
writeHatchLoop1(DL_WriterA & dw,const DL_HatchLoopData & data)3550 void DL_Dxf::writeHatchLoop1(DL_WriterA& dw,
3551                              const DL_HatchLoopData& data) {
3552 
3553     dw.dxfInt(92, 1);
3554     dw.dxfInt(93, data.numEdges);
3555     //dw.dxfInt(97, 0);
3556 }
3557 
3558 
3559 
3560 /**
3561  * Writes the end of a hatch loop to the file.
3562  *
3563  * @param dw DXF writer
3564  * @param data Entity data.
3565  * @param attrib Attributes
3566  */
writeHatchLoop2(DL_WriterA & dw,const DL_HatchLoopData &)3567 void DL_Dxf::writeHatchLoop2(DL_WriterA& dw,
3568                              const DL_HatchLoopData& /*data*/) {
3569 
3570     dw.dxfInt(97, 0);
3571 }
3572 
3573 
3574 /**
3575  * Writes the beginning of a hatch entity to the file.
3576  *
3577  * @param dw DXF writer
3578  * @param data Entity data.
3579  * @param attrib Attributes
3580  */
writeHatchEdge(DL_WriterA & dw,const DL_HatchEdgeData & data)3581 void DL_Dxf::writeHatchEdge(DL_WriterA& dw,
3582                             const DL_HatchEdgeData& data) {
3583 
3584     if (data.type<1 || data.type>4) {
3585         printf("WARNING: unsupported hatch edge type: %d", data.type);
3586     }
3587 
3588     dw.dxfInt(72, data.type);
3589 
3590     switch (data.type) {
3591     // line:
3592     case 1:
3593         dw.dxfReal(10, data.x1);
3594         dw.dxfReal(20, data.y1);
3595         dw.dxfReal(11, data.x2);
3596         dw.dxfReal(21, data.y2);
3597         break;
3598 
3599     // arc:
3600     case 2:
3601         dw.dxfReal(10, data.cx);
3602         dw.dxfReal(20, data.cy);
3603         dw.dxfReal(40, data.radius);
3604         dw.dxfReal(50, data.angle1/(2*M_PI)*360.0);
3605         dw.dxfReal(51, data.angle2/(2*M_PI)*360.0);
3606         dw.dxfInt(73, (int)(data.ccw));
3607         break;
3608 
3609     // ellipse arc:
3610     case 3:
3611         dw.dxfReal(10, data.cx);
3612         dw.dxfReal(20, data.cy);
3613         dw.dxfReal(11, data.mx);
3614         dw.dxfReal(21, data.my);
3615         dw.dxfReal(40, data.ratio);
3616         dw.dxfReal(50, data.angle1/(2*M_PI)*360.0);
3617         dw.dxfReal(51, data.angle2/(2*M_PI)*360.0);
3618         dw.dxfInt(73, (int)(data.ccw));
3619         break;
3620 
3621     // spline:
3622     case 4:
3623         dw.dxfInt(94, data.degree);
3624         dw.dxfBool(73, data.rational);
3625         dw.dxfBool(74, data.periodic);
3626         dw.dxfInt(95, data.nKnots);
3627         dw.dxfInt(96, data.nControl);
3628         for (unsigned int i=0; i<data.knots.size(); i++) {
3629             dw.dxfReal(40, data.knots[i]);
3630         }
3631         for (unsigned int i=0; i<data.controlPoints.size(); i++) {
3632             dw.dxfReal(10, data.controlPoints[i][0]);
3633             dw.dxfReal(20, data.controlPoints[i][1]);
3634         }
3635         for (unsigned int i=0; i<data.weights.size(); i++) {
3636             dw.dxfReal(42, data.weights[i]);
3637         }
3638         if (data.nFit>0) {
3639             dw.dxfInt(97, data.nFit);
3640             for (unsigned int i=0; i<data.fitPoints.size(); i++) {
3641                 dw.dxfReal(11, data.fitPoints[i][0]);
3642                 dw.dxfReal(21, data.fitPoints[i][1]);
3643             }
3644         }
3645         if (fabs(data.startTangentX)>1.0e-4 || fabs(data.startTangentY)>1.0e-4) {
3646             dw.dxfReal(12, data.startTangentX);
3647             dw.dxfReal(22, data.startTangentY);
3648         }
3649         if (fabs(data.endTangentX)>1.0e-4 || fabs(data.endTangentY)>1.0e-4) {
3650             dw.dxfReal(13, data.endTangentX);
3651             dw.dxfReal(23, data.endTangentY);
3652         }
3653         break;
3654 
3655     default:
3656         break;
3657     }
3658 }
3659 
3660 
3661 
3662 /**
3663  * Writes an image entity.
3664  *
3665  * @return IMAGEDEF handle. Needed for the IMAGEDEF counterpart.
3666  */
writeImage(DL_WriterA & dw,const DL_ImageData & data,const DL_Attributes & attrib)3667 int DL_Dxf::writeImage(DL_WriterA& dw,
3668                        const DL_ImageData& data,
3669                        const DL_Attributes& attrib) {
3670 
3671     /*if (data.file.empty()) {
3672         std::cerr << "DL_Dxf::writeImage: "
3673         << "Image file must not be empty\n";
3674         return;
3675 }*/
3676 
3677     dw.entity("IMAGE");
3678 
3679     if (version==DL_VERSION_2000) {
3680         dw.dxfString(100, "AcDbEntity");
3681     }
3682     dw.entityAttributes(attrib);
3683     if (version==DL_VERSION_2000) {
3684         dw.dxfString(100, "AcDbRasterImage");
3685         dw.dxfInt(90, 0);
3686     }
3687     // insertion point
3688     dw.dxfReal(10, data.ipx);
3689     dw.dxfReal(20, data.ipy);
3690     dw.dxfReal(30, data.ipz);
3691 
3692     // vector along bottom side (1 pixel long)
3693     dw.dxfReal(11, data.ux);
3694     dw.dxfReal(21, data.uy);
3695     dw.dxfReal(31, data.uz);
3696 
3697     // vector along left side (1 pixel long)
3698     dw.dxfReal(12, data.vx);
3699     dw.dxfReal(22, data.vy);
3700     dw.dxfReal(32, data.vz);
3701 
3702     // image size in pixel
3703     dw.dxfReal(13, data.width);
3704     dw.dxfReal(23, data.height);
3705 
3706     // handle of IMAGEDEF object
3707     int handle = dw.incHandle();
3708     dw.dxfHex(340, handle);
3709 
3710     // flags
3711     dw.dxfInt(70, 15);
3712 
3713     // clipping:
3714     dw.dxfInt(280, 0);
3715 
3716     // brightness, contrast, fade
3717     dw.dxfInt(281, data.brightness);
3718     dw.dxfInt(282, data.contrast);
3719     dw.dxfInt(283, data.fade);
3720 
3721     return handle;
3722 }
3723 
3724 
3725 
3726 /**
3727  * Writes an image definiition entity.
3728  */
writeImageDef(DL_WriterA & dw,int handle,const DL_ImageData & data)3729 void DL_Dxf::writeImageDef(DL_WriterA& dw,
3730                            int handle,
3731                            const DL_ImageData& data) {
3732 
3733     /*if (data.file.empty()) {
3734         std::cerr << "DL_Dxf::writeImage: "
3735         << "Image file must not be empty\n";
3736         return;
3737 }*/
3738 
3739     dw.dxfString(0, "IMAGEDEF");
3740     if (version==DL_VERSION_2000) {
3741         dw.dxfHex(5, handle);
3742     }
3743 
3744     if (version==DL_VERSION_2000) {
3745         dw.dxfString(100, "AcDbRasterImageDef");
3746         dw.dxfInt(90, 0);
3747     }
3748     // file name:
3749     dw.dxfString(1, data.ref);
3750 
3751     // image size in pixel
3752     dw.dxfReal(10, data.width);
3753     dw.dxfReal(20, data.height);
3754 
3755     dw.dxfReal(11, 1.0);
3756     dw.dxfReal(21, 1.0);
3757 
3758     // loaded:
3759     dw.dxfInt(280, 1);
3760     // units:
3761     dw.dxfInt(281, 0);
3762 }
3763 
3764 
3765 /**
3766  * Writes a layer to the file. Layers are stored in the
3767  * tables section of a DXF file.
3768  *
3769  * @param dw DXF writer
3770  * @param data Entity data from the file
3771  * @param attrib Attributes
3772  */
writeLayer(DL_WriterA & dw,const DL_LayerData & data,const DL_Attributes & attrib)3773 void DL_Dxf::writeLayer(DL_WriterA& dw,
3774                         const DL_LayerData& data,
3775                         const DL_Attributes& attrib) {
3776 
3777     if (data.name.empty()) {
3778         std::cerr << "DL_Dxf::writeLayer: "
3779         << "Layer name must not be empty\n";
3780         return;
3781     }
3782 
3783     int color = attrib.getColor();
3784     if (color>=256) {
3785         std::cerr << "Layer color cannot be " << color << ". Changed to 7.\n";
3786         color = 7;
3787     }
3788     if (data.off) {
3789         // negative color value means layer is off:
3790         color = -color;
3791     }
3792 
3793     if (data.name == "0") {
3794         dw.tableLayerEntry(0x10);
3795     } else {
3796         dw.tableLayerEntry();
3797     }
3798 
3799     dw.dxfString(2, data.name);
3800     dw.dxfInt(70, data.flags);
3801     dw.dxfInt(62, color);
3802     if (version>=DL_VERSION_2000 && attrib.getColor24()!=-1) {
3803         dw.dxfInt(420, attrib.getColor24());
3804     }
3805 
3806     dw.dxfString(6, (attrib.getLinetype().length()==0 ?
3807                      std::string("CONTINUOUS") : attrib.getLinetype()));
3808 
3809     if (version>=DL_VERSION_2000) {
3810         // layer defpoints cannot be plotted
3811         std::string lstr = data.name;
3812         std::transform(lstr.begin(), lstr.end(), lstr.begin(), tolower);
3813         if (lstr=="defpoints") {
3814             dw.dxfInt(290, 0);
3815         }
3816     }
3817     if (version>=DL_VERSION_2000 && attrib.getWidth()!=-1) {
3818         dw.dxfInt(370, attrib.getWidth());
3819     }
3820     if (version>=DL_VERSION_2000) {
3821         dw.dxfHex(390, 0xF);
3822     }
3823 }
3824 
3825 
3826 
3827 /**
3828  * Writes a line type to the file. Line types are stored in the
3829  * tables section of a DXF file.
3830  */
writeLinetype(DL_WriterA & dw,const DL_LinetypeData & data)3831 void DL_Dxf::writeLinetype(DL_WriterA& dw,
3832                            const DL_LinetypeData& data) {
3833 
3834     std::string nameUpper = data.name;
3835     std::transform(nameUpper.begin(), nameUpper.end(), nameUpper.begin(), ::toupper);
3836 
3837     if (data.name.empty()) {
3838         std::cerr << "DL_Dxf::writeLinetype: "
3839         << "Line type name must not be empty\n";
3840         return;
3841     }
3842 
3843     // ignore BYLAYER, BYBLOCK for R12
3844     if (version<DL_VERSION_2000) {
3845         if (nameUpper=="BYBLOCK" || nameUpper=="BYLAYER") {
3846             return;
3847         }
3848     }
3849 
3850     // write id (not for R12)
3851     if (nameUpper=="BYBLOCK") {
3852         dw.tableLinetypeEntry(0x14);
3853     } else if (nameUpper=="BYLAYER") {
3854         dw.tableLinetypeEntry(0x15);
3855     } else if (nameUpper=="CONTINUOUS") {
3856         dw.tableLinetypeEntry(0x16);
3857     } else {
3858         dw.tableLinetypeEntry();
3859     }
3860 
3861     dw.dxfString(2, data.name);
3862     dw.dxfInt(70, data.flags);
3863 
3864     if (nameUpper=="BYBLOCK") {
3865         dw.dxfString(3, "");
3866         dw.dxfInt(72, 65);
3867         dw.dxfInt(73, 0);
3868         dw.dxfReal(40, 0.0);
3869     } else if (nameUpper=="BYLAYER") {
3870         dw.dxfString(3, "");
3871         dw.dxfInt(72, 65);
3872         dw.dxfInt(73, 0);
3873         dw.dxfReal(40, 0.0);
3874     } else if (nameUpper=="CONTINUOUS") {
3875         dw.dxfString(3, "Solid line");
3876         dw.dxfInt(72, 65);
3877         dw.dxfInt(73, 0);
3878         dw.dxfReal(40, 0.0);
3879     } else {
3880         dw.dxfString(3, data.description);
3881         dw.dxfInt(72, 65);
3882         dw.dxfInt(73, data.numberOfDashes);
3883         dw.dxfReal(40, data.patternLength);
3884         for (int i = 0; i < data.numberOfDashes; i++) {
3885             dw.dxfReal(49, data.pattern[i]);
3886             if (version>=DL_VERSION_R13) {
3887                 dw.dxfInt(74, 0);
3888             }
3889         }
3890     }
3891 }
3892 
3893 
3894 
3895 /**
3896  * Writes the APPID section to the DXF file.
3897  *
3898  * @param name Application name
3899  */
writeAppid(DL_WriterA & dw,const std::string & name)3900 void DL_Dxf::writeAppid(DL_WriterA& dw, const std::string& name) {
3901     if (name.empty()) {
3902         std::cerr << "DL_Dxf::writeAppid: "
3903         << "Application  name must not be empty\n";
3904         return;
3905     }
3906 
3907     std::string n = name;
3908     std::transform(n.begin(), n.end(), n.begin(), ::toupper);
3909 
3910     if (n=="ACAD") {
3911         dw.tableAppidEntry(0x12);
3912     } else {
3913         dw.tableAppidEntry();
3914     }
3915     dw.dxfString(2, name);
3916     dw.dxfInt(70, 0);
3917 }
3918 
3919 
3920 
3921 /**
3922  * Writes a block's definition (no entities) to the DXF file.
3923  */
writeBlock(DL_WriterA & dw,const DL_BlockData & data)3924 void DL_Dxf::writeBlock(DL_WriterA& dw, const DL_BlockData& data) {
3925     if (data.name.empty()) {
3926         std::cerr << "DL_Dxf::writeBlock: "
3927         << "Block name must not be empty\n";
3928         return;
3929     }
3930 
3931     std::string n = data.name;
3932     std::transform(n.begin(), n.end(), n.begin(), ::toupper);
3933 
3934     if (n=="*PAPER_SPACE") {
3935         dw.sectionBlockEntry(0x1C);
3936     } else if (n=="*MODEL_SPACE") {
3937         dw.sectionBlockEntry(0x20);
3938     } else if (n=="*PAPER_SPACE0") {
3939         dw.sectionBlockEntry(0x24);
3940     } else {
3941         dw.sectionBlockEntry();
3942     }
3943     dw.dxfString(2, data.name);
3944     dw.dxfInt(70, 0);
3945     dw.coord(10, data.bpx, data.bpy, data.bpz);
3946     dw.dxfString(3, data.name);
3947     dw.dxfString(1, "");
3948 }
3949 
3950 
3951 
3952 /**
3953  * Writes a block end.
3954  *
3955  * @param name Block name
3956  */
writeEndBlock(DL_WriterA & dw,const std::string & name)3957 void DL_Dxf::writeEndBlock(DL_WriterA& dw, const std::string& name) {
3958     std::string n = name;
3959     std::transform(n.begin(), n.end(), n.begin(), ::toupper);
3960 
3961     if (n=="*PAPER_SPACE") {
3962         dw.sectionBlockEntryEnd(0x1D);
3963     } else if (n=="*MODEL_SPACE") {
3964         dw.sectionBlockEntryEnd(0x21);
3965     } else if (n=="*PAPER_SPACE0") {
3966         dw.sectionBlockEntryEnd(0x25);
3967     } else {
3968         dw.sectionBlockEntryEnd();
3969     }
3970 }
3971 
3972 
3973 
3974 /**
3975  * Writes a viewport section. This section is needed in DL_VERSION_R13.
3976  * Note that this method currently only writes a faked VPORT section
3977  * to make the file readable by Aut*cad.
3978  */
writeVPort(DL_WriterA & dw)3979 void DL_Dxf::writeVPort(DL_WriterA& dw) {
3980     dw.dxfString(0, "TABLE");
3981     dw.dxfString(2, "VPORT");
3982     if (version==DL_VERSION_2000) {
3983         dw.dxfHex(5, 0x8);
3984     }
3985     //dw.dxfHex(330, 0);
3986     if (version==DL_VERSION_2000) {
3987         dw.dxfString(100, "AcDbSymbolTable");
3988     }
3989     dw.dxfInt(70, 1);
3990     dw.dxfString(0, "VPORT");
3991     //dw.dxfHex(5, 0x2F);
3992     if (version==DL_VERSION_2000) {
3993         dw.handle();
3994     }
3995     //dw.dxfHex(330, 8);
3996     if (version==DL_VERSION_2000) {
3997         dw.dxfString(100, "AcDbSymbolTableRecord");
3998         dw.dxfString(100, "AcDbViewportTableRecord");
3999     }
4000     dw.dxfString(  2, "*Active");
4001     dw.dxfInt( 70, 0);
4002     dw.dxfReal( 10, 0.0);
4003     dw.dxfReal( 20, 0.0);
4004     dw.dxfReal( 11, 1.0);
4005     dw.dxfReal( 21, 1.0);
4006     dw.dxfReal( 12, 286.3055555555555);
4007     dw.dxfReal( 22, 148.5);
4008     dw.dxfReal( 13, 0.0);
4009     dw.dxfReal( 23, 0.0);
4010     dw.dxfReal( 14, 10.0);
4011     dw.dxfReal( 24, 10.0);
4012     dw.dxfReal( 15, 10.0);
4013     dw.dxfReal( 25, 10.0);
4014     dw.dxfReal( 16, 0.0);
4015     dw.dxfReal( 26, 0.0);
4016     dw.dxfReal( 36, 1.0);
4017     dw.dxfReal( 17, 0.0);
4018     dw.dxfReal( 27, 0.0);
4019     dw.dxfReal( 37, 0.0);
4020     dw.dxfReal( 40, 297.0);
4021     dw.dxfReal( 41, 1.92798353909465);
4022     dw.dxfReal( 42, 50.0);
4023     dw.dxfReal( 43, 0.0);
4024     dw.dxfReal( 44, 0.0);
4025     dw.dxfReal( 50, 0.0);
4026     dw.dxfReal( 51, 0.0);
4027     dw.dxfInt( 71, 0);
4028     dw.dxfInt( 72, 100);
4029     dw.dxfInt( 73, 1);
4030     dw.dxfInt( 74, 3);
4031     dw.dxfInt( 75, 1);
4032     dw.dxfInt( 76, 1);
4033     dw.dxfInt( 77, 0);
4034     dw.dxfInt( 78, 0);
4035 
4036     if (version==DL_VERSION_2000) {
4037         dw.dxfInt(281, 0);
4038         dw.dxfInt( 65, 1);
4039         dw.dxfReal(110, 0.0);
4040         dw.dxfReal(120, 0.0);
4041         dw.dxfReal(130, 0.0);
4042         dw.dxfReal(111, 1.0);
4043         dw.dxfReal(121, 0.0);
4044         dw.dxfReal(131, 0.0);
4045         dw.dxfReal(112, 0.0);
4046         dw.dxfReal(122, 1.0);
4047         dw.dxfReal(132, 0.0);
4048         dw.dxfInt( 79, 0);
4049         dw.dxfReal(146, 0.0);
4050     }
4051     dw.dxfString(  0, "ENDTAB");
4052 }
4053 
4054 
4055 
4056 /**
4057  * Writes a style section. This section is needed in DL_VERSION_R13.
4058  */
writeStyle(DL_WriterA & dw,const DL_StyleData & style)4059 void DL_Dxf::writeStyle(DL_WriterA& dw, const DL_StyleData& style) {
4060 //    dw.dxfString(  0, "TABLE");
4061 //    dw.dxfString(  2, "STYLE");
4062 //    if (version==DL_VERSION_2000) {
4063 //        dw.dxfHex(5, 3);
4064 //    }
4065     //dw.dxfHex(330, 0);
4066 //    if (version==DL_VERSION_2000) {
4067 //        dw.dxfString(100, "AcDbSymbolTable");
4068 //    }
4069 //    dw.dxfInt( 70, 1);
4070     dw.dxfString(  0, "STYLE");
4071     if (version==DL_VERSION_2000) {
4072         if (style.name=="Standard") {
4073             //dw.dxfHex(5, 0x11);
4074             styleHandleStd = dw.handle();
4075         }
4076         else {
4077             dw.handle();
4078         }
4079     }
4080     //dw.dxfHex(330, 3);
4081     if (version==DL_VERSION_2000) {
4082         dw.dxfString(100, "AcDbSymbolTableRecord");
4083         dw.dxfString(100, "AcDbTextStyleTableRecord");
4084     }
4085     dw.dxfString(  2, style.name);
4086     dw.dxfInt( 70, style.flags);
4087     dw.dxfReal( 40, style.fixedTextHeight);
4088     dw.dxfReal( 41, style.widthFactor);
4089     dw.dxfReal( 50, style.obliqueAngle);
4090     dw.dxfInt( 71, style.textGenerationFlags);
4091     dw.dxfReal( 42, style.lastHeightUsed);
4092     if (version==DL_VERSION_2000) {
4093         dw.dxfString(  3, "");
4094         dw.dxfString(  4, "");
4095         dw.dxfString(1001, "ACAD");
4096         //dw.dxfString(1000, style.name);
4097         dw.dxfString(1000, style.primaryFontFile);
4098         int xFlags = 0;
4099         if (style.bold) {
4100             xFlags = xFlags|0x2000000;
4101         }
4102         if (style.italic) {
4103             xFlags = xFlags|0x1000000;
4104         }
4105         dw.dxfInt(1071, xFlags);
4106     }
4107     else {
4108         dw.dxfString(  3, style.primaryFontFile);
4109         dw.dxfString(  4, style.bigFontFile);
4110     }
4111     //dw.dxfString(  0, "ENDTAB");
4112 }
4113 
4114 
4115 
4116 /**
4117  * Writes a view section. This section is needed in DL_VERSION_R13.
4118  * Note that this method currently only writes a faked VIEW section
4119  * to make the file readable by Aut*cad.
4120  */
writeView(DL_WriterA & dw)4121 void DL_Dxf::writeView(DL_WriterA& dw) {
4122     dw.dxfString(  0, "TABLE");
4123     dw.dxfString(  2, "VIEW");
4124     if (version==DL_VERSION_2000) {
4125         dw.dxfHex(5, 6);
4126     }
4127     //dw.dxfHex(330, 0);
4128     if (version==DL_VERSION_2000) {
4129         dw.dxfString(100, "AcDbSymbolTable");
4130     }
4131     dw.dxfInt( 70, 0);
4132     dw.dxfString(  0, "ENDTAB");
4133 }
4134 
4135 
4136 
4137 /**
4138  * Writes a ucs section. This section is needed in DL_VERSION_R13.
4139  * Note that this method currently only writes a faked UCS section
4140  * to make the file readable by Aut*cad.
4141  */
writeUcs(DL_WriterA & dw)4142 void DL_Dxf::writeUcs(DL_WriterA& dw) {
4143     dw.dxfString(  0, "TABLE");
4144     dw.dxfString(  2, "UCS");
4145     if (version==DL_VERSION_2000) {
4146         dw.dxfHex(5, 7);
4147     }
4148     //dw.dxfHex(330, 0);
4149     if (version==DL_VERSION_2000) {
4150         dw.dxfString(100, "AcDbSymbolTable");
4151     }
4152     dw.dxfInt( 70, 0);
4153     dw.dxfString(  0, "ENDTAB");
4154 }
4155 
4156 
4157 
4158 /**
4159  * Writes a dimstyle section. This section is needed in DL_VERSION_R13.
4160  * Note that this method currently only writes a faked DIMSTYLE section
4161  * to make the file readable by Aut*cad.
4162  */
writeDimStyle(DL_WriterA & dw,double dimasz,double dimexe,double dimexo,double dimgap,double dimtxt)4163 void DL_Dxf::writeDimStyle(DL_WriterA& dw,
4164                     double dimasz, double dimexe, double dimexo,
4165                     double dimgap, double dimtxt) {
4166 
4167     dw.dxfString(  0, "TABLE");
4168     dw.dxfString(  2, "DIMSTYLE");
4169     if (version==DL_VERSION_2000) {
4170         dw.dxfHex(5, 0xA);
4171         dw.dxfString(100, "AcDbSymbolTable");
4172     }
4173     dw.dxfInt( 70, 1);
4174     if (version==DL_VERSION_2000) {
4175         dw.dxfString(100, "AcDbDimStyleTable");
4176         dw.dxfInt( 71, 0);
4177     }
4178 
4179 
4180     dw.dxfString(  0, "DIMSTYLE");
4181     if (version==DL_VERSION_2000) {
4182         dw.dxfHex(105, 0x27);
4183     }
4184     //dw.handle(105);
4185     //dw.dxfHex(330, 0xA);
4186     if (version==DL_VERSION_2000) {
4187         dw.dxfString(100, "AcDbSymbolTableRecord");
4188         dw.dxfString(100, "AcDbDimStyleTableRecord");
4189     }
4190     dw.dxfString(  2, "Standard");
4191     if (version==DL_VERSION_R12) {
4192         dw.dxfString(  3, "");
4193         dw.dxfString(  4, "");
4194         dw.dxfString(  5, "");
4195         dw.dxfString(  6, "");
4196         dw.dxfString(  7, "");
4197         dw.dxfReal( 40, 1.0);
4198     }
4199 
4200     dw.dxfReal( 41, dimasz);
4201     dw.dxfReal( 42, dimexo);
4202     dw.dxfReal( 43, 3.75);
4203     dw.dxfReal( 44, dimexe);
4204     if (version==DL_VERSION_R12) {
4205         dw.dxfReal( 45, 0.0);
4206         dw.dxfReal( 46, 0.0);
4207         dw.dxfReal( 47, 0.0);
4208         dw.dxfReal( 48, 0.0);
4209     }
4210     dw.dxfInt( 70, 0);
4211     if (version==DL_VERSION_R12) {
4212         dw.dxfInt( 71, 0);
4213         dw.dxfInt( 72, 0);
4214     }
4215     dw.dxfInt( 73, 0);
4216     dw.dxfInt( 74, 0);
4217     if (version==DL_VERSION_R12) {
4218         dw.dxfInt( 75, 0);
4219         dw.dxfInt( 76, 0);
4220     }
4221     dw.dxfInt( 77, 1);
4222     dw.dxfInt( 78, 8);
4223     dw.dxfReal(140, dimtxt);
4224     dw.dxfReal(141, 2.5);
4225     if (version==DL_VERSION_R12) {
4226         dw.dxfReal(142, 0.0);
4227     }
4228     dw.dxfReal(143, 0.03937007874016);
4229     if (version==DL_VERSION_R12) {
4230         dw.dxfReal(144, 1.0);
4231         dw.dxfReal(145, 0.0);
4232         dw.dxfReal(146, 1.0);
4233     }
4234     dw.dxfReal(147, dimgap);
4235     if (version==DL_VERSION_R12) {
4236         dw.dxfInt(170, 0);
4237     }
4238     dw.dxfInt(171, 3);
4239     dw.dxfInt(172, 1);
4240     if (version==DL_VERSION_R12) {
4241         dw.dxfInt(173, 0);
4242         dw.dxfInt(174, 0);
4243         dw.dxfInt(175, 0);
4244         dw.dxfInt(176, 0);
4245         dw.dxfInt(177, 0);
4246         dw.dxfInt(178, 0);
4247     }
4248     if (version==DL_VERSION_2000) {
4249         dw.dxfInt(271, 2);
4250         dw.dxfInt(272, 2);
4251         dw.dxfInt(274, 3);
4252         dw.dxfInt(278, 44);
4253         dw.dxfInt(283, 0);
4254         dw.dxfInt(284, 8);
4255         dw.dxfHex(340, styleHandleStd);
4256         //dw.dxfHex(340, 0x11);
4257     }
4258     // * /
4259     dw.dxfString(  0, "ENDTAB");
4260 }
4261 
4262 
4263 
4264 /**
4265  * Writes a blockrecord section. This section is needed in DL_VERSION_R13.
4266  * Note that this method currently only writes a faked BLOCKRECORD section
4267  * to make the file readable by Aut*cad.
4268  */
writeBlockRecord(DL_WriterA & dw)4269 void DL_Dxf::writeBlockRecord(DL_WriterA& dw) {
4270     dw.dxfString(  0, "TABLE");
4271     dw.dxfString(  2, "BLOCK_RECORD");
4272     if (version==DL_VERSION_2000) {
4273         dw.dxfHex(5, 1);
4274     }
4275     //dw.dxfHex(330, 0);
4276     if (version==DL_VERSION_2000) {
4277         dw.dxfString(100, "AcDbSymbolTable");
4278     }
4279     dw.dxfInt( 70, 1);
4280 
4281     dw.dxfString(  0, "BLOCK_RECORD");
4282     if (version==DL_VERSION_2000) {
4283         dw.dxfHex(5, 0x1F);
4284     }
4285     //int msh = dw.handle();
4286     //dw.setModelSpaceHandle(msh);
4287     //dw.dxfHex(330, 1);
4288     if (version==DL_VERSION_2000) {
4289         dw.dxfString(100, "AcDbSymbolTableRecord");
4290         dw.dxfString(100, "AcDbBlockTableRecord");
4291     }
4292     dw.dxfString(  2, "*Model_Space");
4293     dw.dxfHex(340, 0x22);
4294 
4295     dw.dxfString(  0, "BLOCK_RECORD");
4296     if (version==DL_VERSION_2000) {
4297         dw.dxfHex(5, 0x1B);
4298     }
4299     //int psh = dw.handle();
4300     //dw.setPaperSpaceHandle(psh);
4301     //dw.dxfHex(330, 1);
4302     if (version==DL_VERSION_2000) {
4303         dw.dxfString(100, "AcDbSymbolTableRecord");
4304         dw.dxfString(100, "AcDbBlockTableRecord");
4305     }
4306     dw.dxfString(  2, "*Paper_Space");
4307     dw.dxfHex(340, 0x1E);
4308 
4309     dw.dxfString(  0, "BLOCK_RECORD");
4310     if (version==DL_VERSION_2000) {
4311         dw.dxfHex(5, 0x23);
4312     }
4313     //int ps0h = dw.handle();
4314     //dw.setPaperSpace0Handle(ps0h);
4315     //dw.dxfHex(330, 1);
4316     if (version==DL_VERSION_2000) {
4317         dw.dxfString(100, "AcDbSymbolTableRecord");
4318         dw.dxfString(100, "AcDbBlockTableRecord");
4319     }
4320     dw.dxfString(  2, "*Paper_Space0");
4321     dw.dxfHex(340, 0x26);
4322 
4323     //dw.dxfString(  0, "ENDTAB");
4324 }
4325 
4326 
4327 
4328 /**
4329  * Writes a single block record with the given name.
4330  */
writeBlockRecord(DL_WriterA & dw,const std::string & name)4331 void DL_Dxf::writeBlockRecord(DL_WriterA& dw, const std::string& name) {
4332     dw.dxfString(  0, "BLOCK_RECORD");
4333     if (version==DL_VERSION_2000) {
4334         dw.handle();
4335     }
4336     //dw->dxfHex(330, 1);
4337     if (version==DL_VERSION_2000) {
4338         dw.dxfString(100, "AcDbSymbolTableRecord");
4339         dw.dxfString(100, "AcDbBlockTableRecord");
4340     }
4341     dw.dxfString(  2, name);
4342     dw.dxfHex(340, 0);
4343 }
4344 
4345 
4346 
4347 /**
4348  * Writes a objects section. This section is needed in DL_VERSION_R13.
4349  * Note that this method currently only writes a faked OBJECTS section
4350  * to make the file readable by Aut*cad.
4351  */
writeObjects(DL_WriterA & dw,const std::string & appDictionaryName)4352 void DL_Dxf::writeObjects(DL_WriterA& dw, const std::string& appDictionaryName) {
4353     dw.dxfString(  0, "SECTION");
4354     dw.dxfString(  2, "OBJECTS");
4355 
4356 
4357     dw.dxfString(  0, "DICTIONARY");
4358     dw.dxfHex(5, 0xC);
4359     dw.dxfString(100, "AcDbDictionary");
4360     dw.dxfInt(280, 0);
4361     dw.dxfInt(281, 1);
4362     dw.dxfString(  3, "ACAD_GROUP");
4363     dw.dxfHex(350, 0xD);
4364     dw.dxfString(  3, "ACAD_LAYOUT");
4365     dw.dxfHex(350, 0x1A);
4366     dw.dxfString(  3, "ACAD_MLINESTYLE");
4367     dw.dxfHex(350, 0x17);
4368     dw.dxfString(  3, "ACAD_PLOTSETTINGS");
4369     dw.dxfHex(350, 0x19);
4370     dw.dxfString(  3, "ACAD_PLOTSTYLENAME");
4371     dw.dxfHex(350, 0xE);
4372     dw.dxfString(  3, "AcDbVariableDictionary");
4373     int acDbVariableDictionaryHandle = dw.handle(350);
4374     //int acDbVariableDictionaryHandle = dw.getNextHandle();
4375     //dw.dxfHex(350, acDbVariableDictionaryHandle);
4376     //dw.incHandle();
4377 
4378     if (appDictionaryName.length()!=0) {
4379         dw.dxfString(  3, appDictionaryName);
4380         appDictionaryHandle = dw.handle(350);
4381         //appDictionaryHandle = dw.getNextHandle();
4382         //dw.dxfHex(350, appDictionaryHandle);
4383         //dw.incHandle();
4384     }
4385 
4386     dw.dxfString(  0, "DICTIONARY");
4387     dw.dxfHex(5, 0xD);
4388     //dw.handle();                                    // D
4389     //dw.dxfHex(330, 0xC);
4390     dw.dxfString(100, "AcDbDictionary");
4391     dw.dxfInt(280, 0);
4392     dw.dxfInt(281, 1);
4393 
4394 
4395     dw.dxfString(  0, "ACDBDICTIONARYWDFLT");
4396     dw.dxfHex(5, 0xE);
4397     //dicId4 = dw.handle();                           // E
4398     //dw.dxfHex(330, 0xC);                       // C
4399     dw.dxfString(100, "AcDbDictionary");
4400     dw.dxfInt(281, 1);
4401     dw.dxfString(  3, "Normal");
4402     dw.dxfHex(350, 0xF);
4403     //dw.dxfHex(350, dw.getNextHandle()+5);        // F
4404     dw.dxfString(100, "AcDbDictionaryWithDefault");
4405     dw.dxfHex(340, 0xF);
4406     //dw.dxfHex(340, dw.getNextHandle()+5);        // F
4407 
4408 
4409     dw.dxfString(  0, "ACDBPLACEHOLDER");
4410     dw.dxfHex(5, 0xF);
4411     //dw.handle();                                    // F
4412     //dw.dxfHex(330, dicId4);                      // E
4413 
4414 
4415     dw.dxfString(  0, "DICTIONARY");
4416     //dicId3 = dw.handle();                           // 17
4417     dw.dxfHex(5, 0x17);
4418     //dw.dxfHex(330, 0xC);                       // C
4419     dw.dxfString(100, "AcDbDictionary");
4420     dw.dxfInt(280, 0);
4421     dw.dxfInt(281, 1);
4422     dw.dxfString(  3, "Standard");
4423     dw.dxfHex(350, 0x18);
4424     //dw.dxfHex(350, dw.getNextHandle()+5);        // 18
4425 
4426 
4427     dw.dxfString(  0, "MLINESTYLE");
4428     dw.dxfHex(5, 0x18);
4429     //dw.handle();                                    // 18
4430     //dw.dxfHex(330, dicId3);                      // 17
4431     dw.dxfString(100, "AcDbMlineStyle");
4432     dw.dxfString(  2, "STANDARD");
4433     dw.dxfInt( 70, 0);
4434     dw.dxfString(  3, "");
4435     dw.dxfInt( 62, 256);
4436     dw.dxfReal( 51, 90.0);
4437     dw.dxfReal( 52, 90.0);
4438     dw.dxfInt( 71, 2);
4439     dw.dxfReal( 49, 0.5);
4440     dw.dxfInt( 62, 256);
4441     dw.dxfString(  6, "BYLAYER");
4442     dw.dxfReal( 49, -0.5);
4443     dw.dxfInt( 62, 256);
4444     dw.dxfString(  6, "BYLAYER");
4445 
4446 
4447     dw.dxfString(  0, "DICTIONARY");
4448     dw.dxfHex(5, 0x19);
4449     //dw.handle();                           // 17
4450     //dw.dxfHex(330, 0xC);                       // C
4451     dw.dxfString(100, "AcDbDictionary");
4452     dw.dxfInt(280, 0);
4453     dw.dxfInt(281, 1);
4454 
4455 
4456     dw.dxfString(  0, "DICTIONARY");
4457     //dicId2 = dw.handle();                           // 1A
4458     dw.dxfHex(5, 0x1A);
4459     //dw.dxfHex(330, 0xC);
4460     dw.dxfString(100, "AcDbDictionary");
4461     dw.dxfInt(281, 1);
4462     dw.dxfString(  3, "Layout1");
4463     dw.dxfHex(350, 0x1E);
4464     //dw.dxfHex(350, dw.getNextHandle()+2);        // 1E
4465     dw.dxfString(  3, "Layout2");
4466     dw.dxfHex(350, 0x26);
4467     //dw.dxfHex(350, dw.getNextHandle()+4);        // 26
4468     dw.dxfString(  3, "Model");
4469     dw.dxfHex(350, 0x22);
4470     //dw.dxfHex(350, dw.getNextHandle()+5);        // 22
4471 
4472 
4473     dw.dxfString(  0, "LAYOUT");
4474     dw.dxfHex(5, 0x1E);
4475     //dw.handle();                                    // 1E
4476     //dw.dxfHex(330, dicId2);                      // 1A
4477     dw.dxfString(100, "AcDbPlotSettings");
4478     dw.dxfString(  1, "");
4479     dw.dxfString(  2, "none_device");
4480     dw.dxfString(  4, "");
4481     dw.dxfString(  6, "");
4482     dw.dxfReal( 40, 0.0);
4483     dw.dxfReal( 41, 0.0);
4484     dw.dxfReal( 42, 0.0);
4485     dw.dxfReal( 43, 0.0);
4486     dw.dxfReal( 44, 0.0);
4487     dw.dxfReal( 45, 0.0);
4488     dw.dxfReal( 46, 0.0);
4489     dw.dxfReal( 47, 0.0);
4490     dw.dxfReal( 48, 0.0);
4491     dw.dxfReal( 49, 0.0);
4492     dw.dxfReal(140, 0.0);
4493     dw.dxfReal(141, 0.0);
4494     dw.dxfReal(142, 1.0);
4495     dw.dxfReal(143, 1.0);
4496     dw.dxfInt( 70, 688);
4497     dw.dxfInt( 72, 0);
4498     dw.dxfInt( 73, 0);
4499     dw.dxfInt( 74, 5);
4500     dw.dxfString(  7, "");
4501     dw.dxfInt( 75, 16);
4502     dw.dxfReal(147, 1.0);
4503     dw.dxfReal(148, 0.0);
4504     dw.dxfReal(149, 0.0);
4505     dw.dxfString(100, "AcDbLayout");
4506     dw.dxfString(  1, "Layout1");
4507     dw.dxfInt( 70, 1);
4508     dw.dxfInt( 71, 1);
4509     dw.dxfReal( 10, 0.0);
4510     dw.dxfReal( 20, 0.0);
4511     dw.dxfReal( 11, 420.0);
4512     dw.dxfReal( 21, 297.0);
4513     dw.dxfReal( 12, 0.0);
4514     dw.dxfReal( 22, 0.0);
4515     dw.dxfReal( 32, 0.0);
4516     dw.dxfReal( 14, 1.000000000000000E+20);
4517     dw.dxfReal( 24, 1.000000000000000E+20);
4518     dw.dxfReal( 34, 1.000000000000000E+20);
4519     dw.dxfReal( 15, -1.000000000000000E+20);
4520     dw.dxfReal( 25, -1.000000000000000E+20);
4521     dw.dxfReal( 35, -1.000000000000000E+20);
4522     dw.dxfReal(146, 0.0);
4523     dw.dxfReal( 13, 0.0);
4524     dw.dxfReal( 23, 0.0);
4525     dw.dxfReal( 33, 0.0);
4526     dw.dxfReal( 16, 1.0);
4527     dw.dxfReal( 26, 0.0);
4528     dw.dxfReal( 36, 0.0);
4529     dw.dxfReal( 17, 0.0);
4530     dw.dxfReal( 27, 1.0);
4531     dw.dxfReal( 37, 0.0);
4532     dw.dxfInt( 76, 0);
4533     //dw.dxfHex(330, dw.getPaperSpaceHandle());    // 1B
4534     dw.dxfHex(330, 0x1B);
4535 
4536 
4537     dw.dxfString(  0, "LAYOUT");
4538     dw.dxfHex(5, 0x22);
4539     //dw.handle();                                    // 22
4540     //dw.dxfHex(330, dicId2);                      // 1A
4541     dw.dxfString(100, "AcDbPlotSettings");
4542     dw.dxfString(  1, "");
4543     dw.dxfString(  2, "none_device");
4544     dw.dxfString(  4, "");
4545     dw.dxfString(  6, "");
4546     dw.dxfReal( 40, 0.0);
4547     dw.dxfReal( 41, 0.0);
4548     dw.dxfReal( 42, 0.0);
4549     dw.dxfReal( 43, 0.0);
4550     dw.dxfReal( 44, 0.0);
4551     dw.dxfReal( 45, 0.0);
4552     dw.dxfReal( 46, 0.0);
4553     dw.dxfReal( 47, 0.0);
4554     dw.dxfReal( 48, 0.0);
4555     dw.dxfReal( 49, 0.0);
4556     dw.dxfReal(140, 0.0);
4557     dw.dxfReal(141, 0.0);
4558     dw.dxfReal(142, 1.0);
4559     dw.dxfReal(143, 1.0);
4560     dw.dxfInt( 70, 1712);
4561     dw.dxfInt( 72, 0);
4562     dw.dxfInt( 73, 0);
4563     dw.dxfInt( 74, 0);
4564     dw.dxfString(  7, "");
4565     dw.dxfInt( 75, 0);
4566     dw.dxfReal(147, 1.0);
4567     dw.dxfReal(148, 0.0);
4568     dw.dxfReal(149, 0.0);
4569     dw.dxfString(100, "AcDbLayout");
4570     dw.dxfString(  1, "Model");
4571     dw.dxfInt( 70, 1);
4572     dw.dxfInt( 71, 0);
4573     dw.dxfReal( 10, 0.0);
4574     dw.dxfReal( 20, 0.0);
4575     dw.dxfReal( 11, 12.0);
4576     dw.dxfReal( 21, 9.0);
4577     dw.dxfReal( 12, 0.0);
4578     dw.dxfReal( 22, 0.0);
4579     dw.dxfReal( 32, 0.0);
4580     dw.dxfReal( 14, 0.0);
4581     dw.dxfReal( 24, 0.0);
4582     dw.dxfReal( 34, 0.0);
4583     dw.dxfReal( 15, 0.0);
4584     dw.dxfReal( 25, 0.0);
4585     dw.dxfReal( 35, 0.0);
4586     dw.dxfReal(146, 0.0);
4587     dw.dxfReal( 13, 0.0);
4588     dw.dxfReal( 23, 0.0);
4589     dw.dxfReal( 33, 0.0);
4590     dw.dxfReal( 16, 1.0);
4591     dw.dxfReal( 26, 0.0);
4592     dw.dxfReal( 36, 0.0);
4593     dw.dxfReal( 17, 0.0);
4594     dw.dxfReal( 27, 1.0);
4595     dw.dxfReal( 37, 0.0);
4596     dw.dxfInt( 76, 0);
4597     //dw.dxfHex(330, dw.getModelSpaceHandle());    // 1F
4598     dw.dxfHex(330, 0x1F);
4599 
4600 
4601     dw.dxfString(  0, "LAYOUT");
4602     //dw.handle();                                    // 26
4603     dw.dxfHex(5, 0x26);
4604     //dw.dxfHex(330, dicId2);                      // 1A
4605     dw.dxfString(100, "AcDbPlotSettings");
4606     dw.dxfString(  1, "");
4607     dw.dxfString(  2, "none_device");
4608     dw.dxfString(  4, "");
4609     dw.dxfString(  6, "");
4610     dw.dxfReal( 40, 0.0);
4611     dw.dxfReal( 41, 0.0);
4612     dw.dxfReal( 42, 0.0);
4613     dw.dxfReal( 43, 0.0);
4614     dw.dxfReal( 44, 0.0);
4615     dw.dxfReal( 45, 0.0);
4616     dw.dxfReal( 46, 0.0);
4617     dw.dxfReal( 47, 0.0);
4618     dw.dxfReal( 48, 0.0);
4619     dw.dxfReal( 49, 0.0);
4620     dw.dxfReal(140, 0.0);
4621     dw.dxfReal(141, 0.0);
4622     dw.dxfReal(142, 1.0);
4623     dw.dxfReal(143, 1.0);
4624     dw.dxfInt( 70, 688);
4625     dw.dxfInt( 72, 0);
4626     dw.dxfInt( 73, 0);
4627     dw.dxfInt( 74, 5);
4628     dw.dxfString(  7, "");
4629     dw.dxfInt( 75, 16);
4630     dw.dxfReal(147, 1.0);
4631     dw.dxfReal(148, 0.0);
4632     dw.dxfReal(149, 0.0);
4633     dw.dxfString(100, "AcDbLayout");
4634     dw.dxfString(  1, "Layout2");
4635     dw.dxfInt( 70, 1);
4636     dw.dxfInt( 71, 2);
4637     dw.dxfReal( 10, 0.0);
4638     dw.dxfReal( 20, 0.0);
4639     dw.dxfReal( 11, 12.0);
4640     dw.dxfReal( 21, 9.0);
4641     dw.dxfReal( 12, 0.0);
4642     dw.dxfReal( 22, 0.0);
4643     dw.dxfReal( 32, 0.0);
4644     dw.dxfReal( 14, 0.0);
4645     dw.dxfReal( 24, 0.0);
4646     dw.dxfReal( 34, 0.0);
4647     dw.dxfReal( 15, 0.0);
4648     dw.dxfReal( 25, 0.0);
4649     dw.dxfReal( 35, 0.0);
4650     dw.dxfReal(146, 0.0);
4651     dw.dxfReal( 13, 0.0);
4652     dw.dxfReal( 23, 0.0);
4653     dw.dxfReal( 33, 0.0);
4654     dw.dxfReal( 16, 1.0);
4655     dw.dxfReal( 26, 0.0);
4656     dw.dxfReal( 36, 0.0);
4657     dw.dxfReal( 17, 0.0);
4658     dw.dxfReal( 27, 1.0);
4659     dw.dxfReal( 37, 0.0);
4660     dw.dxfInt( 76, 0);
4661     //dw.dxfHex(330, dw.getPaperSpace0Handle());   // 23
4662     dw.dxfHex(330, 0x23);
4663 
4664     dw.dxfString(  0, "DICTIONARY");
4665     //dw.dxfHex(5, 0x2C);
4666     //dicId5 =
4667     dw.dxfHex(5, acDbVariableDictionaryHandle);
4668     //dw.handle();                           // 2C
4669     //dw.dxfHex(330, 0xC);                       // C
4670     dw.dxfString(100, "AcDbDictionary");
4671     dw.dxfInt(281, 1);
4672     dw.dxfString(  3, "DIMASSOC");
4673     //dw.dxfHex(350, 0x2F);
4674     dw.dxfHex(350, dw.getNextHandle()+1);        // 2E
4675     dw.dxfString(  3, "HIDETEXT");
4676     //dw.dxfHex(350, 0x2E);
4677     dw.dxfHex(350, dw.getNextHandle());        // 2D
4678 
4679 
4680     dw.dxfString(  0, "DICTIONARYVAR");
4681     //dw.dxfHex(5, 0x2E);
4682     dw.handle();                                    // 2E
4683     //dw.dxfHex(330, dicId5);                      // 2C
4684     dw.dxfString(100, "DictionaryVariables");
4685     dw.dxfInt(280, 0);
4686     dw.dxfInt(  1, 2);
4687 
4688 
4689     dw.dxfString(  0, "DICTIONARYVAR");
4690     //dw.dxfHex(5, 0x2D);
4691     dw.handle();                                    // 2D
4692     //dw.dxfHex(330, dicId5);                      // 2C
4693     dw.dxfString(100, "DictionaryVariables");
4694     dw.dxfInt(280, 0);
4695     dw.dxfInt(  1, 1);
4696 }
4697 
writeAppDictionary(DL_WriterA & dw)4698 void DL_Dxf::writeAppDictionary(DL_WriterA& dw) {
4699     dw.dxfString(  0, "DICTIONARY");
4700     //dw.handle();
4701     dw.dxfHex(5, appDictionaryHandle);
4702     dw.dxfString(100, "AcDbDictionary");
4703     dw.dxfInt(281, 1);
4704 }
4705 
writeDictionaryEntry(DL_WriterA & dw,const std::string & name)4706 int DL_Dxf::writeDictionaryEntry(DL_WriterA& dw, const std::string& name) {
4707     dw.dxfString(  3, name);
4708     int handle = dw.getNextHandle();
4709     dw.dxfHex(350, handle);
4710     dw.incHandle();
4711     return handle;
4712 }
4713 
writeXRecord(DL_WriterA & dw,int handle,int value)4714 void DL_Dxf::writeXRecord(DL_WriterA& dw, int handle, int value) {
4715     dw.dxfString(  0, "XRECORD");
4716     dw.dxfHex(5, handle);
4717     dw.dxfHex(330, appDictionaryHandle);
4718     dw.dxfString(100, "AcDbXrecord");
4719     dw.dxfInt(280, 1);
4720     dw.dxfInt(90, value);
4721 }
4722 
writeXRecord(DL_WriterA & dw,int handle,double value)4723 void DL_Dxf::writeXRecord(DL_WriterA& dw, int handle, double value) {
4724     dw.dxfString(  0, "XRECORD");
4725     dw.dxfHex(5, handle);
4726     dw.dxfHex(330, appDictionaryHandle);
4727     dw.dxfString(100, "AcDbXrecord");
4728     dw.dxfInt(280, 1);
4729     dw.dxfReal(40, value);
4730 }
4731 
writeXRecord(DL_WriterA & dw,int handle,bool value)4732 void DL_Dxf::writeXRecord(DL_WriterA& dw, int handle, bool value) {
4733     dw.dxfString(  0, "XRECORD");
4734     dw.dxfHex(5, handle);
4735     dw.dxfHex(330, appDictionaryHandle);
4736     dw.dxfString(100, "AcDbXrecord");
4737     dw.dxfInt(280, 1);
4738     dw.dxfBool(290, value);
4739 }
4740 
writeXRecord(DL_WriterA & dw,int handle,const std::string & value)4741 void DL_Dxf::writeXRecord(DL_WriterA& dw, int handle, const std::string& value) {
4742     dw.dxfString(  0, "XRECORD");
4743     dw.dxfHex(5, handle);
4744     dw.dxfHex(330, appDictionaryHandle);
4745     dw.dxfString(100, "AcDbXrecord");
4746     dw.dxfInt(280, 1);
4747     dw.dxfString(1000, value);
4748 }
4749 
4750 /**
4751  * Writes the end of the objects section. This section is needed in DL_VERSION_R13.
4752  * Note that this method currently only writes a faked OBJECTS section
4753  * to make the file readable by Aut*cad.
4754  */
writeObjectsEnd(DL_WriterA & dw)4755 void DL_Dxf::writeObjectsEnd(DL_WriterA& dw) {
4756     dw.dxfString(  0, "ENDSEC");
4757 }
4758 
4759 
4760 
4761 /**
4762  * Writes a comment to the DXF file.
4763  */
writeComment(DL_WriterA & dw,const std::string & comment)4764 void DL_Dxf::writeComment(DL_WriterA& dw, const std::string& comment) {
4765     dw.dxfString(999, comment);
4766 }
4767 
4768 
4769 /**
4770  * Checks if the given variable is known by the given DXF version.
4771  */
checkVariable(const char * var,DL_Codes::version version)4772 bool DL_Dxf::checkVariable(const char* var, DL_Codes::version version) {
4773     if (version>=DL_VERSION_2000) {
4774         return true;
4775     } else if (version==DL_VERSION_R12) {
4776         // these are all the variables recognized by dxf r12:
4777         if (!strcmp(var, "$ACADVER")) {
4778             return true;
4779         }
4780         if (!strcmp(var, "$ACADVER")) {
4781             return true;
4782         }
4783         if (!strcmp(var, "$ANGBASE")) {
4784             return true;
4785         }
4786         if (!strcmp(var, "$ANGDIR")) {
4787             return true;
4788         }
4789         if (!strcmp(var, "$ATTDIA")) {
4790             return true;
4791         }
4792         if (!strcmp(var, "$ATTMODE")) {
4793             return true;
4794         }
4795         if (!strcmp(var, "$ATTREQ")) {
4796             return true;
4797         }
4798         if (!strcmp(var, "$AUNITS")) {
4799             return true;
4800         }
4801         if (!strcmp(var, "$AUPREC")) {
4802             return true;
4803         }
4804         if (!strcmp(var, "$AXISMODE")) {
4805             return true;
4806         }
4807         if (!strcmp(var, "$AXISUNIT")) {
4808             return true;
4809         }
4810         if (!strcmp(var, "$BLIPMODE")) {
4811             return true;
4812         }
4813         if (!strcmp(var, "$CECOLOR")) {
4814             return true;
4815         }
4816         if (!strcmp(var, "$CELTYPE")) {
4817             return true;
4818         }
4819         if (!strcmp(var, "$CHAMFERA")) {
4820             return true;
4821         }
4822         if (!strcmp(var, "$CHAMFERB")) {
4823             return true;
4824         }
4825         if (!strcmp(var, "$CLAYER")) {
4826             return true;
4827         }
4828         if (!strcmp(var, "$COORDS")) {
4829             return true;
4830         }
4831         if (!strcmp(var, "$DIMALT")) {
4832             return true;
4833         }
4834         if (!strcmp(var, "$DIMALTD")) {
4835             return true;
4836         }
4837         if (!strcmp(var, "$DIMALTF")) {
4838             return true;
4839         }
4840         if (!strcmp(var, "$DIMAPOST")) {
4841             return true;
4842         }
4843         if (!strcmp(var, "$DIMASO")) {
4844             return true;
4845         }
4846         if (!strcmp(var, "$DIMASZ")) {
4847             return true;
4848         }
4849         if (!strcmp(var, "$DIMBLK")) {
4850             return true;
4851         }
4852         if (!strcmp(var, "$DIMBLK1")) {
4853             return true;
4854         }
4855         if (!strcmp(var, "$DIMBLK2")) {
4856             return true;
4857         }
4858         if (!strcmp(var, "$DIMCEN")) {
4859             return true;
4860         }
4861         if (!strcmp(var, "$DIMCLRD")) {
4862             return true;
4863         }
4864         if (!strcmp(var, "$DIMCLRE")) {
4865             return true;
4866         }
4867         if (!strcmp(var, "$DIMCLRT")) {
4868             return true;
4869         }
4870         if (!strcmp(var, "$DIMDLE")) {
4871             return true;
4872         }
4873         if (!strcmp(var, "$DIMDLI")) {
4874             return true;
4875         }
4876         if (!strcmp(var, "$DIMEXE")) {
4877             return true;
4878         }
4879         if (!strcmp(var, "$DIMEXO")) {
4880             return true;
4881         }
4882         if (!strcmp(var, "$DIMGAP")) {
4883             return true;
4884         }
4885         if (!strcmp(var, "$DIMLFAC")) {
4886             return true;
4887         }
4888         if (!strcmp(var, "$DIMLIM")) {
4889             return true;
4890         }
4891         if (!strcmp(var, "$DIMPOST")) {
4892             return true;
4893         }
4894         if (!strcmp(var, "$DIMRND")) {
4895             return true;
4896         }
4897         if (!strcmp(var, "$DIMSAH")) {
4898             return true;
4899         }
4900         if (!strcmp(var, "$DIMSCALE")) {
4901             return true;
4902         }
4903         if (!strcmp(var, "$DIMSE1")) {
4904             return true;
4905         }
4906         if (!strcmp(var, "$DIMSE2")) {
4907             return true;
4908         }
4909         if (!strcmp(var, "$DIMSHO")) {
4910             return true;
4911         }
4912         if (!strcmp(var, "$DIMSOXD")) {
4913             return true;
4914         }
4915         if (!strcmp(var, "$DIMSTYLE")) {
4916             return true;
4917         }
4918         if (!strcmp(var, "$DIMTAD")) {
4919             return true;
4920         }
4921         if (!strcmp(var, "$DIMTFAC")) {
4922             return true;
4923         }
4924         if (!strcmp(var, "$DIMTIH")) {
4925             return true;
4926         }
4927         if (!strcmp(var, "$DIMTIX")) {
4928             return true;
4929         }
4930         if (!strcmp(var, "$DIMTM")) {
4931             return true;
4932         }
4933         if (!strcmp(var, "$DIMTOFL")) {
4934             return true;
4935         }
4936         if (!strcmp(var, "$DIMTOH")) {
4937             return true;
4938         }
4939         if (!strcmp(var, "$DIMTOL")) {
4940             return true;
4941         }
4942         if (!strcmp(var, "$DIMTP")) {
4943             return true;
4944         }
4945         if (!strcmp(var, "$DIMTSZ")) {
4946             return true;
4947         }
4948         if (!strcmp(var, "$DIMTVP")) {
4949             return true;
4950         }
4951         if (!strcmp(var, "$DIMTXT")) {
4952             return true;
4953         }
4954         if (!strcmp(var, "$DIMZIN")) {
4955             return true;
4956         }
4957         if (!strcmp(var, "$DWGCODEPAGE")) {
4958             return true;
4959         }
4960         if (!strcmp(var, "$DRAGMODE")) {
4961             return true;
4962         }
4963         if (!strcmp(var, "$ELEVATION")) {
4964             return true;
4965         }
4966         if (!strcmp(var, "$EXTMAX")) {
4967             return true;
4968         }
4969         if (!strcmp(var, "$EXTMIN")) {
4970             return true;
4971         }
4972         if (!strcmp(var, "$FILLETRAD")) {
4973             return true;
4974         }
4975         if (!strcmp(var, "$FILLMODE")) {
4976             return true;
4977         }
4978         if (!strcmp(var, "$HANDLING")) {
4979             return true;
4980         }
4981         if (!strcmp(var, "$HANDSEED")) {
4982             return true;
4983         }
4984         if (!strcmp(var, "$INSBASE")) {
4985             return true;
4986         }
4987         if (!strcmp(var, "$LIMCHECK")) {
4988             return true;
4989         }
4990         if (!strcmp(var, "$LIMMAX")) {
4991             return true;
4992         }
4993         if (!strcmp(var, "$LIMMIN")) {
4994             return true;
4995         }
4996         if (!strcmp(var, "$LTSCALE")) {
4997             return true;
4998         }
4999         if (!strcmp(var, "$LUNITS")) {
5000             return true;
5001         }
5002         if (!strcmp(var, "$LUPREC")) {
5003             return true;
5004         }
5005         if (!strcmp(var, "$MAXACTVP")) {
5006             return true;
5007         }
5008         if (!strcmp(var, "$MENU")) {
5009             return true;
5010         }
5011         if (!strcmp(var, "$MIRRTEXT")) {
5012             return true;
5013         }
5014         if (!strcmp(var, "$ORTHOMODE")) {
5015             return true;
5016         }
5017         if (!strcmp(var, "$OSMODE")) {
5018             return true;
5019         }
5020         if (!strcmp(var, "$PDMODE")) {
5021             return true;
5022         }
5023         if (!strcmp(var, "$PDSIZE")) {
5024             return true;
5025         }
5026         if (!strcmp(var, "$PELEVATION")) {
5027             return true;
5028         }
5029         if (!strcmp(var, "$PEXTMAX")) {
5030             return true;
5031         }
5032         if (!strcmp(var, "$PEXTMIN")) {
5033             return true;
5034         }
5035         if (!strcmp(var, "$PLIMCHECK")) {
5036             return true;
5037         }
5038         if (!strcmp(var, "$PLIMMAX")) {
5039             return true;
5040         }
5041         if (!strcmp(var, "$PLIMMIN")) {
5042             return true;
5043         }
5044         if (!strcmp(var, "$PLINEGEN")) {
5045             return true;
5046         }
5047         if (!strcmp(var, "$PLINEWID")) {
5048             return true;
5049         }
5050         if (!strcmp(var, "$PSLTSCALE")) {
5051             return true;
5052         }
5053         if (!strcmp(var, "$PUCSNAME")) {
5054             return true;
5055         }
5056         if (!strcmp(var, "$PUCSORG")) {
5057             return true;
5058         }
5059         if (!strcmp(var, "$PUCSXDIR")) {
5060             return true;
5061         }
5062         if (!strcmp(var, "$PUCSYDIR")) {
5063             return true;
5064         }
5065         if (!strcmp(var, "$QTEXTMODE")) {
5066             return true;
5067         }
5068         if (!strcmp(var, "$REGENMODE")) {
5069             return true;
5070         }
5071         if (!strcmp(var, "$SHADEDGE")) {
5072             return true;
5073         }
5074         if (!strcmp(var, "$SHADEDIF")) {
5075             return true;
5076         }
5077         if (!strcmp(var, "$SKETCHINC")) {
5078             return true;
5079         }
5080         if (!strcmp(var, "$SKPOLY")) {
5081             return true;
5082         }
5083         if (!strcmp(var, "$SPLFRAME")) {
5084             return true;
5085         }
5086         if (!strcmp(var, "$SPLINESEGS")) {
5087             return true;
5088         }
5089         if (!strcmp(var, "$SPLINETYPE")) {
5090             return true;
5091         }
5092         if (!strcmp(var, "$SURFTAB1")) {
5093             return true;
5094         }
5095         if (!strcmp(var, "$SURFTAB2")) {
5096             return true;
5097         }
5098         if (!strcmp(var, "$SURFTYPE")) {
5099             return true;
5100         }
5101         if (!strcmp(var, "$SURFU")) {
5102             return true;
5103         }
5104         if (!strcmp(var, "$SURFV")) {
5105             return true;
5106         }
5107         if (!strcmp(var, "$TDCREATE")) {
5108             return true;
5109         }
5110         if (!strcmp(var, "$TDINDWG")) {
5111             return true;
5112         }
5113         if (!strcmp(var, "$TDUPDATE")) {
5114             return true;
5115         }
5116         if (!strcmp(var, "$TDUSRTIMER")) {
5117             return true;
5118         }
5119         if (!strcmp(var, "$TEXTSIZE")) {
5120             return true;
5121         }
5122         if (!strcmp(var, "$TEXTSTYLE")) {
5123             return true;
5124         }
5125         if (!strcmp(var, "$THICKNESS")) {
5126             return true;
5127         }
5128         if (!strcmp(var, "$TILEMODE")) {
5129             return true;
5130         }
5131         if (!strcmp(var, "$TRACEWID")) {
5132             return true;
5133         }
5134         if (!strcmp(var, "$UCSNAME")) {
5135             return true;
5136         }
5137         if (!strcmp(var, "$UCSORG")) {
5138             return true;
5139         }
5140         if (!strcmp(var, "$UCSXDIR")) {
5141             return true;
5142         }
5143         if (!strcmp(var, "$UCSYDIR")) {
5144             return true;
5145         }
5146         if (!strcmp(var, "$UNITMODE")) {
5147             return true;
5148         }
5149         if (!strcmp(var, "$USERI1")) {
5150             return true;
5151         }
5152         if (!strcmp(var, "$USERR1")) {
5153             return true;
5154         }
5155         if (!strcmp(var, "$USRTIMER")) {
5156             return true;
5157         }
5158         if (!strcmp(var, "$VISRETAIN")) {
5159             return true;
5160         }
5161         if (!strcmp(var, "$WORLDVIEW")) {
5162             return true;
5163         }
5164         if (!strcmp(var, "$FASTZOOM")) {
5165             return true;
5166         }
5167         if (!strcmp(var, "$GRIDMODE")) {
5168             return true;
5169         }
5170         if (!strcmp(var, "$GRIDUNIT")) {
5171             return true;
5172         }
5173         if (!strcmp(var, "$SNAPANG")) {
5174             return true;
5175         }
5176         if (!strcmp(var, "$SNAPBASE")) {
5177             return true;
5178         }
5179         if (!strcmp(var, "$SNAPISOPAIR")) {
5180             return true;
5181         }
5182         if (!strcmp(var, "$SNAPMODE")) {
5183             return true;
5184         }
5185         if (!strcmp(var, "$SNAPSTYLE")) {
5186             return true;
5187         }
5188         if (!strcmp(var, "$SNAPUNIT")) {
5189             return true;
5190         }
5191         if (!strcmp(var, "$VIEWCTR")) {
5192             return true;
5193         }
5194         if (!strcmp(var, "$VIEWDIR")) {
5195             return true;
5196         }
5197         if (!strcmp(var, "$VIEWSIZE")) {
5198             return true;
5199         }
5200         return false;
5201     }
5202 
5203     return false;
5204 }
5205 
5206 
5207 
5208 /**
5209  * @returns the library version as int (4 bytes, each byte one version number).
5210  * e.g. if str = "2.0.2.0" getLibVersion returns 0x02000200
5211  */
getLibVersion(const std::string & str)5212 int DL_Dxf::getLibVersion(const std::string& str) {
5213     int d[4];
5214     int idx = 0;
5215     //char v[4][5];
5216     std::string v[4];
5217     int ret = 0;
5218 
5219     for (unsigned int i=0; i<str.length() && idx<3; ++i) {
5220         if (str[i]=='.') {
5221             d[idx] = i;
5222             idx++;
5223         }
5224     }
5225 
5226     if (idx>=2) {
5227         d[3] = str.length();
5228 
5229         v[0] = str.substr(0, d[0]);
5230         v[1] = str.substr(d[0]+1, d[1]-d[0]-1);
5231         v[2] = str.substr(d[1]+1, d[2]-d[1]-1);
5232         if (idx>=3) {
5233             v[3] = str.substr(d[2]+1, d[3]-d[2]-1);
5234         }
5235         else {
5236             v[3] = "0";
5237         }
5238 
5239         ret = (atoi(v[0].c_str())<<(3*8)) +
5240               (atoi(v[1].c_str())<<(2*8)) +
5241               (atoi(v[2].c_str())<<(1*8)) +
5242               (atoi(v[3].c_str())<<(0*8));
5243 
5244         return ret;
5245     } else {
5246         std::cerr << "DL_Dxf::getLibVersion: invalid version number: " << str << "\n";
5247         return 0;
5248     }
5249 }
5250 
5251 /**
5252  * Converts the given string into a double or returns the given
5253  * default valud (def) if value is NULL or empty.
5254  */
5255 //double DL_Dxf::toReal(const char* value, double def) {
5256 //    if (value!=NULL && value[0] != '\0') {
5257 //        printf("toReal: not empty: %s\n", value);
5258 //        printf("toReal: val: %f\n", atof(value));
5259 //        printf("toReal: 0: %d\n", value[0]);
5260 //        printf("toReal: 1: %d\n", value[1]);
5261 //        printf("toReal: 2: %d\n", value[2]);
5262 //        double ret;
5263 //        if (strchr(value, ',') != NULL) {
5264 //            char* tmp = new char[strlen(value)+1];
5265 //            strcpy(tmp, value);
5266 //            DL_WriterA::strReplace(tmp, ',', '.');
5267 //            ret = atof(tmp);
5268 //            delete[] tmp;
5269 //        }
5270 //        else {
5271 //            ret = atof(value);
5272 //        }
5273 //        return ret;
5274 //    } else {
5275 //        return def;
5276 //    }
5277 //}
5278 
5279 
5280 /**
5281  * Some test routines.
5282  */
test()5283 void DL_Dxf::test() {
5284     char* buf1;
5285     char* buf2;
5286     char* buf3;
5287     char* buf4;
5288     char* buf5;
5289     char* buf6;
5290 
5291     buf1 = new char[10];
5292     buf2 = new char[10];
5293     buf3 = new char[10];
5294     buf4 = new char[10];
5295     buf5 = new char[10];
5296     buf6 = new char[10];
5297 
5298     strcpy(buf1, "  10\n");
5299     strcpy(buf2, "10");
5300     strcpy(buf3, "10\n");
5301     strcpy(buf4, "  10 \n");
5302     strcpy(buf5, "  10 \r");
5303     strcpy(buf6, "\t10 \n");
5304 
5305     std::cout << "1 buf1: '" << buf1 << "'\n";
5306     stripWhiteSpace(&buf1);
5307     std::cout << "2 buf1: '" << buf1 << "'\n";
5308     //assert(!strcmp(buf1, "10"));
5309 
5310     std::cout << "1 buf2: '" << buf2 << "'\n";
5311     stripWhiteSpace(&buf2);
5312     std::cout << "2 buf2: '" << buf2 << "'\n";
5313 
5314     std::cout << "1 buf3: '" << buf3 << "'\n";
5315     stripWhiteSpace(&buf3);
5316     std::cout << "2 buf3: '" << buf3 << "'\n";
5317 
5318     std::cout << "1 buf4: '" << buf4 << "'\n";
5319     stripWhiteSpace(&buf4);
5320     std::cout << "2 buf4: '" << buf4 << "'\n";
5321 
5322     std::cout << "1 buf5: '" << buf5 << "'\n";
5323     stripWhiteSpace(&buf5);
5324     std::cout << "2 buf5: '" << buf5 << "'\n";
5325 
5326     std::cout << "1 buf6: '" << buf6 << "'\n";
5327     stripWhiteSpace(&buf6);
5328     std::cout << "2 buf6: '" << buf6 << "'\n";
5329 
5330 }
5331 
5332 
5333