]> Shamusworld >> Repos - architektonas/blob - src/base/drawing.cpp
3393bfc3e3921da2b12fc1dc9b8e71b23a77d943
[architektonas] / src / base / drawing.cpp
1 // drawing.cpp
2 //
3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // Portions copyright (C) 2001-2003 RibbonSoft
7 // Copyright (C) 2010 Underground Software
8 // See the README and GPLv2 files for licensing and warranty information
9 //
10 // JLH = James L. Hammons <jlhamm@acm.org>
11 //
12 // Who  When        What
13 // ---  ----------  -----------------------------------------------------------
14 // JLH  05/21/2010  Added this text. :-)
15 // JLH  06/02/2010  Changed all references of this class from RS_Graphic to
16 //                  Drawing, as that makes it more clear that this is what it
17 //                  is (a CAD drawing, not a bitmap).
18 //
19
20 #include "drawing.h"
21
22 #include "rs_debug.h"
23 #include "rs_fileio.h"
24 #include "rs_math.h"
25 #include "rs_units.h"
26 #include "settings.h"
27
28 /**
29  * Default constructor.
30  */
31 Drawing::Drawing(RS_EntityContainer * parent): RS_Document(parent), layerList(),
32         blockList(true)
33 #ifdef RS_CAM
34         , camData()
35 #endif
36 {
37         settings.beginGroup("Defaults");
38         setUnit(RS_Units::stringToUnit(settings.value("Unit", "None").toString()));
39         settings.endGroup();
40
41         RS2::Unit unit = getUnit();
42
43         if (unit == RS2::Inch)
44         {
45                 addVariable("$DIMASZ", 0.1, 40);
46                 addVariable("$DIMEXE", 0.05, 40);
47                 addVariable("$DIMEXO", 0.025, 40);
48                 addVariable("$DIMGAP", 0.025, 40);
49                 addVariable("$DIMTXT", 0.1, 40);
50         }
51         else
52         {
53                 addVariable("$DIMASZ", RS_Units::convert(2.5, RS2::Millimeter, unit), 40);
54                 addVariable("$DIMEXE", RS_Units::convert(1.25, RS2::Millimeter, unit), 40);
55                 addVariable("$DIMEXO", RS_Units::convert(0.625, RS2::Millimeter, unit), 40);
56                 addVariable("$DIMGAP", RS_Units::convert(0.625, RS2::Millimeter, unit), 40);
57                 addVariable("$DIMTXT", RS_Units::convert(2.5, RS2::Millimeter, unit), 40);
58         }
59
60         setModified(false);
61 }
62
63 /**
64  * Destructor.
65  */
66 Drawing::~Drawing()
67 {
68 }
69
70 /** @return RS2::EntityGraphic */
71 /*virtual*/ RS2::EntityType Drawing::rtti() const
72 {
73         return RS2::EntityGraphic;
74 }
75
76 /**
77  * Counts the entities on the given layer.
78  */
79 unsigned long int Drawing::countLayerEntities(RS_Layer * layer)
80 {
81     int c = 0;
82
83     if (layer != NULL)
84         {
85         for(RS_Entity * t=firstEntity(RS2::ResolveNone); t!=NULL; t=nextEntity(RS2::ResolveNone))
86                 {
87             if (t->getLayer()!=NULL && t->getLayer()->getName()==layer->getName())
88                         {
89                 c += t->countDeep();
90             }
91         }
92     }
93
94     return c;
95 }
96
97 /*virtual*/ RS_LayerList * Drawing::getLayerList()
98 {
99         return &layerList;
100 }
101
102 /*virtual*/ RS_BlockList * Drawing::getBlockList()
103 {
104         return &blockList;
105 }
106
107 /**
108  * Clears all layers, blocks and entities of this graphic.
109  * A default layer (0) is created.
110  */
111 void Drawing::newDoc()
112 {
113         RS_DEBUG->print("Drawing::newDoc");
114
115         clear();
116
117         clearLayers();
118         clearBlocks();
119
120         addLayer(new RS_Layer("0"));
121         //addLayer(new RS_Layer("ByBlock"));
122
123         setModified(false);
124 }
125
126 /**
127  * Saves this graphic with the current filename and settings.
128  */
129 bool Drawing::save()
130 {
131         bool ret = false;
132
133         RS_DEBUG->print("Drawing::save");
134         RS_DEBUG->print("  file: %s", filename.toLatin1().data());
135         RS_DEBUG->print("  format: %d", (int)formatType);
136
137         RS_DEBUG->print("  export...");
138         ret = RS_FILEIO->fileExport(*this, filename, formatType);
139
140         if (ret)
141         {
142                 setModified(false);
143                 layerList.setModified(false);
144                 blockList.setModified(false);
145         }
146
147         RS_DEBUG->print("Drawing::save ok");
148
149         return ret;
150 }
151
152 /**
153  * Saves this graphic with the given filename and current settings.
154  */
155 bool Drawing::saveAs(const QString & filename, RS2::FormatType type)
156 {
157         RS_DEBUG->print("Drawing::saveAs");
158
159         this->filename = filename;
160         this->formatType = type;
161
162         return save();
163 }
164
165 /**
166  * Loads the given fils into this graphic.
167  */
168 bool Drawing::open(const QString &filename, RS2::FormatType type)
169 {
170         RS_DEBUG->print("Drawing::open(%s)", filename.toLatin1().data());
171
172         bool ret = false;
173
174         this->filename = filename;
175
176         // clean all:
177         newDoc();
178
179         // import file:
180         ret = RS_FILEIO->fileImport(*this, filename, type);
181
182         setModified(false);
183         layerList.setModified(false);
184         blockList.setModified(false);
185
186         //cout << *((Drawing*)graphic);
187         //calculateBorders();
188
189         RS_DEBUG->print("Drawing::open(%s): OK", filename.toLatin1().data());
190
191         return ret;
192 }
193
194 // Wrappers for Layer functions:
195 void Drawing::clearLayers()
196 {
197         layerList.clear();
198 }
199
200 uint Drawing::countLayers() const
201 {
202         return layerList.count();
203 }
204
205 RS_Layer * Drawing::layerAt(uint i)
206 {
207         return layerList.at(i);
208 }
209
210 void Drawing::activateLayer(const QString & name)
211 {
212         layerList.activate(name);
213 }
214
215 void Drawing::activateLayer(RS_Layer * layer)
216 {
217         layerList.activate(layer);
218 }
219
220 RS_Layer * Drawing::getActiveLayer()
221 {
222         return layerList.getActive();
223 }
224
225 /*virtual*/ void Drawing::addLayer(RS_Layer * layer)
226 {
227         layerList.add(layer);
228 }
229
230 /**
231  * Removes the given layer and undoes all entities on it.
232  */
233 /*virtual*/ void Drawing::removeLayer(RS_Layer * layer)
234 {
235         if (layer != NULL && layer->getName() != "0")
236         {
237                 // remove all entities on that layer:
238                 startUndoCycle();
239
240                 for(RS_Entity * e=firstEntity(RS2::ResolveNone); e!=NULL; e=nextEntity(RS2::ResolveNone))
241                 {
242                         if (e->getLayer() != NULL && e->getLayer()->getName() == layer->getName())
243                         {
244                                 e->setUndoState(true);
245                                 e->setLayer("0");
246                                 addUndoable(e);
247                         }
248                 }
249
250                 endUndoCycle();
251
252                 // remove all entities in blocks that are on that layer:
253                 for(uint bi=0; bi<blockList.count(); bi++)
254                 {
255                         RS_Block * blk = blockList.at(bi);
256
257                         if (blk != NULL)
258                         {
259                                 for(RS_Entity * e=blk->firstEntity(RS2::ResolveNone); e!=NULL; e=blk->nextEntity(RS2::ResolveNone))
260                                 {
261                                         if (e->getLayer() != NULL && e->getLayer()->getName() == layer->getName())
262                                         {
263                                                 e->setUndoState(true);
264                                                 e->setLayer("0");
265                                                 //addUndoable(e);
266                                         }
267                                 }
268                         }
269                 }
270
271                 layerList.remove(layer);
272         }
273 }
274
275 /*virtual*/ void Drawing::editLayer(RS_Layer * layer, const RS_Layer & source)
276 {
277         layerList.edit(layer, source);
278 }
279
280 RS_Layer * Drawing::findLayer(const QString & name)
281 {
282         return layerList.find(name);
283 }
284
285 void Drawing::toggleLayer(const QString & name)
286 {
287         layerList.toggle(name);
288 }
289
290 void Drawing::toggleLayer(RS_Layer * layer)
291 {
292         layerList.toggle(layer);
293 }
294
295 void Drawing::toggleLayerLock(RS_Layer * layer)
296 {
297         layerList.toggleLock(layer);
298 }
299
300 void Drawing::freezeAllLayers(bool freeze)
301 {
302         layerList.freezeAll(freeze);
303 }
304
305 void Drawing::addLayerListListener(RS_LayerListListener * listener)
306 {
307         layerList.addListener(listener);
308 }
309
310 void Drawing::removeLayerListListener(RS_LayerListListener * listener)
311 {
312         layerList.removeListener(listener);
313 }
314
315 // Wrapper for block functions:
316
317 void Drawing::clearBlocks()
318 {
319         blockList.clear();
320 }
321
322 uint Drawing::countBlocks()
323 {
324         return blockList.count();
325 }
326
327 RS_Block * Drawing::blockAt(uint i)
328 {
329         return blockList.at(i);
330 }
331
332 void Drawing::activateBlock(const QString & name)
333 {
334         blockList.activate(name);
335 }
336
337 void Drawing::activateBlock(RS_Block * block)
338 {
339         blockList.activate(block);
340 }
341
342 RS_Block * Drawing::getActiveBlock()
343 {
344         return blockList.getActive();
345 }
346
347 /*virtual*/ bool Drawing::addBlock(RS_Block * block, bool notify/*= true*/)
348 {
349         return blockList.add(block, notify);
350 }
351
352 /*virtual*/ void Drawing::addBlockNotification()
353 {
354         blockList.addNotification();
355 }
356
357 /*virtual*/ void Drawing::removeBlock(RS_Block * block)
358 {
359         blockList.remove(block);
360 }
361
362 RS_Block * Drawing::findBlock(const QString & name)
363 {
364         return blockList.find(name);
365 }
366
367 QString Drawing::newBlockName()
368 {
369         return blockList.newName();
370 }
371
372 void Drawing::toggleBlock(const QString & name)
373 {
374         blockList.toggle(name);
375 }
376
377 void Drawing::toggleBlock(RS_Block * block)
378 {
379         blockList.toggle(block);
380 }
381
382 void Drawing::freezeAllBlocks(bool freeze)
383 {
384         blockList.freezeAll(freeze);
385 }
386
387 void Drawing::addBlockListListener(RS_BlockListListener * listener)
388 {
389         blockList.addListener(listener);
390 }
391
392 void Drawing::removeBlockListListener(RS_BlockListListener * listener)
393 {
394         blockList.removeListener(listener);
395 }
396
397 // Wrappers for variable functions:
398 void Drawing::clearVariables()
399 {
400         variableDict.clear();
401 }
402
403 int Drawing::countVariables()
404 {
405         return variableDict.count();
406 }
407
408 void Drawing::addVariable(const QString & key, const Vector & value, int code)
409 {
410         variableDict.add(key, value, code);
411 }
412
413 void Drawing::addVariable(const QString & key, const QString & value, int code)
414 {
415         variableDict.add(key, value, code);
416 }
417
418 void Drawing::addVariable(const QString & key, int value, int code)
419 {
420         variableDict.add(key, value, code);
421 }
422
423 void Drawing::addVariable(const QString & key, double value, int code)
424 {
425         variableDict.add(key, value, code);
426 }
427
428 Vector Drawing::getVariableVector(const QString & key, const Vector & def)
429 {
430         return variableDict.getVector(key, def);
431 }
432
433 QString Drawing::getVariableString(const QString & key, const QString & def)
434 {
435         return variableDict.getString(key, def);
436 }
437
438 int Drawing::getVariableInt(const QString & key, int def)
439 {
440         return variableDict.getInt(key, def);
441 }
442
443 double Drawing::getVariableDouble(const QString & key, double def)
444 {
445         return variableDict.getDouble(key, def);
446 }
447
448 void Drawing::removeVariable(const QString & key)
449 {
450         variableDict.remove(key);
451 }
452
453 //Q3Dict<RS_Variable> & getVariableDict()
454 QMultiHash<QString, RS_Variable *> & Drawing::getVariableDict()
455 {
456         return variableDict.getVariableDict();
457 }
458
459 /**
460  * @return true if the grid is switched on (visible).
461  */
462 bool Drawing::isGridOn()
463 {
464         int on = getVariableInt("$GRIDMODE", 1);
465         return (on != 0);
466 }
467
468 /**
469  * Enables / disables the grid.
470  */
471 void Drawing::setGridOn(bool on)
472 {
473         addVariable("$GRIDMODE", (int)on, 70);
474 }
475
476 /**
477  * Sets the unit of this graphic to 'u'
478  */
479 void Drawing::setUnit(RS2::Unit u)
480 {
481         setPaperSize(RS_Units::convert(getPaperSize(), getUnit(), u));
482
483         addVariable("$INSUNITS", (int)u, 70);
484
485         //unit = u;
486 }
487
488 /**
489  * Gets the unit of this graphic
490  */
491 RS2::Unit Drawing::getUnit()
492 {
493         return (RS2::Unit)getVariableInt("$INSUNITS", 0);
494         //return unit;
495 }
496
497 /**
498  * @return The linear format type for this document.
499  * This is determined by the variable "$LUNITS".
500  */
501 RS2::LinearFormat Drawing::getLinearFormat()
502 {
503         int lunits = getVariableInt("$LUNITS", 2);
504
505         switch (lunits)
506         {
507         default:
508         case 2:
509                 return RS2::Decimal;
510                 break;
511
512         case 1:
513                 return RS2::Scientific;
514                 break;
515
516         case 3:
517                 return RS2::Engineering;
518                 break;
519
520         case 4:
521                 return RS2::Architectural;
522                 break;
523
524         case 5:
525                 return RS2::Fractional;
526                 break;
527         }
528
529         return RS2::Decimal;
530 }
531
532 /**
533  * @return The linear precision for this document.
534  * This is determined by the variable "$LUPREC".
535  */
536 int Drawing::getLinearPrecision()
537 {
538         return getVariableInt("$LUPREC", 4);
539 }
540
541 /**
542  * @return The angle format type for this document.
543  * This is determined by the variable "$AUNITS".
544  */
545 RS2::AngleFormat Drawing::getAngleFormat()
546 {
547         int aunits = getVariableInt("$AUNITS", 0);
548
549         switch (aunits)
550         {
551         default:
552         case 0:
553                 return RS2::DegreesDecimal;
554                 break;
555
556         case 1:
557                 return RS2::DegreesMinutesSeconds;
558                 break;
559
560         case 2:
561                 return RS2::Gradians;
562                 break;
563
564         case 3:
565                 return RS2::Radians;
566                 break;
567
568         case 4:
569                 return RS2::Surveyors;
570                 break;
571         }
572
573         return RS2::DegreesDecimal;
574 }
575
576 /**
577  * @return The linear precision for this document.
578  * This is determined by the variable "$LUPREC".
579  */
580 int Drawing::getAnglePrecision()
581 {
582         return getVariableInt("$AUPREC", 4);
583 }
584
585 /**
586  * @return The insertion point of the drawing into the paper space.
587  * This is the distance from the lower left paper edge to the zero
588  * point of the drawing. DXF: $PINSBASE.
589  */
590 Vector Drawing::getPaperInsertionBase()
591 {
592         return getVariableVector("$PINSBASE", Vector(0.0,0.0));
593 }
594
595 /**
596  * Sets the PINSBASE variable.
597  */
598 void Drawing::setPaperInsertionBase(const Vector & p)
599 {
600         addVariable("$PINSBASE", p, 10);
601 }
602
603 /**
604  * @return Paper size in graphic units.
605  */
606 Vector Drawing::getPaperSize()
607 {
608         Vector def = RS_Units::convert(Vector(210.0, 297.0), RS2::Millimeter, getUnit());
609
610         Vector v1 = getVariableVector("$PLIMMIN", Vector(0.0, 0.0));
611         Vector v2 = getVariableVector("$PLIMMAX", def);
612
613         return v2 - v1;
614 }
615
616 /**
617  * Sets a new paper size.
618  */
619 void Drawing::setPaperSize(const Vector & s)
620 {
621         addVariable("$PLIMMIN", Vector(0.0, 0.0), 10);
622         addVariable("$PLIMMAX", s, 10);
623 }
624
625 /**
626  * @return Paper format.
627  * This is determined by the variables "$PLIMMIN" and "$PLIMMAX".
628  *
629  * @param landscape will be set to true for landscape and false for portrait if not NULL.
630  */
631 RS2::PaperFormat Drawing::getPaperFormat(bool * landscape)
632 {
633         Vector size = RS_Units::convert(getPaperSize(), getUnit(), RS2::Millimeter);
634
635         if (landscape != NULL)
636                 *landscape = (size.x > size.y);
637
638         return RS_Units::paperSizeToFormat(size);
639 }
640
641 /**
642  * Sets the paper format to the given format.
643  */
644 void Drawing::setPaperFormat(RS2::PaperFormat f, bool landscape)
645 {
646         Vector size = RS_Units::paperFormatToSize(f);
647
648         if (landscape)
649         {
650                 double tmp = size.x;
651                 size.x = size.y;
652                 size.y = tmp;
653         }
654
655         if (f != RS2::Custom)
656                 setPaperSize(RS_Units::convert(size, RS2::Millimeter, getUnit()));
657 }
658
659 /**
660  * @return Paper space scaling (DXF: $PSVPSCALE).
661  */
662 double Drawing::getPaperScale()
663 {
664         double ret;
665
666         ret = getVariableDouble("$PSVPSCALE", 1.0);
667
668         if (ret < 1.0e-6)
669                 ret = 1.0;
670
671         return ret;
672 }
673
674 /**
675  * Sets a new scale factor for the paper space.
676  */
677 void Drawing::setPaperScale(double s)
678 {
679         addVariable("$PSVPSCALE", s, 40);
680 }
681
682 /**
683  * Centers drawing on page. Affects DXF variable $PINSBASE.
684  */
685 void Drawing::centerToPage()
686 {
687         Vector size = getPaperSize();
688         double scale = getPaperScale();
689         Vector pinsbase = (size - getSize() * scale) / 2.0 - getMin() * scale;
690         setPaperInsertionBase(pinsbase);
691 }
692
693 /**
694  * Fits drawing on page. Affects DXF variable $PINSBASE.
695  */
696 void Drawing::fitToPage()
697 {
698         double border = RS_Units::convert(25.0, RS2::Millimeter, getUnit());
699         Vector ps = getPaperSize() - Vector(border, border);
700         Vector s = getSize();
701         double fx = RS_MAXDOUBLE;
702         double fy = RS_MAXDOUBLE;
703         //double factor = 1.0;
704
705         //ps = RS_Units::convert(ps, getUnit(), RS2::Millimeter);
706
707         if (fabs(s.x) > 1.0e-6)
708                 fx = ps.x / s.x;
709
710         if (fabs(s.y) > 1.0e-6)
711                 fy = ps.y / s.y;
712
713         setPaperScale(std::min(fx, fy));
714         centerToPage();
715 }
716
717 /**
718  * @retval true The document has been modified since it was last saved.
719  * @retval false The document has not been modified since it was last saved.
720  */
721 /*virtual*/ bool Drawing::isModified() const
722 {
723         return modified || layerList.isModified() || blockList.isModified();
724 }
725
726 /**
727  * Sets the documents modified status to 'm'.
728  */
729 /*virtual*/ void Drawing::setModified(bool m)
730 {
731         modified = m;
732         layerList.setModified(m);
733         blockList.setModified(m);
734 }
735
736 #ifdef RS_CAM
737 RS_CamData & Drawing::getCamData()
738 {
739         return camData;
740 }
741
742 void Drawing::setCamData(const RS_CamData & d)
743 {
744         camData = d;
745 }
746 #endif
747
748 /**
749  * Dumps the entities to stdout.
750  */
751 std::ostream & operator<<(std::ostream & os, Drawing & g)
752 {
753     os << "--- Drawing: \n";
754     os << "---" << *g.getLayerList() << "\n";
755     os << "---" << *g.getBlockList() << "\n";
756     os << "---" << (RS_Undo&)g << "\n";
757     os << "---" << (RS_EntityContainer&)g << "\n";
758
759     return os;
760 }