]> Shamusworld >> Repos - architektonas/blob - src/base/drawing.cpp
Bugfixes related to removing Snapper class.
[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 "debug.h"
23 #include "fileio.h"
24 #include "mathextra.h"
25 #include "units.h"
26 #include "settings.h"
27
28 /**
29  * Default constructor.
30  */
31 Drawing::Drawing(EntityContainer * parent): Document(parent), layerList(),
32         blockList(true)
33 #ifdef RS_CAM
34         , camData()
35 #endif
36 {
37         settings.beginGroup("Defaults");
38         setUnit(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", Units::convert(2.5, RS2::Millimeter, unit), 40);
54                 addVariable("$DIMEXE", Units::convert(1.25, RS2::Millimeter, unit), 40);
55                 addVariable("$DIMEXO", Units::convert(0.625, RS2::Millimeter, unit), 40);
56                 addVariable("$DIMGAP", Units::convert(0.625, RS2::Millimeter, unit), 40);
57                 addVariable("$DIMTXT", 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(Layer * layer)
80 {
81     int c = 0;
82
83     if (layer != NULL)
84         {
85         for(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*/ LayerList * Drawing::getLayerList()
98 {
99         return &layerList;
100 }
101
102 /*virtual*/ 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         DEBUG->print("Drawing::newDoc");
114
115         clear();
116
117         clearLayers();
118         clearBlocks();
119
120         addLayer(new Layer("0"));
121         //addLayer(new 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         DEBUG->print("Drawing::save");
134         DEBUG->print("  file: %s", filename.toLatin1().data());
135         DEBUG->print("  format: %d", (int)formatType);
136         DEBUG->print("  export...");
137         ret = FILEIO->fileExport(*this, filename, formatType);
138
139         if (ret)
140         {
141                 setModified(false);
142                 layerList.setModified(false);
143                 blockList.setModified(false);
144         }
145
146         DEBUG->print("Drawing::save ok");
147
148         return ret;
149 }
150
151 /**
152  * Saves this graphic with the given filename and current settings.
153  */
154 bool Drawing::saveAs(const QString & filename, RS2::FormatType type)
155 {
156         DEBUG->print("Drawing::saveAs");
157
158         this->filename = filename;
159         this->formatType = type;
160
161         return save();
162 }
163
164 /**
165  * Loads the given file into this graphic.
166  */
167 bool Drawing::open(const QString & filename, RS2::FormatType type)
168 {
169         DEBUG->print("Drawing::open(%s)", filename.toLatin1().data());
170         bool ret = false;
171         this->filename = filename;
172         // clean all:
173         newDoc();
174         // import file:
175         ret = FILEIO->fileImport(*this, filename, type);
176         setModified(false);
177         layerList.setModified(false);
178         blockList.setModified(false);
179
180         //cout << *((Drawing*)graphic);
181         //calculateBorders();
182         DEBUG->print("Drawing::open(%s): OK", filename.toLatin1().data());
183
184         return ret;
185 }
186
187 // Wrappers for Layer functions:
188 void Drawing::clearLayers()
189 {
190         layerList.clear();
191 }
192
193 uint Drawing::countLayers() const
194 {
195         return layerList.count();
196 }
197
198 Layer * Drawing::layerAt(uint i)
199 {
200         return layerList.at(i);
201 }
202
203 void Drawing::activateLayer(const QString & name)
204 {
205         layerList.activate(name);
206 }
207
208 void Drawing::activateLayer(Layer * layer)
209 {
210         layerList.activate(layer);
211 }
212
213 Layer * Drawing::getActiveLayer()
214 {
215         return layerList.getActive();
216 }
217
218 /*virtual*/ void Drawing::addLayer(Layer * layer)
219 {
220         layerList.add(layer);
221 }
222
223 /**
224  * Removes the given layer and undoes all entities on it.
225  */
226 /*virtual*/ void Drawing::removeLayer(Layer * layer)
227 {
228         if (layer != NULL && layer->getName() != "0")
229         {
230                 // remove all entities on that layer:
231                 startUndoCycle();
232
233                 for(Entity * e=firstEntity(RS2::ResolveNone); e!=NULL; e=nextEntity(RS2::ResolveNone))
234                 {
235                         if (e->getLayer() && e->getLayer()->getName() == layer->getName())
236                         {
237                                 e->setUndoState(true);
238                                 e->setLayer("0");
239                                 addUndoable(e);
240                         }
241                 }
242
243                 endUndoCycle();
244
245                 // remove all entities in blocks that are on that layer:
246                 for(uint bi=0; bi<blockList.count(); bi++)
247                 {
248                         Block * blk = blockList.at(bi);
249
250                         if (blk)
251                         {
252                                 for(Entity * e=blk->firstEntity(RS2::ResolveNone); e!=NULL; e=blk->nextEntity(RS2::ResolveNone))
253                                 {
254                                         if (e->getLayer() != NULL && e->getLayer()->getName() == layer->getName())
255                                         {
256                                                 e->setUndoState(true);
257                                                 e->setLayer("0");
258                                                 //addUndoable(e);
259                                         }
260                                 }
261                         }
262                 }
263
264                 layerList.remove(layer);
265         }
266 }
267
268 /*virtual*/ void Drawing::editLayer(Layer * layer, const Layer & source)
269 {
270         layerList.edit(layer, source);
271 }
272
273 Layer * Drawing::findLayer(const QString & name)
274 {
275         return layerList.find(name);
276 }
277
278 void Drawing::toggleLayer(const QString & name)
279 {
280         layerList.toggle(name);
281 }
282
283 void Drawing::toggleLayer(Layer * layer)
284 {
285         layerList.toggle(layer);
286 }
287
288 void Drawing::toggleLayerLock(Layer * layer)
289 {
290         layerList.toggleLock(layer);
291 }
292
293 void Drawing::freezeAllLayers(bool freeze)
294 {
295         layerList.freezeAll(freeze);
296 }
297
298 #if 0
299 void Drawing::addLayerListListener(LayerListListener * listener)
300 {
301         layerList.addListener(listener);
302 }
303
304 void Drawing::removeLayerListListener(LayerListListener * listener)
305 {
306         layerList.removeListener(listener);
307 }
308 #endif
309
310 // Wrapper for block functions:
311
312 void Drawing::clearBlocks()
313 {
314         blockList.clear();
315 }
316
317 uint Drawing::countBlocks()
318 {
319         return blockList.count();
320 }
321
322 Block * Drawing::blockAt(uint i)
323 {
324         return blockList.at(i);
325 }
326
327 void Drawing::activateBlock(const QString & name)
328 {
329         blockList.activate(name);
330 }
331
332 void Drawing::activateBlock(Block * block)
333 {
334         blockList.activate(block);
335 }
336
337 Block * Drawing::getActiveBlock()
338 {
339         return blockList.getActive();
340 }
341
342 /*virtual*/ bool Drawing::addBlock(Block * block, bool notify/*= true*/)
343 {
344         return blockList.add(block, notify);
345 }
346
347 /*virtual*/ void Drawing::addBlockNotification()
348 {
349         blockList.addNotification();
350 }
351
352 /*virtual*/ void Drawing::removeBlock(Block * block)
353 {
354         blockList.remove(block);
355 }
356
357 Block * Drawing::findBlock(const QString & name)
358 {
359         return blockList.find(name);
360 }
361
362 QString Drawing::newBlockName()
363 {
364         return blockList.newName();
365 }
366
367 void Drawing::toggleBlock(const QString & name)
368 {
369         blockList.toggle(name);
370 }
371
372 void Drawing::toggleBlock(Block * block)
373 {
374         blockList.toggle(block);
375 }
376
377 void Drawing::freezeAllBlocks(bool freeze)
378 {
379         blockList.freezeAll(freeze);
380 }
381
382 #if 0
383 void Drawing::addBlockListListener(BlockListListener * listener)
384 {
385         blockList.addListener(listener);
386 }
387
388 void Drawing::removeBlockListListener(BlockListListener * listener)
389 {
390         blockList.removeListener(listener);
391 }
392 #endif
393
394 // Wrappers for variable functions:
395 void Drawing::clearVariables()
396 {
397         variableDict.clear();
398 }
399
400 int Drawing::countVariables()
401 {
402         return variableDict.count();
403 }
404
405 void Drawing::addVariable(const QString & key, const Vector & value, int code)
406 {
407         variableDict.add(key, value, code);
408 }
409
410 void Drawing::addVariable(const QString & key, const QString & value, int code)
411 {
412         variableDict.add(key, value, code);
413 }
414
415 void Drawing::addVariable(const QString & key, int value, int code)
416 {
417         variableDict.add(key, value, code);
418 }
419
420 void Drawing::addVariable(const QString & key, double value, int code)
421 {
422         variableDict.add(key, value, code);
423 }
424
425 Vector Drawing::getVariableVector(const QString & key, const Vector & def)
426 {
427         return variableDict.getVector(key, def);
428 }
429
430 QString Drawing::getVariableString(const QString & key, const QString & def)
431 {
432         return variableDict.getString(key, def);
433 }
434
435 int Drawing::getVariableInt(const QString & key, int def)
436 {
437         return variableDict.getInt(key, def);
438 }
439
440 double Drawing::getVariableDouble(const QString & key, double def)
441 {
442         return variableDict.getDouble(key, def);
443 }
444
445 void Drawing::removeVariable(const QString & key)
446 {
447         variableDict.remove(key);
448 }
449
450 //Q3Dict<Variable> & getVariableDict()
451 QMultiHash<QString, Variable *> & Drawing::getVariableDict()
452 {
453         return variableDict.getVariableDict();
454 }
455
456 /**
457  * @return true if the grid is switched on (visible).
458  */
459 bool Drawing::isGridOn()
460 {
461         int on = getVariableInt("$GRIDMODE", 1);
462
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(Units::convert(getPaperSize(), getUnit(), u));
480         addVariable("$INSUNITS", (int)u, 70);
481         //unit = u;
482 }
483
484 /**
485  * Gets the unit of this graphic
486  */
487 RS2::Unit Drawing::getUnit()
488 {
489         return (RS2::Unit)getVariableInt("$INSUNITS", 0);
490         //return unit;
491 }
492
493 /**
494  * @return The linear format type for this document.
495  * This is determined by the variable "$LUNITS".
496  */
497 RS2::LinearFormat Drawing::getLinearFormat()
498 {
499         int lunits = getVariableInt("$LUNITS", 2);
500
501         switch (lunits)
502         {
503         default:
504         case 2:
505                 return RS2::Decimal;
506                 break;
507
508         case 1:
509                 return RS2::Scientific;
510                 break;
511
512         case 3:
513                 return RS2::Engineering;
514                 break;
515
516         case 4:
517                 return RS2::Architectural;
518                 break;
519
520         case 5:
521                 return RS2::Fractional;
522                 break;
523         }
524
525         return RS2::Decimal;
526 }
527
528 /**
529  * @return The linear precision for this document.
530  * This is determined by the variable "$LUPREC".
531  */
532 int Drawing::getLinearPrecision()
533 {
534         return getVariableInt("$LUPREC", 4);
535 }
536
537 /**
538  * @return The angle format type for this document.
539  * This is determined by the variable "$AUNITS".
540  */
541 RS2::AngleFormat Drawing::getAngleFormat()
542 {
543         int aunits = getVariableInt("$AUNITS", 0);
544
545         switch (aunits)
546         {
547         default:
548         case 0:
549                 return RS2::DegreesDecimal;
550                 break;
551
552         case 1:
553                 return RS2::DegreesMinutesSeconds;
554                 break;
555
556         case 2:
557                 return RS2::Gradians;
558                 break;
559
560         case 3:
561                 return RS2::Radians;
562                 break;
563
564         case 4:
565                 return RS2::Surveyors;
566                 break;
567         }
568
569         return RS2::DegreesDecimal;
570 }
571
572 /**
573  * @return The linear precision for this document.
574  * This is determined by the variable "$LUPREC".
575  */
576 int Drawing::getAnglePrecision()
577 {
578         return getVariableInt("$AUPREC", 4);
579 }
580
581 /**
582  * @return The insertion point of the drawing into the paper space.
583  * This is the distance from the lower left paper edge to the zero
584  * point of the drawing. DXF: $PINSBASE.
585  */
586 Vector Drawing::getPaperInsertionBase()
587 {
588         return getVariableVector("$PINSBASE", Vector(0.0,0.0));
589 }
590
591 /**
592  * Sets the PINSBASE variable.
593  */
594 void Drawing::setPaperInsertionBase(const Vector & p)
595 {
596         addVariable("$PINSBASE", p, 10);
597 }
598
599 /**
600  * @return Paper size in graphic units.
601  */
602 Vector Drawing::getPaperSize()
603 {
604         Vector def = Units::convert(Vector(210.0, 297.0), RS2::Millimeter, getUnit());
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 Drawing::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 Drawing::getPaperFormat(bool * landscape)
627 {
628         Vector size = Units::convert(getPaperSize(), getUnit(), RS2::Millimeter);
629
630         if (landscape != NULL)
631                 *landscape = (size.x > size.y);
632
633         return Units::paperSizeToFormat(size);
634 }
635
636 /**
637  * Sets the paper format to the given format.
638  */
639 void Drawing::setPaperFormat(RS2::PaperFormat f, bool landscape)
640 {
641         Vector size = 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(Units::convert(size, RS2::Millimeter, getUnit()));
652 }
653
654 /**
655  * @return Paper space scaling (DXF: $PSVPSCALE).
656  */
657 double Drawing::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 Drawing::setPaperScale(double s)
673 {
674         addVariable("$PSVPSCALE", s, 40);
675 }
676
677 /**
678  * Centers drawing on page. Affects DXF variable $PINSBASE.
679  */
680 void Drawing::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 Drawing::fitToPage()
692 {
693         double border = 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 = 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 Drawing::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 Drawing::setModified(bool m)
725 {
726         modified = m;
727         layerList.setModified(m);
728         blockList.setModified(m);
729 }
730
731 #ifdef RS_CAM
732 RS_CamData & Drawing::getCamData()
733 {
734         return camData;
735 }
736
737 void Drawing::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, Drawing & g)
747 {
748     os << "--- Drawing: \n";
749     os << "---" << *g.getLayerList() << "\n";
750     os << "---" << *g.getBlockList() << "\n";
751     os << "---" << (Undo &)g << "\n";
752     os << "---" << (EntityContainer &)g << "\n";
753
754     return os;
755 }