Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GrammaticalOptimization/SharpVectorModel/Paths/SvgPathSegArc.cs @ 14161

Last change on this file since 14161 was 12762, checked in by aballeit, 9 years ago

#2283 GUI updates, Tree-chart, MCTS Version 2 (prune leaves)

File size: 8.7 KB
Line 
1using System;
2using System.Text;
3
4namespace SharpVectors.Dom.Svg
5{
6    public struct CalculatedArcValues
7    {
8        public double CorrRx;
9        public double CorrRy;
10        public double Cx;
11        public double Cy;
12        public double AngleStart;
13        public double AngleExtent;
14
15        public CalculatedArcValues(double rx, double ry, double cx, double cy,
16            double angleStart, double angleExtent)
17        {
18            this.CorrRx      = rx;
19            this.CorrRy      = ry;
20            this.Cx          = cx;
21            this.Cy          = cy;
22            this.AngleStart  = angleStart;
23            this.AngleExtent = angleExtent;
24        }
25    }
26
27    public abstract class SvgPathSegArc : SvgPathSeg
28    {
29        #region Private Fields
30
31        private bool  largeArcFlag;
32        private bool  sweepFlag;
33        private double x;
34        private double y;
35        private double r1;
36        private double r2;
37        private double angle;
38
39        #endregion
40
41        #region Constructors and Destructor
42
43        protected SvgPathSegArc(SvgPathSegType type, double x, double y, double r1, double r2,
44            double angle, bool largeArcFlag, bool sweepFlag)
45            : base(type)
46        {
47            this.x            = x;
48            this.y            = y;
49            this.r1           = r1;
50            this.r2           = r2;
51            this.angle        = angle;
52            this.largeArcFlag = largeArcFlag;
53            this.sweepFlag    = sweepFlag;
54        }
55
56        #endregion
57
58        #region Public Properties
59
60        public double X
61        {
62            get { return x; }
63            set { x = value; }
64        }
65
66        public double Y
67        {
68            get { return y; }
69            set { y = value; }
70        }
71
72        public double R1
73        {
74            get { return r1; }
75            set { r1 = value; }
76        }
77
78        public double R2
79        {
80            get { return r2; }
81            set { r2 = value; }
82        }
83
84        public double Angle
85        {
86            get { return angle; }
87            set { angle = value; }
88        }
89
90        public bool LargeArcFlag
91        {
92            get { return largeArcFlag; }
93            set { largeArcFlag = value; }
94        }
95
96        public bool SweepFlag
97        {
98            get { return sweepFlag; }
99            set { sweepFlag = value; }
100        }
101
102        public abstract override SvgPointF AbsXY { get; }
103
104        public override double StartAngle
105        {
106            get
107            {
108                double a = GetAngle(false);
109                a += 270;
110                a += 360;
111                a = a % 360;
112                return a;
113            }
114        }
115
116        public override double EndAngle
117        {
118            get
119            {
120                double a = GetAngle(true);
121                a += 90;
122                a += 360;
123                a = a % 360;
124
125                return a;
126            }
127        }
128
129        public override string PathText
130        {
131            get
132            {
133                StringBuilder sb = new StringBuilder();
134                sb.Append(PathSegTypeAsLetter);
135                sb.Append(R1);
136                sb.Append(",");
137                sb.Append(R2);
138                sb.Append(",");
139                sb.Append(Angle);
140                sb.Append(",");
141
142                if (LargeArcFlag)
143                    sb.Append("1");
144                else
145                    sb.Append("0");
146
147                sb.Append(",");
148
149                if (SweepFlag)
150                    sb.Append("1");
151                else
152                    sb.Append("0");
153
154                sb.Append(",");
155                sb.Append(X);
156                sb.Append(",");
157                sb.Append(Y);
158
159                return sb.ToString();
160            }
161        }
162
163        #endregion
164
165        #region Public Methods
166
167        public CalculatedArcValues GetCalculatedArcValues()
168        {
169            CalculatedArcValues calcVal = new CalculatedArcValues();
170
171            /*
172             *  This algorithm is taken from the Batik source. All cudos to the Batik crew.
173             */
174
175            SvgPointF startPoint = PreviousSeg.AbsXY;
176            SvgPointF endPoint = AbsXY;
177
178            double x0 = startPoint.X;
179            double y0 = startPoint.Y;
180
181            double x = endPoint.X;
182            double y = endPoint.Y;
183
184            // Compute the half distance between the current and the final point
185            double dx2 = (x0 - x) / 2.0;
186            double dy2 = (y0 - y) / 2.0;
187
188            // Convert angle from degrees to radians
189            double radAngle = Angle * Math.PI / 180;
190            double cosAngle = Math.Cos(radAngle);
191            double sinAngle = Math.Sin(radAngle);
192
193            //
194            // Step 1 : Compute (x1, y1)
195            //
196            double x1 = (cosAngle * dx2 + sinAngle * dy2);
197            double y1 = (-sinAngle * dx2 + cosAngle * dy2);
198            // Ensure radii are large enough
199
200            double rx = Math.Abs(R1);
201            double ry = Math.Abs(R2);
202
203            double Prx = rx * rx;
204            double Pry = ry * ry;
205            double Px1 = x1 * x1;
206            double Py1 = y1 * y1;
207
208            // check that radii are large enough
209            double radiiCheck = Px1 / Prx + Py1 / Pry;
210            if (radiiCheck > 1)
211            {
212                rx = Math.Sqrt(radiiCheck) * rx;
213                ry = Math.Sqrt(radiiCheck) * ry;
214                Prx = rx * rx;
215                Pry = ry * ry;
216            }
217
218            //
219            // Step 2 : Compute (cx1, cy1)
220            //
221            double sign = (LargeArcFlag == SweepFlag) ? -1 : 1;
222            double sq = ((Prx * Pry) - (Prx * Py1) - (Pry * Px1)) / ((Prx * Py1) + (Pry * Px1));
223            sq = (sq < 0) ? 0 : sq;
224            double coef = (sign * Math.Sqrt(sq));
225            double cx1 = coef * ((rx * y1) / ry);
226            double cy1 = coef * -((ry * x1) / rx);
227
228            //
229            // Step 3 : Compute (cx, cy) from (cx1, cy1)
230            //
231            double sx2 = (x0 + x) / 2.0;
232            double sy2 = (y0 + y) / 2.0;
233            double cx = sx2 + (cosAngle * cx1 - sinAngle * cy1);
234            double cy = sy2 + (sinAngle * cx1 + cosAngle * cy1);
235
236            //
237            // Step 4 : Compute the angleStart (angle1) and the angleExtent (dangle)
238            //
239            double ux = (x1 - cx1); // rx;
240            double uy = (y1 - cy1); // ry;
241            double vx = (-x1 - cx1); // rx;
242            double vy = (-y1 - cy1); // ry;
243            double p, n;
244            // Compute the angle start
245            n = Math.Sqrt((ux * ux) + (uy * uy));
246            p = ux; // (1 * ux) + (0 * uy)
247            sign = (uy < 0) ? -1d : 1d;
248            double angleStart = sign * Math.Acos(p / n);
249            angleStart = angleStart * 180 / Math.PI;
250
251            // Compute the angle extent
252            n = Math.Sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));
253            p = ux * vx + uy * vy;
254            sign = (ux * vy - uy * vx < 0) ? -1d : 1d;
255            double angleExtent = sign * Math.Acos(p / n);
256            angleExtent = angleExtent * 180 / Math.PI;
257
258            if (!sweepFlag && angleExtent > 0)
259            {
260                angleExtent -= 360f;
261            }
262            else if (sweepFlag && angleExtent < 0)
263            {
264                angleExtent += 360f;
265            }
266            angleExtent %= 360f;
267            angleStart %= 360f;
268
269            calcVal.CorrRx = rx;
270            calcVal.CorrRy = ry;
271            calcVal.Cx = cx;
272            calcVal.Cy = cy;
273            calcVal.AngleStart = angleStart;
274            calcVal.AngleExtent = angleExtent;
275
276            return calcVal;
277        }
278
279        #endregion
280
281        #region Private Methods
282
283        private double GetAngle(bool addExtent)
284        {
285            CalculatedArcValues calcValues = GetCalculatedArcValues();
286
287            double radAngle = calcValues.AngleStart;
288            if (addExtent)
289            {
290                radAngle += calcValues.AngleExtent;
291            }
292
293            radAngle *= (Math.PI / 180);
294            double cosAngle = Math.Cos(radAngle);
295            double sinAngle = Math.Sin(radAngle);
296
297            double denom = Math.Sqrt(
298                calcValues.CorrRy * calcValues.CorrRy * cosAngle * cosAngle +
299                calcValues.CorrRx * calcValues.CorrRx * sinAngle * sinAngle);
300
301            double xt = -calcValues.CorrRx * sinAngle / denom;
302            double yt = calcValues.CorrRy * cosAngle / denom;
303
304            double a = (Math.Atan2(yt, xt) * 180 / Math.PI);
305            a += Angle;
306            return a;
307        }
308
309        #endregion
310    }
311}
Note: See TracBrowser for help on using the repository browser.