1
2
3
4
5
6
7
8
9 package org.locationtech.spatial4j.shape.impl;
10
11 import org.locationtech.spatial4j.shape.Point;
12 import org.locationtech.spatial4j.shape.Rectangle;
13 import org.locationtech.spatial4j.shape.SpatialRelation;
14
15 import static org.locationtech.spatial4j.shape.SpatialRelation.*;
16
17
18
19
20
21 public class InfBufLine {
22
23
24 private static final double EPS = 10e-14;
25
26
27
28
29
30
31
32 private final double slope;
33
34 private final double intercept;
35
36 private final double buf;
37
38 private final double distDenomInv;
39
40 InfBufLine(double slope, Point point, double buf) {
41 assert !Double.isNaN(slope);
42 this.slope = slope;
43 if (Double.isInfinite(slope)) {
44 intercept = point.getX();
45 distDenomInv = Double.NaN;
46 } else {
47 intercept = point.getY() - slope * point.getX();
48 distDenomInv = 1 / Math.sqrt(slope * slope + 1);
49 }
50 this.buf = buf;
51 }
52
53 SpatialRelation relate(Rectangle r, Point prC, Point scratch) {
54 assert r.getCenter().equals(prC);
55
56 int cQuad = quadrant(prC);
57
58 Point nearestP = scratch;
59 cornerByQuadrant(r, oppositeQuad[cQuad], nearestP);
60 boolean nearestContains = contains(nearestP);
61
62 if (nearestContains) {
63 Point farthestP = scratch;
64 nearestP = null;
65 cornerByQuadrant(r, cQuad, farthestP);
66 boolean farthestContains = contains(farthestP);
67 if (farthestContains)
68 return CONTAINS;
69 return INTERSECTS;
70 } else {
71 if (quadrant(nearestP) == cQuad)
72 return DISJOINT;
73 return INTERSECTS;
74 }
75 }
76
77 boolean contains(Point p) {
78 return (distanceUnbuffered(p) <= buf + EPS);
79 }
80
81
82 public double distanceUnbuffered(Point c) {
83 if (Double.isInfinite(slope))
84 return Math.abs(c.getX() - intercept);
85
86 double num = Math.abs(c.getY() - slope * c.getX() - intercept);
87 return num * distDenomInv;
88 }
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 public int quadrant(Point c) {
105
106 if (Double.isInfinite(slope)) {
107
108 return c.getX() > intercept ? 1 : 2;
109 }
110
111
112 double yAtCinLine = slope * c.getX() + intercept;
113 boolean above = c.getY() >= yAtCinLine;
114 if (slope > 0) {
115
116 return above ? 2 : 4;
117 } else {
118
119 return above ? 1 : 3;
120 }
121 }
122
123
124
125
126 private static final int[] oppositeQuad= {-1,3,4,1,2};
127
128 public static void cornerByQuadrant(Rectangle r, int cornerQuad, Point out) {
129 double x = (cornerQuad == 1 || cornerQuad == 4) ? r.getMaxX() : r.getMinX();
130 double y = (cornerQuad == 1 || cornerQuad == 2) ? r.getMaxY() : r.getMinY();
131 out.reset(x, y);
132 }
133
134 public double getSlope() {
135 return slope;
136 }
137
138 public double getIntercept() {
139 return intercept;
140 }
141
142 public double getBuf() {
143 return buf;
144 }
145
146
147 public double getDistDenomInv() {
148 return distDenomInv;
149 }
150
151 @Override
152 public String toString() {
153 return "InfBufLine{" +
154 "buf=" + buf +
155 ", intercept=" + intercept +
156 ", slope=" + slope +
157 '}';
158 }
159 }