]> Shamusworld >> Repos - architektonas/blob - src/base/rs_dimension.cpp
Initial import
[architektonas] / src / base / rs_dimension.cpp
1 // rs_dimension.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_dimension.h"
16
17 #include "rs_solid.h"
18 #include "rs_text.h"
19 #include "rs_units.h"
20
21 /**
22  * Constructor.
23  */
24 RS_Dimension::RS_Dimension(RS_EntityContainer * parent, const RS_DimensionData & d):
25         RS_EntityContainer(parent), data(d)
26 {
27 }
28
29 /*virtual*/ RS_Dimension::~RS_Dimension()
30 {
31 }
32
33 /** @return Copy of data that defines the dimension. */
34 RS_DimensionData RS_Dimension::getData() const
35 {
36         return data;
37 }
38
39 Vector RS_Dimension::getNearestRef(const Vector & coord, double * dist)
40 {
41     return RS_Entity::getNearestRef(coord, dist);
42 }
43
44 Vector RS_Dimension::getNearestSelectedRef(const Vector & coord, double * dist)
45 {
46     return RS_Entity::getNearestSelectedRef(coord, dist);
47 }
48
49 /**
50  * @return Dimension text. Either a text the user defined or
51  *         the measured text.
52  *
53  * @param resolve false: return plain value. true: return measured
54  *      label if appropriate.
55  * @see getMeasuredLabel
56  */
57 QString RS_Dimension::getLabel(bool resolve)
58 {
59         if (!resolve) {
60                 return data.text;
61         }
62
63     QString ret="";
64
65     // One space suppresses the text:
66     if (data.text==" ") {
67         ret = "";
68     }
69
70     // No text prints actual measurement:
71     else if (data.text=="") {
72         ret = getMeasuredLabel();
73     }
74
75     // Others print the text (<> is replaced by the measurement)
76     else {
77         ret = data.text;
78         ret = ret.replace(QString("<>"), getMeasuredLabel());
79     }
80
81     return ret;
82 }
83
84 /**
85  * Sets a new text for the label.
86  */
87 void RS_Dimension::setLabel(const QString & l)
88 {
89         data.text = l;
90 }
91
92 /**
93  * Creates a dimensioning line (line with one, two or no arrows and a text).
94  *
95  * @param forceAutoText Automatically reposition the text label.
96  */
97 void RS_Dimension::updateCreateDimensionLine(const Vector& p1,
98         const Vector& p2, bool arrow1, bool arrow2, bool forceAutoText)
99 {
100     // text height (DIMTXT)
101     double dimtxt = getTextHeight();
102     // text distance to line (DIMGAP)
103     double dimgap = getDimensionLineGap();
104
105     // length of dimension line:
106     double distance = p1.distanceTo(p2);
107
108     // do we have to put the arrows outside of the line?
109     bool outsideArrows = (distance<getArrowSize()*2.5);
110
111     // arrow angles:
112     double arrowAngle1, arrowAngle2;
113
114     // Create dimension line:
115     RS_Line* dimensionLine = new RS_Line(this, RS_LineData(p1, p2));
116     dimensionLine->setPen(RS_Pen(RS2::FlagInvalid));
117     dimensionLine->setLayer(NULL);
118     addEntity(dimensionLine);
119
120     if (outsideArrows==false) {
121         arrowAngle1 = dimensionLine->getAngle2();
122         arrowAngle2 = dimensionLine->getAngle1();
123     } else {
124         arrowAngle1 = dimensionLine->getAngle1();
125         arrowAngle2 = dimensionLine->getAngle2();
126
127         // extend dimension line outside arrows
128         Vector dir;
129         dir.setPolar(getArrowSize()*2, arrowAngle2);
130         dimensionLine->setStartpoint(p1 + dir);
131         dimensionLine->setEndpoint(p2 - dir);
132     }
133
134     // Arrows:
135     RS_SolidData sd;
136     RS_Solid* arrow;
137
138     if (arrow1) {
139         // arrow 1
140         arrow = new RS_Solid(this, sd);
141         arrow->shapeArrow(p1,
142                           arrowAngle1,
143                           getArrowSize());
144         arrow->setPen(RS_Pen(RS2::FlagInvalid));
145         arrow->setLayer(NULL);
146         addEntity(arrow);
147     }
148
149     if (arrow2) {
150         // arrow 2:
151         arrow = new RS_Solid(this, sd);
152         arrow->shapeArrow(p2,
153                           arrowAngle2,
154                           getArrowSize());
155         arrow->setPen(RS_Pen(RS2::FlagInvalid));
156         arrow->setLayer(NULL);
157         addEntity(arrow);
158     }
159
160     // Text label:
161     RS_TextData textData;
162     Vector textPos;
163
164         double dimAngle1 = dimensionLine->getAngle1();
165         double textAngle;
166         bool corrected=false;
167         textAngle = RS_Math::makeAngleReadable(dimAngle1, true, &corrected);
168
169     if (data.middleOfText.valid && !forceAutoText) {
170         textPos = data.middleOfText;
171     } else {
172         textPos = dimensionLine->getMiddlepoint();
173
174         Vector distV;
175
176         // rotate text so it's readable from the bottom or right (ISO)
177         // quadrant 1 & 4
178         if (corrected) {
179             distV.setPolar(dimgap + dimtxt/2.0, dimAngle1-M_PI/2.0);
180         } else {
181             distV.setPolar(dimgap + dimtxt/2.0, dimAngle1+M_PI/2.0);
182         }
183
184         // move text away from dimension line:
185         textPos+=distV;
186         //// the next update should still be able to adjust this
187         ////   auto text position. leave it invalid
188                 data.middleOfText = textPos;
189     }
190
191     textData = RS_TextData(textPos,
192                            dimtxt, 30.0,
193                            RS2::VAlignMiddle,
194                            RS2::HAlignCenter,
195                            RS2::LeftToRight,
196                            RS2::Exact,
197                            1.0,
198                            getLabel(),
199                            "standard",
200                            textAngle);
201
202     RS_Text* text = new RS_Text(this, textData);
203
204     // move text to the side:
205     Vector distH;
206     if (text->getUsedTextWidth()>distance) {
207         distH.setPolar(text->getUsedTextWidth()/2.0
208                        +distance/2.0+dimgap, textAngle);
209         text->move(distH);
210     }
211     text->setPen(RS_Pen(RS2::FlagInvalid));
212     text->setLayer(NULL);
213     addEntity(text);
214 }
215
216 Vector RS_Dimension::getDefinitionPoint()
217 {
218         return data.definitionPoint;
219 }
220
221 Vector RS_Dimension::getMiddleOfText()
222 {
223         return data.middleOfText;
224 }
225
226 RS2::VAlign RS_Dimension::getVAlign()
227 {
228         return data.valign;
229 }
230
231 RS2::HAlign RS_Dimension::getHAlign()
232 {
233         return data.halign;
234 }
235
236 RS2::TextLineSpacingStyle RS_Dimension::getLineSpacingStyle()
237 {
238         return data.lineSpacingStyle;
239 }
240
241 double RS_Dimension::getLineSpacingFactor()
242 {
243         return data.lineSpacingFactor;
244 }
245
246 QString RS_Dimension::getText()
247 {
248         return data.text;
249 }
250
251 QString RS_Dimension::getStyle()
252 {
253         return data.style;
254 }
255
256 double RS_Dimension::getAngle()
257 {
258         return data.angle;
259 }
260
261 /**
262  * @return arrow size in drawing units.
263  */
264 double RS_Dimension::getArrowSize()
265 {
266         return getGraphicVariable("$DIMASZ", 2.5, 40);
267 }
268
269 /**
270  * @return extension line overlength in drawing units.
271  */
272 double RS_Dimension::getExtensionLineExtension()
273 {
274         return getGraphicVariable("$DIMEXE", 1.25, 40);
275 }
276
277 /**
278  * @return extension line offset from entities in drawing units.
279  */
280 double RS_Dimension::getExtensionLineOffset()
281 {
282         return getGraphicVariable("$DIMEXO", 0.625, 40);
283 }
284
285 /**
286  * @return extension line gap to text in drawing units.
287  */
288 double RS_Dimension::getDimensionLineGap()
289 {
290         return getGraphicVariable("$DIMGAP", 0.625, 40);
291 }
292
293 /**
294  * @return Dimension lables text height.
295  */
296 double RS_Dimension::getTextHeight()
297 {
298         return getGraphicVariable("$DIMTXT", 2.5, 40);
299 }
300
301 /**
302  * @return the given graphic variable or the default value given in mm
303  * converted to the graphic unit.
304  * If the variable is not found it is added with the given default
305  * value converted to the local unit.
306  */
307 double RS_Dimension::getGraphicVariable(const QString & key, double defMM, int code)
308 {
309         double v = getGraphicVariableDouble(key, RS_MINDOUBLE);
310
311         if (v <= RS_MINDOUBLE)
312         {
313                 addGraphicVariable(key, RS_Units::convert(defMM, RS2::Millimeter, getGraphicUnit()),
314                         code);
315                 v = getGraphicVariableDouble(key, 1.0);
316         }
317
318         return v;
319 }
320
321 /*virtual*/ double RS_Dimension::getLength()
322 {
323         return -1.0;
324 }
325
326 void RS_Dimension::move(Vector offset)
327 {
328         data.definitionPoint.move(offset);
329         data.middleOfText.move(offset);
330 }
331
332 void RS_Dimension::rotate(Vector center, double angle)
333 {
334         data.definitionPoint.rotate(center, angle);
335         data.middleOfText.rotate(center, angle);
336         data.angle = RS_Math::correctAngle(data.angle+angle);
337 }
338
339 void RS_Dimension::scale(Vector center, Vector factor)
340 {
341         data.definitionPoint.scale(center, factor);
342         data.middleOfText.scale(center, factor);
343 }
344
345 void RS_Dimension::mirror(Vector axisPoint1, Vector axisPoint2)
346 {
347         data.definitionPoint.mirror(axisPoint1, axisPoint2);
348         data.middleOfText.mirror(axisPoint1, axisPoint2);
349 }