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