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