~librecad-dev/librecad/librecad

« back to all changes in this revision

Viewing changes to librecad/src/lib/engine/rs_dimangular.cpp

  • Committer: Scott Howard
  • Date: 2014-02-21 19:07:55 UTC
  • Revision ID: showard@debian.org-20140221190755-csjax9wb146hgdq4
first commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** This file is part of the LibreCAD project, a 2D CAD program
 
4
**
 
5
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
 
6
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
 
7
**
 
8
**
 
9
** This file may be distributed and/or modified under the terms of the
 
10
** GNU General Public License version 2 as published by the Free Software
 
11
** Foundation and appearing in the file gpl-2.0.txt included in the
 
12
** packaging of this file.
 
13
**
 
14
** This program is distributed in the hope that it will be useful,
 
15
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
** GNU General Public License for more details.
 
18
**
 
19
** You should have received a copy of the GNU General Public License
 
20
** along with this program; if not, write to the Free Software
 
21
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 
22
**
 
23
** This copyright notice MUST APPEAR in all copies of the script!
 
24
**
 
25
**********************************************************************/
 
26
 
 
27
 
 
28
#include "rs_dimangular.h"
 
29
 
 
30
#include "rs_constructionline.h"
 
31
#include "rs_graphic.h"
 
32
#include "rs_information.h"
 
33
#include "rs_solid.h"
 
34
#include "rs_mtext.h"
 
35
 
 
36
 
 
37
/**
 
38
 * Constructor.
 
39
 *
 
40
 * @para parent Parent Entity Container.
 
41
 * @para d Common dimension geometrical data.
 
42
 * @para ed Extended geometrical data for angular dimension.
 
43
 */
 
44
RS_DimAngular::RS_DimAngular(RS_EntityContainer* parent,
 
45
                             const RS_DimensionData& d,
 
46
                             const RS_DimAngularData& ed)
 
47
        : RS_Dimension(parent, d), edata(ed) {
 
48
 
 
49
    calculateBorders();
 
50
}
 
51
 
 
52
 
 
53
 
 
54
/**
 
55
 * @return Automatically created label for the default
 
56
 * measurement of this dimension.
 
57
 */
 
58
QString RS_DimAngular::getMeasuredLabel() {
 
59
    QString ret;
 
60
 
 
61
        int dimaunit = getGraphicVariableInt("$DIMAUNIT", 0);
 
62
        int dimadec = getGraphicVariableInt("$DIMADEC", 0);
 
63
 
 
64
        ret = RS_Units::formatAngle(getAngle(),
 
65
                RS_Units::numberToAngleFormat(dimaunit),
 
66
                dimadec);
 
67
 
 
68
    /*
 
69
        ret = QString("%1%2")
 
70
          .arg(RS_Math::rad2deg(getAngle()))
 
71
          .arg(QChar(0xB0));
 
72
        */
 
73
    return ret;
 
74
}
 
75
 
 
76
 
 
77
 
 
78
/**
 
79
 * @return Angle of the measured dimension.
 
80
 */
 
81
double RS_DimAngular::getAngle() {
 
82
    double ang1 = 0.0;
 
83
    double ang2 = 0.0;
 
84
    bool reversed = false;
 
85
        RS_Vector p1;
 
86
        RS_Vector p2;
 
87
 
 
88
    getAngles(ang1, ang2, reversed, p1, p2);
 
89
    return reversed ? RS_Math::correctAngle(ang1 - ang2) :  RS_Math::correctAngle(ang2 - ang1);
 
90
//
 
91
//    if (!reversed) {
 
92
//        if (ang2<ang1) {
 
93
//            ang2+=2*M_PI;
 
94
//        }
 
95
//        return ang2-ang1;
 
96
//    } else {
 
97
//        if (ang1<ang2) {
 
98
//            ang1+=2*M_PI;
 
99
//        }
 
100
//        return ang1-ang2;
 
101
//    }
 
102
}
 
103
 
 
104
 
 
105
 
 
106
/**
 
107
 * @return Center of the measured dimension.
 
108
 */
 
109
RS_Vector RS_DimAngular::getCenter() const {
 
110
    RS_ConstructionLine l1(NULL, RS_ConstructionLineData(edata.definitionPoint1,
 
111
                           edata.definitionPoint2));
 
112
    RS_ConstructionLine l2(NULL, RS_ConstructionLineData(edata.definitionPoint3,
 
113
                           data.definitionPoint));
 
114
    RS_VectorSolutions vs = RS_Information::getIntersection(&l1, &l2, false);
 
115
 
 
116
    return vs.get(0);
 
117
}
 
118
 
 
119
 
 
120
 
 
121
/**
 
122
 * finds out which angles this dimension actually measures.
 
123
 *
 
124
 * @param ang1 Reference will return the start angle
 
125
 * @param ang2 Reference will return the end angle
 
126
 * @param reversed Reference will return the reversed flag.
 
127
 *
 
128
 * @return true: on success
 
129
 */
 
130
bool RS_DimAngular::getAngles(double& ang1, double& ang2, bool& reversed,
 
131
                              RS_Vector& p1, RS_Vector& p2) {
 
132
 
 
133
RS_Vector vp0(edata.definitionPoint4 - getCenter());
 
134
RS_Vector vp1(edata.definitionPoint2 - edata.definitionPoint1);
 
135
RS_Vector vp2(data.definitionPoint - edata.definitionPoint3);
 
136
// project p0 to the basis of p1 and p2
 
137
// p0 = a1 p1 + a2 p2
 
138
// <p0.p1>= a1 |p1|^2 + a2 <p1.p2>
 
139
// <p0,p2>= a1 <p1.p2> + a2 |p2|^2
 
140
// a1 = ( |p2|^2 <p0.p1> - <p1.p2><p0.p2>) /( |p1|^2 |p2|^2 - <p1.p2>^2)
 
141
// a2 = ( |p1|^2 <p0.p2> - <p1.p2><p0.p1>) /( |p1|^2 |p2|^2 - <p1.p2>^2)
 
142
 
 
143
double rp1=vp1.squared();
 
144
double rp2=vp2.squared();
 
145
double p0p1=RS_Vector::dotP(vp0,vp1);
 
146
double p0p2=RS_Vector::dotP(vp0,vp2);
 
147
double p1p2=RS_Vector::dotP(vp1,vp2);
 
148
double d= rp1*rp2 - p1p2*p1p2;
 
149
double a1=d*(rp2*p0p1-p1p2*p0p2); // we only need the sign, so, use multiply instead of division to avoid divid by zero;
 
150
if ( a1 >= 0. ) {
 
151
            p1 = edata.definitionPoint2;
 
152
} else {
 
153
            vp1 *= -1;
 
154
            p1 = edata.definitionPoint1;
 
155
}
 
156
a1 = d*(rp1*p0p2-p1p2*p0p1);
 
157
if ( a1 >= 0. ) {
 
158
            p2 = data.definitionPoint;
 
159
} else {
 
160
            vp2 *= -1;
 
161
            p2 = edata.definitionPoint3;
 
162
}
 
163
 
 
164
    RS_Vector center = getCenter();
 
165
    double ang = center.angleTo(edata.definitionPoint4);
 
166
ang1=vp1.angle();
 
167
ang2=vp2.angle();
 
168
if ( ! RS_Math::isAngleBetween(ang, ang1,ang2,false) ) {
 
169
reversed = true;
 
170
}
 
171
return true;
 
172
}
 
173
//
 
174
//std::cout<<"RS_DimAngular::getAngles(): new algorithm, angle1= "<<vp1.angle()<<"\tangle2= "<<vp2.angle()<<"\treversed= "<<reversed<<std::endl;
 
175
//    bool done = false;
 
176
//
 
177
//    // find out the angles this dimension refers to:
 
178
//    for (int f1=0; f1<=1 && !done; ++f1) {
 
179
//        ang1 = RS_Math::correctAngle(
 
180
//                   edata.definitionPoint1.angleTo(edata.definitionPoint2) + f1*M_PI);
 
181
//        if (f1==0) {
 
182
//            p1 = edata.definitionPoint2;
 
183
//        } else {
 
184
//            p1 = edata.definitionPoint1;
 
185
//        }
 
186
//        for (int f2=0; f2<=1 && !done; ++f2) {
 
187
//            ang2 = RS_Math::correctAngle(
 
188
//                       edata.definitionPoint3.angleTo(data.definitionPoint) + f2*M_PI);
 
189
//            if (f2==0) {
 
190
//                p2 = data.definitionPoint;
 
191
//            } else {
 
192
//                p2 = edata.definitionPoint3;
 
193
//            }
 
194
//            for (int t=0; t<=1 && !done; ++t) {
 
195
//                reversed = (bool)t;
 
196
//
 
197
//                double angDiff;
 
198
//
 
199
//                if (!reversed) {
 
200
//                    if (ang2<ang1) {
 
201
//                        ang2+=2*M_PI;
 
202
//                    }
 
203
//                    angDiff = ang2-ang1;
 
204
//                } else {
 
205
//                    if (ang1<ang2) {
 
206
//                        ang1+=2*M_PI;
 
207
//                    }
 
208
//                    angDiff = ang1-ang2;
 
209
//                }
 
210
//
 
211
//                ang1 = RS_Math::correctAngle(ang1);
 
212
//                ang2 = RS_Math::correctAngle(ang2);
 
213
//
 
214
//                if (RS_Math::isAngleBetween(ang, ang1, ang2, reversed) &&
 
215
//                        angDiff<=M_PI) {
 
216
//                    done = true;
 
217
//                    break;
 
218
//                }
 
219
//            }
 
220
//        }
 
221
//    }
 
222
//std::cout<<"RS_DimAngular::getAngles(): old algorithm, ang1= "<<ang1<<"\tang2= "<<ang2<<"\treversed= "<<reversed<<std::endl;
 
223
//
 
224
//    return done;
 
225
//}
 
226
 
 
227
 
 
228
 
 
229
/**
 
230
 * Updates the sub entities of this dimension. Called when the
 
231
 * dimension or the position, alignment, .. changes.
 
232
 *
 
233
 * @param autoText Automatically reposition the text label
 
234
 */
 
235
void RS_DimAngular::updateDim(bool /*autoText*/) {
 
236
 
 
237
    RS_DEBUG->print("RS_DimAngular::update");
 
238
 
 
239
    clear();
 
240
 
 
241
    if (isUndone()) {
 
242
        return;
 
243
    }
 
244
 
 
245
    // general scale (DIMSCALE)
 
246
    double dimscale = getGeneralScale();
 
247
    // distance from entities (DIMEXO)
 
248
    double dimexo = getExtensionLineOffset()*dimscale;
 
249
    // extension line extension (DIMEXE)
 
250
    double dimexe = getExtensionLineExtension()*dimscale;
 
251
    // text height (DIMTXT)
 
252
    double dimtxt = getTextHeight()*dimscale;
 
253
    // text distance to line (DIMGAP)
 
254
    double dimgap = getDimensionLineGap()*dimscale;
 
255
    // arrow size:
 
256
    double arrowSize = getArrowSize()*dimscale;
 
257
 
 
258
    // find out center:
 
259
    RS_Vector center = getCenter();
 
260
 
 
261
    if (!center.valid) {
 
262
        return;
 
263
    }
 
264
 
 
265
    double ang1 = 0.0;
 
266
    double ang2 = 0.0;
 
267
    bool reversed = false;
 
268
    RS_Vector p1;
 
269
    RS_Vector p2;
 
270
 
 
271
    getAngles(ang1, ang2, reversed, p1, p2);
 
272
 
 
273
    double rad = edata.definitionPoint4.distanceTo(center);
 
274
 
 
275
    RS_Line* line;
 
276
    RS_Vector dir;
 
277
    double len;
 
278
    double dist;
 
279
 
 
280
    // 1st extension line:
 
281
    dist = center.distanceTo(p1);
 
282
    len = rad - dist + dimexe;
 
283
    dir.setPolar(1.0, ang1);
 
284
    line = new RS_Line(this,
 
285
                       RS_LineData(center + dir*dist + dir*dimexo,
 
286
                                   center + dir*dist + dir*len));
 
287
    line->setPen(RS_Pen(RS2::FlagInvalid));
 
288
    line->setLayer(NULL);
 
289
    addEntity(line);
 
290
 
 
291
    // 2nd extension line:
 
292
    dist = center.distanceTo(p2);
 
293
    len = rad - dist + dimexe;
 
294
    dir.setPolar(1.0, ang2);
 
295
    line = new RS_Line(this,
 
296
                       RS_LineData(center + dir*dist + dir*dimexo,
 
297
                                   center + dir*dist + dir*len));
 
298
    line->setPen(RS_Pen(RS2::FlagInvalid));
 
299
    line->setLayer(NULL);
 
300
    addEntity(line);
 
301
 
 
302
    // Create dimension line (arc):
 
303
    RS_Arc* arc = new RS_Arc(this,
 
304
                             RS_ArcData(center,
 
305
                                        rad, ang1, ang2, reversed));
 
306
    arc->setPen(RS_Pen(RS2::FlagInvalid));
 
307
    arc->setLayer(NULL);
 
308
    addEntity(arc);
 
309
 
 
310
    // length of dimension arc:
 
311
    double distance = arc->getLength();
 
312
 
 
313
    // do we have to put the arrows outside of the arc?
 
314
    bool outsideArrows = (distance<arrowSize*2);
 
315
 
 
316
    // arrow angles:
 
317
    double arrowAngle1, arrowAngle2;
 
318
    double arrowAng;
 
319
        if (rad>1.0e-6) {
 
320
                arrowAng = arrowSize / rad;
 
321
        }
 
322
        else {
 
323
                arrowAng = 0.0;
 
324
        }
 
325
    RS_Vector v1, v2;
 
326
    if (!arc->isReversed()) {
 
327
        v1.setPolar(rad, arc->getAngle1()+arrowAng);
 
328
    } else {
 
329
        v1.setPolar(rad, arc->getAngle1()-arrowAng);
 
330
    }
 
331
    v1+=arc->getCenter();
 
332
    arrowAngle1 = arc->getStartpoint().angleTo(v1);
 
333
 
 
334
 
 
335
    if (!arc->isReversed()) {
 
336
        v2.setPolar(rad, arc->getAngle2()-arrowAng);
 
337
    } else {
 
338
        v2.setPolar(rad, arc->getAngle2()+arrowAng);
 
339
    }
 
340
    v2+=arc->getCenter();
 
341
    arrowAngle2 = arc->getEndpoint().angleTo(v2);
 
342
 
 
343
    if (!outsideArrows) {
 
344
        arrowAngle1 = arrowAngle1+M_PI;
 
345
        arrowAngle2 = arrowAngle2+M_PI;
 
346
    }
 
347
 
 
348
    // Arrows:
 
349
    RS_SolidData sd;
 
350
    RS_Solid* arrow;
 
351
 
 
352
    // arrow 1
 
353
    arrow = new RS_Solid(this, sd);
 
354
    arrow->shapeArrow(arc->getStartpoint(),
 
355
                      arrowAngle1,
 
356
                      arrowSize);
 
357
    arrow->setPen(RS_Pen(RS2::FlagInvalid));
 
358
    arrow->setLayer(NULL);
 
359
    addEntity(arrow);
 
360
 
 
361
    // arrow 2:
 
362
    arrow = new RS_Solid(this, sd);
 
363
    arrow->shapeArrow(arc->getEndpoint(),
 
364
                      arrowAngle2,
 
365
                      arrowSize);
 
366
    arrow->setPen(RS_Pen(RS2::FlagInvalid));
 
367
    arrow->setLayer(NULL);
 
368
    addEntity(arrow);
 
369
 
 
370
 
 
371
    // text label:
 
372
    RS_MTextData textData;
 
373
    RS_Vector textPos = arc->getMiddlePoint();
 
374
 
 
375
    RS_Vector distV;
 
376
    double textAngle;
 
377
    double dimAngle1 = textPos.angleTo(arc->getCenter())-M_PI/2.0;
 
378
 
 
379
    // rotate text so it's readable from the bottom or right (ISO)
 
380
    // quadrant 1 & 4
 
381
    if (dimAngle1>M_PI/2.0*3.0+0.001 ||
 
382
            dimAngle1<M_PI/2.0+0.001) {
 
383
 
 
384
        distV.setPolar(dimgap, dimAngle1+M_PI/2.0);
 
385
        textAngle = dimAngle1;
 
386
    }
 
387
    // quadrant 2 & 3
 
388
    else {
 
389
        distV.setPolar(dimgap, dimAngle1-M_PI/2.0);
 
390
        textAngle = dimAngle1+M_PI;
 
391
    }
 
392
 
 
393
    // move text away from dimension line:
 
394
    textPos+=distV;
 
395
 
 
396
    textData = RS_MTextData(textPos,
 
397
                           dimtxt, 30.0,
 
398
                           RS_MTextData::VABottom,
 
399
                           RS_MTextData::HACenter,
 
400
                           RS_MTextData::LeftToRight,
 
401
                           RS_MTextData::Exact,
 
402
                           1.0,
 
403
                           getLabel(),
 
404
                           "standard",
 
405
                           textAngle);
 
406
 
 
407
    RS_MText* text = new RS_MText(this, textData);
 
408
 
 
409
    // move text to the side:
 
410
    text->setPen(RS_Pen(RS2::FlagInvalid));
 
411
    text->setLayer(NULL);
 
412
    addEntity(text);
 
413
 
 
414
    calculateBorders();
 
415
}
 
416
 
 
417
 
 
418
 
 
419
void RS_DimAngular::move(const RS_Vector& offset) {
 
420
    RS_Dimension::move(offset);
 
421
 
 
422
    edata.definitionPoint1.move(offset);
 
423
    edata.definitionPoint2.move(offset);
 
424
    edata.definitionPoint3.move(offset);
 
425
    edata.definitionPoint4.move(offset);
 
426
    update();
 
427
}
 
428
 
 
429
 
 
430
 
 
431
void RS_DimAngular::rotate(const RS_Vector& center, const double& angle) {
 
432
    rotate(center, RS_Vector(angle));
 
433
}
 
434
 
 
435
void RS_DimAngular::rotate(const RS_Vector& center, const RS_Vector& angleVector) {
 
436
    RS_Dimension::rotate(center, angleVector);
 
437
 
 
438
    edata.definitionPoint1.rotate(center, angleVector);
 
439
    edata.definitionPoint2.rotate(center, angleVector);
 
440
    edata.definitionPoint3.rotate(center, angleVector);
 
441
    edata.definitionPoint4.rotate(center, angleVector);
 
442
    update();
 
443
}
 
444
 
 
445
 
 
446
void RS_DimAngular::scale(const RS_Vector& center, const RS_Vector& factor) {
 
447
    RS_Dimension::scale(center, factor);
 
448
 
 
449
    edata.definitionPoint1.scale(center, factor);
 
450
    edata.definitionPoint2.scale(center, factor);
 
451
    edata.definitionPoint3.scale(center, factor);
 
452
    edata.definitionPoint4.scale(center, factor);
 
453
    update();
 
454
}
 
455
 
 
456
 
 
457
 
 
458
void RS_DimAngular::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) {
 
459
    RS_Dimension::mirror(axisPoint1, axisPoint2);
 
460
 
 
461
    edata.definitionPoint1.mirror(axisPoint1, axisPoint2);
 
462
    edata.definitionPoint2.mirror(axisPoint1, axisPoint2);
 
463
    edata.definitionPoint3.mirror(axisPoint1, axisPoint2);
 
464
    edata.definitionPoint4.mirror(axisPoint1, axisPoint2);
 
465
    update();
 
466
}
 
467
 
 
468
/**
 
469
 * Dumps the point's data to stdout.
 
470
 */
 
471
std::ostream& operator << (std::ostream& os, const RS_DimAngular& d) {
 
472
    os << " DimAngular: " << d.getData() << "\n" << d.getEData() << "\n";
 
473
    return os;
 
474
}
 
475