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