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