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