]> Shamusworld >> Repos - architektonas/blob - src/base/dimangular.cpp
Bugfixes related to removing Snapper class.
[architektonas] / src / base / dimangular.cpp
1 // dimangular.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/28/2010  Added this text. :-)
15 //
16
17 #include "dimangular.h"
18
19 #include "constructionline.h"
20 #include "filterdxf.h"
21 #include "drawing.h"
22 #include "information.h"
23 #include "solid.h"
24 #include "text.h"
25 #include "units.h"
26
27 /**
28  * Constructor.
29  *
30  * @para parent Parent Entity Container.
31  * @para d Common dimension geometrical data.
32  * @para ed Extended geometrical data for angular dimension.
33  */
34 DimAngular::DimAngular(EntityContainer * parent, const DimensionData & d,
35         const DimAngularData & ed): Dimension(parent, d), edata(ed)
36 {
37         calculateBorders();
38 }
39
40 /*virtual*/ DimAngular::~DimAngular()
41 {
42 }
43
44 /*virtual*/ Entity * DimAngular::clone()
45 {
46         DimAngular * d = new DimAngular(*this);
47 #warning "!!! Need to deal with setAutoDelete() Qt3->Qt4 !!!"
48 //      d->entities.setAutoDelete(entities.autoDelete());
49         d->initId();
50         d->detach();
51         return d;
52 }
53
54 /**     @return RS2::EntityDimAngular */
55 /*virtual*/ RS2::EntityType DimAngular::rtti() const
56 {
57         return RS2::EntityDimAngular;
58 }
59
60 /**
61  * @return Copy of data that defines the angular dimension.
62  * @see getData()
63  */
64 DimAngularData DimAngular::getEData() const
65 {
66         return edata;
67 }
68
69 /**
70  * @return Automatically created label for the default
71  * measurement of this dimension.
72  */
73 QString DimAngular::getMeasuredLabel()
74 {
75     QString ret;
76
77         int dimaunit = getGraphicVariableInt("$DIMAUNIT", 0);
78         int dimadec = getGraphicVariableInt("$DIMADEC", 0);
79
80         ret = Units::formatAngle(getAngle(),
81                 FilterDXF::numberToAngleFormat(dimaunit),
82                 dimadec);
83
84     /*
85         ret = QString("%1%2")
86           .arg(Math::rad2deg(getAngle()))
87           .arg(RS_Char(0xB0));
88         */
89     return ret;
90 }
91
92
93
94 /**
95  * @return Angle of the measured dimension.
96  */
97 double DimAngular::getAngle() {
98     double ang1 = 0.0;
99     double ang2 = 0.0;
100     bool reversed = false;
101         Vector p1;
102         Vector p2;
103
104     getAngles(ang1, ang2, reversed, p1, p2);
105
106     if (!reversed) {
107         if (ang2<ang1) {
108             ang2+=2*M_PI;
109         }
110         return ang2-ang1;
111     } else {
112         if (ang1<ang2) {
113             ang1+=2*M_PI;
114         }
115         return ang1-ang2;
116     }
117 }
118
119
120
121 /**
122  * @return Center of the measured dimension.
123  */
124 Vector DimAngular::getCenter() {
125     ConstructionLine l1(NULL, ConstructionLineData(edata.definitionPoint1,
126                            edata.definitionPoint2));
127     ConstructionLine l2(NULL, ConstructionLineData(edata.definitionPoint3,
128                            data.definitionPoint));
129     VectorSolutions vs = Information::getIntersection(&l1, &l2, false);
130
131     return vs.get(0);
132 }
133
134
135
136 /**
137  * finds out which angles this dimension actually measures.
138  *
139  * @param ang1 Reference will return the start angle
140  * @param ang2 Reference will return the end angle
141  * @param reversed Reference will return the reversed flag.
142  *
143  * @return true: on success
144  */
145 bool DimAngular::getAngles(double& ang1, double& ang2, bool& reversed,
146                               Vector& p1, Vector& p2) {
147
148     Vector center = getCenter();
149     double ang = center.angleTo(edata.definitionPoint4);
150     bool done = false;
151
152     // find out the angles this dimension refers to:
153     for (int f1=0; f1<=1 && !done; ++f1) {
154         ang1 = Math::correctAngle(
155                    edata.definitionPoint1.angleTo(edata.definitionPoint2) + f1*M_PI);
156         if (f1==0) {
157             p1 = edata.definitionPoint2;
158         } else {
159             p1 = edata.definitionPoint1;
160         }
161         for (int f2=0; f2<=1 && !done; ++f2) {
162             ang2 = Math::correctAngle(
163                        edata.definitionPoint3.angleTo(data.definitionPoint) + f2*M_PI);
164             if (f2==0) {
165                 p2 = data.definitionPoint;
166             } else {
167                 p2 = edata.definitionPoint3;
168             }
169             for (int t=0; t<=1 && !done; ++t) {
170                 reversed = (bool)t;
171
172                 double angDiff;
173
174                 if (!reversed) {
175                     if (ang2<ang1) {
176                         ang2+=2*M_PI;
177                     }
178                     angDiff = ang2-ang1;
179                 } else {
180                     if (ang1<ang2) {
181                         ang1+=2*M_PI;
182                     }
183                     angDiff = ang1-ang2;
184                 }
185
186                 ang1 = Math::correctAngle(ang1);
187                 ang2 = Math::correctAngle(ang2);
188
189                 if (Math::isAngleBetween(ang, ang1, ang2, reversed) &&
190                         angDiff<=M_PI) {
191                     done = true;
192                     break;
193                 }
194             }
195         }
196     }
197
198     return done;
199 }
200
201
202
203 /**
204  * Updates the sub entities of this dimension. Called when the
205  * dimension or the position, alignment, .. changes.
206  *
207  * @param autoText Automatically reposition the text label
208  */
209 void DimAngular::update(bool /*autoText*/) {
210
211     DEBUG->print("DimAngular::update");
212
213     clear();
214
215         if (isUndone()) {
216                 return;
217         }
218
219     // distance from entities (DIMEXO)
220     double dimexo = getExtensionLineOffset();
221     // extension line extension (DIMEXE)
222     double dimexe = getExtensionLineExtension();
223     // text height (DIMTXT)
224     double dimtxt = getTextHeight();
225     // text distance to line (DIMGAP)
226     double dimgap = getDimensionLineGap();
227
228     // find out center:
229     Vector center = getCenter();
230
231     if (!center.valid) {
232         return;
233     }
234
235     double ang1 = 0.0;
236     double ang2 = 0.0;
237     bool reversed = false;
238     Vector p1;
239     Vector p2;
240
241     getAngles(ang1, ang2, reversed, p1, p2);
242
243     double rad = edata.definitionPoint4.distanceTo(center);
244
245     Line* line;
246     Vector dir;
247     double len;
248     double dist;
249
250     // 1st extension line:
251     dist = center.distanceTo(p1);
252     len = rad - dist + dimexe;
253     dir.setPolar(1.0, ang1);
254     line = new Line(this,
255                        LineData(center + dir*dist + dir*dimexo,
256                                    center + dir*dist + dir*len));
257     line->setPen(Pen(RS2::FlagInvalid));
258     line->setLayer(NULL);
259     addEntity(line);
260
261     // 2nd extension line:
262     dist = center.distanceTo(p2);
263     len = rad - dist + dimexe;
264     dir.setPolar(1.0, ang2);
265     line = new Line(this,
266                        LineData(center + dir*dist + dir*dimexo,
267                                    center + dir*dist + dir*len));
268     line->setPen(Pen(RS2::FlagInvalid));
269     line->setLayer(NULL);
270     addEntity(line);
271
272     // Create dimension line (arc):
273     Arc* arc = new Arc(this,
274                              ArcData(center,
275                                         rad, ang1, ang2, reversed));
276     arc->setPen(Pen(RS2::FlagInvalid));
277     arc->setLayer(NULL);
278     addEntity(arc);
279
280     // length of dimension arc:
281     double distance = arc->getLength();
282
283     // do we have to put the arrows outside of the arc?
284     bool outsideArrows = (distance<getArrowSize()*2);
285
286     // arrow angles:
287     double arrowAngle1, arrowAngle2;
288     double arrowAng;
289         if (rad>1.0e-6) {
290                 arrowAng = getArrowSize() / rad;
291         }
292         else {
293                 arrowAng = 0.0;
294         }
295     Vector v1, v2;
296     if (!arc->isReversed()) {
297         v1.setPolar(rad, arc->getAngle1()+arrowAng);
298     } else {
299         v1.setPolar(rad, arc->getAngle1()-arrowAng);
300     }
301     v1+=arc->getCenter();
302     arrowAngle1 = arc->getStartpoint().angleTo(v1);
303
304
305     if (!arc->isReversed()) {
306         v2.setPolar(rad, arc->getAngle2()-arrowAng);
307     } else {
308         v2.setPolar(rad, arc->getAngle2()+arrowAng);
309     }
310     v2+=arc->getCenter();
311     arrowAngle2 = arc->getEndpoint().angleTo(v2);
312
313     if (!outsideArrows) {
314         arrowAngle1 = arrowAngle1+M_PI;
315         arrowAngle2 = arrowAngle2+M_PI;
316     }
317
318     // Arrows:
319     SolidData sd;
320     Solid* arrow;
321
322     // arrow 1
323     arrow = new Solid(this, sd);
324     arrow->shapeArrow(arc->getStartpoint(),
325                       arrowAngle1,
326                       getArrowSize());
327     arrow->setPen(Pen(RS2::FlagInvalid));
328     arrow->setLayer(NULL);
329     addEntity(arrow);
330
331     // arrow 2:
332     arrow = new Solid(this, sd);
333     arrow->shapeArrow(arc->getEndpoint(),
334                       arrowAngle2,
335                       getArrowSize());
336     arrow->setPen(Pen(RS2::FlagInvalid));
337     arrow->setLayer(NULL);
338     addEntity(arrow);
339
340
341     // text label:
342     TextData textData;
343     Vector textPos = arc->getMiddlepoint();
344
345     Vector distV;
346     double textAngle;
347     double dimAngle1 = textPos.angleTo(arc->getCenter())-M_PI/2.0;
348
349     // rotate text so it's readable from the bottom or right (ISO)
350     // quadrant 1 & 4
351     if (dimAngle1>M_PI/2.0*3.0+0.001 ||
352             dimAngle1<M_PI/2.0+0.001) {
353
354         distV.setPolar(dimgap, dimAngle1+M_PI/2.0);
355         textAngle = dimAngle1;
356     }
357     // quadrant 2 & 3
358     else {
359         distV.setPolar(dimgap, dimAngle1-M_PI/2.0);
360         textAngle = dimAngle1+M_PI;
361     }
362
363     // move text away from dimension line:
364     textPos+=distV;
365
366     textData = TextData(textPos,
367                            dimtxt, 30.0,
368                            RS2::VAlignBottom,
369                            RS2::HAlignCenter,
370                            RS2::LeftToRight,
371                            RS2::Exact,
372                            1.0,
373                            getLabel(),
374                            "standard",
375                            textAngle);
376
377     Text* text = new Text(this, textData);
378
379     // move text to the side:
380     text->setPen(Pen(RS2::FlagInvalid));
381     text->setLayer(NULL);
382     addEntity(text);
383
384     calculateBorders();
385 }
386
387 Vector DimAngular::getDefinitionPoint1()
388 {
389         return edata.definitionPoint1;
390 }
391
392 Vector DimAngular::getDefinitionPoint2()
393 {
394         return edata.definitionPoint2;
395 }
396
397 Vector DimAngular::getDefinitionPoint3()
398 {
399         return edata.definitionPoint3;
400 }
401
402 Vector DimAngular::getDefinitionPoint4()
403 {
404         return edata.definitionPoint4;
405 }
406
407 void DimAngular::move(Vector offset)
408 {
409     Dimension::move(offset);
410
411     edata.definitionPoint1.move(offset);
412     edata.definitionPoint2.move(offset);
413     edata.definitionPoint3.move(offset);
414     edata.definitionPoint4.move(offset);
415     update();
416 }
417
418
419
420 void DimAngular::rotate(Vector center, double angle) {
421     Dimension::rotate(center, angle);
422
423     edata.definitionPoint1.rotate(center, angle);
424     edata.definitionPoint2.rotate(center, angle);
425     edata.definitionPoint3.rotate(center, angle);
426     edata.definitionPoint4.rotate(center, angle);
427     update();
428 }
429
430
431
432 void DimAngular::scale(Vector center, Vector factor) {
433     Dimension::scale(center, factor);
434
435     edata.definitionPoint1.scale(center, factor);
436     edata.definitionPoint2.scale(center, factor);
437     edata.definitionPoint3.scale(center, factor);
438     edata.definitionPoint4.scale(center, factor);
439     update();
440 }
441
442
443
444 void DimAngular::mirror(Vector axisPoint1, Vector axisPoint2) {
445     Dimension::mirror(axisPoint1, axisPoint2);
446
447     edata.definitionPoint1.mirror(axisPoint1, axisPoint2);
448     edata.definitionPoint2.mirror(axisPoint1, axisPoint2);
449     edata.definitionPoint3.mirror(axisPoint1, axisPoint2);
450     edata.definitionPoint4.mirror(axisPoint1, axisPoint2);
451     update();
452 }
453
454 /**
455  * Dumps the point's data to stdout.
456  */
457 std::ostream& operator << (std::ostream& os, const DimAngular& d) {
458     os << " DimAngular: " << d.getData() << "\n" << d.getEData() << "\n";
459     return os;
460 }
461