]> Shamusworld >> Repos - architektonas/blob - src/base/rs_arc.cpp
d674fcf19c01fbe457ec80d75e04a36fb8d75aff
[architektonas] / src / base / rs_arc.cpp
1 // rs_arc.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 // JLH  06/16/2010  Moved implementation from header file to this file
14 //
15
16 #include "rs_arc.h"
17
18 #include "rs_constructionline.h"
19 #include "rs_linetypepattern.h"
20 #include "rs_information.h"
21 #include "rs_math.h"
22 #include "graphicview.h"
23 #include "paintinterface.h"
24
25 /**
26  * Default constructor.
27  */
28 RS_Arc::RS_Arc(RS_EntityContainer * parent, const RS_ArcData & d):
29         RS_AtomicEntity(parent), data(d)
30 {
31         calculateEndpoints();
32         calculateBorders();
33 }
34
35 /*virtual*/ RS_Arc::~RS_Arc()
36 {
37 }
38
39 /*virtual*/ RS_Entity * RS_Arc::clone()
40 {
41         RS_Arc * a = new RS_Arc(*this);
42         a->initId();
43         return a;
44 }
45
46 /**     @return RS2::EntityArc */
47 /*virtual*/ RS2::EntityType RS_Arc::rtti() const
48 {
49         return RS2::EntityArc;
50 }
51
52 /** @return true */
53 /*virtual*/ bool RS_Arc::isEdge() const
54 {
55         return true;
56 }
57
58 /** @return Copy of data that defines the arc. **/
59 RS_ArcData RS_Arc::getData() const
60 {
61         return data;
62 }
63
64 /*virtual*/ VectorSolutions RS_Arc::getRefPoints()
65 {
66         VectorSolutions ret(startpoint, endpoint, data.center);
67         return ret;
68 }
69
70 /** Sets new arc parameters. **/
71 void RS_Arc::setData(RS_ArcData d)
72 {
73         data = d;
74 }
75
76 /** @return The center point (x) of this arc */
77 Vector RS_Arc::getCenter() const
78 {
79         return data.center;
80 }
81
82 /** Sets new center. */
83 void RS_Arc::setCenter(const Vector & c)
84 {
85         data.center = c;
86 }
87
88 /** @return The radius of this arc */
89 double RS_Arc::getRadius() const
90 {
91         return data.radius;
92 }
93
94 /** Sets new radius. */
95 void RS_Arc::setRadius(double r)
96 {
97         data.radius = r;
98 }
99
100 /** @return The start angle of this arc */
101 double RS_Arc::getAngle1() const
102 {
103         return data.angle1;
104 }
105
106 /** Sets new start angle. */
107 void RS_Arc::setAngle1(double a1)
108 {
109         data.angle1 = a1;
110 }
111
112 /** @return The end angle of this arc */
113 double RS_Arc::getAngle2() const
114 {
115         return data.angle2;
116 }
117
118 /** Sets new end angle. */
119 void RS_Arc::setAngle2(double a2)
120 {
121         data.angle2 = a2;
122 }
123
124 /**
125  * @return Direction 1. The angle at which the arc starts at
126  * the startpoint.
127  */
128 double RS_Arc::getDirection1() const
129 {
130         if (!data.reversed)
131                 return RS_Math::correctAngle(data.angle1 + M_PI / 2.0);
132
133         return RS_Math::correctAngle(data.angle1 - M_PI / 2.0);
134 }
135
136 /**
137  * @return Direction 2. The angle at which the arc starts at
138  * the endpoint.
139  */
140 double RS_Arc::getDirection2() const
141 {
142         if (!data.reversed)
143                 return RS_Math::correctAngle(data.angle2 - M_PI / 2.0);
144
145         return RS_Math::correctAngle(data.angle2 + M_PI / 2.0);
146 }
147
148 /**
149  * @retval true if the arc is reversed (clockwise),
150  * @retval false otherwise
151  */
152 bool RS_Arc::isReversed() const
153 {
154         return data.reversed;
155 }
156
157 /** sets the reversed status. */
158 void RS_Arc::setReversed(bool r)
159 {
160         data.reversed = r;
161 }
162
163 /** @return Start point of the entity. */
164 /*virtual*/ Vector RS_Arc::getStartpoint() const
165 {
166         return startpoint;
167 }
168
169 /** @return End point of the entity. */
170 /*virtual*/ Vector RS_Arc::getEndpoint() const
171 {
172         return endpoint;
173 }
174
175 /**
176  * Creates this arc from 3 given points which define the arc line.
177  *
178  * @param p1 1st point.
179  * @param p2 2nd point.
180  * @param p3 3rd point.
181  */
182 bool RS_Arc::createFrom3P(const Vector & p1, const Vector & p2, const Vector & p3)
183 {
184         if (p1.distanceTo(p2) > RS_TOLERANCE
185             && p2.distanceTo(p3) > RS_TOLERANCE
186             && p3.distanceTo(p1) > RS_TOLERANCE)
187         {
188                 // middle points between 3 points:
189                 Vector mp1, mp2;
190                 Vector dir1, dir2;
191                 double a1, a2;
192
193                 // intersection of two middle lines
194                 mp1 = (p1 + p2) / 2.0;
195                 a1 = p1.angleTo(p2) + M_PI / 2.0;
196                 dir1.setPolar(100.0, a1);
197                 mp2 = (p2 + p3) / 2.0;
198                 a2 = p2.angleTo(p3) + M_PI / 2.0;
199                 dir2.setPolar(100.0, a2);
200
201                 RS_ConstructionLineData d1(mp1, mp1 + dir1);
202                 RS_ConstructionLineData d2(mp2, mp2 + dir2);
203                 RS_ConstructionLine midLine1(NULL, d1);
204                 RS_ConstructionLine midLine2(NULL, d2);
205
206                 VectorSolutions sol =
207                         RS_Information::getIntersection(&midLine1, &midLine2);
208
209                 data.center = sol.get(0);
210                 data.radius = data.center.distanceTo(p3);
211                 data.angle1 = data.center.angleTo(p1);
212                 data.angle2 = data.center.angleTo(p3);
213                 data.reversed = RS_Math::isAngleBetween(data.center.angleTo(p2),
214                                 data.angle1, data.angle2, true);
215
216                 if (sol.get(0).valid && data.radius < 1.0e14
217                     && data.radius > RS_TOLERANCE)
218                 {
219                         calculateEndpoints();
220                         calculateBorders();
221                         return true;
222                 }
223                 else
224                 {
225                         RS_DEBUG->print("RS_Arc::createFrom3P(): "
226                                 "Cannot create an arc with inf radius.");
227                         return false;
228                 }
229         }
230         else
231         {
232                 RS_DEBUG->print("RS_Arc::createFrom3P(): "
233                         "Cannot create an arc with radius 0.0.");
234                 return false;
235         }
236 }
237
238 /**
239  * Creates an arc from its startpoint, endpoint, start direction (angle)
240  * and radius.
241  *
242  * @retval true Successfully created arc
243  * @retval false Cannot creats arc (radius to small or endpoint to far away)
244  */
245 bool RS_Arc::createFrom2PDirectionRadius(const Vector & startPoint, const Vector & endPoint, double direction1, double radius)
246 {
247         Vector ortho;
248         ortho.setPolar(radius, direction1 + M_PI / 2.0);
249         Vector center1 = startPoint + ortho;
250         Vector center2 = startPoint - ortho;
251
252         if (center1.distanceTo(endPoint) < center2.distanceTo(endPoint))
253                 data.center = center1;
254         else
255                 data.center = center2;
256
257         data.radius = radius;
258         data.angle1 = data.center.angleTo(startPoint);
259         data.angle2 = data.center.angleTo(endPoint);
260         data.reversed = false;
261
262         double diff = RS_Math::correctAngle(getDirection1() - direction1);
263
264         if (fabs(diff - M_PI) < 1.0e-1)
265                 data.reversed = true;
266
267         calculateEndpoints();
268         calculateBorders();
269
270         return true;
271 }
272
273 /**
274  * Creates an arc from its startpoint, endpoint and bulge.
275  */
276 bool RS_Arc::createFrom2PBulge(const Vector & startPoint, const Vector & endPoint, double bulge)
277 {
278         data.reversed = (bulge < 0.0);
279         double alpha = atan(bulge) * 4.0;
280
281         Vector middle = (startPoint + endPoint) / 2.0;
282         double dist = startPoint.distanceTo(endPoint) / 2.0;
283
284         // alpha can't be 0.0 at this point
285         data.radius = fabs(dist / sin(alpha / 2.0));
286
287         double wu = fabs(RS_Math::pow(data.radius, 2.0) - RS_Math::pow(dist, 2.0));
288         double h = sqrt(wu);
289         double angle = startPoint.angleTo(endPoint);
290
291         if (bulge > 0.0)
292                 angle += M_PI / 2.0;
293         else
294                 angle -= M_PI / 2.0;
295
296         if (fabs(alpha) > M_PI)
297                 h *= -1.0;
298
299         data.center.setPolar(h, angle);
300         data.center += middle;
301         data.angle1 = data.center.angleTo(startPoint);
302         data.angle2 = data.center.angleTo(endPoint);
303
304         calculateEndpoints();
305         calculateBorders();
306
307         return true;
308 }
309
310 /**
311  * Recalculates the endpoints using the angles and the radius.
312  */
313 void RS_Arc::calculateEndpoints()
314 {
315         startpoint.set(data.center.x + cos(data.angle1) * data.radius,
316                 data.center.y + sin(data.angle1) * data.radius);
317         endpoint.set(data.center.x + cos(data.angle2) * data.radius,
318                 data.center.y + sin(data.angle2) * data.radius);
319 }
320
321 void RS_Arc::calculateBorders()
322 {
323         double minX = std::min(startpoint.x, endpoint.x);
324         double minY = std::min(startpoint.y, endpoint.y);
325         double maxX = std::max(startpoint.x, endpoint.x);
326         double maxY = std::max(startpoint.y, endpoint.y);
327
328         double a1 = !isReversed() ? data.angle1 : data.angle2;
329         double a2 = !isReversed() ? data.angle2 : data.angle1;
330
331         // check for left limit:
332         if ((a1 < M_PI && a2 > M_PI)
333             || (a1 > a2 - 1.0e-12 && a2 > M_PI)
334             || (a1 > a2 - 1.0e-12 && a1 < M_PI) )
335
336                 minX = std::min(data.center.x - data.radius, minX);
337
338         // check for right limit:
339         if (a1 > a2 - 1.0e-12)
340                 maxX = std::max(data.center.x + data.radius, maxX);
341
342         // check for bottom limit:
343         if ((a1 < (M_PI_2 * 3) && a2 > (M_PI_2 * 3))
344             || (a1 > a2 - 1.0e-12    && a2 > (M_PI_2 * 3))
345             || (a1 > a2 - 1.0e-12    && a1 < (M_PI_2 * 3)) )
346
347                 minY = std::min(data.center.y - data.radius, minY);
348
349         // check for top limit:
350         if ((a1 < M_PI_2 && a2 > M_PI_2)
351             || (a1 > a2 - 1.0e-12   && a2 > M_PI_2)
352             || (a1 > a2 - 1.0e-12   && a1 < M_PI_2) )
353
354                 maxY = std::max(data.center.y + data.radius, maxY);
355
356         minV.set(minX, minY);
357         maxV.set(maxX, maxY);
358 }
359
360 Vector RS_Arc::getNearestEndpoint(const Vector & coord, double * dist)
361 {
362         double dist1, dist2;
363         Vector * nearerPoint;
364
365         dist1 = startpoint.distanceTo(coord);
366         dist2 = endpoint.distanceTo(coord);
367
368         if (dist2 < dist1)
369         {
370                 if (dist != NULL)
371                         *dist = dist2;
372                 nearerPoint = &endpoint;
373         }
374         else
375         {
376                 if (dist != NULL)
377                         *dist = dist1;
378                 nearerPoint = &startpoint;
379         }
380
381         return *nearerPoint;
382 }
383
384 Vector RS_Arc::getNearestPointOnEntity(const Vector & coord, bool onEntity, double * dist, RS_Entity * * entity)
385 {
386         Vector vec(false);
387
388         if (entity != NULL)
389                 *entity = this;
390
391         double angle = (coord - data.center).angle();
392
393         if (onEntity == false || RS_Math::isAngleBetween(angle,
394                     data.angle1, data.angle2, isReversed()))
395         {
396                 vec.setPolar(data.radius, angle);
397                 vec += data.center;
398         }
399
400         if (dist != NULL)
401                 *dist = fabs((vec - data.center).magnitude() - data.radius);
402
403         return vec;
404 }
405
406 Vector RS_Arc::getNearestCenter(const Vector & coord, double * dist)
407 {
408         if (dist != NULL)
409                 *dist = coord.distanceTo(data.center);
410         return data.center;
411 }
412
413 Vector RS_Arc::getNearestMiddle(const Vector & coord, double * dist)
414 {
415         Vector ret = getMiddlepoint();
416
417         if (dist != NULL)
418                 *dist = coord.distanceTo(ret);
419         return ret;
420 }
421
422 Vector RS_Arc::getNearestDist(double distance, const Vector & coord, double * dist)
423 {
424         if (data.radius < 1.0e-6)
425         {
426                 if (dist != NULL)
427                         *dist = RS_MAXDOUBLE;
428                 return Vector(false);
429         }
430
431         double a1, a2;
432         Vector p1, p2;
433         double aDist = distance / data.radius;
434
435         if (isReversed())
436         {
437                 a1 = data.angle1 - aDist;
438                 a2 = data.angle2 + aDist;
439         }
440         else
441         {
442                 a1 = data.angle1 + aDist;
443                 a2 = data.angle2 - aDist;
444         }
445
446         p1.setPolar(data.radius, a1);
447         p1 += data.center;
448         p2.setPolar(data.radius, a2);
449         p2 += data.center;
450
451         double dist1, dist2;
452         Vector * nearerPoint;
453
454         dist1 = p1.distanceTo(coord);
455         dist2 = p2.distanceTo(coord);
456
457         if (dist2 < dist1)
458         {
459                 if (dist != NULL)
460                         *dist = dist2;
461                 nearerPoint = &p2;
462         }
463         else
464         {
465                 if (dist != NULL)
466                         *dist = dist1;
467                 nearerPoint = &p1;
468         }
469
470         return *nearerPoint;
471 }
472
473 Vector RS_Arc::getNearestDist(double distance, bool startp)
474 {
475         if (data.radius < 1.0e-6)
476                 return Vector(false);
477
478         double a;
479         Vector p;
480         double aDist = distance / data.radius;
481
482         if (isReversed())
483         {
484                 if (startp)
485                         a = data.angle1 - aDist;
486                 else
487                         a = data.angle2 + aDist;
488         }
489         else
490         {
491                 if (startp)
492                         a = data.angle1 + aDist;
493                 else
494                         a = data.angle2 - aDist;
495         }
496
497         p.setPolar(data.radius, a);
498         p += data.center;
499
500         return p;
501 }
502
503 double RS_Arc::getDistanceToPoint(const Vector & coord, RS_Entity * * entity, RS2::ResolveLevel, double)
504 {
505         if (entity != NULL)
506                 *entity = this;
507
508         // check endpoints first:
509         double dist = coord.distanceTo(getStartpoint());
510
511         if (dist < 1.0e-4)
512                 return dist;
513         dist = coord.distanceTo(getEndpoint());
514
515         if (dist < 1.0e-4)
516                 return dist;
517
518         if (RS_Math::isAngleBetween(data.center.angleTo(coord),
519                     data.angle1, data.angle2,
520                     isReversed()))
521
522                 return fabs((coord - data.center).magnitude() - data.radius);
523         else
524                 return RS_MAXDOUBLE;
525 }
526
527 void RS_Arc::moveStartpoint(const Vector & pos)
528 {
529         // polyline arcs: move point not angle:
530         //if (parent!=NULL && parent->rtti()==RS2::EntityPolyline) {
531         double bulge = getBulge();
532         createFrom2PBulge(pos, getEndpoint(), bulge);
533         //}
534
535         // normal arc: move angle1
536         /*else {
537            data.angle1 = data.center.angleTo(pos);
538            calculateEndpoints();
539            calculateBorders();
540            }*/
541 }
542
543 void RS_Arc::moveEndpoint(const Vector & pos)
544 {
545         // polyline arcs: move point not angle:
546         //if (parent!=NULL && parent->rtti()==RS2::EntityPolyline) {
547         double bulge = getBulge();
548         createFrom2PBulge(getStartpoint(), pos, bulge);
549         //}
550
551         // normal arc: move angle1
552         /*else {
553            data.angle2 = data.center.angleTo(pos);
554             calculateEndpoints();
555            calculateBorders();
556            }*/
557 }
558
559 void RS_Arc::trimStartpoint(const Vector & pos)
560 {
561         data.angle1 = data.center.angleTo(pos);
562         calculateEndpoints();
563         calculateBorders();
564 }
565
566 void RS_Arc::trimEndpoint(const Vector & pos)
567 {
568         data.angle2 = data.center.angleTo(pos);
569         calculateEndpoints();
570         calculateBorders();
571 }
572
573 RS2::Ending RS_Arc::getTrimPoint(const Vector & coord, const Vector & trimPoint)
574 {
575         double angEl = data.center.angleTo(trimPoint);
576         double angM = data.center.angleTo(coord);
577
578         if (RS_Math::getAngleDifference(angM, angEl) > M_PI)
579         {
580                 if (data.reversed)
581                         return RS2::EndingEnd;
582                 else
583                         return RS2::EndingStart;
584         }
585         else
586         {
587                 if (data.reversed)
588                         return RS2::EndingStart;
589                 else
590                         return RS2::EndingEnd;
591         }
592 }
593
594 void RS_Arc::reverse()
595 {
596         double a = data.angle1;
597         data.angle1 = data.angle2;
598         data.angle2 = a;
599         data.reversed = !data.reversed;
600         calculateEndpoints();
601         calculateBorders();
602 }
603
604 void RS_Arc::move(Vector offset)
605 {
606         data.center.move(offset);
607         calculateEndpoints();
608         calculateBorders();
609 }
610
611 void RS_Arc::rotate(Vector center, double angle)
612 {
613         RS_DEBUG->print("RS_Arc::rotate");
614         data.center.rotate(center, angle);
615         data.angle1 = RS_Math::correctAngle(data.angle1 + angle);
616         data.angle2 = RS_Math::correctAngle(data.angle2 + angle);
617         calculateEndpoints();
618         calculateBorders();
619         RS_DEBUG->print("RS_Arc::rotate: OK");
620 }
621
622 void RS_Arc::scale(Vector center, Vector factor)
623 {
624         // negative scaling: mirroring
625         if (factor.x < 0.0)
626                 mirror(data.center, data.center + Vector(0.0, 1.0));
627                 //factor.x*=-1;
628
629
630         if (factor.y < 0.0)
631                 mirror(data.center, data.center + Vector(1.0, 0.0));
632                 //factor.y*=-1;
633
634         data.center.scale(center, factor);
635         data.radius *= factor.x;
636
637         if (data.radius < 0.0)
638                 data.radius *= -1.0;
639         calculateEndpoints();
640         calculateBorders();
641 }
642
643 void RS_Arc::mirror(Vector axisPoint1, Vector axisPoint2)
644 {
645         data.center.mirror(axisPoint1, axisPoint2);
646         data.reversed = (!data.reversed);
647         /*
648            startpoint.mirror(axisPoint1, axisPoint2);
649            endpoint.mirror(axisPoint1, axisPoint2);
650
651            data.angle1 = data.center.angleTo(startpoint);
652            data.angle2 = data.center.angleTo(endpoint);
653          */
654
655         Vector vec;
656         vec.setPolar(1.0, data.angle1);
657         vec.mirror(Vector(0.0, 0.0), axisPoint2 - axisPoint1);
658         data.angle1 = vec.angle();
659
660         vec.setPolar(1.0, data.angle2);
661         vec.mirror(Vector(0.0, 0.0), axisPoint2 - axisPoint1);
662         data.angle2 = vec.angle();
663
664         calculateEndpoints();
665         calculateBorders();
666 }
667
668 void RS_Arc::moveRef(const Vector & ref, const Vector & offset)
669 {
670         if (ref.distanceTo(startpoint) < 1.0e-4)
671                 moveStartpoint(startpoint + offset);
672
673
674         if (ref.distanceTo(endpoint) < 1.0e-4)
675                 moveEndpoint(endpoint + offset);
676 }
677
678 void RS_Arc::stretch(Vector firstCorner, Vector secondCorner, Vector offset)
679 {
680         if (getMin().isInWindow(firstCorner, secondCorner)
681             && getMax().isInWindow(firstCorner, secondCorner))
682
683                 move(offset);
684         else
685         {
686                 if (getStartpoint().isInWindow(firstCorner,
687                             secondCorner))
688                         moveStartpoint(getStartpoint() + offset);
689
690
691                 if (getEndpoint().isInWindow(firstCorner,
692                             secondCorner))
693                         moveEndpoint(getEndpoint() + offset);
694         }
695 }
696
697 void RS_Arc::draw(PaintInterface * painter, GraphicView * view, double /*patternOffset*/)
698 {
699         if (painter == NULL || view == NULL)
700                 return;
701
702         //double styleFactor = getStyleFactor();
703
704         // simple style-less lines
705         if (getPen().getLineType() == RS2::SolidLine
706             || isSelected()
707             || view->getDrawingMode() == RS2::ModePreview)
708
709                 painter->drawArc(view->toGui(getCenter()),
710                         getRadius() * view->getFactor().x,
711                         getAngle1(), getAngle2(),
712                         isReversed());
713         else
714         {
715                 double styleFactor = getStyleFactor(view);
716
717                 if (styleFactor < 0.0)
718                 {
719                         painter->drawArc(view->toGui(getCenter()),
720                                 getRadius() * view->getFactor().x,
721                                 getAngle1(), getAngle2(),
722                                 isReversed());
723                         return;
724                 }
725
726                 // Pattern:
727                 RS_LineTypePattern * pat;
728
729                 if (isSelected())
730                         pat = &patternSelected;
731                 else
732                         pat = view->getPattern(getPen().getLineType());
733
734                 if (pat == NULL)
735                         return;
736
737                 if (getRadius() < 1.0e-6)
738                         return;
739
740                 // Pen to draw pattern is always solid:
741                 RS_Pen pen = painter->getPen();
742                 pen.setLineType(RS2::SolidLine);
743                 painter->setPen(pen);
744
745                 double a1;
746                 double a2;
747
748                 if (data.reversed)
749                 {
750                         a2 = getAngle1();
751                         a1 = getAngle2();
752                 }
753                 else
754                 {
755                         a1 = getAngle1();
756                         a2 = getAngle2();
757                 }
758
759                 double * da; // array of distances in x.
760                 int i;  // index counter
761
762                 double length = getAngleLength();
763
764                 // create scaled pattern:
765                 da = new double[pat->num];
766
767                 for (i = 0; i < pat->num; ++i)
768                         da[i] = fabs(pat->pattern[i] * styleFactor) / getRadius();
769
770                 double tot = 0.0;
771                 i = 0;
772                 bool done = false;
773                 double curA = a1;
774                 //double cx = getCenter().x * factor.x + offsetX;
775                 //double cy = - a->getCenter().y * factor.y + getHeight() - offsetY;
776                 Vector cp = view->toGui(getCenter());
777                 double r = getRadius() * view->getFactor().x;
778
779                 do
780                 {
781                         if (pat->pattern[i] > 0.0)
782                         {
783                                 if (tot + da[i] < length)
784                                         painter->drawArc(cp, r,
785                                                 curA,
786                                                 curA + da[i],
787                                                 false);
788                                 else
789                                         painter->drawArc(cp, r,
790                                                 curA,
791                                                 a2,
792                                                 false);
793                         }
794                         curA += da[i];
795                         tot += da[i];
796                         done = tot > length;
797
798                         i++;
799
800                         if (i >= pat->num)
801                                 i = 0;
802                 }
803                 while (!done);
804
805                 delete[] da;
806         }
807 }
808
809 /**
810  * @return Middle point of the entity.
811  */
812 Vector RS_Arc::getMiddlepoint() const
813 {
814         double a;
815         Vector ret;
816
817         if (isReversed())
818                 a = data.angle1 - getAngleLength() / 2.0;
819         else
820                 a = data.angle1 + getAngleLength() / 2.0;
821         ret.setPolar(data.radius, a);
822         ret += data.center;
823
824         return ret;
825 }
826
827 /**
828  * @return Angle length in rad.
829  */
830 double RS_Arc::getAngleLength() const
831 {
832         double ret = 0.0;
833
834         if (isReversed())
835         {
836                 if (data.angle1 < data.angle2)
837                         ret = data.angle1 + 2 * M_PI - data.angle2;
838                 else
839                         ret = data.angle1 - data.angle2;
840         }
841         else
842         {
843                 if (data.angle2 < data.angle1)
844                         ret = data.angle2 + 2 * M_PI - data.angle1;
845                 else
846                         ret = data.angle2 - data.angle1;
847         }
848
849         // full circle:
850         if (fabs(ret) < 1.0e-6)
851                 ret = 2 * M_PI;
852
853         return ret;
854 }
855
856 /**
857  * @return Length of the arc.
858  */
859 double RS_Arc::getLength()
860 {
861         return getAngleLength() * data.radius;
862 }
863
864 /**
865  * Gets the arc's bulge (tangens of angle length divided by 4).
866  */
867 double RS_Arc::getBulge() const
868 {
869         double bulge = tan(fabs(getAngleLength()) / 4.0);
870
871         if (isReversed())
872                 bulge *= -1;
873         return bulge;
874 }
875
876 /**
877  * Dumps the point's data to stdout.
878  */
879 std::ostream & operator<<(std::ostream & os, const RS_Arc & a)
880 {
881         os << " Arc: " << a.data << "\n";
882         return os;
883 }
884