1 /****************************************************************************
2 **
3 ** This file is part of the LibreCAD project, a 2D CAD program
4 **
5 ** Copyright (C) 2015 A. Stebich (librecad@mail.lordofbikes.de)
6 ** Copyright (C) 2011 Rallaz, rallazz@gmail.com
7 ** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
8 **
9 **
10 ** This file may be distributed and/or modified under the terms of the
11 ** GNU General Public License as published by the Free Software
12 ** Foundation either version 2 of the License, or (at your option)
13 **  any later version.
14 **
15 ** This program is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ** GNU General Public License for more details.
19 **
20 ** You should have received a copy of the GNU General Public License
21 ** along with this program; if not, write to the Free Software
22 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
23 **
24 **********************************************************************/
25 
26 #include<cstdlib>
27 #include <QStringList>
28 #include <QTextCodec>
29 
30 #include "rs_filterdxfrw.h"
31 
32 #include "rs_arc.h"
33 #include "rs_circle.h"
34 #include "rs_dimaligned.h"
35 #include "rs_dimangular.h"
36 #include "rs_dimdiametric.h"
37 #include "rs_dimlinear.h"
38 #include "rs_dimradial.h"
39 #include "rs_ellipse.h"
40 #include "rs_hatch.h"
41 #include "rs_image.h"
42 #include "rs_insert.h"
43 #include "rs_layer.h"
44 #include "rs_leader.h"
45 #include "rs_line.h"
46 #include "rs_mtext.h"
47 #include "rs_point.h"
48 #include "rs_polyline.h"
49 #include "rs_solid.h"
50 #include "rs_spline.h"
51 #include "lc_splinepoints.h"
52 #include "rs_system.h"
53 #include "rs_text.h"
54 #include "rs_graphicview.h"
55 #include "rs_dialogfactory.h"
56 #include "rs_math.h"
57 
58 #ifdef DWGSUPPORT
59 #include "libdwgr.h"
60 #include "rs_debug.h"
61 #endif
62 
63 /**
64  * Default constructor.
65  *
66  */
RS_FilterDXFRW()67 RS_FilterDXFRW::RS_FilterDXFRW()
68     :RS_FilterInterface(),DRW_Interface() {
69 
70     RS_DEBUG->print("RS_FilterDXFRW::RS_FilterDXFRW()");
71 
72 	currentContainer = nullptr;
73 	graphic = nullptr;
74 // Init hash to change the QCAD "normal" style to the more correct ISO-3059
75 // or draftsight symbol (AR*.shx) to sy*.lff
76     fontList["normal"] = "iso";
77     fontList["normallatin1"] = "iso";
78     fontList["normallatin2"] = "iso";
79     fontList["arastro"] = "syastro";
80     fontList["armap"] = "symap";
81     fontList["math"] = "symath";
82     fontList["armeteo"] = "symeteo";
83     fontList["armusic"] = "symusic";
84 
85 
86     RS_DEBUG->print("RS_FilterDXFRW::RS_FilterDXFRW(): OK");
87 }
88 
89 /**
90  * Destructor.
91  */
~RS_FilterDXFRW()92 RS_FilterDXFRW::~RS_FilterDXFRW() {
93     RS_DEBUG->print("RS_FilterDXFRW::~RS_FilterDXFRW(): OK");
94 }
95 
96 
97 
98 /**
99  * Implementation of the method used for RS_Import to communicate
100  * with this filter.
101  *
102  * @param g The graphic in which the entities from the file
103  * will be created or the graphics from which the entities are
104  * taken to be stored in a file.
105  */
fileImport(RS_Graphic & g,const QString & file,RS2::FormatType type)106 bool RS_FilterDXFRW::fileImport(RS_Graphic& g, const QString& file, RS2::FormatType type) {
107     RS_DEBUG->print("RS_FilterDXFRW::fileImport");
108 
109     RS_DEBUG->print("DXFRW Filter: importing file '%s'...", (const char*)QFile::encodeName(file));
110 #ifndef DWGSUPPORT
111     Q_UNUSED(type)
112 #endif
113 
114     graphic = &g;
115     currentContainer = graphic;
116 	dummyContainer = new RS_EntityContainer(nullptr, true);
117 
118     this->file = file;
119     // add some variables that need to be there for DXF drawings:
120     graphic->addVariable("$DIMSTYLE", "Standard", 2);
121     dimStyle = "Standard";
122     codePage = "ANSI_1252";
123     textStyle = "Standard";
124     //reset library version
125     isLibDxfRw = false;
126     libDxfRwVersion = 0;
127 
128 #ifdef DWGSUPPORT
129     if (type == RS2::FormatDWG) {
130         dwgR dwgr(QFile::encodeName(file));
131         RS_DEBUG->print("RS_FilterDXFRW::fileImport: reading DWG file");
132         if (RS_DEBUG->getLevel()== RS_Debug::D_DEBUGGING)
133             dwgr.setDebug(DRW::DEBUG);
134         bool success = dwgr.read(this, true);
135         RS_DEBUG->print("RS_FilterDXFRW::fileImport: reading DWG file: OK");
136         RS_DIALOGFACTORY->commandMessage(QObject::tr("Opened dwg file version %1.").arg(printDwgVersion(dwgr.getVersion())));
137         int  lastError = dwgr.getError();
138         if (success==false) {
139             printDwgError(lastError);
140             RS_DEBUG->print(RS_Debug::D_WARNING,
141                             "Cannot open DWG file '%s'.", (const char*)QFile::encodeName(file));
142             return false;
143         }
144     } else {
145 #endif
146         dxfRW dxfR(QFile::encodeName(file));
147 
148         RS_DEBUG->print("RS_FilterDXFRW::fileImport: reading file");
149         bool success = dxfR.read(this, true);
150         RS_DEBUG->print("RS_FilterDXFRW::fileImport: reading file: OK");
151         //graphic->setAutoUpdateBorders(true);
152 
153         if (success==false) {
154             RS_DEBUG->print(RS_Debug::D_WARNING,
155                             "Cannot open DXF file '%s'.", (const char*)QFile::encodeName(file));
156             return false;
157         }
158 #ifdef DWGSUPPORT
159     }
160 #endif
161 
162     delete dummyContainer;
163     /*set current layer */
164     RS_Layer* cl = graphic->findLayer(graphic->getVariableString("$CLAYER", "0"));
165 	if (cl ){
166         //require to notify
167         graphic->getLayerList()->activate(cl, true);
168     }
169     RS_DEBUG->print("RS_FilterDXFRW::fileImport: updating inserts");
170     graphic->updateInserts();
171 
172     RS_DEBUG->print("RS_FilterDXFRW::fileImport OK");
173 
174     return true;
175 }
176 
177 /**
178  * Implementation of the method which handles layers.
179  */
addLayer(const DRW_Layer & data)180 void RS_FilterDXFRW::addLayer(const DRW_Layer &data) {
181     RS_DEBUG->print("RS_FilterDXF::addLayer");
182     RS_DEBUG->print("  adding layer: %s", data.name.c_str());
183 
184     RS_DEBUG->print("RS_FilterDXF::addLayer: creating layer");
185 
186     QString name = QString::fromUtf8(data.name.c_str());
187     if (name != "0" && graphic->findLayer(name)) {
188         return;
189     }
190     RS_Layer* layer = new RS_Layer(name);
191     RS_DEBUG->print("RS_FilterDXF::addLayer: set pen");
192     layer->setPen(attributesToPen(&data));
193 
194     RS_DEBUG->print("RS_FilterDXF::addLayer: flags");
195     if (data.flags&0x01) {
196         layer->freeze(true);
197     }
198     if (data.flags&0x04) {
199         layer->lock(true);
200     }
201     layer->setPrint(data.plotF);
202 
203     //parse extended data to read construction flag
204     if (!data.extData.empty()){
205         RS_DEBUG->print(RS_Debug::D_WARNING, "RS_FilterDXF::addLayer: layer %s have extended data", layer->getName().toStdString().c_str());
206         bool isLCdata = false;
207         for (std::vector<DRW_Variant*>::const_iterator it=data.extData.begin(); it!=data.extData.end(); ++it){
208             if ((*it)->code() == 1001){
209                 if (*(*it)->content.s == std::string("LibreCad"))
210                     isLCdata = true;
211                 else
212                     isLCdata = false;
213             } else if (isLCdata && (*it)->code() == 1070){
214                 if ((*it)->content.i == 1){
215                     layer->setConstruction(true);
216                 }
217             }
218         }
219     }
220     //pre dxfrw 0.5.13 plot flag are used to store construction layer
221     if( isLibDxfRw && libDxfRwVersion < LIBDXFRW_VERSION( 0, 5, 13)) {
222         layer->setConstruction(! data.plotF);
223     }
224 
225     if (layer->isConstruction())
226         RS_DEBUG->print(RS_Debug::D_WARNING, "RS_FilterDXF::addLayer: layer %s is construction layer", layer->getName().toStdString().c_str());
227 
228     RS_DEBUG->print("RS_FilterDXF::addLayer: add layer to graphic");
229     graphic->addLayer(layer);
230     RS_DEBUG->print("RS_FilterDXF::addLayer: OK");
231 }
232 
233 /**
234  * Implementation of the method which handles dimension styles.
235  */
addDimStyle(const DRW_Dimstyle & data)236 void RS_FilterDXFRW::addDimStyle(const DRW_Dimstyle& data){
237     RS_DEBUG->print("RS_FilterDXFRW::addLayer");
238     QString dimstyle = graphic->getVariableString("$DIMSTYLE", "standard");
239 
240     if (QString::compare(data.name.c_str(), dimstyle, Qt::CaseInsensitive) == 0) {
241         if( isLibDxfRw && libDxfRwVersion < LIBDXFRW_VERSION( 0, 6, 2)) {
242             graphic->addVariable("$DIMDEC", graphic->getVariableInt("$DIMDEC",
243                                             graphic->getVariableInt("$LUPREC", 4)), 70);
244             graphic->addVariable("$DIMADEC", graphic->getVariableInt("$DIMADEC",
245                                              graphic->getVariableInt("$AUPREC", 2)), 70);
246             //do nothing;
247         } else {
248             graphic->addVariable("$DIMDEC", data.dimdec, 70);
249             graphic->addVariable("$DIMADEC", data.dimadec, 70);
250         }
251     }
252 }
253 
254 /**
255  * Implementation of the method which handles vports.
256  */
addVport(const DRW_Vport & data)257 void RS_FilterDXFRW::addVport(const DRW_Vport &data) {
258     QString name = QString::fromStdString(data.name);
259     if (name.toLower() == "*active") {
260         data.grid == 1? graphic->setGridOn(true):graphic->setGridOn(false);
261         graphic->setIsometricGrid(data.snapStyle);
262         graphic->setCrosshairType( (RS2::CrosshairType)data.snapIsopair);
263         RS_GraphicView *gv = graphic->getGraphicView();
264 		if (gv ) {
265             double width = data.height * data.ratio;
266             double factorX= gv->getWidth() / width;
267             double factorY= gv->getHeight() / data.height;
268             if (factorX > factorY)
269                 factorX = factorY;
270             int ox = gv->getWidth() -data.center.x*2*factorX;
271             int oy = gv->getHeight() -data.center.y*2*factorX;
272             gv->setOffset(ox, oy);
273             gv->setFactor(factorX);
274         }
275     }
276 }
277 
278 /**
279  * Implementation of the method which handles blocks.
280  *
281  * @todo Adding blocks to blocks (stack for currentContainer)
282  */
addBlock(const DRW_Block & data)283 void RS_FilterDXFRW::addBlock(const DRW_Block& data) {
284 
285     RS_DEBUG->print("RS_FilterDXF::addBlock");
286 
287     RS_DEBUG->print("  adding block: %s", data.name.c_str());
288 /*TODO correct handle of model-space*/
289 
290     QString name = QString::fromUtf8(data.name.c_str());
291     QString mid = name.mid(1,11);
292 // Prevent special blocks (paper_space, model_space) from being added:
293     if (mid.toLower() != "paper_space" && mid.toLower() != "model_space") {
294 
295             RS_Vector bp(data.basePoint.x, data.basePoint.y);
296             RS_Block* block =
297                 new RS_Block(graphic, RS_BlockData(name, bp, false ));
298             //block->setFlags(flags);
299 
300             if (graphic->addBlock(block)) {
301                 currentContainer = block;
302                 blockHash.insert(data.parentHandle, currentContainer);
303             } else
304                 blockHash.insert(data.parentHandle, dummyContainer);
305     } else {
306         if (mid.toLower() == "model_space") {
307             blockHash.insert(data.parentHandle, graphic);
308         } else {
309             blockHash.insert(data.parentHandle, dummyContainer);
310         }
311     }
312 }
313 
314 
setBlock(const int handle)315 void RS_FilterDXFRW::setBlock(const int handle){
316     if (blockHash.contains(handle)) {
317         currentContainer = blockHash.value(handle);
318     } else
319         currentContainer = graphic;
320 }
321 
322 /**
323  * Implementation of the method which closes blocks.
324  */
endBlock()325 void RS_FilterDXFRW::endBlock() {
326     if (currentContainer->rtti() == RS2::EntityBlock) {
327         RS_Block *bk = (RS_Block *)currentContainer;
328         //remove unnamed blocks *D only if version != R12
329         if (version!=1009) {
330             if (bk->getName().startsWith("*D") )
331                 graphic->removeBlock(bk);
332         }
333     }
334     currentContainer = graphic;
335 }
336 
337 
338 
339 /**
340  * Implementation of the method which handles point entities.
341  */
addPoint(const DRW_Point & data)342 void RS_FilterDXFRW::addPoint(const DRW_Point& data) {
343     RS_Vector v(data.basePoint.x, data.basePoint.y);
344 
345     RS_Point* entity = new RS_Point(currentContainer,
346                                     RS_PointData(v));
347     setEntityAttributes(entity, &data);
348 
349     currentContainer->addEntity(entity);
350 }
351 
352 
353 
354 /**
355  * Implementation of the method which handles line entities.
356  */
addLine(const DRW_Line & data)357 void RS_FilterDXFRW::addLine(const DRW_Line& data) {
358     RS_DEBUG->print("RS_FilterDXF::addLine");
359 
360     RS_Vector v1(data.basePoint.x, data.basePoint.y);
361     RS_Vector v2(data.secPoint.x, data.secPoint.y);
362 
363     RS_DEBUG->print("RS_FilterDXF::addLine: create line");
364 
365 	if (!currentContainer) {
366 		RS_DEBUG->print("RS_FilterDXF::addLine: currentContainer is nullptr");
367     }
368 
369 	RS_Line* entity = new RS_Line{currentContainer, {v1, v2}};
370     RS_DEBUG->print("RS_FilterDXF::addLine: set attributes");
371     setEntityAttributes(entity, &data);
372 
373     RS_DEBUG->print("RS_FilterDXF::addLine: add entity");
374 
375 	if (currentContainer) currentContainer->addEntity(entity);
376 
377     RS_DEBUG->print("RS_FilterDXF::addLine: OK");
378 }
379 
380 
381 /**
382  * Implementation of the method which handles ray entities.
383  */
addRay(const DRW_Ray & data)384 void RS_FilterDXFRW::addRay(const DRW_Ray& data) {
385     RS_DEBUG->print("RS_FilterDXF::addRay");
386 
387 	RS_Vector v1{data.basePoint.x, data.basePoint.y};
388 	RS_Vector v2{data.basePoint.x+data.secPoint.x,
389 				data.basePoint.y+data.secPoint.y};
390 
391     RS_DEBUG->print("RS_FilterDXF::addRay: create line");
392 
393 	if (!currentContainer) {
394 		RS_DEBUG->print("RS_FilterDXF::addRay: currentContainer is nullptr");
395     }
396 
397 	RS_Line* entity = new RS_Line{currentContainer, {v1, v2}};
398     RS_DEBUG->print("RS_FilterDXF::addRay: set attributes");
399     setEntityAttributes(entity, &data);
400 
401     RS_DEBUG->print("RS_FilterDXF::addRay: add entity");
402 
403 	if (currentContainer) currentContainer->addEntity(entity);
404 
405     RS_DEBUG->print("RS_FilterDXF::addRay: OK");
406 }
407 
408 
409 /**
410  * Implementation of the method which handles line entities.
411  */
addXline(const DRW_Xline & data)412 void RS_FilterDXFRW::addXline(const DRW_Xline& data) {
413     RS_DEBUG->print("RS_FilterDXF::addXline");
414 
415     RS_Vector v1(data.basePoint.x, data.basePoint.y);
416     RS_Vector v2(data.basePoint.x+data.secPoint.x, data.basePoint.y+data.secPoint.y);
417 
418     RS_DEBUG->print("RS_FilterDXF::addXline: create line");
419 
420 	if (!currentContainer) {
421 		RS_DEBUG->print("RS_FilterDXF::addXline: currentContainer is nullptr");
422     }
423 
424 	RS_Line* entity = new RS_Line{currentContainer, {v1, v2}};
425     RS_DEBUG->print("RS_FilterDXF::addXline: set attributes");
426     setEntityAttributes(entity, &data);
427 
428     RS_DEBUG->print("RS_FilterDXF::addXline: add entity");
429 
430 	if (currentContainer) currentContainer->addEntity(entity);
431 
432     RS_DEBUG->print("RS_FilterDXF::addXline: OK");
433 }
434 
435 
436 
437 /**
438  * Implementation of the method which handles circle entities.
439  */
addCircle(const DRW_Circle & data)440 void RS_FilterDXFRW::addCircle(const DRW_Circle& data) {
441     RS_DEBUG->print("RS_FilterDXF::addCircle");
442 
443 	RS_Vector v{data.basePoint.x, data.basePoint.y};
444 	RS_Circle* entity = new RS_Circle(currentContainer, {v, data.radious});
445     setEntityAttributes(entity, &data);
446 
447     currentContainer->addEntity(entity);
448 }
449 
450 
451 
452 /**
453  * Implementation of the method which handles arc entities.
454  *
455  * @param angle1 Start angle in deg (!)
456  * @param angle2 End angle in deg (!)
457  */
addArc(const DRW_Arc & data)458 void RS_FilterDXFRW::addArc(const DRW_Arc& data) {
459     RS_DEBUG->print("RS_FilterDXF::addArc");
460     RS_Vector v(data.basePoint.x, data.basePoint.y);
461     RS_ArcData d(v, data.radious,
462                  data.staangle,
463                  data.endangle,
464                  false);
465     RS_Arc* entity = new RS_Arc(currentContainer, d);
466     setEntityAttributes(entity, &data);
467 
468     currentContainer->addEntity(entity);
469 }
470 
471 
472 
473 /**
474  * Implementation of the method which handles ellipse entities.
475  *
476  * @param angle1 Start angle in rad (!)
477  * @param angle2 End angle in rad (!)
478  */
addEllipse(const DRW_Ellipse & data)479 void RS_FilterDXFRW::addEllipse(const DRW_Ellipse& data) {
480     RS_DEBUG->print("RS_FilterDXFRW::addEllipse");
481 
482 	RS_Vector v1(data.basePoint.x, data.basePoint.y);
483 	RS_Vector v2(data.secPoint.x, data.secPoint.y);
484 	double ang2 = data.endparam;
485 	if (fabs(ang2 - 2.*M_PI) < RS_TOLERANCE &&
486 			fabs(data.staparam) < RS_TOLERANCE)
487 		ang2 = 0.;
488 	RS_Ellipse* entity = new RS_Ellipse{currentContainer,
489 										{v1, v2,
490 										data.ratio,
491 										data.staparam, ang2, false}};
492     setEntityAttributes(entity, &data);
493 
494     currentContainer->addEntity(entity);
495 }
496 
497 
498 /**
499  * Implementation of the method which handles trace entities.
500  */
addTrace(const DRW_Trace & data)501 void RS_FilterDXFRW::addTrace(const DRW_Trace& data) {
502     RS_Solid* entity;
503 	RS_Vector v1{data.basePoint.x, data.basePoint.y};
504 	RS_Vector v2{data.secPoint.x, data.secPoint.y};
505 	RS_Vector v3{data.thirdPoint.x, data.thirdPoint.y};
506 	RS_Vector v4{data.fourPoint.x, data.fourPoint.y};
507     if (v3 == v4)
508         entity = new RS_Solid(currentContainer, RS_SolidData(v1, v2, v3));
509     else
510         entity = new RS_Solid(currentContainer, RS_SolidData(v1, v2, v3,v4));
511 
512     setEntityAttributes(entity, &data);
513     currentContainer->addEntity(entity);
514 }
515 
516 /**
517  * Implementation of the method which handles solid entities.
518  */
addSolid(const DRW_Solid & data)519 void RS_FilterDXFRW::addSolid(const DRW_Solid& data) {
520     addTrace(data);
521 }
522 
523 /**
524  * Implementation of the method which handles lightweight polyline entities.
525  */
addLWPolyline(const DRW_LWPolyline & data)526 void RS_FilterDXFRW::addLWPolyline(const DRW_LWPolyline& data) {
527     RS_DEBUG->print("RS_FilterDXFRW::addLWPolyline");
528     if (data.vertlist.empty())
529         return;
530     RS_PolylineData d(RS_Vector{},
531                       RS_Vector{},
532                       data.flags&0x1);
533     RS_Polyline *polyline = new RS_Polyline(currentContainer, d);
534     setEntityAttributes(polyline, &data);
535 
536     std::vector< std::pair<RS_Vector, double> > verList;
537     for (auto const& v: data.vertlist)
538         verList.emplace_back(std::make_pair(RS_Vector{v->x, v->y}, v->bulge));
539 
540     polyline->appendVertexs(verList);
541 
542     currentContainer->addEntity(polyline);
543 }
544 
545 
546 /**
547  * Implementation of the method which handles polyline entities.
548  */
addPolyline(const DRW_Polyline & data)549 void RS_FilterDXFRW::addPolyline(const DRW_Polyline& data) {
550     RS_DEBUG->print("RS_FilterDXFRW::addPolyline");
551     if ( data.flags&0x10)
552         return; //the polyline is a polygon mesh, not handled
553 
554     if ( data.flags&0x40)
555         return; //the polyline is a poliface mesh, TODO convert
556 
557     RS_PolylineData d(RS_Vector{},
558                       RS_Vector{},
559                       data.flags&0x1);
560     RS_Polyline *polyline = new RS_Polyline(currentContainer, d);
561     setEntityAttributes(polyline, &data);
562 
563     std::vector< std::pair<RS_Vector, double> > verList;
564 
565     for (auto const& v: data.vertlist)
566         verList.emplace_back(
567                     std::make_pair(RS_Vector{v->basePoint.x, v->basePoint.y},
568                                    v->bulge));
569 
570     polyline->appendVertexs(verList);
571 
572     currentContainer->addEntity(polyline);
573 }
574 
575 
576 /**
577  * Implementation of the method which handles splines.
578  */
addSpline(const DRW_Spline * data)579 void RS_FilterDXFRW::addSpline(const DRW_Spline* data) {
580     RS_DEBUG->print("RS_FilterDXFRW::addSpline: degree: %d", data->degree);
581 
582 	if(data->degree == 2)
583 	{
584 		LC_SplinePoints* splinePoints;
585 		LC_SplinePointsData d(((data->flags&0x1)==0x1), true);
586 		splinePoints = new LC_SplinePoints(currentContainer, d);
587 		setEntityAttributes(splinePoints, data);
588 		currentContainer->addEntity(splinePoints);
589 
590 		for(auto const& vert: data->controllist) {
591 			RS_Vector v(vert->x, vert->y);
592 			splinePoints->addControlPoint(v);
593 		}
594 		splinePoints->update();
595 		return;
596 	}
597 
598         RS_Spline* spline;
599         if (data->degree>=1 && data->degree<=3) {
600         RS_SplineData d(data->degree, ((data->flags&0x1)==0x1));
601 		if (data->knotslist.size())
602 			d.knotslist = data->knotslist;
603         spline = new RS_Spline(currentContainer, d);
604         setEntityAttributes(spline, data);
605 
606         currentContainer->addEntity(spline);
607     } else {
608         RS_DEBUG->print(RS_Debug::D_WARNING,
609                         "RS_FilterDXF::addSpline: Invalid degree for spline: %d. "
610                         "Accepted values are 1..3.", data->degree);
611         return;
612 	}
613 	for (auto const& vert: data->controllist)
614 		spline->addControlPoint({vert->x, vert->y});
615 
616     if (data->ncontrol== 0 && data->degree != 2){
617 		for (auto const& vert: data->fitlist)
618 			spline->addControlPoint({vert->x, vert->y});
619 
620     }
621     spline->update();
622 }
623 
624 
625 /**
626  * Implementation of the method which handles inserts.
627  */
addInsert(const DRW_Insert & data)628 void RS_FilterDXFRW::addInsert(const DRW_Insert& data) {
629 
630     RS_DEBUG->print("RS_FilterDXF::addInsert");
631 
632     RS_Vector ip(data.basePoint.x, data.basePoint.y);
633     RS_Vector sc(data.xscale, data.yscale);
634     RS_Vector sp(data.colspace, data.rowspace);
635 
636     //cout << "Insert: " << name << " " << ip << " " << cols << "/" << rows << endl;
637 
638     RS_InsertData d( QString::fromUtf8(data.name.c_str()),
639                     ip, sc, data.angle,
640                     data.colcount, data.rowcount,
641 					sp, nullptr, RS2::NoUpdate);
642     RS_Insert* entity = new RS_Insert(currentContainer, d);
643     setEntityAttributes(entity, &data);
644     RS_DEBUG->print("  id: %d", entity->getId());
645 //    entity->update();
646     currentContainer->addEntity(entity);
647 }
648 
649 
650 
651 /**
652  * Implementation of the method which handles
653  * multi texts (MTEXT).
654  */
addMText(const DRW_MText & data)655 void RS_FilterDXFRW::addMText(const DRW_MText& data) {
656     RS_DEBUG->print("RS_FilterDXF::addMText: %s", data.text.c_str());
657 
658     RS_MTextData::VAlign valign;
659     RS_MTextData::HAlign halign;
660     RS_MTextData::MTextDrawingDirection dir;
661     RS_MTextData::MTextLineSpacingStyle lss;
662     QString sty = QString::fromUtf8(data.style.c_str());
663     sty=sty.toLower();
664 
665     if (data.textgen<=3) {
666         valign=RS_MTextData::VATop;
667     } else if (data.textgen<=6) {
668         valign=RS_MTextData::VAMiddle;
669     } else {
670         valign=RS_MTextData::VABottom;
671     }
672 
673     if (data.textgen%3==1) {
674         halign=RS_MTextData::HALeft;
675     } else if (data.textgen%3==2) {
676         halign=RS_MTextData::HACenter;
677     } else {
678         halign=RS_MTextData::HARight;
679     }
680 
681     if (data.alignH==1) {
682         dir = RS_MTextData::LeftToRight;
683     } else if (data.alignH==3) {
684         dir = RS_MTextData::TopToBottom;
685     } else {
686         dir = RS_MTextData::ByStyle;
687     }
688 
689     if (data.alignV==1) {
690         lss = RS_MTextData::AtLeast;
691     } else {
692         lss = RS_MTextData::Exact;
693     }
694 
695     QString mtext = toNativeString(QString::fromUtf8(data.text.c_str()));
696     // use default style for the drawing:
697     if (sty.isEmpty()) {
698         // japanese, cyrillic:
699         if (codePage=="ANSI_932" || codePage=="ANSI_1251") {
700             sty = "Unicode";
701         } else {
702             sty = textStyle;
703         }
704     } else {
705         sty = fontList.value(sty, sty);
706     }
707 
708     RS_DEBUG->print("Text as unicode:");
709     RS_DEBUG->printUnicode(mtext);
710     double interlin = data.interlin;
711     double angle = data.angle*M_PI/180.;
712     RS_Vector ip = RS_Vector(data.basePoint.x, data.basePoint.y);
713 
714 //Correct bad alignment of older dxflib or libdxfrw < 0.5.4
715     if (oldMText) {
716         interlin = data.interlin*0.96;
717         if (valign == RS_MTextData::VABottom) {
718             QStringList tl = mtext.split('\n', QString::SkipEmptyParts);
719             if (!tl.isEmpty()) {
720                 QString txt = tl.at(tl.size()-1);
721                 RS_TextData d(RS_Vector(0.,0.,0.), RS_Vector(0.,0.,0.),
722 
723                               data.height, 1, RS_TextData::VABaseline, RS_TextData::HALeft,
724                               RS_TextData::None, txt, sty, 0,
725                               RS2::Update);
726 				RS_Text* entity = new RS_Text(nullptr, d);
727                 double textTail = entity->getMin().y;
728                 delete entity;
729                 RS_Vector ot = RS_Vector(0.0,textTail).rotate(angle);
730                 ip.move(ot);
731             }
732         }
733     }
734 
735     RS_MTextData d(ip, data.height, data.widthscale,
736                   valign, halign,
737                   dir, lss,
738                   interlin,
739                   mtext, sty, angle,
740                   RS2::NoUpdate);
741     RS_MText* entity = new RS_MText(currentContainer, d);
742 
743     setEntityAttributes(entity, &data);
744     entity->update();
745     currentContainer->addEntity(entity);
746 }
747 
748 
749 
750 /**
751  * Implementation of the method which handles
752  * texts (TEXT).
753  */
addText(const DRW_Text & data)754 void RS_FilterDXFRW::addText(const DRW_Text& data) {
755     RS_DEBUG->print("RS_FilterDXFRW::addText");
756     RS_Vector refPoint = RS_Vector(data.basePoint.x, data.basePoint.y);;
757     RS_Vector secPoint = RS_Vector(data.secPoint.x, data.secPoint.y);;
758     double angle = data.angle;
759 
760     if (data.alignV !=0 || data.alignH !=0 ||data.alignH ==DRW_Text::HMiddle){
761         if (data.alignH !=DRW_Text::HAligned && data.alignH !=DRW_Text::HFit){
762             secPoint = RS_Vector(data.basePoint.x, data.basePoint.y);
763             refPoint = RS_Vector(data.secPoint.x, data.secPoint.y);
764         }
765     }
766 
767     RS_TextData::VAlign valign = (RS_TextData::VAlign)data.alignV;
768     RS_TextData::HAlign halign = (RS_TextData::HAlign)data.alignH;
769     RS_TextData::TextGeneration dir;
770     QString sty = QString::fromUtf8(data.style.c_str());
771     sty=sty.toLower();
772 
773     if (data.textgen==2) {
774         dir = RS_TextData::Backward;
775     } else if (data.textgen==4) {
776         dir = RS_TextData::UpsideDown;
777     } else {
778         dir = RS_TextData::None;
779     }
780 
781     QString mtext = toNativeString(QString::fromUtf8(data.text.c_str()));
782     // use default style for the drawing:
783     if (sty.isEmpty()) {
784         // japanese, cyrillic:
785         if (codePage=="ANSI_932" || codePage=="ANSI_1251") {
786             sty = "Unicode";
787         } else {
788             sty = textStyle;
789         }
790     } else {
791         sty = fontList.value(sty, sty);
792     }
793 
794     RS_DEBUG->print("Text as unicode:");
795     RS_DEBUG->printUnicode(mtext);
796 
797     RS_TextData d(refPoint, secPoint, data.height, data.widthscale,
798                   valign, halign, dir,
799                   mtext, sty, angle*M_PI/180,
800                   RS2::NoUpdate);
801     RS_Text* entity = new RS_Text(currentContainer, d);
802 
803     setEntityAttributes(entity, &data);
804     entity->update();
805     currentContainer->addEntity(entity);
806 }
807 
808 
809 
810 /**
811  * Implementation of the method which handles
812  * dimensions (DIMENSION).
813  */
convDimensionData(const DRW_Dimension * data)814 RS_DimensionData RS_FilterDXFRW::convDimensionData(const  DRW_Dimension* data) {
815 
816     DRW_Coord crd = data->getDefPoint();
817     RS_Vector defP(crd.x, crd.y);
818     crd = data->getTextPoint();
819     RS_Vector midP(crd.x, crd.y);
820     RS_MTextData::VAlign valign;
821     RS_MTextData::HAlign halign;
822     RS_MTextData::MTextLineSpacingStyle lss;
823     QString sty = QString::fromUtf8(data->getStyle().c_str());
824 
825     QString t; //= data.text;
826 
827     // middlepoint of text can be 0/0 which is considered to be invalid (!):
828     //  0/0 because older QCad versions save the middle of the text as 0/0
829     //  although they didn't support saving of the middle of the text.
830     if (fabs(crd.x)<1.0e-6 && fabs(crd.y)<1.0e-6) {
831         midP = RS_Vector(false);
832     }
833 
834     if (data->getAlign()<=3) {
835         valign=RS_MTextData::VATop;
836     } else if (data->getAlign()<=6) {
837         valign=RS_MTextData::VAMiddle;
838     } else {
839         valign=RS_MTextData::VABottom;
840     }
841 
842     if (data->getAlign()%3==1) {
843         halign=RS_MTextData::HALeft;
844     } else if (data->getAlign()%3==2) {
845         halign=RS_MTextData::HACenter;
846     } else {
847         halign=RS_MTextData::HARight;
848     }
849 
850     if (data->getTextLineStyle()==1) {
851         lss = RS_MTextData::AtLeast;
852     } else {
853         lss = RS_MTextData::Exact;
854     }
855 
856     t = toNativeString(QString::fromUtf8( data->getText().c_str() ));
857 
858     if (sty.isEmpty()) {
859         sty = dimStyle;
860     }
861 
862     RS_DEBUG->print("Text as unicode:");
863     RS_DEBUG->printUnicode(t);
864 
865     // data needed to add the actual dimension entity
866     return RS_DimensionData(defP, midP,
867                             valign, halign,
868                             lss,
869                             data->getTextLineFactor(),
870                             t, sty, data->getDir());
871 }
872 
873 
874 
875 /**
876  * Implementation of the method which handles
877  * aligned dimensions (DIMENSION).
878  */
addDimAlign(const DRW_DimAligned * data)879 void RS_FilterDXFRW::addDimAlign(const DRW_DimAligned *data) {
880     RS_DEBUG->print("RS_FilterDXFRW::addDimAligned");
881 
882     RS_DimensionData dimensionData = convDimensionData((DRW_Dimension*)data);
883 
884     RS_Vector ext1(data->getDef1Point().x, data->getDef1Point().y);
885     RS_Vector ext2(data->getDef2Point().x, data->getDef2Point().y);
886 
887     RS_DimAlignedData d(ext1, ext2);
888 
889     RS_DimAligned* entity = new RS_DimAligned(currentContainer,
890                             dimensionData, d);
891     setEntityAttributes(entity, data);
892     entity->updateDimPoint();
893     entity->update();
894     currentContainer->addEntity(entity);
895 }
896 
897 
898 
899 /**
900  * Implementation of the method which handles
901  * linear dimensions (DIMENSION).
902  */
addDimLinear(const DRW_DimLinear * data)903 void RS_FilterDXFRW::addDimLinear(const DRW_DimLinear *data) {
904     RS_DEBUG->print("RS_FilterDXFRW::addDimLinear");
905 
906     RS_DimensionData dimensionData = convDimensionData((DRW_Dimension*)data);
907 
908     RS_Vector dxt1(data->getDef1Point().x, data->getDef1Point().y);
909     RS_Vector dxt2(data->getDef2Point().x, data->getDef2Point().y);
910 
911     RS_DimLinearData d(dxt1, dxt2, RS_Math::deg2rad(data->getAngle()),
912                        RS_Math::deg2rad(data->getOblique()));
913 
914     RS_DimLinear* entity = new RS_DimLinear(currentContainer,
915                                             dimensionData, d);
916     setEntityAttributes(entity, data);
917     entity->update();
918     currentContainer->addEntity(entity);
919 }
920 
921 
922 
923 /**
924  * Implementation of the method which handles
925  * radial dimensions (DIMENSION).
926  */
addDimRadial(const DRW_DimRadial * data)927 void RS_FilterDXFRW::addDimRadial(const DRW_DimRadial* data) {
928     RS_DEBUG->print("RS_FilterDXFRW::addDimRadial");
929 
930     RS_DimensionData dimensionData = convDimensionData((DRW_Dimension*)data);
931     RS_Vector dp(data->getDiameterPoint().x, data->getDiameterPoint().y);
932 
933     RS_DimRadialData d(dp, data->getLeaderLength());
934 
935     RS_DimRadial* entity = new RS_DimRadial(currentContainer,
936                                             dimensionData, d);
937 
938     setEntityAttributes(entity, data);
939     entity->update();
940     currentContainer->addEntity(entity);
941 }
942 
943 
944 
945 /**
946  * Implementation of the method which handles
947  * diametric dimensions (DIMENSION).
948  */
addDimDiametric(const DRW_DimDiametric * data)949 void RS_FilterDXFRW::addDimDiametric(const DRW_DimDiametric* data) {
950     RS_DEBUG->print("RS_FilterDXFRW::addDimDiametric");
951 
952     RS_DimensionData dimensionData = convDimensionData((DRW_Dimension*)data);
953     RS_Vector dp(data->getDiameter1Point().x, data->getDiameter1Point().y);
954 
955     RS_DimDiametricData d(dp, data->getLeaderLength());
956 
957     RS_DimDiametric* entity = new RS_DimDiametric(currentContainer,
958                               dimensionData, d);
959 
960     setEntityAttributes(entity, data);
961     entity->update();
962     currentContainer->addEntity(entity);
963 }
964 
965 
966 
967 /**
968  * Implementation of the method which handles
969  * angular dimensions (DIMENSION).
970  */
addDimAngular(const DRW_DimAngular * data)971 void RS_FilterDXFRW::addDimAngular(const DRW_DimAngular* data) {
972     RS_DEBUG->print("RS_FilterDXFRW::addDimAngular");
973 
974     RS_DimensionData dimensionData = convDimensionData(data);
975     RS_Vector dp1(data->getFirstLine1().x, data->getFirstLine1().y);
976     RS_Vector dp2(data->getFirstLine2().x, data->getFirstLine2().y);
977     RS_Vector dp3(data->getSecondLine1().x, data->getSecondLine1().y);
978     RS_Vector dp4(data->getDimPoint().x, data->getDimPoint().y);
979 
980     RS_DimAngularData d(dp1, dp2, dp3, dp4);
981 
982     RS_DimAngular* entity = new RS_DimAngular(currentContainer,
983                             dimensionData, d);
984 
985     setEntityAttributes(entity, data);
986     entity->update();
987     currentContainer->addEntity(entity);
988 }
989 
990 
991 
992 /**
993  * Implementation of the method which handles
994  * angular dimensions (DIMENSION).
995  */
addDimAngular3P(const DRW_DimAngular3p * data)996 void RS_FilterDXFRW::addDimAngular3P(const DRW_DimAngular3p* data) {
997     RS_DEBUG->print("RS_FilterDXFRW::addDimAngular3P");
998 
999     RS_DimensionData dimensionData = convDimensionData(data);
1000     RS_Vector dp1(data->getFirstLine().x, data->getFirstLine().y);
1001     RS_Vector dp2(data->getSecondLine().x, data->getSecondLine().y);
1002     RS_Vector dp3(data->getVertexPoint().x, data->getVertexPoint().y);
1003 	RS_Vector dp4 = dimensionData.definitionPoint;
1004 	dimensionData.definitionPoint = RS_Vector(data->getVertexPoint().x, data->getVertexPoint().y);
1005 
1006     RS_DimAngularData d(dp1, dp2, dp3, dp4);
1007 
1008     RS_DimAngular* entity = new RS_DimAngular(currentContainer,
1009                             dimensionData, d);
1010 
1011     setEntityAttributes(entity, data);
1012     entity->update();
1013     currentContainer->addEntity(entity);
1014 }
1015 
1016 
1017 
addDimOrdinate(const DRW_DimOrdinate *)1018 void RS_FilterDXFRW::addDimOrdinate(const DRW_DimOrdinate* /*data*/) {
1019     RS_DEBUG->print("RS_FilterDXFRW::addDimOrdinate(const DL_DimensionData&, const DL_DimOrdinateData&) not yet implemented");
1020 }
1021 
1022 
1023 /**
1024  * Implementation of the method which handles leader entities.
1025  */
addLeader(const DRW_Leader * data)1026 void RS_FilterDXFRW::addLeader(const DRW_Leader *data) {
1027     RS_DEBUG->print("RS_FilterDXFRW::addDimLeader");
1028     RS_LeaderData d(data->arrow!=0);
1029     RS_Leader* leader = new RS_Leader(currentContainer, d);
1030     setEntityAttributes(leader, data);
1031 
1032 	for (auto const& vert: data->vertexlist)
1033 		leader->addVertex({vert->x, vert->y});
1034 
1035     leader->update();
1036     currentContainer->addEntity(leader);
1037 
1038 }
1039 
1040 
1041 
1042 /**
1043  * Implementation of the method which handles hatch entities.
1044  */
addHatch(const DRW_Hatch * data)1045 void RS_FilterDXFRW::addHatch(const DRW_Hatch *data) {
1046     RS_DEBUG->print("RS_FilterDXF::addHatch()");
1047     RS_Hatch* hatch;
1048     RS_EntityContainer* hatchLoop;
1049 
1050     hatch = new RS_Hatch(currentContainer,
1051                          RS_HatchData(data->solid, data->scale, data->angle,
1052                                       QString::fromUtf8(data->name.c_str())));
1053     setEntityAttributes(hatch, data);
1054     currentContainer->appendEntity(hatch);
1055 
1056     for (unsigned int i=0; i < data->looplist.size(); i++) {
1057 		auto& loop = data->looplist.at(i);
1058         if ((loop->type & 32) == 32) continue;
1059         hatchLoop = new RS_EntityContainer(hatch);
1060 		hatchLoop->setLayer(nullptr);
1061         hatch->addEntity(hatchLoop);
1062 
1063 		RS_Entity* e = nullptr;
1064         if ((loop->type & 2) == 2){   //polyline, convert to lines & arcs
1065 			DRW_LWPolyline* pline = (DRW_LWPolyline *)loop->objlist.at(0).get();
1066 			RS_Polyline polyline{nullptr,
1067 					RS_PolylineData(RS_Vector(false), RS_Vector(false), pline->flags)};
1068 			for (auto const& vert: pline->vertlist)
1069 				polyline.addVertex(RS_Vector{vert->x, vert->y}, vert->bulge);
1070 
1071 			for (RS_Entity* e=polyline.firstEntity(); e;
1072 					e=polyline.nextEntity()) {
1073                 RS_Entity* tmp = e->clone();
1074                 tmp->reparent(hatchLoop);
1075 				tmp->setLayer(nullptr);
1076                 hatchLoop->addEntity(tmp);
1077 			}
1078 
1079         } else {
1080             for (unsigned int j=0; j<loop->objlist.size(); j++) {
1081 				e = nullptr;
1082 				auto& ent = loop->objlist.at(j);
1083                 switch (ent->eType) {
1084                 case DRW::LINE: {
1085 					DRW_Line *e2 = (DRW_Line *)ent.get();
1086 					e = new RS_Line{hatchLoop,
1087 					{{e2->basePoint.x, e2->basePoint.y},
1088 					{e2->secPoint.x, e2->secPoint.y}}};
1089 					break;
1090                 }
1091                 case DRW::ARC: {
1092 					DRW_Arc *e2 = (DRW_Arc *)ent.get();
1093                     if (e2->isccw && e2->staangle<1.0e-6 && e2->endangle>RS_Math::deg2rad(360)-1.0e-6) {
1094                         e = new RS_Circle(hatchLoop,
1095 						{{e2->basePoint.x, e2->basePoint.y},
1096 														e2->radious});
1097                     } else {
1098 
1099                         if (e2->isccw) {
1100                             e = new RS_Arc(hatchLoop,
1101                                         RS_ArcData(RS_Vector(e2->basePoint.x, e2->basePoint.y), e2->radious,
1102                                                    RS_Math::correctAngle(e2->staangle),
1103                                                    RS_Math::correctAngle(e2->endangle),
1104                                                    false));
1105                         } else {
1106                             e = new RS_Arc(hatchLoop,
1107                                         RS_ArcData(RS_Vector(e2->basePoint.x, e2->basePoint.y), e2->radious,
1108                                                    RS_Math::correctAngle(2*M_PI-e2->staangle),
1109                                                    RS_Math::correctAngle(2*M_PI-e2->endangle),
1110                                                    true));
1111                         }
1112                     }
1113                     break;
1114                 }
1115                 case DRW::ELLIPSE: {
1116 					DRW_Ellipse *e2 = (DRW_Ellipse *)ent.get();
1117                     double ang1 = e2->staparam;
1118                     double ang2 = e2->endparam;
1119 					if ( fabs(ang2 - 2.*M_PI) < 1.0e-10 && fabs(ang1) < 1.0e-10 )
1120                         ang2 = 0.0;
1121                     else { //convert angle to parameter
1122                         ang1 = atan(tan(ang1)/e2->ratio);
1123                         ang2 = atan(tan(ang2)/e2->ratio);
1124                         if (ang1 < 0){//quadrant 2 & 4
1125                             ang1 +=M_PI;
1126                             if (e2->staparam > M_PI) //quadrant 4
1127                                 ang1 +=M_PI;
1128                         } else if (e2->staparam > M_PI){//3 quadrant
1129                             ang1 +=M_PI;
1130                         }
1131                         if (ang2 < 0){//quadrant 2 & 4
1132                             ang2 +=M_PI;
1133                             if (e2->endparam > M_PI) //quadrant 4
1134                                 ang2 +=M_PI;
1135                         } else if (e2->endparam > M_PI){//3 quadrant
1136                             ang2 +=M_PI;
1137                         }
1138                     }
1139 					e = new RS_Ellipse{hatchLoop,
1140 					{{e2->basePoint.x, e2->basePoint.y},
1141 					{e2->secPoint.x, e2->secPoint.y},
1142 							e2->ratio, ang1, ang2, !e2->isccw}};
1143 					break;
1144                 }
1145                 default:
1146                     break;
1147                 }
1148                 if (e) {
1149 					e->setLayer(nullptr);
1150                     hatchLoop->addEntity(e);
1151                 }
1152             }
1153         }
1154 
1155     }
1156 
1157     RS_DEBUG->print("hatch->update()");
1158     if (hatch->validate()) {
1159         hatch->update();
1160     } else {
1161         graphic->removeEntity(hatch);
1162         RS_DEBUG->print(RS_Debug::D_ERROR,
1163                     "RS_FilterDXFRW::endEntity(): updating hatch failed: invalid hatch area");
1164     }
1165 }
1166 
1167 
1168 /**
1169  * Implementation of the method which handles image entities.
1170  */
addImage(const DRW_Image * data)1171 void RS_FilterDXFRW::addImage(const DRW_Image *data) {
1172     RS_DEBUG->print("RS_FilterDXF::addImage");
1173 
1174     RS_Vector ip(data->basePoint.x, data->basePoint.y);
1175     RS_Vector uv(data->secPoint.x, data->secPoint.y);
1176     RS_Vector vv(data->vVector.x, data->vVector.y);
1177     RS_Vector size(data->sizeu, data->sizev);
1178 
1179     RS_Image* image = new RS_Image( currentContainer,
1180             RS_ImageData(data->ref, ip, uv, vv, size,
1181                          QString(""), data->brightness,
1182                          data->contrast, data->fade));
1183 
1184     setEntityAttributes(image, data);
1185     currentContainer->appendEntity(image);
1186 }
1187 
1188 
1189 
1190 /**
1191  * Implementation of the method which links image entities to image files.
1192  */
linkImage(const DRW_ImageDef * data)1193 void RS_FilterDXFRW::linkImage(const DRW_ImageDef *data) {
1194     RS_DEBUG->print("RS_FilterDXFRW::linkImage");
1195 
1196     int handle = data->handle;
1197     QString sfile(QString::fromUtf8(data->name.c_str()));
1198     QFileInfo fiDxf(file);
1199     QFileInfo fiBitmap(sfile);
1200 
1201     // try to find the image file:
1202 
1203     // first: absolute path:
1204     if (!fiBitmap.exists()) {
1205         RS_DEBUG->print("File %s doesn't exist.",
1206                         (const char*)QFile::encodeName(sfile));
1207         // try relative path:
1208         QString f1 = fiDxf.absolutePath() + "/" + sfile;
1209         if (QFileInfo(f1).exists()) {
1210             sfile = f1;
1211         } else {
1212             RS_DEBUG->print("File %s doesn't exist.", (const char*)QFile::encodeName(f1));
1213             // try drawing path:
1214             QString f2 = fiDxf.absolutePath() + "/" + fiBitmap.fileName();
1215             if (QFileInfo(f2).exists()) {
1216                 sfile = f2;
1217             } else {
1218                 RS_DEBUG->print("File %s doesn't exist.", (const char*)QFile::encodeName(f2));
1219             }
1220         }
1221     }
1222 
1223     // Also link images in subcontainers (e.g. inserts):
1224     for (RS_Entity* e=graphic->firstEntity(RS2::ResolveNone);
1225             e; e=graphic->nextEntity(RS2::ResolveNone)) {
1226         if (e->rtti()==RS2::EntityImage) {
1227             RS_Image* img = (RS_Image*)e;
1228             if (img->getHandle()==handle) {
1229                 img->setFile(sfile);
1230                 RS_DEBUG->print("image found: %s", (const char*)QFile::encodeName(img->getFile()));
1231                 img->update();
1232             }
1233         }
1234     }
1235 
1236     // update images in blocks:
1237     for (unsigned i=0; i<graphic->countBlocks(); ++i) {
1238         RS_Block* b = graphic->blockAt(i);
1239         for (RS_Entity* e=b->firstEntity(RS2::ResolveNone);
1240                 e; e=b->nextEntity(RS2::ResolveNone)) {
1241             if (e->rtti()==RS2::EntityImage) {
1242                 RS_Image* img = (RS_Image*)e;
1243                 if (img->getHandle()==handle) {
1244                     img->setFile(sfile);
1245                     RS_DEBUG->print("image in block found: %s",
1246                                     (const char*)QFile::encodeName(img->getFile()));
1247                     img->update();
1248                 }
1249             }
1250         }
1251     }
1252     RS_DEBUG->print("linking image: OK");
1253 }
1254 
1255 using std::map;
1256 /**
1257  * Sets the header variables from the DXF file.
1258  */
addHeader(const DRW_Header * data)1259 void RS_FilterDXFRW::addHeader(const DRW_Header* data){
1260 	RS_Graphic* container = nullptr;
1261     if (currentContainer->rtti()==RS2::EntityGraphic) {
1262         container = (RS_Graphic*)currentContainer;
1263     } else return;
1264 
1265     map<std::string,DRW_Variant *>::const_iterator it;
1266     for ( it=data->vars.begin() ; it != data->vars.end(); ++it ){
1267         QString key = QString::fromStdString((*it).first);
1268         DRW_Variant *var = (*it).second;
1269         switch (var->type()) {
1270         case DRW_Variant::COORD:
1271             container->addVariable(key,
1272             RS_Vector(var->content.v->x, var->content.v->y, var->content.v->z), var->code());
1273             break;
1274         case DRW_Variant::STRING:
1275             container->addVariable(key, QString::fromUtf8(var->content.s->c_str()), var->code());
1276             break;
1277         case DRW_Variant::INTEGER:
1278             container->addVariable(key, var->content.i, var->code());
1279             break;
1280         case DRW_Variant::DOUBLE:
1281             container->addVariable(key, var->content.d, var->code());
1282             break;
1283         default:
1284             break;
1285         }
1286 
1287     }
1288     codePage = graphic->getVariableString("$DWGCODEPAGE", "ANSI_1252");
1289     textStyle = graphic->getVariableString("$TEXTSTYLE", "Standard");
1290     dimStyle = graphic->getVariableString("$DIMSTYLE", "Standard");
1291     //initialize units vars if not are present in dxf file
1292     graphic->getVariableInt("$LUNITS", 2);
1293     graphic->getVariableInt("$LUPREC", 4);
1294     graphic->getVariableInt("$AUNITS", 0);
1295     graphic->getVariableInt("$AUPREC", 4);
1296 
1297 
1298     QString acadver = versionStr = graphic->getVariableString("$ACADVER", "");
1299     acadver.replace(QRegExp("[a-zA-Z]"), "");
1300     bool ok;
1301     version=acadver.toInt(&ok);
1302     if (!ok) { version = 1021;}
1303 
1304     //detect if dxf lib are a old dxflib or libdxfrw < 0.5.4 (used to correct mtext alignment)
1305     oldMText = false;
1306     isLibDxfRw = false;
1307     libDxfRwVersion = 0;
1308     QStringList commentList = QString::fromStdString( data->getComments()).split('\n',QString::SkipEmptyParts);
1309     for( auto commentLine: commentList) {
1310         QStringList commentWords = commentLine.split(' ',QString::SkipEmptyParts);
1311         if( 0 < commentWords.size()) {
1312             if( "dxflib" == commentWords.at(0)) {
1313                 oldMText = true;
1314                 break;
1315             } else if( "dxfrw" == commentWords.at(0)) {
1316                 QStringList libVersionList = commentWords.at(1).split('.',QString::SkipEmptyParts);
1317                 if( 2 < libVersionList.size()) {
1318                     isLibDxfRw = true;
1319                     libDxfRwVersion = LIBDXFRW_VERSION( libVersionList.at(0).toInt(),
1320                                                         libVersionList.at(1).toInt(),
1321                                                         libVersionList.at(2).toInt() );
1322                     if( libDxfRwVersion < LIBDXFRW_VERSION( 0, 5, 4)) {
1323                         oldMText = true;
1324                     }
1325                 }
1326                 break;
1327             }
1328         }
1329     }
1330 }
1331 
1332 
1333 /**
1334  * Implementation of the method used for RS_Export to communicate
1335  * with this filter.
1336  *
1337  * @param file Full path to the DXF file that will be written.
1338  */
fileExport(RS_Graphic & g,const QString & file,RS2::FormatType type)1339 bool RS_FilterDXFRW::fileExport(RS_Graphic& g, const QString& file, RS2::FormatType type) {
1340 
1341     RS_DEBUG->print("RS_FilterDXFDW::fileExport: exporting file '%s'...",
1342                     (const char*)QFile::encodeName(file));
1343     RS_DEBUG->print("RS_FilterDXFDW::fileExport: file type '%d'", (int)type);
1344 
1345     this->graphic = &g;
1346 
1347     // check if we can write to that directory:
1348 #ifndef Q_OS_WIN
1349 
1350     QString path = QFileInfo(file).absolutePath();
1351     if (QFileInfo(path).isWritable()==false) {
1352         RS_DEBUG->print("RS_FilterDXFRW::fileExport: can't write file: "
1353                         "no permission");
1354         return false;
1355     }
1356     //
1357 #endif
1358 
1359     // set version for DXF filter:
1360     exactColor = false;
1361     DRW::Version exportVersion;
1362     if (type==RS2::FormatDXFRW12) {
1363         exportVersion = DRW::AC1009;
1364         version = 1009;
1365     } else if (type==RS2::FormatDXFRW14) {
1366         exportVersion = DRW::AC1014;
1367         version = 1014;
1368     } else if (type==RS2::FormatDXFRW2000) {
1369         exportVersion = DRW::AC1015;
1370         version = 1015;
1371     } else if (type==RS2::FormatDXFRW2004) {
1372         exportVersion = DRW::AC1018;
1373         version = 1018;
1374         exactColor = true;
1375     } else {
1376         exportVersion = DRW::AC1021;
1377         version = 1021;
1378         exactColor = true;
1379     }
1380 
1381     dxfW = new dxfRW(QFile::encodeName(file));
1382     bool success = dxfW->write(this, exportVersion, false); //ascii
1383 //    bool success = dxf->write(this, exportVersion, true); //binary
1384     delete dxfW;
1385 
1386     if (!success) {
1387         RS_DEBUG->print("RS_FilterDXFDW::fileExport: can't write file");
1388         return false;
1389     }
1390 /*RLZ pte*/
1391 /*    RS_DEBUG->print("writing tables...");
1392     dw->sectionTables();
1393     // VPORT:
1394     dxf.writeVPort(*dw);
1395     dw->tableEnd();
1396 
1397     // VIEW:
1398     RS_DEBUG->print("writing views...");
1399     dxf.writeView(*dw);
1400 
1401     // UCS:
1402     RS_DEBUG->print("writing ucs...");
1403     dxf.writeUcs(*dw);
1404 
1405     // Appid:
1406     RS_DEBUG->print("writing appid...");
1407     dw->tableAppid(1);
1408     writeAppid(*dw, "ACAD");
1409     dw->tableEnd();
1410 */
1411     return success;
1412 }
1413 
1414 /**
1415  * Prepare unnamed blocks.
1416  */
prepareBlocks()1417 void RS_FilterDXFRW::prepareBlocks() {
1418     RS_Block *blk;
1419     int dimNum = 0, hatchNum= 0;
1420     QString prefix, sufix;
1421 
1422     //check for existing *D?? or  *U??
1423     for (unsigned i = 0; i < graphic->countBlocks(); i++) {
1424         blk = graphic->blockAt(i);
1425         prefix = blk->getName().left(2).toUpper();
1426         sufix = blk->getName().mid(2);
1427         if (prefix == "*D") {
1428             if (sufix.toInt() > dimNum) dimNum = sufix.toInt();
1429         } else if (prefix == "*U") {
1430             if (sufix.toInt() > hatchNum) hatchNum = sufix.toInt();
1431         }
1432     }
1433     //Add a name to each dimension, in dxfR12 also for hatches
1434     for (RS_Entity *e = graphic->firstEntity(RS2::ResolveNone);
1435 		 e ; e = graphic->nextEntity(RS2::ResolveNone)) {
1436         if ( !(e->getFlag(RS2::FlagUndone)) ) {
1437             switch (e->rtti()) {
1438             case RS2::EntityDimLinear:
1439             case RS2::EntityDimAligned:
1440             case RS2::EntityDimAngular:
1441             case RS2::EntityDimRadial:
1442             case RS2::EntityDimDiametric:
1443             case RS2::EntityDimLeader:
1444                 prefix = "*D" + QString::number(++dimNum);
1445                 noNameBlock[e] = prefix;
1446                 break;
1447             case RS2::EntityHatch:
1448                 if (version==1009) {
1449                     if ( !((RS_Hatch*)e)->isSolid() ) {
1450                         prefix = "*U" + QString::number(++hatchNum);
1451                         noNameBlock[e] = prefix;
1452                     }
1453                 }
1454                 break;
1455             default:
1456                 break;
1457             }//end switch
1458         }//end if !RS2::FlagUndone
1459     }
1460 }
1461 
1462 /**
1463  * Writes block records (just the name, not the entities in it).
1464  */
writeBlockRecords()1465 void RS_FilterDXFRW::writeBlockRecords(){
1466     //first prepare and send unnamed blocks, the while loop can be omitted for R12
1467     prepareBlocks();
1468     QHash<RS_Entity*, QString>::const_iterator it = noNameBlock.constBegin();
1469     while (it != noNameBlock.constEnd()) {
1470         dxfW->writeBlockRecord(it.value().toStdString());
1471         ++it;
1472     }
1473 
1474     //next send "normal" blocks
1475     RS_Block *blk;
1476     for (unsigned i = 0; i < graphic->countBlocks(); i++) {
1477         blk = graphic->blockAt(i);
1478         if (!blk->isUndone()){
1479             RS_DEBUG->print("writing block record: %s", (const char*)blk->getName().toLocal8Bit());
1480             dxfW->writeBlockRecord(blk->getName().toUtf8().data());
1481         }
1482     }
1483 }
1484 
1485 /**
1486  * Writes blocks.
1487  */
writeBlocks()1488 void RS_FilterDXFRW::writeBlocks() {
1489     RS_Block *blk;
1490 
1491     //write unnamed blocks
1492     QHash<RS_Entity*, QString>::const_iterator it = noNameBlock.constBegin();
1493     while (it != noNameBlock.constEnd()) {
1494         DRW_Block block;
1495         block.name = it.value().toStdString();
1496         block.basePoint.x = 0.0;
1497         block.basePoint.y = 0.0;
1498         block.basePoint.z = 0.0;
1499         block.flags = 1;//flag for unnamed block
1500         dxfW->writeBlock(&block);
1501         RS_EntityContainer *ct = (RS_EntityContainer *)it.key();
1502         for (RS_Entity* e=ct->firstEntity(RS2::ResolveNone);
1503              e; e=ct->nextEntity(RS2::ResolveNone)) {
1504             if ( !(e->getFlag(RS2::FlagUndone)) ) {
1505                 writeEntity(e);
1506             }
1507         }
1508         ++it;
1509     }
1510 
1511     //next write "normal" blocks
1512     for (unsigned i = 0; i < graphic->countBlocks(); i++) {
1513         blk = graphic->blockAt(i);
1514         if (!blk->isUndone()) {
1515             RS_DEBUG->print("writing block: %s", (const char*)blk->getName().toLocal8Bit());
1516 
1517             DRW_Block block;
1518             block.name = blk->getName().toUtf8().data();
1519             block.basePoint.x = blk->getBasePoint().x;
1520             block.basePoint.y = blk->getBasePoint().y;
1521             block.basePoint.z = blk->getBasePoint().z;
1522             dxfW->writeBlock(&block);
1523             for (RS_Entity* e=blk->firstEntity(RS2::ResolveNone);
1524                  e; e=blk->nextEntity(RS2::ResolveNone)) {
1525                 if ( !(e->getFlag(RS2::FlagUndone)) ) {
1526                     writeEntity(e);
1527                 }
1528             }
1529         }
1530     }
1531 }
1532 
1533 
writeHeader(DRW_Header & data)1534 void RS_FilterDXFRW::writeHeader(DRW_Header& data){
1535     RS_Vector v;
1536 /*TODO $ISOMETRICGRID == $SNAPSTYLE and "GRID on/off" not handled because is part of
1537  active vport to save is required read/write VPORT table */
1538     QHash<QString, RS_Variable>vars = graphic->getVariableDict();
1539     QHash<QString, RS_Variable>::iterator it = vars.begin();
1540     if (!vars.contains ( "$DWGCODEPAGE" )) {
1541 //RLZ: TODO verify this
1542         codePage = RS_SYSTEM->localeToISO(QLocale::system().name().toLocal8Bit());
1543 //        RS_Variable v( QString(RS_SYSTEM->localeToISO(QLocale::system().name().toLocal8Bit())),0 );
1544         vars.insert(QString("$DWGCODEPAGE"), RS_Variable(codePage, 0) );
1545     }
1546 
1547     while (it != vars.end()) {
1548             switch (it.value().getType()) {
1549             case RS2::VariableInt:
1550                 data.addInt(it.key().toStdString(), it.value().getInt(), it.value().getCode());
1551                 break;
1552             case RS2::VariableDouble:
1553                 data.addDouble(it.key().toStdString(), it.value().getDouble(), it.value().getCode());
1554                 break;
1555             case RS2::VariableString:
1556                 data.addStr(it.key().toStdString(), it.value().getString().toUtf8().data(), it.value().getCode());
1557                 break;
1558             case RS2::VariableVector:
1559                 v = it.value().getVector();
1560                 data.addCoord(it.key().toStdString(), DRW_Coord(v.x, v.y, v.z), it.value().getCode());
1561                 break;
1562             default:
1563                 break;
1564             }
1565             ++it;
1566     }
1567     v = graphic->getMin();
1568     data.addCoord("$EXTMIN", DRW_Coord(v.x, v.y, 0.0), 0);
1569     v = graphic->getMax();
1570     data.addCoord("$EXTMAX", DRW_Coord(v.x, v.y, 0.0), 0);
1571 
1572     //when saving a block, there is no active layer. ignore it to avoid crash
1573     if(graphic->getActiveLayer()==0) return;
1574     data.addStr("$CLAYER", (graphic->getActiveLayer()->getName()).toUtf8().data(), 8);
1575 }
1576 
writeLTypes()1577 void RS_FilterDXFRW::writeLTypes(){
1578     DRW_LType ltype;
1579     // Standard linetypes for LibreCAD / AutoCAD
1580     ltype.name = "CONTINUOUS";
1581     ltype.desc = "Solid line";
1582     dxfW->writeLineType(&ltype);
1583     ltype.name = "ByLayer";
1584     dxfW->writeLineType(&ltype);
1585     ltype.name = "ByBlock";
1586     dxfW->writeLineType(&ltype);
1587 
1588     ltype.name = "DOT";
1589     ltype.desc = "Dot . . . . . . . . . . . . . . . . . . . . . .";
1590     ltype.size = 2;
1591 	ltype.length = 6.35;
1592     ltype.path.push_back(0.0);
1593     ltype.path.push_back(-6.35);
1594     dxfW->writeLineType(&ltype);
1595 
1596     ltype.path.clear();
1597     ltype.name = "DOTTINY";
1598     ltype.desc = "Dot (.15x) .....................................";
1599     ltype.size = 2;
1600     ltype.length = 0.9525;
1601     ltype.path.push_back(0.0);
1602     ltype.path.push_back(-0.9525);
1603     dxfW->writeLineType(&ltype);
1604 
1605     ltype.path.clear();
1606     ltype.name = "DOT2";
1607     ltype.desc = "Dot (.5x) .....................................";
1608     ltype.size = 2;
1609     ltype.length = 3.175;
1610     ltype.path.push_back(0.0);
1611     ltype.path.push_back(-3.175);
1612     dxfW->writeLineType(&ltype);
1613 
1614     ltype.path.clear();
1615     ltype.name = "DOTX2";
1616     ltype.desc = "Dot (2x) .  .  .  .  .  .  .  .  .  .  .  .  .";
1617     ltype.size = 2;
1618     ltype.length = 12.7;
1619     ltype.path.push_back(0.0);
1620     ltype.path.push_back(-12.7);
1621     dxfW->writeLineType(&ltype);
1622 
1623     ltype.path.clear();
1624     ltype.name = "DASHED";
1625     ltype.desc = "Dashed _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _";
1626     ltype.size = 2;
1627     ltype.length = 19.05;
1628     ltype.path.push_back(12.7);
1629     ltype.path.push_back(-6.35);
1630     dxfW->writeLineType(&ltype);
1631 
1632     ltype.path.clear();
1633     ltype.name = "DASHEDTINY";
1634     ltype.desc = "Dashed (.15x) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _";
1635     ltype.size = 2;
1636     ltype.length = 2.8575;
1637     ltype.path.push_back(1.905);
1638     ltype.path.push_back(-0.9525);
1639     dxfW->writeLineType(&ltype);
1640 
1641     ltype.path.clear();
1642     ltype.name = "DASHED2";
1643     ltype.desc = "Dashed (.5x) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _";
1644     ltype.size = 2;
1645     ltype.length = 9.525;
1646     ltype.path.push_back(6.35);
1647     ltype.path.push_back(-3.175);
1648     dxfW->writeLineType(&ltype);
1649 
1650     ltype.path.clear();
1651     ltype.name = "DASHEDX2";
1652     ltype.desc = "Dashed (2x) ____  ____  ____  ____  ____  ___";
1653     ltype.size = 2;
1654     ltype.length = 38.1;
1655     ltype.path.push_back(25.4);
1656     ltype.path.push_back(-12.7);
1657     dxfW->writeLineType(&ltype);
1658 
1659     ltype.path.clear();
1660     ltype.name = "DASHDOT";
1661     ltype.desc = "Dash dot __ . __ . __ . __ . __ . __ . __ . __";
1662     ltype.size = 4;
1663     ltype.length = 25.4;
1664     ltype.path.push_back(12.7);
1665     ltype.path.push_back(-6.35);
1666     ltype.path.push_back(0.0);
1667     ltype.path.push_back(-6.35);
1668     dxfW->writeLineType(&ltype);
1669 
1670     ltype.path.clear();
1671     ltype.name = "DASHDOTTINY";
1672     ltype.desc = "Dash dot (.15x) _._._._._._._._._._._._._._._.";
1673     ltype.size = 4;
1674     ltype.length = 3.81;
1675     ltype.path.push_back(1.905);
1676     ltype.path.push_back(-0.9525);
1677     ltype.path.push_back(0.0);
1678     ltype.path.push_back(-0.9525);
1679     dxfW->writeLineType(&ltype);
1680 
1681     ltype.path.clear();
1682     ltype.name = "DASHDOT2";
1683     ltype.desc = "Dash dot (.5x) _._._._._._._._._._._._._._._.";
1684     ltype.size = 4;
1685     ltype.length = 12.7;
1686     ltype.path.push_back(6.35);
1687     ltype.path.push_back(-3.175);
1688     ltype.path.push_back(0.0);
1689     ltype.path.push_back(-3.175);
1690     dxfW->writeLineType(&ltype);
1691 
1692     ltype.path.clear();
1693     ltype.name = "DASHDOTX2";
1694     ltype.desc = "Dash dot (2x) ____  .  ____  .  ____  .  ___";
1695     ltype.size = 4;
1696     ltype.length = 50.8;
1697     ltype.path.push_back(25.4);
1698     ltype.path.push_back(-12.7);
1699     ltype.path.push_back(0.0);
1700     ltype.path.push_back(-12.7);
1701     dxfW->writeLineType(&ltype);
1702 
1703     ltype.path.clear();
1704     ltype.name = "DIVIDE";
1705     ltype.desc = "Divide ____ . . ____ . . ____ . . ____ . . ____";
1706     ltype.size = 6;
1707     ltype.length = 31.75;
1708     ltype.path.push_back(12.7);
1709     ltype.path.push_back(-6.35);
1710     ltype.path.push_back(0.0);
1711     ltype.path.push_back(-6.35);
1712     ltype.path.push_back(0.0);
1713     ltype.path.push_back(-6.35);
1714     dxfW->writeLineType(&ltype);
1715 
1716     ltype.path.clear();
1717     ltype.name = "DIVIDETINY";
1718     ltype.desc = "Divide (.15x) __..__..__..__..__..__..__..__.._";
1719     ltype.size = 6;
1720     ltype.length = 4.7625;
1721     ltype.path.push_back(1.905);
1722     ltype.path.push_back(-0.9525);
1723     ltype.path.push_back(0.0);
1724     ltype.path.push_back(-0.9525);
1725     ltype.path.push_back(0.0);
1726     ltype.path.push_back(-0.9525);
1727     dxfW->writeLineType(&ltype);
1728 
1729     ltype.path.clear();
1730     ltype.name = "DIVIDE2";
1731     ltype.desc = "Divide (.5x) __..__..__..__..__..__..__..__.._";
1732     ltype.size = 6;
1733     ltype.length = 15.875;
1734     ltype.path.push_back(6.35);
1735     ltype.path.push_back(-3.175);
1736     ltype.path.push_back(0.0);
1737     ltype.path.push_back(-3.175);
1738     ltype.path.push_back(0.0);
1739     ltype.path.push_back(-3.175);
1740     dxfW->writeLineType(&ltype);
1741 
1742     ltype.path.clear();
1743     ltype.name = "DIVIDEX2";
1744     ltype.desc = "Divide (2x) ________  .  .  ________  .  .  _";
1745     ltype.size = 6;
1746     ltype.length = 63.5;
1747     ltype.path.push_back(25.4);
1748     ltype.path.push_back(-12.7);
1749     ltype.path.push_back(0.0);
1750     ltype.path.push_back(-12.7);
1751     ltype.path.push_back(0.0);
1752     ltype.path.push_back(-12.7);
1753     dxfW->writeLineType(&ltype);
1754 
1755     ltype.path.clear();
1756     ltype.name = "BORDER";
1757     ltype.desc = "Border __ __ . __ __ . __ __ . __ __ . __ __ .";
1758     ltype.size = 6;
1759     ltype.length = 44.45;
1760     ltype.path.push_back(12.7);
1761     ltype.path.push_back(-6.35);
1762     ltype.path.push_back(12.7);
1763     ltype.path.push_back(-6.35);
1764     ltype.path.push_back(0.0);
1765     ltype.path.push_back(-6.35);
1766     dxfW->writeLineType(&ltype);
1767 
1768     ltype.path.clear();
1769     ltype.name = "BORDERTINY";
1770     ltype.desc = "Border (.15x) __.__.__.__.__.__.__.__.__.__.__.";
1771     ltype.size = 6;
1772     ltype.length = 6.6675;
1773     ltype.path.push_back(1.905);
1774     ltype.path.push_back(-0.9525);
1775     ltype.path.push_back(1.905);
1776     ltype.path.push_back(-0.9525);
1777     ltype.path.push_back(0.0);
1778     ltype.path.push_back(-0.9525);
1779     dxfW->writeLineType(&ltype);
1780 
1781     ltype.path.clear();
1782     ltype.name = "BORDER2";
1783     ltype.desc = "Border (.5x) __.__.__.__.__.__.__.__.__.__.__.";
1784     ltype.size = 6;
1785     ltype.length = 22.225;
1786     ltype.path.push_back(6.35);
1787     ltype.path.push_back(-3.175);
1788     ltype.path.push_back(6.35);
1789     ltype.path.push_back(-3.175);
1790     ltype.path.push_back(0.0);
1791     ltype.path.push_back(-3.175);
1792     dxfW->writeLineType(&ltype);
1793 
1794     ltype.path.clear();
1795     ltype.name = "BORDERX2";
1796     ltype.desc = "Border (2x) ____  ____  .  ____  ____  .  ___";
1797     ltype.size = 6;
1798     ltype.length = 88.9;
1799     ltype.path.push_back(25.4);
1800     ltype.path.push_back(-12.7);
1801     ltype.path.push_back(25.4);
1802     ltype.path.push_back(-12.7);
1803     ltype.path.push_back(0.0);
1804     ltype.path.push_back(-12.7);
1805     dxfW->writeLineType(&ltype);
1806 
1807     ltype.path.clear();
1808     ltype.name = "CENTER";
1809     ltype.desc = "Center ____ _ ____ _ ____ _ ____ _ ____ _ ____";
1810     ltype.size = 4;
1811     ltype.length = 50.8;
1812     ltype.path.push_back(31.75);
1813     ltype.path.push_back(-6.35);
1814     ltype.path.push_back(6.35);
1815     ltype.path.push_back(-6.35);
1816     dxfW->writeLineType(&ltype);
1817 
1818     ltype.path.clear();
1819     ltype.name = "CENTERTINY";
1820     ltype.desc = "Center (.15x) ___ _ ___ _ ___ _ ___ _ ___ _ ___";
1821     ltype.size = 4;
1822     ltype.length = 7.62;
1823     ltype.path.push_back(4.7625);
1824     ltype.path.push_back(-0.9525);
1825     ltype.path.push_back(0.9525);
1826     ltype.path.push_back(-0.9525);
1827     dxfW->writeLineType(&ltype);
1828 
1829     ltype.path.clear();
1830     ltype.name = "CENTER2";
1831     ltype.desc = "Center (.5x) ___ _ ___ _ ___ _ ___ _ ___ _ ___";
1832     ltype.size = 4;
1833     ltype.length = 28.575;
1834     ltype.path.push_back(19.05);
1835     ltype.path.push_back(-3.175);
1836     ltype.path.push_back(3.175);
1837     ltype.path.push_back(-3.175);
1838     dxfW->writeLineType(&ltype);
1839 
1840     ltype.path.clear();
1841     ltype.name = "CENTERX2";
1842     ltype.desc = "Center (2x) ________  __  ________  __  _____";
1843     ltype.size = 4;
1844     ltype.length = 101.6;
1845     ltype.path.push_back(63.5);
1846     ltype.path.push_back(-12.7);
1847     ltype.path.push_back(12.7);
1848     ltype.path.push_back(-12.7);
1849     dxfW->writeLineType(&ltype);
1850 }
1851 
writeLayers()1852 void RS_FilterDXFRW::writeLayers(){
1853     DRW_Layer lay;
1854     RS_LayerList* ll = graphic->getLayerList();
1855     int exact_rgb;
1856     for (unsigned int i = 0; i < ll->count(); i++) {
1857         lay.reset();
1858         RS_Layer* l = ll->at(i);
1859         RS_Pen pen = l->getPen();
1860         lay.name = l->getName().toUtf8().data();
1861         lay.color = colorToNumber(pen.getColor(), &exact_rgb);
1862         lay.color24 = exact_rgb;
1863         lay.lWeight = widthToNumber(pen.getWidth());
1864         lay.lineType = lineTypeToName(pen.getLineType()).toStdString();
1865         lay.flags = l->isFrozen() ? 0x01 : 0x00;
1866         if (l->isLocked()) lay.flags |=0x04;
1867         lay.plotF = l->isPrint();
1868         if( l->isConstruction()) {
1869             lay.extData.push_back(new DRW_Variant(1001, "LibreCad"));
1870             lay.extData.push_back(new DRW_Variant(1070, 1));
1871             RS_DEBUG->print(RS_Debug::D_WARNING, "RS_FilterDXF::writeLayers: layer %s saved as construction layer", lay.name.c_str());
1872         }
1873         dxfW->writeLayer(&lay);
1874     }
1875 }
1876 
writeTextstyles()1877 void RS_FilterDXFRW::writeTextstyles(){
1878     QHash<QString, QString> styles;
1879     QString sty;
1880     //Find fonts used by text entities in drawing
1881     for (RS_Entity *e = graphic->firstEntity(RS2::ResolveNone);
1882 		 e ; e = graphic->nextEntity(RS2::ResolveNone)) {
1883         if ( !(e->getFlag(RS2::FlagUndone)) ) {
1884             switch (e->rtti()) {
1885             case RS2::EntityMText:
1886                 sty = ((RS_MText*)e)->getStyle();
1887                 break;
1888             case RS2::EntityText:
1889                 sty = ((RS_Text*)e)->getStyle();
1890                 break;
1891             default:
1892                 sty.clear();
1893                 break;
1894             }
1895             if (!sty.isEmpty() && !styles.contains(sty))
1896                 styles.insert(sty, sty);
1897         }
1898     }
1899     //Find fonts used by text entities in blocks
1900     RS_Block *blk;
1901     for (unsigned i = 0; i < graphic->countBlocks(); i++) {
1902         blk = graphic->blockAt(i);
1903         for (RS_Entity *e = blk->firstEntity(RS2::ResolveNone);
1904 			 e ; e = blk->nextEntity(RS2::ResolveNone)) {
1905             if ( !(e->getFlag(RS2::FlagUndone)) ) {
1906                 switch (e->rtti()) {
1907                 case RS2::EntityMText:
1908                     sty = ((RS_MText*)e)->getStyle();
1909                     break;
1910                 case RS2::EntityText:
1911                     sty = ((RS_Text*)e)->getStyle();
1912                     break;
1913                 default:
1914                     sty.clear();
1915                     break;
1916                 }
1917                 if (!sty.isEmpty() && !styles.contains(sty))
1918                     styles.insert(sty, sty);
1919             }
1920         }
1921     }
1922     DRW_Textstyle ts;
1923     QHash<QString, QString>::const_iterator it = styles.constBegin();
1924      while (it != styles.constEnd()) {
1925          ts.name = (it.key()).toStdString();
1926          ts.font = it.value().toStdString();
1927 //         ts.flags;
1928          dxfW->writeTextstyle( &ts );
1929          ++it;
1930      }
1931 }
1932 
writeVports()1933 void RS_FilterDXFRW::writeVports(){
1934     DRW_Vport vp;
1935     vp.name = "*Active";
1936     graphic->isGridOn()? vp.grid = 1 : vp.grid = 0;
1937     RS_Vector spacing = graphic->getVariableVector("$GRIDUNIT",
1938                                                    RS_Vector(0.0,0.0));
1939     vp.gridBehavior = 3;
1940     vp.gridSpacing.x = spacing.x;
1941     vp.gridSpacing.y = spacing.y;
1942     vp.snapStyle = graphic->isIsometricGrid();
1943     vp.snapIsopair = graphic->getCrosshairType();
1944     if (vp.snapIsopair > 2)
1945         vp.snapIsopair = 0;
1946     if (fabs(spacing.x) < 1.0e-6) {
1947         vp.gridBehavior = 7; //auto
1948         vp.gridSpacing.x = 10;
1949     }
1950     if (fabs(spacing.y) < 1.0e-6) {
1951         vp.gridBehavior = 7; //auto
1952         vp.gridSpacing.y = 10;
1953     }
1954     RS_GraphicView *gv = graphic->getGraphicView();
1955 	if (gv ) {
1956         RS_Vector fac =gv->getFactor();
1957         vp.height = gv->getHeight()/fac.y;
1958         vp.ratio = (double)gv->getWidth() / (double)gv->getHeight();
1959         vp.center.x = ( gv->getWidth() - gv->getOffsetX() )/ (fac.x * 2.0);
1960         vp.center.y = ( gv->getHeight() - gv->getOffsetY() )/ (fac.y * 2.0);
1961     }
1962     dxfW->writeVport(&vp);
1963 }
1964 
1965 
writeDimstyles()1966 void RS_FilterDXFRW::writeDimstyles(){
1967     DRW_Dimstyle dsty;
1968     dsty.name = "Standard";
1969     dsty.dimscale = graphic->getVariableDouble("$DIMSCALE", 1.0);
1970     dsty.dimasz = graphic->getVariableDouble("$DIMASZ", 2.5);
1971     dsty.dimexo = graphic->getVariableDouble("$DIMEXO", 0.625);
1972     dsty.dimexe = graphic->getVariableDouble("$DIMEXE", 1.25);
1973     dsty.dimfxl = graphic->getVariableDouble("$DIMFXL", 1.0);
1974     dsty.dimtxt = graphic->getVariableDouble("$DIMTXT", 2.5);
1975     dsty.dimtsz = graphic->getVariableDouble("$DIMTSZ", 2.5);
1976     dsty.dimlfac = graphic->getVariableDouble("$DIMLFAC", 1.0);
1977     dsty.dimgap = graphic->getVariableDouble("$DIMGAP", 0.625);
1978     dsty.dimtih = graphic->getVariableInt("$DIMTIH", 2);
1979     dsty.dimzin = graphic->getVariableInt("$DIMZIN", 1);
1980     dsty.dimazin = graphic->getVariableInt("$DIMAZIN", 0);
1981     dsty.dimclrd = graphic->getVariableInt("$DIMCLRD", 0);
1982     dsty.dimclre = graphic->getVariableInt("$DIMCLRE", 0);
1983     dsty.dimclrt = graphic->getVariableInt("$DIMCLRT", 0);
1984     dsty.dimadec = graphic->getVariableInt("$DIMADEC", 0);
1985     dsty.dimdec = graphic->getVariableInt("$DIMDEC", 2);
1986     dsty.dimaunit = graphic->getVariableInt("$DIMAUNIT", 0);
1987     dsty.dimlunit = graphic->getVariableInt("$DIMLUNIT", 2);
1988     dsty.dimdsep = graphic->getVariableInt("$DIMDSEP", 0);
1989     dsty.dimfxlon = graphic->getVariableInt("$DIMFXLON", 0);
1990     dsty.dimtxsty = graphic->getVariableString("$DIMTXSTY", "standard").toStdString();
1991     dsty.dimlwd = graphic->getVariableInt("$DIMLWD", -2);
1992     dsty.dimlwe = graphic->getVariableInt("$DIMLWE", -2);
1993     dxfW->writeDimstyle(&dsty);
1994 }
1995 
writeObjects()1996 void RS_FilterDXFRW::writeObjects() {
1997     /* PLOTSETTINGS */
1998     DRW_PlotSettings ps;
1999     QString horizXvert = QString("%1x%2").arg(graphic->getPagesNumHoriz())
2000                                          .arg(graphic->getPagesNumVert());
2001     ps.plotViewName = horizXvert.toStdString();
2002     ps.marginLeft = graphic->getMarginLeft();
2003     ps.marginTop = graphic->getMarginTop();
2004     ps.marginRight = graphic->getMarginRight();
2005     ps.marginBottom = graphic->getMarginBottom();
2006     dxfW->writePlotSettings(&ps);
2007 }
2008 
writeAppId()2009 void RS_FilterDXFRW::writeAppId(){
2010     DRW_AppId ai;
2011     ai.name ="LibreCad";
2012     dxfW->writeAppId(&ai);
2013 }
2014 
writeEntities()2015 void RS_FilterDXFRW::writeEntities(){
2016     for (RS_Entity *e = graphic->firstEntity(RS2::ResolveNone);
2017 		 e ; e = graphic->nextEntity(RS2::ResolveNone)) {
2018         if ( !(e->getFlag(RS2::FlagUndone)) ) {
2019             writeEntity(e);
2020         }
2021     }
2022 }
2023 
writeEntity(RS_Entity * e)2024 void RS_FilterDXFRW::writeEntity(RS_Entity* e){
2025     switch (e->rtti()) {
2026     case RS2::EntityPoint:
2027         writePoint((RS_Point*)e);
2028         break;
2029     case RS2::EntityLine:
2030         writeLine((RS_Line*)e);
2031         break;
2032     case RS2::EntityCircle:
2033         writeCircle((RS_Circle*)e);
2034         break;
2035     case RS2::EntityArc:
2036         writeArc((RS_Arc*)e);
2037         break;
2038     case RS2::EntitySolid:
2039         writeSolid((RS_Solid*)e);
2040         break;
2041     case RS2::EntityEllipse:
2042         writeEllipse((RS_Ellipse*)e);
2043         break;
2044     case RS2::EntityPolyline:
2045         writeLWPolyline((RS_Polyline*)e);
2046         break;
2047     case RS2::EntitySpline:
2048         writeSpline((RS_Spline*)e);
2049         break;
2050     case RS2::EntitySplinePoints:
2051         writeSplinePoints((LC_SplinePoints*)e);
2052         break;
2053 //    case RS2::EntityVertex:
2054 //        break;
2055     case RS2::EntityInsert:
2056         writeInsert((RS_Insert*)e);
2057         break;
2058     case RS2::EntityMText:
2059         writeMText((RS_MText*)e);
2060         break;
2061     case RS2::EntityText:
2062         writeText((RS_Text*)e);
2063         break;
2064     case RS2::EntityDimLinear:
2065     case RS2::EntityDimAligned:
2066     case RS2::EntityDimAngular:
2067     case RS2::EntityDimRadial:
2068     case RS2::EntityDimDiametric:
2069         writeDimension((RS_Dimension*)e);
2070         break;
2071     case RS2::EntityDimLeader:
2072         writeLeader((RS_Leader*)e);
2073         break;
2074     case RS2::EntityHatch:
2075         writeHatch((RS_Hatch*)e);
2076         break;
2077     case RS2::EntityImage:
2078         writeImage((RS_Image*)e);
2079         break;
2080     default:
2081         break;
2082     }
2083 }
2084 
2085 
2086 /**
2087  * Writes the given Point entity to the file.
2088  */
writePoint(RS_Point * p)2089 void RS_FilterDXFRW::writePoint(RS_Point* p) {
2090     DRW_Point point;
2091     getEntityAttributes(&point, p);
2092     point.basePoint.x = p->getStartpoint().x;
2093     point.basePoint.y = p->getStartpoint().y;
2094     dxfW->writePoint(&point);
2095 }
2096 
2097 
2098 /**
2099  * Writes the given Line( entity to the file.
2100  */
writeLine(RS_Line * l)2101 void RS_FilterDXFRW::writeLine(RS_Line* l) {
2102     DRW_Line line;
2103     getEntityAttributes(&line, l);
2104     line.basePoint.x = l->getStartpoint().x;
2105     line.basePoint.y = l->getStartpoint().y;
2106     line.secPoint.x = l->getEndpoint().x;
2107     line.secPoint.y = l->getEndpoint().y;
2108     dxfW->writeLine(&line);
2109 }
2110 
2111 
2112 /**
2113  * Writes the given circle entity to the file.
2114  */
writeCircle(RS_Circle * c)2115 void RS_FilterDXFRW::writeCircle(RS_Circle* c) {
2116     DRW_Circle circle;
2117     getEntityAttributes(&circle, c);
2118     circle.basePoint.x = c->getCenter().x;
2119     circle.basePoint.y = c->getCenter().y;
2120     circle.radious = c->getRadius();
2121     dxfW->writeCircle(&circle);
2122 }
2123 
2124 
2125 /**
2126  * Writes the given arc entity to the file.
2127  */
writeArc(RS_Arc * a)2128 void RS_FilterDXFRW::writeArc(RS_Arc* a) {
2129     DRW_Arc arc;
2130     getEntityAttributes(&arc, a);
2131     arc.basePoint.x = a->getCenter().x;
2132     arc.basePoint.y = a->getCenter().y;
2133     arc.radious = a->getRadius();
2134     if (a->isReversed()) {
2135         arc.staangle = a->getAngle2();
2136         arc.endangle = a->getAngle1();
2137     } else {
2138         arc.staangle = a->getAngle1();
2139         arc.endangle = a->getAngle2();
2140     }
2141     dxfW->writeArc(&arc);
2142 }
2143 
2144 
2145 /**
2146  * Writes the given polyline entity to the file as lwpolyline.
2147  */
writeLWPolyline(RS_Polyline * l)2148 void RS_FilterDXFRW::writeLWPolyline(RS_Polyline* l) {
2149     //skip if are empty polyline
2150     if (l->isEmpty())
2151             return;
2152     // version 12 are old style polyline
2153     if (version==1009) {
2154         writePolyline(l);
2155         return;
2156     }
2157     DRW_LWPolyline pol;
2158     RS_Entity* currEntity = 0;
2159     RS_Entity* nextEntity = 0;
2160 	RS_AtomicEntity* ae = nullptr;
2161     double bulge=0.0;
2162 
2163     for (RS_Entity* e=l->firstEntity(RS2::ResolveNone);
2164          e; e=nextEntity) {
2165 
2166         currEntity = e;
2167         nextEntity = l->nextEntity(RS2::ResolveNone);
2168 
2169         if (!e->isAtomic()) {
2170             continue;
2171         }
2172         ae = (RS_AtomicEntity*)e;
2173 
2174         // Write vertex:
2175             if (e->rtti()==RS2::EntityArc) {
2176                 bulge = ((RS_Arc*)e)->getBulge();
2177             } else
2178                 bulge = 0.0;
2179             pol.addVertex( DRW_Vertex2D(ae->getStartpoint().x,
2180                                       ae->getStartpoint().y, bulge));
2181     }
2182     if (l->isClosed()) {
2183         pol.flags = 1;
2184     } else {
2185         ae = (RS_AtomicEntity*)currEntity;
2186         if (ae->rtti()==RS2::EntityArc) {
2187             bulge = ((RS_Arc*)ae)->getBulge();
2188         }
2189         pol.addVertex( DRW_Vertex2D(ae->getEndpoint().x,
2190                                   ae->getEndpoint().y, bulge));
2191     }
2192     pol.vertexnum = pol.vertlist.size();
2193     getEntityAttributes(&pol, l);
2194     dxfW->writeLWPolyline(&pol);
2195 }
2196 
2197 /**
2198  * Writes the given polyline entity to the file (old style).
2199  */
writePolyline(RS_Polyline * p)2200 void RS_FilterDXFRW::writePolyline(RS_Polyline* p) {
2201     DRW_Polyline pol;
2202     RS_Entity* currEntity = 0;
2203     RS_Entity* nextEntity = 0;
2204 	RS_AtomicEntity* ae = nullptr;
2205     double bulge=0.0;
2206 
2207     for (RS_Entity* e=p->firstEntity(RS2::ResolveNone);
2208          e; e=nextEntity) {
2209 
2210         currEntity = e;
2211         nextEntity = p->nextEntity(RS2::ResolveNone);
2212 
2213         if (!e->isAtomic()) {
2214             continue;
2215         }
2216         ae = (RS_AtomicEntity*)e;
2217 
2218         // Write vertex:
2219             if (e->rtti()==RS2::EntityArc) {
2220                 bulge = ((RS_Arc*)e)->getBulge();
2221             } else
2222                 bulge = 0.0;
2223             pol.addVertex( DRW_Vertex(ae->getStartpoint().x,
2224                                       ae->getStartpoint().y, 0.0, bulge));
2225     }
2226     if (p->isClosed()) {
2227         pol.flags = 1;
2228     } else {
2229         ae = (RS_AtomicEntity*)currEntity;
2230         if (ae->rtti()==RS2::EntityArc) {
2231             bulge = ((RS_Arc*)ae)->getBulge();
2232         }
2233         pol.addVertex( DRW_Vertex(ae->getEndpoint().x,
2234                                   ae->getEndpoint().y, 0.0, bulge));
2235     }
2236     getEntityAttributes(&pol, p);
2237     dxfW->writePolyline(&pol);
2238 }
2239 
2240 
2241 
2242 /**
2243  * Writes the given spline entity to the file.
2244  */
writeSpline(RS_Spline * s)2245 void RS_FilterDXFRW::writeSpline(RS_Spline *s) {
2246 
2247     if (s->getNumberOfControlPoints() < s->getDegree()+1) {
2248         RS_DEBUG->print(RS_Debug::D_ERROR, "RS_FilterDXF::writeSpline: "
2249                         "Discarding spline: not enough control points given.");
2250         return;
2251     }
2252 
2253     // version 12 do not support Spline write as polyline
2254     if (version==1009) {
2255         DRW_Polyline pol;
2256         RS_Entity* e;
2257         for (e=s->firstEntity(RS2::ResolveNone);
2258              e; e=s->nextEntity(RS2::ResolveNone)) {
2259             pol.addVertex( DRW_Vertex(e->getStartpoint().x,
2260                                       e->getStartpoint().y, 0.0, 0.0));
2261         }
2262         if (s->isClosed()) {
2263             pol.flags = 1;
2264         } else {
2265             pol.addVertex( DRW_Vertex(s->getEndpoint().x,
2266                                       s->getEndpoint().y, 0.0, 0.0));
2267         }
2268         getEntityAttributes(&pol, s);
2269         dxfW->writePolyline(&pol);
2270         return;
2271     }
2272 
2273     DRW_Spline sp;
2274 
2275     if (s->isClosed())
2276         sp.flags = 11;
2277     else
2278         sp.flags = 8;
2279     sp.ncontrol = s->getNumberOfControlPoints();
2280     sp.degree = s->getDegree();
2281     sp.nknots = sp.ncontrol + sp.degree + 1;
2282 
2283     // write spline knots:
2284 	if (s->getData().knotslist.size()) {
2285 		sp.knotslist = s->getData().knotslist;
2286 	} else {
2287 		int k = sp.degree+1;
2288 		for (int i=1; i<=sp.nknots; i++) {
2289 			if (i<=k) {
2290 				sp.knotslist.push_back(0.0);
2291 			} else if (i<=sp.nknots-k) {
2292 				sp.knotslist.push_back(1.0/(sp.nknots-2*k+1) * (i-k));
2293 			} else {
2294 				sp.knotslist.push_back(1.0);
2295 			}
2296 		}
2297 	}
2298 
2299     // write spline control points:
2300 	auto cp = s->getControlPoints();
2301 	for (const RS_Vector& v: cp)
2302 		sp.controllist.push_back(std::make_shared<DRW_Coord>(v.x, v.y, 0.));
2303 
2304     getEntityAttributes(&sp, s);
2305     dxfW->writeSpline(&sp);
2306 
2307 }
2308 
2309 
2310 /**
2311  * Writes the given spline entity to the file.
2312  */
writeSplinePoints(LC_SplinePoints * s)2313 void RS_FilterDXFRW::writeSplinePoints(LC_SplinePoints *s)
2314 {
2315 	int nCtrls = s->getNumberOfControlPoints();
2316 	auto const& cp = s->getControlPoints();
2317 
2318 	if(nCtrls < 3)
2319 	{
2320 		if(nCtrls > 1)
2321 		{
2322 			DRW_Line line;
2323 			line.basePoint.x = cp.at(0).x;
2324 			line.basePoint.y = cp.at(0).y;
2325 			line.secPoint.x = cp.at(1).x;
2326 			line.secPoint.y = cp.at(1).y;
2327 			getEntityAttributes(&line, s);
2328 			dxfW->writeLine(&line);
2329 		}
2330 		return;
2331 	}
2332 
2333 	// version 12 do not support Spline write as polyline
2334 	if(version == 1009)
2335 	{
2336 		DRW_Polyline pol;
2337 		auto const& sp = s->getStrokePoints();
2338 
2339 		for(size_t i = 0; i < sp.size(); i++)
2340 		{
2341 			pol.addVertex(DRW_Vertex(sp.at(i).x, sp.at(i).y, 0.0, 0.0));
2342 		}
2343 
2344 		if(s->isClosed()) pol.flags = 1;
2345 
2346 		getEntityAttributes(&pol, s);
2347 		dxfW->writePolyline(&pol);
2348 		return;
2349 	}
2350 
2351 	DRW_Spline sp;
2352 
2353 	if(s->isClosed()) sp.flags = 11;
2354 	else sp.flags = 8;
2355 
2356 	sp.ncontrol = nCtrls;
2357 	sp.degree = 2;
2358 	sp.nknots = nCtrls + 3;
2359 
2360 	// write spline knots:
2361 	for(int i = 1; i <= sp.nknots; i++)
2362 	{
2363 		if(i <= 3)
2364 		{
2365 			sp.knotslist.push_back(0.0);
2366 		}
2367 		else if(i <= nCtrls)
2368 		{
2369 			sp.knotslist.push_back((i - 3.0)/(nCtrls - 2.0));
2370 		}
2371 		else
2372 		{
2373 			sp.knotslist.push_back(1.0);
2374 		}
2375 	}
2376 
2377 	// write spline control points:
2378 	for (auto const& v: cp)
2379 		sp.controllist.push_back(std::make_shared<DRW_Coord>(v.x, v.y, 0.));
2380 
2381 	getEntityAttributes(&sp, s);
2382 	dxfW->writeSpline(&sp);
2383 }
2384 
2385 
2386 /**
2387  * Writes the given Ellipse entity to the file.
2388  */
writeEllipse(RS_Ellipse * s)2389 void RS_FilterDXFRW::writeEllipse(RS_Ellipse* s) {
2390 // version 12 do not support Ellipse but are
2391 // converted in polyline by library
2392     DRW_Ellipse el;
2393     getEntityAttributes(&el, s);
2394     el.basePoint.x = s->getCenter().x;
2395     el.basePoint.y = s->getCenter().y;
2396     el.secPoint.x = s->getMajorP().x;
2397     el.secPoint.y = s->getMajorP().y;
2398     el.ratio = s->getRatio();
2399     if (s->isReversed()) {
2400         el.staparam = s->getAngle2();
2401         el.endparam = s->getAngle1();
2402     } else {
2403         el.staparam = s->getAngle1();
2404         el.endparam = s->getAngle2();
2405     }
2406     dxfW->writeEllipse(&el);
2407 }
2408 
2409 /**
2410  * Writes the given block insert entity to the file.
2411  */
writeInsert(RS_Insert * i)2412 void RS_FilterDXFRW::writeInsert(RS_Insert* i) {
2413     DRW_Insert in;
2414     getEntityAttributes(&in, i);
2415     in.basePoint.x = i->getInsertionPoint().x;
2416     in.basePoint.y = i->getInsertionPoint().y;
2417     in.basePoint.z = i->getInsertionPoint().z;
2418     in.name = i->getName().toUtf8().data();
2419     in.xscale = i->getScale().x;
2420     in.yscale = i->getScale().y;
2421     in.zscale = i->getScale().z;
2422     in.angle = i->getAngle();
2423     in.colcount = i->getCols();
2424     in.rowcount = i->getRows();
2425     in.colspace = i->getSpacing().x;
2426     in.rowspace =i->getSpacing().y;
2427     dxfW->writeInsert(&in);
2428 }
2429 
2430 
2431 /**
2432  * Writes the given mText entity to the file.
2433  */
writeMText(RS_MText * t)2434 void RS_FilterDXFRW::writeMText(RS_MText* t) {
2435     DRW_Text *text;
2436     DRW_Text txt1;
2437     DRW_MText txt2;
2438 
2439     if (version==1009)
2440         text = &txt1;
2441     else
2442         text = &txt2;
2443 
2444     getEntityAttributes(text, t);
2445     text->basePoint.x = t->getInsertionPoint().x;
2446     text->basePoint.y = t->getInsertionPoint().y;
2447     text->height = t->getHeight();
2448     text->angle = t->getAngle()*180/M_PI;
2449     text->style = t->getStyle().toStdString();
2450 
2451     if (version==1009) {
2452         if (t->getHAlign()==RS_MTextData::HALeft) {
2453             text->alignH =DRW_Text::HLeft;
2454         } else if (t->getHAlign()==RS_MTextData::HACenter) {
2455             text->alignH =DRW_Text::HCenter;
2456         } else if (t->getHAlign()==RS_MTextData::HARight) {
2457             text->alignH = DRW_Text::HRight;
2458         }
2459         if (t->getVAlign()==RS_MTextData::VATop) {
2460             text->alignV = DRW_Text::VTop;
2461         } else if (t->getVAlign()==RS_MTextData::VAMiddle) {
2462             text->alignV = DRW_Text::VMiddle;
2463         } else if (t->getVAlign()==RS_MTextData::VABottom) {
2464             text->alignV = DRW_Text::VBaseLine;
2465         }
2466         QStringList txtList = t->getText().split('\n',QString::KeepEmptyParts);
2467         double dist = t->getLineSpacingFactor()*5*t->getHeight()/3;
2468         bool setSec = false;
2469         if (text->alignH != DRW_Text::HLeft || text->alignV != DRW_Text::VBaseLine) {
2470             text->secPoint.x = t->getInsertionPoint().x;
2471             text->secPoint.y = t->getInsertionPoint().y;
2472             setSec = true;
2473         }
2474         if (text->alignV == DRW_Text::VTop)
2475             dist = dist * -1;
2476         for (int i=0; i<txtList.size();++i){
2477             if (!txtList.at(i).isEmpty()) {
2478                 text->text = toDxfString(txtList.at(i)).toUtf8().data();
2479 				RS_Vector inc  = RS_Vector::polar(dist*i, t->getAngle()+M_PI_2);
2480                 if (setSec) {
2481                     text->secPoint.x += inc.x;
2482                     text->secPoint.y += inc.y;
2483                 } else {
2484                     text->basePoint.x += inc.x;
2485                     text->basePoint.y += inc.y;
2486                 }
2487                 dxfW->writeText(text);
2488             }
2489         }
2490     } else {
2491         if (t->getHAlign()==RS_MTextData::HALeft) {
2492             text->textgen =1;
2493         } else if (t->getHAlign()==RS_MTextData::HACenter) {
2494             text->textgen =2;
2495         } else if (t->getHAlign()==RS_MTextData::HARight) {
2496             text->textgen = 3;
2497         }
2498         if (t->getVAlign()==RS_MTextData::VAMiddle) {
2499             text->textgen += 3;
2500         } else if (t->getVAlign()==RS_MTextData::VABottom) {
2501             text->textgen += 6;
2502         }
2503         if (t->getDrawingDirection() == RS_MTextData::LeftToRight)
2504             text->alignH = (DRW_Text::HAlign)1;
2505         else if (t->getDrawingDirection() == RS_MTextData::TopToBottom)
2506             text->alignH = (DRW_Text::HAlign)3;
2507         else text->alignH = (DRW_Text::HAlign)5;
2508 		if (t->getLineSpacingStyle() == RS_MTextData::AtLeast)
2509             text->alignV = (DRW_Text::VAlign)1;
2510         else text->alignV = (DRW_Text::VAlign)2;
2511 
2512         text->text = toDxfString(t->getText()).toUtf8().data();
2513         //        text->widthscale =t->getWidth();
2514         text->widthscale =t->getUsedTextWidth(); //getSize().x;
2515 		txt2.interlin = t->getLineSpacingFactor();
2516 
2517         dxfW->writeMText((DRW_MText*)text);
2518     }
2519 }
2520 
2521 /**
2522  * Writes the given Text entity to the file.
2523  */
writeText(RS_Text * t)2524 void RS_FilterDXFRW::writeText(RS_Text* t){
2525     DRW_Text text;
2526 
2527     getEntityAttributes(&text, t);
2528     text.basePoint.x = t->getInsertionPoint().x;
2529     text.basePoint.y = t->getInsertionPoint().y;
2530     text.height = t->getHeight();
2531     text.angle = t->getAngle()*180/M_PI;
2532     text.style = t->getStyle().toStdString();
2533     text.alignH =(DRW_Text::HAlign)t->getHAlign();
2534     text.alignV =(DRW_Text::VAlign)t->getVAlign();
2535     text.widthscale = t->getWidthRel();
2536 
2537     if (text.alignV != DRW_Text::VBaseLine || text.alignH != DRW_Text::HLeft) {
2538 //    if (text.alignV != DRW_Text::VBaseLine || text.alignH == DRW_Text::HMiddle) {
2539 //        if (text.alignH != DRW_Text::HLeft) {
2540         if (text.alignH == DRW_Text::HAligned || text.alignH == DRW_Text::HFit) {
2541             text.secPoint.x = t->getSecondPoint().x;
2542             text.secPoint.y = t->getSecondPoint().y;
2543         } else {
2544             text.secPoint.x = t->getInsertionPoint().x;
2545             text.secPoint.y = t->getInsertionPoint().y;
2546         }
2547     }
2548 
2549 /*    if (text.alignH == DRW_Text::HAligned || text.alignH == DRW_Text::HFit) {
2550         text.secPoint.x = t->getSecondPoint().x;
2551         text.secPoint.y = t->getSecondPoint().y;
2552     }*/
2553 
2554     if (!t->getText().isEmpty()) {
2555         text.text = toDxfString(t->getText()).toUtf8().data();
2556         dxfW->writeText(&text);
2557     }
2558 }
2559 
2560 /**
2561  * Writes the given dimension entity to the file.
2562  */
writeDimension(RS_Dimension * d)2563 void RS_FilterDXFRW::writeDimension(RS_Dimension* d) {
2564     QString blkName;
2565     if (noNameBlock.contains(d)) {
2566         blkName = noNameBlock.take(d);
2567     }
2568 
2569     // version 12 are inserts of *D blocks
2570     if (version==1009) {
2571         if (!blkName.isEmpty()) {
2572             DRW_Insert in;
2573             getEntityAttributes(&in, d);
2574             in.basePoint.x = in.basePoint.y = 0.0;
2575             in.basePoint.z = 0.0;
2576             in.name = blkName.toStdString();
2577             in.xscale = in.yscale = 1.0;
2578             in.zscale = 1.0;
2579             in.angle = 0.0;
2580             in.colcount = in.rowcount = 1;
2581             in.colspace = in.rowspace = 0.0;
2582             dxfW->writeInsert(&in);
2583         }
2584         return;
2585     }
2586 
2587     DRW_Dimension* dim;
2588     int attachmentPoint=1;
2589     if (d->getHAlign()==RS_MTextData::HALeft) {
2590         attachmentPoint=1;
2591     } else if (d->getHAlign()==RS_MTextData::HACenter) {
2592         attachmentPoint=2;
2593     } else if (d->getHAlign()==RS_MTextData::HARight) {
2594         attachmentPoint=3;
2595     }
2596     if (d->getVAlign()==RS_MTextData::VATop) {
2597         attachmentPoint+=0;
2598     } else if (d->getVAlign()==RS_MTextData::VAMiddle) {
2599         attachmentPoint+=3;
2600     } else if (d->getVAlign()==RS_MTextData::VABottom) {
2601         attachmentPoint+=6;
2602     }
2603 
2604     switch (d->rtti()) {
2605     case RS2::EntityDimAligned: {
2606         RS_DimAligned* da = (RS_DimAligned*)d;
2607         DRW_DimAligned * dd = new DRW_DimAligned();
2608         dim = dd ;
2609         dim->type = 1 +32;
2610         dd->setDef1Point(DRW_Coord (da->getExtensionPoint1().x, da->getExtensionPoint1().y, 0.0));
2611         dd->setDef2Point(DRW_Coord (da->getExtensionPoint2().x, da->getExtensionPoint2().y, 0.0));
2612         break; }
2613     case RS2::EntityDimDiametric: {
2614         RS_DimDiametric* dr = (RS_DimDiametric*)d;
2615         DRW_DimDiametric * dd = new DRW_DimDiametric();
2616         dim = dd ;
2617         dim->type = 3+32;
2618         dd->setDiameter1Point(DRW_Coord (dr->getDefinitionPoint().x, dr->getDefinitionPoint().y, 0.0));
2619         dd->setLeaderLength(dr->getLeader());
2620         break; }
2621     case RS2::EntityDimRadial: {
2622         RS_DimRadial* dr = (RS_DimRadial*)d;
2623         DRW_DimRadial * dd = new DRW_DimRadial();
2624         dim = dd ;
2625         dim->type = 4+32;
2626         dd->setDiameterPoint(DRW_Coord (dr->getDefinitionPoint().x, dr->getDefinitionPoint().y, 0.0));
2627         dd->setLeaderLength(dr->getLeader());
2628         break; }
2629     case RS2::EntityDimAngular: {
2630 		RS_DimAngular* da = static_cast<RS_DimAngular*>(d);
2631 		if (da->getDefinitionPoint3() == da->getData().definitionPoint) {
2632             DRW_DimAngular3p * dd = new DRW_DimAngular3p();
2633             dim = dd ;
2634             dim->type = 5+32;
2635             dd->setFirstLine(DRW_Coord (da->getDefinitionPoint().x, da->getDefinitionPoint().y, 0.0)); //13
2636             dd->setSecondLine(DRW_Coord (da->getDefinitionPoint().x, da->getDefinitionPoint().y, 0.0)); //14
2637             dd->SetVertexPoint(DRW_Coord (da->getDefinitionPoint().x, da->getDefinitionPoint().y, 0.0)); //15
2638             dd->setDimPoint(DRW_Coord (da->getDefinitionPoint().x, da->getDefinitionPoint().y, 0.0)); //10
2639         } else {
2640             DRW_DimAngular * dd = new DRW_DimAngular();
2641             dim = dd ;
2642             dim->type = 2+32;
2643             dd->setFirstLine1(DRW_Coord (da->getDefinitionPoint1().x, da->getDefinitionPoint1().y, 0.0)); //13
2644             dd->setFirstLine2(DRW_Coord (da->getDefinitionPoint2().x, da->getDefinitionPoint2().y, 0.0)); //14
2645             dd->setSecondLine1(DRW_Coord (da->getDefinitionPoint3().x, da->getDefinitionPoint3().y, 0.0)); //15
2646             dd->setDimPoint(DRW_Coord (da->getDefinitionPoint4().x, da->getDefinitionPoint4().y, 0.0)); //16
2647         }
2648         break; }
2649     default: { //default to DimLinear
2650         RS_DimLinear* dl = (RS_DimLinear*)d;
2651         DRW_DimLinear * dd = new DRW_DimLinear();
2652         dim = dd ;
2653         dim->type = 0+32;
2654         dd->setDef1Point(DRW_Coord (dl->getExtensionPoint1().x, dl->getExtensionPoint1().y, 0.0));
2655         dd->setDef2Point(DRW_Coord (dl->getExtensionPoint2().x, dl->getExtensionPoint2().y, 0.0));
2656         dd->setAngle( RS_Math::rad2deg(dl->getAngle()) );
2657         dd->setOblique(dl->getOblique());
2658         break; }
2659     }
2660     getEntityAttributes(dim, d);
2661     dim->setDefPoint(DRW_Coord(d->getDefinitionPoint().x, d->getDefinitionPoint().y, 0));
2662     dim->setTextPoint(DRW_Coord(d->getMiddleOfText().x, d->getMiddleOfText().y, 0));
2663     dim->setStyle (d->getStyle().toUtf8().data());
2664     dim->setAlign (attachmentPoint);
2665     dim->setTextLineStyle(d->getLineSpacingStyle());
2666     dim->setText (toDxfString(d->getText()).toUtf8().data());
2667     dim->setTextLineFactor(d->getLineSpacingFactor());
2668     if (!blkName.isEmpty()) {
2669         dim->setName(blkName.toStdString());
2670     }
2671 
2672     dxfW->writeDimension(dim);
2673     delete dim;
2674 }
2675 
2676 
2677 /**
2678  * Writes the given leader entity to the file.
2679  */
writeLeader(RS_Leader * l)2680 void RS_FilterDXFRW::writeLeader(RS_Leader* l) {
2681     if (l->count()<=0)
2682         RS_DEBUG->print(RS_Debug::D_WARNING, "dropping leader with no vertices");
2683 
2684     DRW_Leader leader;
2685     getEntityAttributes(&leader, l);
2686     leader.style = "Standard";
2687     leader.arrow = l->hasArrowHead();
2688     leader.leadertype = 0;
2689     leader.flag = 3;
2690     leader.hookline = 0;
2691     leader.hookflag = 0;
2692     leader.textheight = 1;
2693     leader.textwidth = 10;
2694     leader.vertnum = l->count();
2695 	RS_Line* li =nullptr;
2696     for (RS_Entity* v=l->firstEntity(RS2::ResolveNone);
2697             v;   v=l->nextEntity(RS2::ResolveNone)) {
2698         if (v->rtti()==RS2::EntityLine) {
2699             li = (RS_Line*)v;
2700 			leader.vertexlist.push_back(std::make_shared<DRW_Coord>(li->getStartpoint().x, li->getStartpoint().y, 0.0));
2701         }
2702     }
2703 	if (li )
2704 		leader.vertexlist.push_back(std::make_shared<DRW_Coord>(li->getEndpoint().x, li->getEndpoint().y, 0.0));
2705 
2706     dxfW->writeLeader(&leader);
2707 }
2708 
2709 
2710 /**
2711  * Writes the given hatch entity to the file.
2712  */
writeHatch(RS_Hatch * h)2713 void RS_FilterDXFRW::writeHatch(RS_Hatch * h) {
2714     // version 12 are inserts of *U blocks
2715     if (version==1009) {
2716         if (noNameBlock.contains(h)) {
2717             DRW_Insert in;
2718             getEntityAttributes(&in, h);
2719             in.basePoint.x = in.basePoint.y = 0.0;
2720             in.basePoint.z = 0.0;
2721             in.name = noNameBlock.value(h).toUtf8().data();
2722             in.xscale = in.yscale = 1.0;
2723             in.zscale = 1.0;
2724             in.angle = 0.0;
2725             in.colcount = in.rowcount = 1;
2726             in.colspace = in.rowspace = 0.0;
2727             dxfW->writeInsert(&in);
2728         }
2729         return;
2730     }
2731 
2732     bool writeIt = true;
2733     if (h->countLoops()>0) {
2734         // check if all of the loops contain entities:
2735         for (RS_Entity* l=h->firstEntity(RS2::ResolveNone);
2736                 l;
2737                 l=h->nextEntity(RS2::ResolveNone)) {
2738 
2739             if (l->isContainer() && !l->getFlag(RS2::FlagTemp)) {
2740                 if (l->count()==0) {
2741                     writeIt = false;
2742                 }
2743             }
2744         }
2745     } else {
2746         writeIt = false;
2747     }
2748 
2749     if (!writeIt) {
2750         RS_DEBUG->print(RS_Debug::D_WARNING,
2751                         "RS_FilterDXF::writeHatch: Dropping Hatch");
2752         return;
2753     }
2754 
2755     DRW_Hatch ha;
2756     getEntityAttributes(&ha, h);
2757     ha.solid = h->isSolid();
2758     ha.scale = h->getScale();
2759     ha.angle = h->getAngle();
2760     if (ha.solid)
2761         ha.name = "SOLID";
2762     else
2763         ha.name = h->getPattern().toUtf8().data();
2764     ha.loopsnum = h->countLoops();
2765 
2766     for (RS_Entity* l=h->firstEntity(RS2::ResolveNone);
2767          l;
2768          l=h->nextEntity(RS2::ResolveNone)) {
2769 
2770         // Write hatch loops:
2771         if (l->isContainer() && !l->getFlag(RS2::FlagTemp)) {
2772             RS_EntityContainer* loop = (RS_EntityContainer*)l;
2773 			std::shared_ptr<DRW_HatchLoop> lData = std::make_shared<DRW_HatchLoop>(0);
2774 
2775             for (RS_Entity* ed=loop->firstEntity(RS2::ResolveNone);
2776                  ed;
2777                  ed=loop->nextEntity(RS2::ResolveNone)) {
2778 
2779                 // Write hatch loop edges:
2780                 if (ed->rtti()==RS2::EntityLine) {
2781                     RS_Line* ln = (RS_Line*)ed;
2782 					std::shared_ptr<DRW_Line> line = std::make_shared<DRW_Line>();
2783                     line->basePoint.x = ln->getStartpoint().x;
2784                     line->basePoint.y = ln->getStartpoint().y;
2785                     line->secPoint.x = ln->getEndpoint().x;
2786                     line->secPoint.y = ln->getEndpoint().y;
2787                     lData->objlist.push_back(line);
2788                 } else if (ed->rtti()==RS2::EntityArc) {
2789                     RS_Arc* ar = (RS_Arc*)ed;
2790 					std::shared_ptr<DRW_Arc> arc = std::make_shared<DRW_Arc>();
2791                     arc->basePoint.x = ar->getCenter().x;
2792                     arc->basePoint.y = ar->getCenter().y;
2793                     arc->radious = ar->getRadius();
2794                     if (!ar->isReversed()) {
2795                         arc->staangle = ar->getAngle1();
2796                         arc->endangle = ar->getAngle2();
2797                         arc->isccw = true;
2798                     } else {
2799                         arc->staangle = 2*M_PI-ar->getAngle1();
2800                         arc->endangle = 2*M_PI-ar->getAngle2();
2801                         arc->isccw = false;
2802                     }
2803                     lData->objlist.push_back(arc);
2804                 } else if (ed->rtti()==RS2::EntityCircle) {
2805                     RS_Circle* ci = (RS_Circle*)ed;
2806 					std::shared_ptr<DRW_Arc> arc = std::make_shared<DRW_Arc>();
2807 					arc->basePoint.x = ci->getCenter().x;
2808                     arc->basePoint.y = ci->getCenter().y;
2809                     arc->radious = ci->getRadius();
2810                     arc->staangle = 0.0;
2811                     arc->endangle = 2*M_PI; //2*M_PI;
2812                     arc->isccw = true;
2813                     lData->objlist.push_back(arc);
2814                 } else if (ed->rtti()==RS2::EntityEllipse) {
2815                     RS_Ellipse* el = (RS_Ellipse*)ed;
2816 					std::shared_ptr<DRW_Ellipse> ell = std::make_shared<DRW_Ellipse>();
2817                     ell->basePoint.x = el->getCenter().x;
2818                     ell->basePoint.y = el->getCenter().y;
2819                     ell->secPoint.x = el->getMajorP().x;
2820                     ell->secPoint.y = el->getMajorP().y;
2821                     ell->ratio = el->getRatio();
2822                     double rot = el->getMajorP().angle();
2823                     double startAng = el->getCenter().angleTo(el->getStartpoint()) - rot;
2824                     double endAng = el->getCenter().angleTo(el->getEndpoint()) - rot;
2825                     if (startAng < 0) startAng = M_PI*2 + startAng;
2826                     if (endAng < 0) endAng = M_PI*2 + endAng;
2827                     ell->staparam = startAng;
2828                     ell->endparam = endAng;
2829                     ell->isccw = !el->isReversed();
2830                     lData->objlist.push_back(ell);
2831                 }
2832             }
2833             lData->update(); //change to DRW_HatchLoop
2834             ha.appendLoop(lData);
2835         }
2836     }
2837     dxfW->writeHatch(&ha);
2838 }
2839 
2840 
2841 /**
2842  * Writes the given Solid entity to the file.
2843  */
writeSolid(RS_Solid * s)2844 void RS_FilterDXFRW::writeSolid(RS_Solid* s) {
2845     RS_SolidData data;
2846     DRW_Solid solid;
2847     RS_Vector corner;
2848     getEntityAttributes(&solid, s);
2849     corner = s->getCorner(0);
2850     solid.basePoint.x = corner.x;
2851     solid.basePoint.y = corner.y;
2852     corner = s->getCorner(1);
2853     solid.secPoint.x = corner.x;
2854     solid.secPoint.y = corner.y;
2855     corner = s->getCorner(2);
2856     solid.thirdPoint.x = corner.x;
2857     solid.thirdPoint.y = corner.y;
2858     if (s->isTriangle()) {
2859         solid.fourPoint.x = solid.thirdPoint.x;
2860         solid.fourPoint.y = solid.thirdPoint.y;
2861     } else {
2862         corner = s->getCorner(3);
2863         solid.fourPoint.x = corner.x;
2864         solid.fourPoint.y = corner.y;
2865     }
2866     dxfW->writeSolid(&solid);
2867 }
2868 
2869 
writeImage(RS_Image * i)2870 void RS_FilterDXFRW::writeImage(RS_Image * i) {
2871     DRW_Image image;
2872     getEntityAttributes(&image, i);
2873 
2874     image.basePoint.x = i->getInsertionPoint().x;
2875     image.basePoint.y = i->getInsertionPoint().y;
2876     image.secPoint.x = i->getUVector().x;
2877     image.secPoint.y = i->getUVector().y;
2878     image.vVector.x = i->getVVector().x;
2879     image.vVector.y = i->getVVector().y;
2880     image.sizeu = i->getWidth();
2881     image.sizev = i->getHeight();
2882     image.brightness = i->getBrightness();
2883     image.contrast = i->getContrast();
2884     image.fade = i->getFade();
2885 
2886     DRW_ImageDef *imgDef = dxfW->writeImage(&image, i->getFile().toUtf8().data());
2887 	if (imgDef ) {
2888         imgDef->loaded = 1;
2889         imgDef->u = i->getData().size.x;
2890         imgDef->v = i->getData().size.y;
2891         imgDef->up = 1;
2892         imgDef->vp = 1;
2893         imgDef->resolution = 0;
2894     }
2895 }
2896 
2897 
2898 
2899 /*void RS_FilterDXFRW::writeEntityContainer(DL_WriterA& dw, RS_EntityContainer* con,
2900                                         const DRW_Entity& attrib) {
2901     QString blkName;
2902     blkName = "__CE";
2903 
2904     // Creating an unique ID from the element ID
2905     int tmp, c=1; // tmp = temporary var c = counter var
2906     tmp = con->getId();
2907 
2908     while (true) {
2909         tmp = tmp/c;
2910         blkName.append((char) tmp %10 + 48);
2911         c *= 10;
2912         if (tmp < 10) {
2913             break;
2914         }
2915     }
2916 
2917     //Block definition
2918     dw.sectionTables();
2919     dxf.writeBlockRecord(dw);
2920     dw.dxfString(  0, "BLOCK_RECORD");
2921 
2922     dw.handle();
2923     dw.dxfHex(330, 1);
2924     dw.dxfString(100, "AcDbSymbolTableRecord");
2925     dw.dxfString(100, "AcDbBlockTableRecord");
2926     dw.dxfString(  2, blkName.toLatin1().data());
2927     dw.dxfHex(340, 0);
2928     dw.dxfString(0, "ENDTAB");
2929 
2930     //Block creation
2931     RS_BlockData blkdata(blkName, RS_Vector(0,0), false);
2932 
2933     RS_Block* blk = new RS_Block(graphic, blkdata);
2934 
2935 	for (RS_Entity* e1 = con->firstEntity(); e1 ;
2936             e1 = con->nextEntity() ) {
2937         blk->addEntity(e1);
2938     }
2939     writeBlock(dw, blk);
2940     //delete e1;
2941 }*/
2942 
2943 
2944 
2945 /**
2946  * Writes the atomic entities of the given container to the file.
2947  */
2948 /*void RS_FilterDXFRW::writeAtomicEntities(DL_WriterA& dw, RS_EntityContainer* c,
2949                                        const DRW_Entity& attrib,
2950                                        RS2::ResolveLevel level) {
2951 
2952     for (RS_Entity* e=c->firstEntity(level);
2953             e;
2954             e=c->nextEntity(level)) {
2955 
2956         writeEntity(dw, e, attrib);
2957     }
2958 }*/
2959 
2960 
2961 /**
2962  * Sets the entities attributes according to the attributes
2963  * that come from a DXF file.
2964  */
setEntityAttributes(RS_Entity * entity,const DRW_Entity * attrib)2965 void RS_FilterDXFRW::setEntityAttributes(RS_Entity* entity,
2966                                        const DRW_Entity* attrib) {
2967     RS_DEBUG->print("RS_FilterDXF::setEntityAttributes");
2968 
2969     RS_Pen pen;
2970     pen.setColor(Qt::black);
2971     pen.setLineType(RS2::SolidLine);
2972     QString layName = toNativeString(QString::fromUtf8(attrib->layer.c_str()));
2973 
2974     // Layer: add layer in case it doesn't exist:
2975 	if (!graphic->findLayer(layName)) {
2976         DRW_Layer lay;
2977         lay.name = attrib->layer;
2978         addLayer(lay);
2979     }
2980     entity->setLayer(layName);
2981 
2982     // Color:
2983     if (attrib->color24 >= 0)
2984         pen.setColor(RS_Color(attrib->color24 >> 16,
2985                               attrib->color24 >> 8 & 0xFF,
2986                               attrib->color24 & 0xFF));
2987     else
2988     pen.setColor(numberToColor(attrib->color));
2989 
2990     // Linetype:
2991     pen.setLineType(nameToLineType( QString::fromUtf8(attrib->lineType.c_str()) ));
2992 
2993     // Width:
2994     pen.setWidth(numberToWidth(attrib->lWeight));
2995 
2996     entity->setPen(pen);
2997     RS_DEBUG->print("RS_FilterDXF::setEntityAttributes: OK");
2998 }
2999 
3000 
3001 
3002 /**
3003  * Gets the entities attributes as a DL_Attributes object.
3004  */
getEntityAttributes(DRW_Entity * ent,const RS_Entity * entity)3005 void RS_FilterDXFRW::getEntityAttributes(DRW_Entity* ent, const RS_Entity* entity) {
3006 //DRW_Entity RS_FilterDXFRW::getEntityAttributes(RS_Entity* /*entity*/) {
3007 
3008     // Layer:
3009     RS_Layer* layer = entity->getLayer();
3010     QString layerName;
3011     if (layer) {
3012         layerName = layer->getName();
3013     } else {
3014         layerName = "0";
3015     }
3016 
3017     RS_Pen pen = entity->getPen(false);
3018 
3019     // Color:
3020     int exact_rgb;
3021     int color = colorToNumber(pen.getColor(), &exact_rgb);
3022     //printf("Color is: %s -> %d\n", pen.getColor().name().toLatin1().data(), color);
3023 
3024     // Linetype:
3025     QString lineType = lineTypeToName(pen.getLineType());
3026 
3027     // Width:
3028     DRW_LW_Conv::lineWidth width = widthToNumber(pen.getWidth());
3029 
3030     ent->layer = toDxfString(layerName).toUtf8().data();
3031     ent->color = color;
3032     ent->color24 = exact_rgb;
3033     ent->lWeight = width;
3034     ent->lineType = lineType.toUtf8().data();
3035 }
3036 
3037 
3038 
3039 /**
3040  * @return Pen with the same attributes as 'attrib'.
3041  */
attributesToPen(const DRW_Layer * att) const3042 RS_Pen RS_FilterDXFRW::attributesToPen(const DRW_Layer* att) const {
3043 
3044     RS_Color col;
3045     if (att->color24 >= 0)
3046         col = RS_Color(att->color24 >> 16,
3047                               att->color24 >> 8 & 0xFF,
3048                               att->color24 & 0xFF);
3049     else
3050         col = numberToColor(att->color);
3051 
3052     RS_Pen pen(col, numberToWidth(att->lWeight),
3053                nameToLineType(QString::fromUtf8(att->lineType.c_str())) );
3054     return pen;
3055 }
3056 
3057 
3058 
3059 /**
3060  * Converts a color index (num) into a RS_Color object.
3061  * Please refer to the dxflib documentation for details.
3062  *
3063  * @param num Color number.
3064  */
numberToColor(int num)3065 RS_Color RS_FilterDXFRW::numberToColor(int num) {
3066         if (num==0) {
3067             return RS_Color(RS2::FlagByBlock);
3068         } else if (num==256) {
3069             return RS_Color(RS2::FlagByLayer);
3070         } else if (num<=255 && num>=0) {
3071             return RS_Color(DRW::dxfColors[num][0],
3072                             DRW::dxfColors[num][1],
3073                             DRW::dxfColors[num][2]);
3074         } else {
3075             RS_DEBUG->print(RS_Debug::D_WARNING,
3076                                 "RS_FilterDXF::numberToColor: Invalid color number given.");
3077             return RS_Color(RS2::FlagByLayer);
3078         }
3079 
3080     return RS_Color();
3081 }
3082 
3083 
3084 
3085 /**
3086  * Converts a color into a color number in the DXF palette.
3087  * The color that fits best is chosen.
3088  */
colorToNumber(const RS_Color & col,int * rgb)3089 int RS_FilterDXFRW::colorToNumber(const RS_Color& col, int *rgb) {
3090 
3091     //printf("Searching color for %s\n", col.name().toLatin1().data());
3092 
3093     *rgb = -1;
3094     // Special color BYBLOCK:
3095     if (col.getFlag(RS2::FlagByBlock)) {
3096         return 0;
3097     }
3098 
3099     // Special color BYLAYER
3100     else if (col.getFlag(RS2::FlagByLayer)) {
3101         return 256;
3102     }
3103 
3104     // Special color black is not in the table but white represents both
3105     // black and white
3106     else if (col.red()==0 && col.green()==0 && col.blue()==0) {
3107         return 7;
3108     }
3109 
3110     // All other colors
3111     else {
3112         int num=0;
3113         int diff=255*3;  // smallest difference to a color in the table found so far
3114 
3115         // Run through the whole table and compare
3116         for (int i=1; i<=255; i++) {
3117             int d = abs(col.red()-DRW::dxfColors[i][0])
3118                     + abs(col.green()-DRW::dxfColors[i][1])
3119                     + abs(col.blue()-DRW::dxfColors[i][2]);
3120 
3121             if (d<diff) {
3122                 /*
3123                 printf("color %f,%f,%f is closer\n",
3124                        dxfColors[i][0],
3125                        dxfColors[i][1],
3126                        dxfColors[i][2]);
3127                 */
3128                 diff = d;
3129                 num = i;
3130                 if (d==0) {
3131                     break;
3132                 }
3133             }
3134         }
3135         //printf("  Found: %d, diff: %d\n", num, diff);
3136         if(diff != 0) {
3137             *rgb = 0;
3138             *rgb = col.red()<<16 | col.green()<<8 | col.blue();
3139         }
3140         return num;
3141     }
3142 }
3143 
add3dFace(const DRW_3Dface & data)3144 void RS_FilterDXFRW::add3dFace(const DRW_3Dface& data) {
3145     RS_DEBUG->print("RS_FilterDXFRW::add3dFace");
3146     RS_PolylineData d(RS_Vector(false),
3147                       RS_Vector(false),
3148                       !data.invisibleflag);
3149     RS_Polyline *polyline = new RS_Polyline(currentContainer, d);
3150     setEntityAttributes(polyline, &data);
3151     RS_Vector v1(data.basePoint.x, data.basePoint.y);
3152     RS_Vector v2(data.secPoint.x, data.secPoint.y);
3153     RS_Vector v3(data.thirdPoint.x, data.thirdPoint.y);
3154     RS_Vector v4(data.fourPoint.x, data.fourPoint.y);
3155 
3156     polyline->addVertex(v1, 0.0);
3157     polyline->addVertex(v2, 0.0);
3158     polyline->addVertex(v3, 0.0);
3159     polyline->addVertex(v4, 0.0);
3160 
3161     currentContainer->addEntity(polyline);
3162 }
3163 
addComment(const char *)3164 void RS_FilterDXFRW::addComment(const char*) {
3165     RS_DEBUG->print("RS_FilterDXF::addComment(const char*) not yet implemented.");
3166 }
3167 
addPlotSettings(const DRW_PlotSettings * data)3168 void RS_FilterDXFRW::addPlotSettings(const DRW_PlotSettings *data) {
3169     graphic->setPagesNum(QString::fromStdString(data->plotViewName));
3170     graphic->setMargins(data->marginLeft, data->marginTop,
3171                         data->marginRight, data->marginBottom);
3172 }
3173 
3174 /**
3175  * Converts a line type name (e.g. "CONTINUOUS") into a RS2::LineType
3176  * object.
3177  */
nameToLineType(const QString & name)3178 RS2::LineType RS_FilterDXFRW::nameToLineType(const QString& name) {
3179 
3180     QString uName = name.toUpper();
3181 
3182     // Standard linetypes for QCad II / AutoCAD
3183     if (uName.isEmpty() || uName=="BYLAYER") {
3184         return RS2::LineByLayer;
3185 
3186     } else if (uName=="BYBLOCK") {
3187         return RS2::LineByBlock;
3188 
3189     } else if (uName=="CONTINUOUS" || uName=="ACAD_ISO01W100") {
3190         return RS2::SolidLine;
3191 
3192     } else if (uName=="ACAD_ISO07W100" || uName=="DOT") {
3193         return RS2::DotLine;
3194 
3195     } else if (uName=="DOTTINY") {
3196         return RS2::DotLineTiny;
3197 
3198     } else if (uName=="DOT2") {
3199         return RS2::DotLine2;
3200 
3201     } else if (uName=="DOTX2") {
3202         return RS2::DotLineX2;
3203 
3204 
3205     } else if (uName=="ACAD_ISO02W100" || uName=="ACAD_ISO03W100" ||
3206                uName=="DASHED" || uName=="HIDDEN") {
3207         return RS2::DashLine;
3208 
3209     } else if (uName=="DASHEDTINY" || uName=="HIDDEN2") {
3210         return RS2::DashLineTiny;
3211 
3212     } else if (uName=="DASHED2" || uName=="HIDDEN2") {
3213         return RS2::DashLine2;
3214 
3215     } else if (uName=="DASHEDX2" || uName=="HIDDENX2") {
3216         return RS2::DashLineX2;
3217 
3218 
3219     } else if (uName=="ACAD_ISO10W100" ||
3220                uName=="DASHDOT") {
3221         return RS2::DashDotLine;
3222 
3223     } else if (uName=="DASHDOTTINY") {
3224         return RS2::DashDotLineTiny;
3225 
3226     } else if (uName=="DASHDOT2") {
3227         return RS2::DashDotLine2;
3228 
3229     } else if (uName=="ACAD_ISO04W100" ||
3230                uName=="DASHDOTX2") {
3231         return RS2::DashDotLineX2;
3232 
3233 
3234     } else if (uName=="ACAD_ISO12W100" || uName=="DIVIDE") {
3235         return RS2::DivideLine;
3236 
3237     } else if (uName=="DIVIDETINY") {
3238         return RS2::DivideLineTiny;
3239 
3240     } else if (uName=="DIVIDE2") {
3241         return RS2::DivideLine2;
3242 
3243     } else if (uName=="ACAD_ISO05W100" || uName=="DIVIDEX2") {
3244         return RS2::DivideLineX2;
3245 
3246 
3247     } else if (uName=="CENTER") {
3248         return RS2::CenterLine;
3249 
3250     } else if (uName=="CENTERTINY") {
3251         return RS2::CenterLineTiny;
3252 
3253     } else if (uName=="CENTER2") {
3254         return RS2::CenterLine2;
3255 
3256     } else if (uName=="CENTERX2") {
3257         return RS2::CenterLineX2;
3258 
3259 
3260     } else if (uName=="BORDER") {
3261         return RS2::BorderLine;
3262 
3263     } else if (uName=="BORDERTINY") {
3264         return RS2::BorderLineTiny;
3265 
3266     } else if (uName=="BORDER2") {
3267         return RS2::BorderLine2;
3268 
3269     } else if (uName=="BORDERX2") {
3270         return RS2::BorderLineX2;
3271     }
3272 
3273     return RS2::SolidLine;
3274 }
3275 
3276 
3277 
3278 /**
3279  * Converts a RS_LineType into a name for a line type.
3280  */
lineTypeToName(RS2::LineType lineType)3281 QString RS_FilterDXFRW::lineTypeToName(RS2::LineType lineType) {
3282 
3283     // Standard linetypes for QCad II / AutoCAD
3284     switch (lineType) {
3285 
3286     case RS2::SolidLine:
3287         return "CONTINUOUS";
3288         break;
3289 
3290     case RS2::DotLine:
3291         return "DOT";
3292         break;
3293     case RS2::DotLineTiny:
3294         return "DOTTINY";
3295         break;
3296     case RS2::DotLine2:
3297         return "DOT2";
3298         break;
3299     case RS2::DotLineX2:
3300         return "DOTX2";
3301         break;
3302 
3303     case RS2::DashLine:
3304         return "DASHED";
3305         break;
3306     case RS2::DashLineTiny:
3307         return "DASHEDTINY";
3308         break;
3309     case RS2::DashLine2:
3310         return "DASHED2";
3311         break;
3312     case RS2::DashLineX2:
3313         return "DASHEDX2";
3314         break;
3315 
3316     case RS2::DashDotLine:
3317         return "DASHDOT";
3318         break;
3319     case RS2::DashDotLineTiny:
3320         return "DASHDOTTINY";
3321         break;
3322     case RS2::DashDotLine2:
3323         return "DASHDOT2";
3324         break;
3325     case RS2::DashDotLineX2:
3326         return "DASHDOTX2";
3327         break;
3328 
3329     case RS2::DivideLine:
3330         return "DIVIDE";
3331         break;
3332     case RS2::DivideLineTiny:
3333         return "DIVIDETINY";
3334         break;
3335     case RS2::DivideLine2:
3336         return "DIVIDE2";
3337         break;
3338     case RS2::DivideLineX2:
3339         return "DIVIDEX2";
3340         break;
3341 
3342     case RS2::CenterLine:
3343         return "CENTER";
3344         break;
3345     case RS2::CenterLineTiny:
3346         return "CENTERTINY";
3347         break;
3348     case RS2::CenterLine2:
3349         return "CENTER2";
3350         break;
3351     case RS2::CenterLineX2:
3352         return "CENTERX2";
3353         break;
3354 
3355     case RS2::BorderLine:
3356         return "BORDER";
3357         break;
3358     case RS2::BorderLineTiny:
3359         return "BORDERTINY";
3360         break;
3361     case RS2::BorderLine2:
3362         return "BORDER2";
3363         break;
3364     case RS2::BorderLineX2:
3365         return "BORDERX2";
3366         break;
3367 
3368     case RS2::LineByLayer:
3369         return "ByLayer";
3370         break;
3371     case RS2::LineByBlock:
3372         return "ByBlock";
3373         break;
3374     default:
3375         break;
3376     }
3377 
3378     return "CONTINUOUS";
3379 }
3380 
3381 
3382 
3383 /**
3384  * Converts a RS_LineType into a name for a line type.
3385  */
3386 /*QString RS_FilterDXFRW::lineTypeToDescription(RS2::LineType lineType) {
3387 
3388     // Standard linetypes for QCad II / AutoCAD
3389     switch (lineType) {
3390     case RS2::SolidLine:
3391         return "Solid line";
3392     case RS2::DotLine:
3393         return "ISO Dashed __ __ __ __ __ __ __ __ __ __ _";
3394     case RS2::DashLine:
3395         return "ISO Dashed with Distance __    __    __    _";
3396     case RS2::DashDotLine:
3397         return "ISO Long Dashed Dotted ____ . ____ . __";
3398     case RS2::DashDotDotLine:
3399         return "ISO Long Dashed Double Dotted ____ .. __";
3400     case RS2::LineByLayer:
3401         return "";
3402     case RS2::LineByBlock:
3403         return "";
3404     default:
3405         break;
3406     }
3407 
3408     return "CONTINUOUS";
3409 }*/
3410 
3411 
3412 
3413 /**
3414  * Converts a DRW_LW_Conv::lineWidth into a RS2::LineWidth.
3415  */
numberToWidth(DRW_LW_Conv::lineWidth lw)3416 RS2::LineWidth RS_FilterDXFRW::numberToWidth(DRW_LW_Conv::lineWidth lw) {
3417     switch (lw) {
3418     case DRW_LW_Conv::widthByLayer:
3419         return RS2::WidthByLayer;
3420         break;
3421     case DRW_LW_Conv::widthByBlock:
3422         return RS2::WidthByBlock;
3423         break;
3424     case DRW_LW_Conv::widthDefault:
3425         return RS2::WidthDefault;
3426         break;
3427     case DRW_LW_Conv::width00:
3428         return RS2::Width00;
3429         break;
3430     case DRW_LW_Conv::width01:
3431         return RS2::Width01;
3432         break;
3433     case DRW_LW_Conv::width02:
3434         return RS2::Width02;
3435         break;
3436     case DRW_LW_Conv::width03:
3437         return RS2::Width03;
3438         break;
3439     case DRW_LW_Conv::width04:
3440         return RS2::Width04;
3441         break;
3442     case DRW_LW_Conv::width05:
3443         return RS2::Width05;
3444         break;
3445     case DRW_LW_Conv::width06:
3446         return RS2::Width06;
3447         break;
3448     case DRW_LW_Conv::width07:
3449         return RS2::Width07;
3450         break;
3451     case DRW_LW_Conv::width08:
3452         return RS2::Width08;
3453         break;
3454     case DRW_LW_Conv::width09:
3455         return RS2::Width09;
3456         break;
3457     case DRW_LW_Conv::width10:
3458         return RS2::Width10;
3459         break;
3460     case DRW_LW_Conv::width11:
3461         return RS2::Width11;
3462         break;
3463     case DRW_LW_Conv::width12:
3464         return RS2::Width12;
3465         break;
3466     case DRW_LW_Conv::width13:
3467         return RS2::Width13;
3468         break;
3469     case DRW_LW_Conv::width14:
3470         return RS2::Width14;
3471         break;
3472     case DRW_LW_Conv::width15:
3473         return RS2::Width15;
3474         break;
3475     case DRW_LW_Conv::width16:
3476         return RS2::Width16;
3477         break;
3478     case DRW_LW_Conv::width17:
3479         return RS2::Width17;
3480         break;
3481     case DRW_LW_Conv::width18:
3482         return RS2::Width18;
3483         break;
3484     case DRW_LW_Conv::width19:
3485         return RS2::Width19;
3486         break;
3487     case DRW_LW_Conv::width20:
3488         return RS2::Width20;
3489         break;
3490     case DRW_LW_Conv::width21:
3491         return RS2::Width21;
3492         break;
3493     case DRW_LW_Conv::width22:
3494         return RS2::Width22;
3495         break;
3496     case DRW_LW_Conv::width23:
3497         return RS2::Width23;
3498         break;
3499     default:
3500         break;
3501     }
3502     return RS2::WidthDefault;
3503 }
3504 
3505 
3506 
3507 /**
3508  * Converts a RS2::LineWidth into an DRW_LW_Conv::lineWidth.
3509  */
widthToNumber(RS2::LineWidth width)3510 DRW_LW_Conv::lineWidth RS_FilterDXFRW::widthToNumber(RS2::LineWidth width) {
3511     switch (width) {
3512     case RS2::WidthByLayer:
3513         return DRW_LW_Conv::widthByLayer;
3514         break;
3515     case RS2::WidthByBlock:
3516         return DRW_LW_Conv::widthByBlock;
3517         break;
3518     case RS2::WidthDefault:
3519         return DRW_LW_Conv::widthDefault;
3520         break;
3521     case RS2::Width00:
3522         return DRW_LW_Conv::width00;
3523         break;
3524     case RS2::Width01:
3525         return DRW_LW_Conv::width01;
3526         break;
3527     case RS2::Width02:
3528         return DRW_LW_Conv::width02;
3529         break;
3530     case RS2::Width03:
3531         return DRW_LW_Conv::width03;
3532         break;
3533     case RS2::Width04:
3534         return DRW_LW_Conv::width04;
3535         break;
3536     case RS2::Width05:
3537         return DRW_LW_Conv::width05;
3538         break;
3539     case RS2::Width06:
3540         return DRW_LW_Conv::width06;
3541         break;
3542     case RS2::Width07:
3543         return DRW_LW_Conv::width07;
3544         break;
3545     case RS2::Width08:
3546         return DRW_LW_Conv::width08;
3547         break;
3548     case RS2::Width09:
3549         return DRW_LW_Conv::width09;
3550         break;
3551     case RS2::Width10:
3552         return DRW_LW_Conv::width10;
3553         break;
3554     case RS2::Width11:
3555         return DRW_LW_Conv::width11;
3556         break;
3557     case RS2::Width12:
3558         return DRW_LW_Conv::width12;
3559         break;
3560     case RS2::Width13:
3561         return DRW_LW_Conv::width13;
3562         break;
3563     case RS2::Width14:
3564         return DRW_LW_Conv::width14;
3565         break;
3566     case RS2::Width15:
3567         return DRW_LW_Conv::width15;
3568         break;
3569     case RS2::Width16:
3570         return DRW_LW_Conv::width16;
3571         break;
3572     case RS2::Width17:
3573         return DRW_LW_Conv::width17;
3574         break;
3575     case RS2::Width18:
3576         return DRW_LW_Conv::width18;
3577         break;
3578     case RS2::Width19:
3579         return DRW_LW_Conv::width19;
3580         break;
3581     case RS2::Width20:
3582         return DRW_LW_Conv::width20;
3583         break;
3584     case RS2::Width21:
3585         return DRW_LW_Conv::width21;
3586         break;
3587     case RS2::Width22:
3588         return DRW_LW_Conv::width22;
3589         break;
3590     case RS2::Width23:
3591         return DRW_LW_Conv::width23;
3592         break;
3593     default:
3594         break;
3595     }
3596     return DRW_LW_Conv::widthDefault;
3597 }
3598 
3599 
3600 /**
3601  * Converts a native unicode string into a DXF encoded string.
3602  *
3603  * DXF endoding includes the following special sequences:
3604  * - %%%c for a diameter sign
3605  * - %%%d for a degree sign
3606  * - %%%p for a plus/minus sign
3607  */
toDxfString(const QString & str)3608 QString RS_FilterDXFRW::toDxfString(const QString& str) {
3609     QString res = "";
3610     int j=0;
3611     for (int i=0; i<str.length(); ++i) {
3612         int c = str.at(i).unicode();
3613         if (c>175 || c<11){
3614             res.append(str.mid(j,i-j));
3615             j=i;
3616 
3617             switch (c) {
3618             case 0x0A:
3619                 res+="\\P";
3620                 break;
3621                 // diameter:
3622             case 0x2205://RLZ: Empty_set, diameter is 0x2300 need to add in all fonts
3623             case 0x2300:
3624                 res+="%%C";
3625                 break;
3626                 // degree:
3627             case 0x00B0:
3628                 res+="%%D";
3629                 break;
3630                 // plus/minus
3631             case 0x00B1:
3632                 res+="%%P";
3633                 break;
3634             default:
3635                 j--;
3636                 break;
3637             }
3638             j++;
3639         }
3640 
3641     }
3642     res.append(str.mid(j));
3643     return res;
3644 }
3645 
3646 
3647 
3648 /**
3649  * Converts a DXF encoded string into a native Unicode string.
3650  */
toNativeString(const QString & data)3651 QString RS_FilterDXFRW::toNativeString(const QString& data) {
3652     QString res;
3653 
3654     // Ignore font tags:
3655     int j = 0;
3656     for (int i=0; i<data.length(); ++i) {
3657         if (data.at(i).unicode() == 0x7B){ //is '{' ?
3658             if (data.at(i+1).unicode() == 0x5c){ //and is "{\" ?
3659                 //check known codes
3660                 if ( (data.at(i+2).unicode() == 0x66) || //is "\f" ?
3661                      (data.at(i+2).unicode() == 0x48) || //is "\H" ?
3662                      (data.at(i+2).unicode() == 0x43)    //is "\C" ?
3663                    ) {
3664                     //found tag, append parsed part
3665                     res.append(data.mid(j,i-j));
3666                     int pos = data.indexOf(0x7D, i+3);//find '}'
3667                     if (pos <0) break; //'}' not found
3668                     QString tmp = data.mid(i+1, pos-i-1);
3669                     do {
3670                         tmp = tmp.remove(0,tmp.indexOf(0x3B, 0)+1 );//remove to ';'
3671                     } while(tmp.startsWith("\\f") || tmp.startsWith("\\H") || tmp.startsWith("\\C"));
3672                     res.append(tmp);
3673                     i = j = pos;
3674                     ++j;
3675                 }
3676             }
3677         }
3678     }
3679     res.append(data.mid(j));
3680 
3681     // Line feed:
3682     res = res.replace(QRegExp("\\\\P"), "\n");
3683     // Space:
3684     res = res.replace(QRegExp("\\\\~"), " ");
3685     // Tab:
3686     res = res.replace(QRegExp("\\^I"), "    ");//RLZ: change 4 spaces for \t when mtext have support for tab
3687     // diameter:
3688     res = res.replace(QRegExp("%%[cC]"), QChar(0x2300));//RLZ: Empty_set is 0x2205, diameter is 0x2300 need to add in all fonts
3689     // degree:
3690     res = res.replace(QRegExp("%%[dD]"), QChar(0x00B0));
3691     // plus/minus
3692     res = res.replace(QRegExp("%%[pP]"), QChar(0x00B1));
3693 
3694     return res;
3695 }
3696 
3697 
3698 
3699 /**
3700  * Converts the given number from a DXF file into an AngleFormat enum.
3701  *
3702  * @param num $DIMAUNIT from DXF (0: decimal deg, 1: deg/min/sec, 2: gradians,
3703  *                                3: radians, 4: surveyor's units)
3704  *
3705  * @ret Matching AngleFormat enum value.
3706  */
numberToAngleFormat(int num)3707 RS2::AngleFormat RS_FilterDXFRW::numberToAngleFormat(int num) {
3708 
3709     RS2::AngleFormat af;
3710 
3711     switch (num) {
3712     default:
3713     case 0:
3714         af = RS2::DegreesDecimal;
3715         break;
3716     case 1:
3717         af = RS2::DegreesMinutesSeconds;
3718         break;
3719     case 2:
3720         af = RS2::Gradians;
3721         break;
3722     case 3:
3723         af = RS2::Radians;
3724         break;
3725     case 4:
3726         af = RS2::Surveyors;
3727         break;
3728     }
3729 
3730     return af;
3731 }
3732 
3733 
3734 /**
3735  * Converts AngleFormat enum to DXF number.
3736  */
angleFormatToNumber(RS2::AngleFormat af)3737 int RS_FilterDXFRW::angleFormatToNumber(RS2::AngleFormat af) {
3738 
3739     int num;
3740 
3741     switch (af) {
3742     default:
3743     case RS2::DegreesDecimal:
3744         num = 0;
3745         break;
3746     case RS2::DegreesMinutesSeconds:
3747         num = 1;
3748         break;
3749     case RS2::Gradians:
3750         num = 2;
3751         break;
3752     case RS2::Radians:
3753         num = 3;
3754         break;
3755     case RS2::Surveyors:
3756         num = 4;
3757         break;
3758     }
3759 
3760     return num;
3761 }
3762 
3763 
3764 
3765 /**
3766  * converts a DXF unit setting (e.g. INSUNITS) to a unit enum.
3767  */
numberToUnit(int num)3768 RS2::Unit RS_FilterDXFRW::numberToUnit(int num) {
3769     switch (num) {
3770     default:
3771     case  0:
3772         return RS2::None;
3773         break;
3774     case  1:
3775         return RS2::Inch;
3776         break;
3777     case  2:
3778         return RS2::Foot;
3779         break;
3780     case  3:
3781         return RS2::Mile;
3782         break;
3783     case  4:
3784         return RS2::Millimeter;
3785         break;
3786     case  5:
3787         return RS2::Centimeter;
3788         break;
3789     case  6:
3790         return RS2::Meter;
3791         break;
3792     case  7:
3793         return RS2::Kilometer;
3794         break;
3795     case  8:
3796         return RS2::Microinch;
3797         break;
3798     case  9:
3799         return RS2::Mil;
3800         break;
3801     case 10:
3802         return RS2::Yard;
3803         break;
3804     case 11:
3805         return RS2::Angstrom;
3806         break;
3807     case 12:
3808         return RS2::Nanometer;
3809         break;
3810     case 13:
3811         return RS2::Micron;
3812         break;
3813     case 14:
3814         return RS2::Decimeter;
3815         break;
3816     case 15:
3817         return RS2::Decameter;
3818         break;
3819     case 16:
3820         return RS2::Hectometer;
3821         break;
3822     case 17:
3823         return RS2::Gigameter;
3824         break;
3825     case 18:
3826         return RS2::Astro;
3827         break;
3828     case 19:
3829         return RS2::Lightyear;
3830         break;
3831     case 20:
3832         return RS2::Parsec;
3833         break;
3834     }
3835 
3836     return RS2::None;
3837 }
3838 
3839 
3840 
3841 /**
3842  * Converts a unit enum into a DXF unit number e.g. for INSUNITS.
3843  */
unitToNumber(RS2::Unit unit)3844 int RS_FilterDXFRW::unitToNumber(RS2::Unit unit) {
3845     switch (unit) {
3846     default:
3847     case RS2::None:
3848         return  0;
3849         break;
3850     case RS2::Inch:
3851         return  1;
3852         break;
3853     case RS2::Foot:
3854         return  2;
3855         break;
3856     case RS2::Mile:
3857         return  3;
3858         break;
3859     case RS2::Millimeter:
3860         return  4;
3861         break;
3862     case RS2::Centimeter:
3863         return  5;
3864         break;
3865     case RS2::Meter:
3866         return  6;
3867         break;
3868     case RS2::Kilometer:
3869         return  7;
3870         break;
3871     case RS2::Microinch:
3872         return  8;
3873         break;
3874     case RS2::Mil:
3875         return  9;
3876         break;
3877     case RS2::Yard:
3878         return 10;
3879         break;
3880     case RS2::Angstrom:
3881         return 11;
3882         break;
3883     case RS2::Nanometer:
3884         return 12;
3885         break;
3886     case RS2::Micron:
3887         return 13;
3888         break;
3889     case RS2::Decimeter:
3890         return 14;
3891         break;
3892     case RS2::Decameter:
3893         return 15;
3894         break;
3895     case RS2::Hectometer:
3896         return 16;
3897         break;
3898     case RS2::Gigameter:
3899         return 17;
3900         break;
3901     case RS2::Astro:
3902         return 18;
3903         break;
3904     case RS2::Lightyear:
3905         return 19;
3906         break;
3907     case RS2::Parsec:
3908         return 20;
3909         break;
3910     }
3911 
3912     return 0;
3913 }
3914 
3915 
3916 
3917 /**
3918  * Checks if the given variable is two-dimensional (e.g. $LIMMIN).
3919  */
isVariableTwoDimensional(const QString & var)3920 bool RS_FilterDXFRW::isVariableTwoDimensional(const QString& var) {
3921     if (var=="$LIMMIN" ||
3922             var=="$LIMMAX" ||
3923             var=="$PLIMMIN" ||
3924             var=="$PLIMMAX" ||
3925             var=="$GRIDUNIT" ||
3926             var=="$VIEWCTR") {
3927 
3928         return true;
3929     } else {
3930         return false;
3931     }
3932 }
3933 
3934 #ifdef DWGSUPPORT
printDwgVersion(int v)3935 QString RS_FilterDXFRW::printDwgVersion(int v){
3936     switch (v) {
3937     case DRW::AC1006:
3938         return "10";
3939         break;
3940     case DRW::AC1009:
3941         return "dwg version 11 or 12";
3942     case DRW::AC1012:
3943         return "dwg version 13";
3944     case DRW::AC1014:
3945         return "dwg version 14";
3946     case DRW::AC1015:
3947         return "dwg version 2000";
3948     case DRW::AC1018:
3949         return "dwg version 2004";
3950     case DRW::AC1021:
3951         return "dwg version 2007";
3952     case DRW::AC1024:
3953         return "dwg version 2010";
3954     case DRW::AC1027:
3955         return "dwg version 2013";
3956     default:
3957         return "unknown";
3958     }
3959 }
3960 
printDwgError(int le)3961 void RS_FilterDXFRW::printDwgError(int le){
3962     switch (le) {
3963     case DRW::BAD_UNKNOWN:
3964         RS_DIALOGFACTORY->commandMessage(QObject::tr("unknown error opening dwg file"));
3965         RS_DEBUG->print("RS_FilterDXFRW::printDwgError: DRW::BAD_UNKNOWN");
3966         break;
3967     case DRW::BAD_OPEN:
3968         RS_DIALOGFACTORY->commandMessage(QObject::tr("can't open this dwg file"));
3969         RS_DEBUG->print("RS_FilterDXFRW::printDwgError: DRW::BAD_OPEN");
3970         break;
3971     case DRW::BAD_VERSION:
3972         RS_DIALOGFACTORY->commandMessage(QObject::tr("unsupported dwg version"));
3973         RS_DEBUG->print("RS_FilterDXFRW::printDwgError: DRW::BAD_VERSION");
3974         break;
3975     case DRW::BAD_READ_METADATA:
3976         RS_DIALOGFACTORY->commandMessage(QObject::tr("error reading file metadata in dwg file"));
3977         RS_DEBUG->print("RS_FilterDXFRW::printDwgError: DRW::BAD_READ_FILE_HEADER");
3978         break;
3979     case DRW::BAD_READ_FILE_HEADER:
3980         RS_DIALOGFACTORY->commandMessage(QObject::tr("error reading file header in dwg file"));
3981         RS_DEBUG->print("RS_FilterDXFRW::printDwgError: DRW::BAD_READ_FILE_HEADER");
3982         break;
3983     case DRW::BAD_READ_HEADER:
3984         RS_DIALOGFACTORY->commandMessage(QObject::tr("error reading header vars in dwg file"));
3985         RS_DEBUG->print("RS_FilterDXFRW::printDwgError: DRW::BAD_READ_HEADER");
3986         break;
3987     case DRW::BAD_READ_CLASSES:
3988         RS_DIALOGFACTORY->commandMessage(QObject::tr("error reading classes in dwg file"));
3989         RS_DEBUG->print("RS_FilterDXFRW::printDwgError: DRW::BAD_READ_CLASSES");
3990         break;
3991     case DRW::BAD_READ_HANDLES:
3992         RS_DIALOGFACTORY->commandMessage(QObject::tr("error reading offsets in dwg file"));
3993         RS_DEBUG->print("RS_FilterDXFRW::printDwgError: DRW::BAD_READ_OFFSETS");
3994         break;
3995     case DRW::BAD_READ_TABLES:
3996         RS_DIALOGFACTORY->commandMessage(QObject::tr("error reading tables in dwg file"));
3997         RS_DEBUG->print("RS_FilterDXFRW::printDwgError: DRW::BAD_READ_TABLES");
3998         break;
3999     case DRW::BAD_READ_BLOCKS:
4000         RS_DIALOGFACTORY->commandMessage(QObject::tr("error reading blocks in dwg file"));
4001         RS_DEBUG->print("RS_FilterDXFRW::printDwgError: DRW::BAD_READ_OFFSETS");
4002         break;
4003     case DRW::BAD_READ_ENTITIES:
4004         RS_DIALOGFACTORY->commandMessage(QObject::tr("error reading entities in dwg file"));
4005         RS_DEBUG->print("RS_FilterDXFRW::printDwgError: DRW::BAD_READ_ENTITIES");
4006         break;
4007     case DRW::BAD_READ_OBJECTS:
4008         RS_DIALOGFACTORY->commandMessage(QObject::tr("error reading objects in dwg file"));
4009         RS_DEBUG->print("RS_FilterDXFRW::printDwgError: DRW::BAD_READ_OBJECTS");
4010         break;
4011     default:
4012         break;
4013     }
4014 }
4015 #endif
4016 
4017 // EOF
4018 
4019