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