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