1 package org.djutils.draw.curve;
2
3 import org.djutils.draw.function.ContinuousPiecewiseLinearFunction;
4 import org.djutils.draw.line.PolyLine2d;
5 import org.djutils.draw.point.DirectedPoint2d;
6 import org.djutils.draw.point.Point2d;
7 import org.djutils.exceptions.Throw;
8 import org.djutils.math.AngleUtil;
9
10
11
12
13
14
15
16
17
18
19
20 public class Arc2d implements Curvature, Curve2d, OffsetCurve2d
21 {
22
23
24 private final DirectedPoint2d startPoint;
25
26
27 private final double radius;
28
29
30 private final double angle;
31
32
33 private final double sign;
34
35
36 private final Point2d center;
37
38
39
40
41
42
43
44
45 public Arc2d(final DirectedPoint2d startPoint, final double radius, final boolean left, final double angle)
46 {
47 Throw.whenNull(startPoint, "startPoint");
48 Throw.when(radius < 0.0, IllegalArgumentException.class, "radius must be positive");
49 Throw.when(angle < 0.0, IllegalArgumentException.class, "angle must be positive");
50 this.startPoint = startPoint;
51 this.radius = radius;
52 this.sign = left ? 1.0 : -1.0;
53 this.angle = angle;
54 double dx = Math.cos(startPoint.dirZ) * this.sign * radius;
55 double dy = Math.sin(startPoint.dirZ) * this.sign * radius;
56 this.center = new Point2d(startPoint.x - dy, startPoint.y + dx);
57 }
58
59 @Override
60 public double getStartCurvature()
61 {
62 return 1.0 / this.radius;
63 }
64
65 @Override
66 public double getEndCurvature()
67 {
68 return getStartCurvature();
69 }
70
71 @Override
72 public double getStartRadius()
73 {
74 return this.radius;
75 }
76
77 @Override
78 public double getEndRadius()
79 {
80 return this.radius;
81 }
82
83
84
85
86
87 public boolean isLeft()
88 {
89 return this.sign > 0;
90 }
91
92
93
94
95
96 public double getAngle()
97 {
98 return this.angle;
99 }
100
101
102
103
104
105
106
107 private Point2d getPoint(final double fraction, final double offset)
108 {
109 double len = this.radius - this.sign * offset;
110 double a = this.startPoint.dirZ + this.sign * this.angle * fraction;
111 double dx = this.sign * Math.cos(a) * len;
112 double dy = this.sign * Math.sin(a) * len;
113 return new Point2d(this.center.x + dy, this.center.y - dx);
114 }
115
116 @Override
117 public Point2d getPoint(final double fraction)
118 {
119 return getPoint(fraction, 0);
120 }
121
122 @Override
123 public Point2d getPoint(final double fraction, final ContinuousPiecewiseLinearFunction of)
124 {
125 return getPoint(fraction, of.get(fraction));
126 }
127
128 @Override
129 public Double getDirection(final double fraction)
130 {
131 return AngleUtil.normalizeAroundZero(this.startPoint.dirZ + this.sign * this.angle * fraction);
132 }
133
134 @Override
135 public double getDirection(final double fraction, final ContinuousPiecewiseLinearFunction of)
136 {
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151 double phi = (Arc2d.this.startPoint.dirZ + Arc2d.this.sign * (Arc2d.this.angle * fraction - Math.PI / 2));
152 double sinPhi = Math.sin(phi);
153 double cosPhi = Math.cos(phi);
154 double sPhi = Arc2d.this.sign * of.get(fraction);
155 double sPhiD = of.getDerivative(fraction) / Arc2d.this.angle;
156 double dx = -sinPhi * (Arc2d.this.radius - sPhi) - cosPhi * sPhiD;
157 double dy = cosPhi * (Arc2d.this.radius - sPhi) - sinPhi * sPhiD;
158 double direction = Math.atan2(Arc2d.this.sign * dy, Arc2d.this.sign * dx);
159 return direction;
160 }
161
162 @Override
163 public PolyLine2d toPolyLine(final Flattener2d flattener)
164 {
165 Throw.whenNull(flattener, "Flattener");
166 return flattener.flatten(this);
167 }
168
169 @Override
170 public PolyLine2d toPolyLine(final OffsetFlattener2d flattener, final ContinuousPiecewiseLinearFunction offsets)
171 {
172 Throw.whenNull(offsets, "Offsets");
173 return flattener.flatten(this, offsets);
174 }
175
176 @Override
177 public double getLength()
178 {
179 return this.angle * this.radius;
180 }
181
182 @Override
183 public String toString()
184 {
185 return "Arc [startPoint=" + this.startPoint + ", radius=" + this.radius + ", angle=" + this.angle + ", left="
186 + (this.sign > 0.0) + "]";
187 }
188
189 }