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