-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy patharc.cpp
More file actions
128 lines (102 loc) · 4.82 KB
/
arc.cpp
File metadata and controls
128 lines (102 loc) · 4.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include "arc.h"
/*!
* \brief Arc::Arc
* \param radii - radius of x and y axis of ellipse, semi-minor and semi-major axis
* \param rotation - rotated relative to the current coordinate system.
* \param largeArcFlag - large arc flag. If true the arc spanning less than or equal
* to 180 degrees is chose, otherwise the spanning greate than 180
* degrees is chosen
* \param sweepFlag - If true line joining center to arch sweeps though decreasing angles
* otherwise it sweeps thorugh decreasing angles
* \param endPos - absolute position of final points of the arc (read from SVG)
* \param initPos - absoule initial position of the arc (cPos)
*/
Arc::Arc(QPointF radii, double rotation, int largeArcFlag, int sweepFlag, QPointF endPos, QPointF initPos)
{
//See these pages for implemenatation:
//https://java.net/projects/svgsalamander/sources/svn/content/trunk/svg-core/src/main/java/com/kitfox/svg/pathcmd/Arc.java
//http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
//Compute half distance between current and final point
QPointF deltaPos = (initPos-endPos)/2.0;
double angle = qDegreesToRadians( fmod( rotation, 360.0) );
double cosAngle = qCos(angle);
double sinAngle = qSin(angle);
//Step 1 : Compute (x1, y1)
QPointF primePos = QPointF(
cosAngle * deltaPos.x() + sinAngle * deltaPos.y(),
-sinAngle * deltaPos.x() + cosAngle * deltaPos.y()
);
//Corrention of out-of-range-radii
radii = QPointF( qAbs(radii.x()), qAbs(radii.y()) );
double deltaRadii = (primePos.x() * primePos.x())/(radii.x()*radii.x())
+ (primePos.y()*primePos.y())/(radii.y() * radii.y());
if(deltaRadii > 1)
{
radii = QPointF(
qSqrt(deltaRadii) * radii.x(),
qSqrt(deltaRadii) * radii.y()
);
}
//Step 2 : Compute (cx1, cy1)
QPointF radiiSq = QPointF( radii.x() * radii.x() , radii.y() * radii.y()); //Squared radii
int sign = largeArcFlag == sweepFlag ? -1 : 1;
double sq = (radiiSq.x()*radiiSq.y() - radiiSq.x()*(primePos.y()*primePos.y()) - radiiSq.y()*(primePos.x()*primePos.x()))
/ ( radiiSq.x()*(primePos.y()*primePos.y()) + radiiSq.y()*(primePos.x()*primePos.x()) );
sq = sq < 0 ? 0 : sq;
double coef = sign * qSqrt(sq);
QPointF cp1 = QPointF(
coef*((radii.x()*primePos.y())/radii.y()),
coef* (-( (radii.y()*primePos.x())/(radii.x()) ))
); //center position prime
//Step 3 : compute (cx, cy) from cx' and cy'
QPointF sumPos = (initPos+endPos)/2.0;
QPointF cp = QPointF(
cosAngle*cp1.x() - sinAngle*cp1.y() + sumPos.x(),
sinAngle*cp1.x() + cosAngle*cp1.y() + sumPos.y()
);
//Step 4 : compute theta1 and deltaTheta
QPointF up = QPointF(
(primePos.x()-cp1.x()) / radii.x(),
(primePos.y()-cp1.y()) / radii.y()
);
QPointF vp = QPointF(
(-primePos.x()-cp1.x()) / radii.x(),
(-primePos.y()-cp1.y()) / radii.y()
);
double p, n;
//Compute theta
n = qSqrt( up.x()*up.x() + up.y()*up.y() );
p = up.x(); //(1*up.x())+(0*u.y());
sign = (up.y() < 0) ? -1 : 1;
double theta = qRadiansToDegrees( sign* qAcos( p/n ) );
//Compute deltaTheta
n = qSqrt( (up.x()*up.x()+up.y()*up.y()) * ( vp.x()*vp.x()+vp.y()*vp.y() ) );
p = up.x()*vp.x()+up.y()*vp.y();
sign = (up.x() * vp.y() - up.y()*vp.x() < 0) ? -1 : 1;
double deltaTheta = qRadiansToDegrees( sign*qAcos( p/n ) );
if(!sweepFlag && deltaTheta > 0)
deltaTheta -= 360.0;
else if(sweepFlag && deltaTheta < 0)
deltaTheta += 360.0;
deltaTheta = fmod(deltaTheta, 360.0);
theta = fmod(theta, 360.0);
constructPolygon( cp , radii , qDegreesToRadians(-theta), qDegreesToRadians(-deltaTheta) );
//Finally rotate:
RotationTransform* rot = new RotationTransform(rotation, cp);
setRotation( rot );
}
void Arc::constructPolygon(QPointF center, QPointF radii, double start, double extent)
{
qDebug() << "Arc: " << center << radii << start << extent << qRadiansToDegrees(start) << qRadiansToDegrees(extent);
double inc = (extent) / (ARC_POINTS-1);
double theta = start;
for(int i=0; i<=ARC_POINTS-1; i++)
{
myPolygon << QPointF(
center.x() + radii.x()*qCos(theta),
center.y() - radii.y()*qSin(theta)
);
theta += inc;
}
//myPolygon << myPolygon[0];
}