1
2
3
4
5
6
7
8
9 package org.locationtech.spatial4j.shape.impl;
10
11 import org.locationtech.spatial4j.context.SpatialContext;
12 import org.locationtech.spatial4j.shape.BaseShape;
13 import org.locationtech.spatial4j.shape.Circle;
14 import org.locationtech.spatial4j.shape.Point;
15 import org.locationtech.spatial4j.shape.Rectangle;
16 import org.locationtech.spatial4j.shape.Shape;
17 import org.locationtech.spatial4j.shape.SpatialRelation;
18
19
20
21
22
23
24
25 public class CircleImpl extends BaseShape<SpatialContext> implements Circle {
26
27 protected final Point point;
28 protected double radiusDEG;
29
30
31 protected Rectangle enclosingBox;
32
33 public CircleImpl(Point p, double radiusDEG, SpatialContext ctx) {
34 super(ctx);
35
36 this.point = p;
37 this.radiusDEG = point.isEmpty() ? Double.NaN : radiusDEG;
38 this.enclosingBox = point.isEmpty() ? ctx.makeRectangle(Double.NaN, Double.NaN, Double.NaN, Double.NaN) :
39 ctx.getDistCalc().calcBoxByDistFromPt(point, this.radiusDEG, ctx, null);
40 }
41
42 @Override
43 public void reset(double x, double y, double radiusDEG) {
44 assert ! isEmpty();
45 point.reset(x, y);
46 this.radiusDEG = radiusDEG;
47 this.enclosingBox = ctx.getDistCalc().calcBoxByDistFromPt(point, this.radiusDEG, ctx, enclosingBox);
48 }
49
50 @Override
51 public boolean isEmpty() {
52 return point.isEmpty();
53 }
54
55 @Override
56 public Point getCenter() {
57 return point;
58 }
59
60 @Override
61 public double getRadius() {
62 return radiusDEG;
63 }
64
65 @Override
66 public double getArea(SpatialContext ctx) {
67 if (ctx == null) {
68 return Math.PI * radiusDEG * radiusDEG;
69 } else {
70 return ctx.getDistCalc().area(this);
71 }
72 }
73
74 @Override
75 public Circle getBuffered(double distance, SpatialContext ctx) {
76 return ctx.makeCircle(point, distance + radiusDEG);
77 }
78
79 public boolean contains(double x, double y) {
80 return ctx.getDistCalc().within(point, x, y, radiusDEG);
81 }
82
83 @Override
84 public boolean hasArea() {
85 return radiusDEG > 0;
86 }
87
88
89
90
91 @Override
92 public Rectangle getBoundingBox() {
93 return enclosingBox;
94 }
95
96 @Override
97 public SpatialRelation relate(Shape other) {
98
99
100
101
102 if (isEmpty() || other.isEmpty())
103 return SpatialRelation.DISJOINT;
104 if (other instanceof Point) {
105 return relate((Point) other);
106 }
107 if (other instanceof Rectangle) {
108 return relate((Rectangle) other);
109 }
110 if (other instanceof Circle) {
111 return relate((Circle) other);
112 }
113 return other.relate(this).transpose();
114 }
115
116 public SpatialRelation relate(Point point) {
117 return contains(point.getX(),point.getY()) ? SpatialRelation.CONTAINS : SpatialRelation.DISJOINT;
118 }
119
120 public SpatialRelation relate(Rectangle r) {
121
122
123
124 final SpatialRelation bboxSect = enclosingBox.relate(r);
125 if (bboxSect == SpatialRelation.DISJOINT || bboxSect == SpatialRelation.WITHIN)
126 return bboxSect;
127 else if (bboxSect == SpatialRelation.CONTAINS && enclosingBox.equals(r))
128 return SpatialRelation.WITHIN;
129
130
131
132 return relateRectanglePhase2(r, bboxSect);
133 }
134
135 protected SpatialRelation relateRectanglePhase2(final Rectangle r, SpatialRelation bboxSect) {
136
137
138
139
140
141
142
143 final double closestX, farthestX;
144 final double xAxis = getXAxis();
145 if (xAxis < r.getMinX()) {
146 closestX = r.getMinX();
147 farthestX = r.getMaxX();
148 } else if (xAxis > r.getMaxX()) {
149 closestX = r.getMaxX();
150 farthestX = r.getMinX();
151 } else {
152 closestX = xAxis;
153 farthestX = r.getMaxX() - xAxis > xAxis - r.getMinX() ? r.getMaxX() : r.getMinX();
154 }
155
156 final double closestY, farthestY;
157 final double yAxis = getYAxis();
158 if (yAxis < r.getMinY()) {
159 closestY = r.getMinY();
160 farthestY = r.getMaxY();
161 } else if (yAxis > r.getMaxY()) {
162 closestY = r.getMaxY();
163 farthestY = r.getMinY();
164 } else {
165 closestY = yAxis;
166 farthestY = r.getMaxY() - yAxis > yAxis - r.getMinY() ? r.getMaxY() : r.getMinY();
167 }
168
169
170 if (xAxis != closestX && yAxis != closestY) {
171 if (!contains(closestX, closestY))
172 return SpatialRelation.DISJOINT;
173 }
174
175
176
177
178
179 if (bboxSect != SpatialRelation.CONTAINS)
180 return SpatialRelation.INTERSECTS;
181
182
183
184 if (!contains(farthestX, farthestY))
185 return SpatialRelation.INTERSECTS;
186
187
188
189 if (point.getY() != getYAxis()) {
190 if (yAxis == closestY) {
191 double otherY = (farthestY == r.getMaxY() ? r.getMinY() : r.getMaxY());
192 if (!contains(farthestX, otherY))
193 return SpatialRelation.INTERSECTS;
194 }
195 }
196
197 return SpatialRelation.CONTAINS;
198 }
199
200
201
202
203 protected double getYAxis() {
204 return point.getY();
205 }
206
207
208
209
210 protected double getXAxis() {
211 return point.getX();
212 }
213
214 public SpatialRelation relate(Circle circle) {
215 double crossDist = ctx.getDistCalc().distance(point, circle.getCenter());
216 double aDist = radiusDEG, bDist = circle.getRadius();
217 if (crossDist > aDist + bDist)
218 return SpatialRelation.DISJOINT;
219 if (crossDist < aDist && crossDist + bDist <= aDist)
220 return SpatialRelation.CONTAINS;
221 if (crossDist < bDist && crossDist + aDist <= bDist)
222 return SpatialRelation.WITHIN;
223
224 return SpatialRelation.INTERSECTS;
225 }
226
227 @Override
228 public String toString() {
229 return "Circle(" + point + ", d=" + radiusDEG + "°)";
230 }
231
232 @Override
233 public boolean equals(Object obj) {
234 return equals(this,obj);
235 }
236
237
238
239
240 public static boolean equals(Circle thiz, Object o) {
241 assert thiz != null;
242 if (thiz == o) return true;
243 if (!(o instanceof Circle)) return false;
244
245 Circle circle = (Circle) o;
246
247 if (!thiz.getCenter().equals(circle.getCenter())) return false;
248 if (Double.compare(circle.getRadius(), thiz.getRadius()) != 0) return false;
249
250 return true;
251 }
252
253 @Override
254 public int hashCode() {
255 return hashCode(this);
256 }
257
258
259
260
261 public static int hashCode(Circle thiz) {
262 int result;
263 long temp;
264 result = thiz.getCenter().hashCode();
265 temp = thiz.getRadius() != +0.0d ? Double.doubleToLongBits(thiz.getRadius()) : 0L;
266 result = 31 * result + (int) (temp ^ (temp >>> 32));
267 return result;
268 }
269 }