-
Notifications
You must be signed in to change notification settings - Fork 34
/
Circumcircle.java
240 lines (218 loc) · 6.88 KB
/
Circumcircle.java
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/*
* Copyright 2014 Gary W. Lucas.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* -----------------------------------------------------------------------
*
* Revision History:
* Date Name Description
* ------ --------- -------------------------------------------------
* 04/2014 G. Lucas Created
*
* Notes:
*
* -----------------------------------------------------------------------
*/
package org.tinfour.common;
import java.awt.geom.Rectangle2D;
/**
* Provides center coordinates and radius for a circumcircle.
*/
public class Circumcircle {
/**
* The x coordinate of the center of the circumcircle.
*/
private double centerX;
/**
* The y coordinate of the center of the circumcircle.
*/
private double centerY;
/**
* The square of the radius of the center of the circumcircle.
*/
private double r2;
/**
* An arbitrary minimum area for which a circumcircle should be constructed
* in order to avoid failures due to numerical precision issues.
*/
private static final double MIN_TRIG_AREA = 1.0e-20;
/**
* Gets the square of the radius of the circumcircle.
*
* @return for a non-degenerate triangle, a positive floating point value
* (potentially Infinity for a ghost triangle).
*/
public double getRadiusSq() {
return r2;
}
/**
* Gets the radius of the circumcircle
* @return for a non-degenerate triangle, a positive floating point value
*/
public double getRadius(){
return Math.sqrt(r2);
}
/**
* Gets the x coordinate of the center of the circumcircle.
*
* @return a valid floating point value.
*/
public double getX() {
return centerX;
}
/**
* Gets the y coordinate of the center of the circumcircle.
*
* @return a valid floating point value.
*/
public double getY() {
return centerY;
}
/**
* Copies the content of the specified circumcircle instance.
*
* @param c a valid circumcircle instance.
*/
public void copy(final Circumcircle c) {
centerX = c.centerX;
centerY = c.centerY;
r2 = c.r2;
}
/**
* Computes the circumcircle for the specified vertices.
* Vertices are assumed to be given in counterclockwise order.
* Any null inputs for the vertices results in an infinite circumcircle.
* Vertices resulting in a degenerate (nearly zero area) triangle
* result in an infinite circumcircle.
*
* @param a the initial vertex.
* @param b the second vertex.
* @param c the third vertex.
* @return a valid circumcircle.
*/
public static Circumcircle computeCircumcircle(
final Vertex a,
final Vertex b,
final Vertex c) {
Circumcircle circle = new Circumcircle();
if (a == null || b == null || c == null) {
circle.centerX = Double.POSITIVE_INFINITY;
circle.centerY = Double.POSITIVE_INFINITY;
circle.r2 = Double.POSITIVE_INFINITY;
return circle;
}
circle.compute(a.getX(), a.getY(), b.getX(), b.getY(), c.getX(), c.getY());
return circle;
}
/**
* Computes the circumcircle for the specified vertices and stores
* results in elements of this instance.
* Vertices are assumed to be given in counterclockwise order.
* Any null inputs for the vertices results in an infinite circumcircle.
* Vertices resulting in a degenerate (nearly zero area) triangle
* result in an infinite circumcircle.
*
* @param a the initial vertex.
* @param b the second vertex.
* @param c the third vertex.
* @return true if the computation successfully yields a circle of
* finite radius; otherwise, false.
*
*/
public boolean compute(final Vertex a, final Vertex b, final Vertex c) {
if (a == null || b == null || c == null) {
centerX = Double.POSITIVE_INFINITY;
centerY = Double.POSITIVE_INFINITY;
r2 = Double.POSITIVE_INFINITY;
return false;
}
compute(a.getX(), a.getY(), b.getX(), b.getY(), c.getX(), c.getY());
return Double.isFinite(r2); // also covers NaN case
}
/**
* Computes the circumcircle for the specified vertices and stores
* results in elements of this instance.
* Vertices are assumed to be given in counterclockwise order.
* Any null inputs for the vertices results in an infinite circumcircle.
* Vertices resulting in a degenerate (nearly zero area) triangle
* result in an infinite circumcircle.
*
* @param x0 the x coordinate of the first vertex
* @param y0 the y coordinate of the first vertex
* @param x1 the x coordinate of the second vertex
* @param y1 the y coordinate of the second vertex
* @param x2 the x coordinate of the third vertex
* @param y2 the y coordinate of the third vertex
*
*/
public void compute(
final double x0,
final double y0,
final double x1,
final double y1,
final double x2,
final double y2) {
double bx, by, cx, cy, d, c2, b2;
bx = x1 - x0;
by = y1 - y0;
cx = x2 - x0;
cy = y2 - y0;
d = 2 * (bx * cy - by * cx);
if (Math.abs(d) < MIN_TRIG_AREA) {
// the triangle is close to the degenerate case
// (all 3 points in a straight line)
// even if determinant d is not zero, numeric precision
// issues might lead to a very poor computation for
// the circumcircle.
this.centerX = Double.POSITIVE_INFINITY;
this.centerY = Double.POSITIVE_INFINITY;
r2 = Double.POSITIVE_INFINITY;
return;
}
b2 = bx * bx + by * by;
c2 = cx * cx + cy * cy;
this.centerX = (cy * b2 - by * c2) / d;
this.centerY = (bx * c2 - cx * b2) / d;
r2 = this.centerX * this.centerX + this.centerY * this.centerY;
this.centerX += x0;
this.centerY += y0;
}
/**
* Sets the coordinate for the circumcenter and radius for this
* instance.
*
* @param x the x coordinate for the circumcenter
* @param y the y coordinate for the circumcenter
* @param r2 the square of the radius for the circumcircle
*/
public void setCircumcenter(final double x, final double y, final double r2) {
this.centerX = x;
this.centerY = y;
this.r2 = r2;
}
@Override
public String toString(){
return String.format("(%7.4f,%7.4f) r=%6.4f",
centerX, centerY, Math.sqrt(r2));
}
/**
* Gets the bounds of the circumcircle.
* @return a valid rectangle instance.
*/
public Rectangle2D getBounds(){
double r = getRadius();
return new Rectangle2D.Double(centerX-r, centerY-r, 2*r, 2*r);
}
}