]> Shamusworld >> Repos - architektonas/blob - src/base/drawing.cpp
Removed useless *Listener class and references.
[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 #if 0
306 void Drawing::addLayerListListener(RS_LayerListListener * listener)
307 {
308         layerList.addListener(listener);
309 }
310
311 void Drawing::removeLayerListListener(RS_LayerListListener * listener)
312 {
313         layerList.removeListener(listener);
314 }
315 #endif
316
317 // Wrapper for block functions:
318
319 void Drawing::clearBlocks()
320 {
321         blockList.clear();
322 }
323
324 uint Drawing::countBlocks()
325 {
326         return blockList.count();
327 }
328
329 RS_Block * Drawing::blockAt(uint i)
330 {
331         return blockList.at(i);
332 }
333
334 void Drawing::activateBlock(const QString & name)
335 {
336         blockList.activate(name);
337 }
338
339 void Drawing::activateBlock(RS_Block * block)
340 {
341         blockList.activate(block);
342 }
343
344 RS_Block * Drawing::getActiveBlock()
345 {
346         return blockList.getActive();
347 }
348
349 /*virtual*/ bool Drawing::addBlock(RS_Block * block, bool notify/*= true*/)
350 {
351         return blockList.add(block, notify);
352 }
353
354 /*virtual*/ void Drawing::addBlockNotification()
355 {
356         blockList.addNotification();
357 }
358
359 /*virtual*/ void Drawing::removeBlock(RS_Block * block)
360 {
361         blockList.remove(block);
362 }
363
364 RS_Block * Drawing::findBlock(const QString & name)
365 {
366         return blockList.find(name);
367 }
368
369 QString Drawing::newBlockName()
370 {
371         return blockList.newName();
372 }
373
374 void Drawing::toggleBlock(const QString & name)
375 {
376         blockList.toggle(name);
377 }
378
379 void Drawing::toggleBlock(RS_Block * block)
380 {
381         blockList.toggle(block);
382 }
383
384 void Drawing::freezeAllBlocks(bool freeze)
385 {
386         blockList.freezeAll(freeze);
387 }
388
389 #if 0
390 void Drawing::addBlockListListener(RS_BlockListListener * listener)
391 {
392         blockList.addListener(listener);
393 }
394
395 void Drawing::removeBlockListListener(RS_BlockListListener * listener)
396 {
397         blockList.removeListener(listener);
398 }
399 #endif
400
401 // Wrappers for variable functions:
402 void Drawing::clearVariables()
403 {
404         variableDict.clear();
405 }
406
407 int Drawing::countVariables()
408 {
409         return variableDict.count();
410 }
411
412 void Drawing::addVariable(const QString & key, const Vector & value, int code)
413 {
414         variableDict.add(key, value, code);
415 }
416
417 void Drawing::addVariable(const QString & key, const QString & value, int code)
418 {
419         variableDict.add(key, value, code);
420 }
421
422 void Drawing::addVariable(const QString & key, int value, int code)
423 {
424         variableDict.add(key, value, code);
425 }
426
427 void Drawing::addVariable(const QString & key, double value, int code)
428 {
429         variableDict.add(key, value, code);
430 }
431
432 Vector Drawing::getVariableVector(const QString & key, const Vector & def)
433 {
434         return variableDict.getVector(key, def);
435 }
436
437 QString Drawing::getVariableString(const QString & key, const QString & def)
438 {
439         return variableDict.getString(key, def);
440 }
441
442 int Drawing::getVariableInt(const QString & key, int def)
443 {
444         return variableDict.getInt(key, def);
445 }
446
447 double Drawing::getVariableDouble(const QString & key, double def)
448 {
449         return variableDict.getDouble(key, def);
450 }
451
452 void Drawing::removeVariable(const QString & key)
453 {
454         variableDict.remove(key);
455 }
456
457 //Q3Dict<RS_Variable> & getVariableDict()
458 QMultiHash<QString, RS_Variable *> & Drawing::getVariableDict()
459 {
460         return variableDict.getVariableDict();
461 }
462
463 /**
464  * @return true if the grid is switched on (visible).
465  */
466 bool Drawing::isGridOn()
467 {
468         int on = getVariableInt("$GRIDMODE", 1);
469
470         return (on != 0);
471 }
472
473 /**
474  * Enables / disables the grid.
475  */
476 void Drawing::setGridOn(bool on)
477 {
478         addVariable("$GRIDMODE", (int)on, 70);
479 }
480
481 /**
482  * Sets the unit of this graphic to 'u'
483  */
484 void Drawing::setUnit(RS2::Unit u)
485 {
486         setPaperSize(RS_Units::convert(getPaperSize(), getUnit(), u));
487         addVariable("$INSUNITS", (int)u, 70);
488         //unit = u;
489 }
490
491 /**
492  * Gets the unit of this graphic
493  */
494 RS2::Unit Drawing::getUnit()
495 {
496         return (RS2::Unit)getVariableInt("$INSUNITS", 0);
497         //return unit;
498 }
499
500 /**
501  * @return The linear format type for this document.
502  * This is determined by the variable "$LUNITS".
503  */
504 RS2::LinearFormat Drawing::getLinearFormat()
505 {
506         int lunits = getVariableInt("$LUNITS", 2);
507
508         switch (lunits)
509         {
510         default:
511         case 2:
512                 return RS2::Decimal;
513                 break;
514
515         case 1:
516                 return RS2::Scientific;
517                 break;
518
519         case 3:
520                 return RS2::Engineering;
521                 break;
522
523         case 4:
524                 return RS2::Architectural;
525                 break;
526
527         case 5:
528                 return RS2::Fractional;
529                 break;
530         }
531
532         return RS2::Decimal;
533 }
534
535 /**
536  * @return The linear precision for this document.
537  * This is determined by the variable "$LUPREC".
538  */
539 int Drawing::getLinearPrecision()
540 {
541         return getVariableInt("$LUPREC", 4);
542 }
543
544 /**
545  * @return The angle format type for this document.
546  * This is determined by the variable "$AUNITS".
547  */
548 RS2::AngleFormat Drawing::getAngleFormat()
549 {
550         int aunits = getVariableInt("$AUNITS", 0);
551
552         switch (aunits)
553         {
554         default:
555         case 0:
556                 return RS2::DegreesDecimal;
557                 break;
558
559         case 1:
560                 return RS2::DegreesMinutesSeconds;
561                 break;
562
563         case 2:
564                 return RS2::Gradians;
565                 break;
566
567         case 3:
568                 return RS2::Radians;
569                 break;
570
571         case 4:
572                 return RS2::Surveyors;
573                 break;
574         }
575
576         return RS2::DegreesDecimal;
577 }
578
579 /**
580  * @return The linear precision for this document.
581  * This is determined by the variable "$LUPREC".
582  */
583 int Drawing::getAnglePrecision()
584 {
585         return getVariableInt("$AUPREC", 4);
586 }
587
588 /**
589  * @return The insertion point of the drawing into the paper space.
590  * This is the distance from the lower left paper edge to the zero
591  * point of the drawing. DXF: $PINSBASE.
592  */
593 Vector Drawing::getPaperInsertionBase()
594 {
595         return getVariableVector("$PINSBASE", Vector(0.0,0.0));
596 }
597
598 /**
599  * Sets the PINSBASE variable.
600  */
601 void Drawing::setPaperInsertionBase(const Vector & p)
602 {
603         addVariable("$PINSBASE", p, 10);
604 }
605
606 /**
607  * @return Paper size in graphic units.
608  */
609 Vector Drawing::getPaperSize()
610 {
611         Vector def = RS_Units::convert(Vector(210.0, 297.0), RS2::Millimeter, getUnit());
612         Vector v1 = getVariableVector("$PLIMMIN", Vector(0.0, 0.0));
613         Vector v2 = getVariableVector("$PLIMMAX", def);
614
615         return v2 - v1;
616 }
617
618 /**
619  * Sets a new paper size.
620  */
621 void Drawing::setPaperSize(const Vector & s)
622 {
623         addVariable("$PLIMMIN", Vector(0.0, 0.0), 10);
624         addVariable("$PLIMMAX", s, 10);
625 }
626
627 /**
628  * @return Paper format.
629  * This is determined by the variables "$PLIMMIN" and "$PLIMMAX".
630  *
631  * @param landscape will be set to true for landscape and false for portrait if not NULL.
632  */
633 RS2::PaperFormat Drawing::getPaperFormat(bool * landscape)
634 {
635         Vector size = RS_Units::convert(getPaperSize(), getUnit(), RS2::Millimeter);
636
637         if (landscape != NULL)
638                 *landscape = (size.x > size.y);
639
640         return RS_Units::paperSizeToFormat(size);
641 }
642
643 /**
644  * Sets the paper format to the given format.
645  */
646 void Drawing::setPaperFormat(RS2::PaperFormat f, bool landscape)
647 {
648         Vector size = RS_Units::paperFormatToSize(f);
649
650         if (landscape)
651         {
652                 double tmp = size.x;
653                 size.x = size.y;
654                 size.y = tmp;
655         }
656
657         if (f != RS2::Custom)
658                 setPaperSize(RS_Units::convert(size, RS2::Millimeter, getUnit()));
659 }
660
661 /**
662  * @return Paper space scaling (DXF: $PSVPSCALE).
663  */
664 double Drawing::getPaperScale()
665 {
666         double ret;
667
668         ret = getVariableDouble("$PSVPSCALE", 1.0);
669
670         if (ret < 1.0e-6)
671                 ret = 1.0;
672
673         return ret;
674 }
675
676 /**
677  * Sets a new scale factor for the paper space.
678  */
679 void Drawing::setPaperScale(double s)
680 {
681         addVariable("$PSVPSCALE", s, 40);
682 }
683
684 /**
685  * Centers drawing on page. Affects DXF variable $PINSBASE.
686  */
687 void Drawing::centerToPage()
688 {
689         Vector size = getPaperSize();
690         double scale = getPaperScale();
691         Vector pinsbase = (size - getSize() * scale) / 2.0 - getMin() * scale;
692         setPaperInsertionBase(pinsbase);
693 }
694
695 /**
696  * Fits drawing on page. Affects DXF variable $PINSBASE.
697  */
698 void Drawing::fitToPage()
699 {
700         double border = RS_Units::convert(25.0, RS2::Millimeter, getUnit());
701         Vector ps = getPaperSize() - Vector(border, border);
702         Vector s = getSize();
703         double fx = RS_MAXDOUBLE;
704         double fy = RS_MAXDOUBLE;
705         //double factor = 1.0;
706
707         //ps = RS_Units::convert(ps, getUnit(), RS2::Millimeter);
708
709         if (fabs(s.x) > 1.0e-6)
710                 fx = ps.x / s.x;
711
712         if (fabs(s.y) > 1.0e-6)
713                 fy = ps.y / s.y;
714
715         setPaperScale(std::min(fx, fy));
716         centerToPage();
717 }
718
719 /**
720  * @retval true The document has been modified since it was last saved.
721  * @retval false The document has not been modified since it was last saved.
722  */
723 /*virtual*/ bool Drawing::isModified() const
724 {
725         return modified || layerList.isModified() || blockList.isModified();
726 }
727
728 /**
729  * Sets the documents modified status to 'm'.
730  */
731 /*virtual*/ void Drawing::setModified(bool m)
732 {
733         modified = m;
734         layerList.setModified(m);
735         blockList.setModified(m);
736 }
737
738 #ifdef RS_CAM
739 RS_CamData & Drawing::getCamData()
740 {
741         return camData;
742 }
743
744 void Drawing::setCamData(const RS_CamData & d)
745 {
746         camData = d;
747 }
748 #endif
749
750 /**
751  * Dumps the entities to stdout.
752  */
753 std::ostream & operator<<(std::ostream & os, Drawing & g)
754 {
755     os << "--- Drawing: \n";
756     os << "---" << *g.getLayerList() << "\n";
757     os << "---" << *g.getBlockList() << "\n";
758     os << "---" << (RS_Undo &)g << "\n";
759     os << "---" << (RS_EntityContainer &)g << "\n";
760
761     return os;
762 }