/src/geos/src/operation/distance/FacetSequence.cpp
Line | Count | Source |
1 | | /********************************************************************** |
2 | | * |
3 | | * GEOS - Geometry Engine Open Source |
4 | | * http://geos.osgeo.org |
5 | | * |
6 | | * Copyright (C) 2016 Daniel Baston |
7 | | * |
8 | | * This is free software; you can redistribute and/or modify it under |
9 | | * the terms of the GNU Lesser General Public Licence as published |
10 | | * by the Free Software Foundation. |
11 | | * See the COPYING file for more information. |
12 | | * |
13 | | ********************************************************************** |
14 | | * |
15 | | * Last port: operation/distance/FacetSequence.java (f6187ee2 JTS-1.14) |
16 | | * |
17 | | **********************************************************************/ |
18 | | |
19 | | #include <geos/algorithm/Distance.h> |
20 | | #include <geos/operation/distance/FacetSequence.h> |
21 | | |
22 | | #include <memory> |
23 | | |
24 | | using namespace geos::geom; |
25 | | using namespace geos::operation::distance; |
26 | | using namespace geos::algorithm; |
27 | | |
28 | | FacetSequence::FacetSequence(const Geometry *p_geom, const CoordinateSequence* p_pts, std::size_t p_start, std::size_t p_end) : |
29 | 0 | pts(p_pts), |
30 | 0 | start(p_start), |
31 | 0 | end(p_end), |
32 | 0 | geom(p_geom) |
33 | 0 | { |
34 | 0 | computeEnvelope(); |
35 | 0 | } |
36 | | |
37 | | FacetSequence::FacetSequence(const CoordinateSequence* p_pts, std::size_t p_start, std::size_t p_end) : |
38 | 0 | pts(p_pts), |
39 | 0 | start(p_start), |
40 | 0 | end(p_end), |
41 | 0 | geom(nullptr) |
42 | 0 | { |
43 | 0 | computeEnvelope(); |
44 | 0 | } |
45 | | |
46 | | size_t |
47 | | FacetSequence::size() const |
48 | 0 | { |
49 | 0 | return end - start; |
50 | 0 | } |
51 | | |
52 | | bool |
53 | | FacetSequence::isPoint() const |
54 | 0 | { |
55 | 0 | return end - start == 1; |
56 | 0 | } |
57 | | |
58 | | double |
59 | | FacetSequence::distance(const FacetSequence& facetSeq) const |
60 | 0 | { |
61 | 0 | bool isPointThis = isPoint(); |
62 | 0 | bool isPointOther = facetSeq.isPoint(); |
63 | |
|
64 | 0 | if(isPointThis && isPointOther) { |
65 | 0 | const Coordinate& pt = pts->getAt(start); |
66 | 0 | const Coordinate& seqPt = facetSeq.pts->getAt(facetSeq.start); |
67 | 0 | return pt.distance(seqPt); |
68 | 0 | } |
69 | 0 | else if(isPointThis) { |
70 | 0 | const Coordinate& pt = pts->getAt(start); |
71 | 0 | return computeDistancePointLine(pt, facetSeq, nullptr); |
72 | 0 | } |
73 | 0 | else if(isPointOther) { |
74 | 0 | const Coordinate& seqPt = facetSeq.pts->getAt(facetSeq.start); |
75 | 0 | return computeDistancePointLine(seqPt, *this, nullptr); |
76 | 0 | } |
77 | 0 | else { |
78 | 0 | return computeDistanceLineLine(facetSeq, nullptr); |
79 | 0 | } |
80 | 0 | } |
81 | | |
82 | | /* |
83 | | * Rather than get bent out of shape about returning a pointer |
84 | | * just return the whole mess, since it only ends up holding two |
85 | | * locations. |
86 | | */ |
87 | | std::vector<GeometryLocation> |
88 | | FacetSequence::nearestLocations(const FacetSequence& facetSeq) const |
89 | 0 | { |
90 | 0 | bool isPointThis = isPoint(); |
91 | 0 | bool isPointOther = facetSeq.isPoint(); |
92 | 0 | std::vector<GeometryLocation> locs; |
93 | 0 | if (isPointThis && isPointOther) { |
94 | 0 | const Coordinate& pt = pts->getAt(start); |
95 | 0 | const Coordinate& seqPt = facetSeq.pts->getAt(facetSeq.start); |
96 | 0 | GeometryLocation gl1(geom, start, pt); |
97 | 0 | GeometryLocation gl2(facetSeq.geom, facetSeq.start, seqPt); |
98 | 0 | locs.clear(); |
99 | 0 | locs.push_back(gl1); |
100 | 0 | locs.push_back(gl2); |
101 | 0 | } |
102 | 0 | else if (isPointThis) { |
103 | 0 | const Coordinate& pt = pts->getAt(start); |
104 | 0 | computeDistancePointLine(pt, facetSeq, &locs); |
105 | 0 | } |
106 | 0 | else if (isPointOther) { |
107 | 0 | const Coordinate& seqPt = facetSeq.pts->getAt(facetSeq.start); |
108 | 0 | computeDistancePointLine(seqPt, *this, &locs); |
109 | | // unflip the locations |
110 | 0 | GeometryLocation tmp = locs[0]; |
111 | 0 | locs[0] = locs[1]; |
112 | 0 | locs[1] = tmp; |
113 | 0 | } |
114 | 0 | else { |
115 | 0 | computeDistanceLineLine(facetSeq, &locs); |
116 | 0 | } |
117 | 0 | return locs; |
118 | 0 | } |
119 | | |
120 | | double |
121 | | FacetSequence::computeDistancePointLine(const Coordinate& pt, |
122 | | const FacetSequence& facetSeq, |
123 | | std::vector<GeometryLocation> *locs) const |
124 | 0 | { |
125 | 0 | double minDistance = DoubleInfinity; |
126 | |
|
127 | 0 | for(std::size_t i = facetSeq.start; i < facetSeq.end - 1; i++) { |
128 | 0 | const Coordinate& q0 = facetSeq.pts->getAt(i); |
129 | 0 | const Coordinate& q1 = facetSeq.pts->getAt(i + 1); |
130 | 0 | double dist = Distance::pointToSegment(pt, q0, q1); |
131 | 0 | if(dist < minDistance || (locs != nullptr && locs->empty())) { |
132 | 0 | minDistance = dist; |
133 | 0 | if (locs != nullptr) { |
134 | 0 | updateNearestLocationsPointLine(pt, facetSeq, i, q0, q1, locs); |
135 | 0 | } |
136 | 0 | if(minDistance <= 0.0) { |
137 | 0 | return minDistance; |
138 | 0 | } |
139 | 0 | } |
140 | 0 | } |
141 | | |
142 | 0 | return minDistance; |
143 | 0 | } |
144 | | |
145 | | void |
146 | | FacetSequence::updateNearestLocationsPointLine(const Coordinate& pt, |
147 | | const FacetSequence& facetSeq, std::size_t i, |
148 | | const Coordinate& q0, const Coordinate &q1, |
149 | | std::vector<GeometryLocation> *locs) const |
150 | 0 | { |
151 | 0 | geom::LineSegment seg(q0, q1); |
152 | 0 | Coordinate segClosestPoint; |
153 | 0 | seg.closestPoint(pt, segClosestPoint); |
154 | 0 | locs->clear(); |
155 | 0 | locs->emplace_back(geom, start, pt); |
156 | 0 | locs->emplace_back(facetSeq.geom, i, segClosestPoint); |
157 | 0 | return; |
158 | 0 | } |
159 | | |
160 | | double |
161 | | FacetSequence::computeDistanceLineLine(const FacetSequence& facetSeq, std::vector<GeometryLocation> *locs) const |
162 | 0 | { |
163 | 0 | double minDistance = DoubleInfinity; |
164 | |
|
165 | 0 | for(std::size_t i = start; i < end - 1; i++) { |
166 | 0 | const Coordinate& p0 = pts->getAt(i); |
167 | 0 | const Coordinate& p1 = pts->getAt(i + 1); |
168 | | |
169 | | // Avoid calculating distance from zero-length segment |
170 | 0 | if (p0 == p1) |
171 | 0 | continue; |
172 | | |
173 | 0 | Envelope pEnv(p0, p1); |
174 | 0 | if (pEnv.distanceSquared(*facetSeq.getEnvelope()) > minDistance*minDistance) { |
175 | 0 | continue; |
176 | 0 | } |
177 | | |
178 | 0 | for(std::size_t j = facetSeq.start; j < facetSeq.end - 1; j++) { |
179 | 0 | const Coordinate& q0 = facetSeq.pts->getAt(j); |
180 | 0 | const Coordinate& q1 = facetSeq.pts->getAt(j + 1); |
181 | | |
182 | | // Avoid calculating distance to zero-length segment |
183 | 0 | if (q0 == q1) |
184 | 0 | continue; |
185 | | |
186 | 0 | Envelope qEnv(q0, q1); |
187 | 0 | if (pEnv.distanceSquared(qEnv) > minDistance*minDistance) { |
188 | 0 | continue; |
189 | 0 | } |
190 | | |
191 | 0 | double dist = Distance::segmentToSegment(p0, p1, q0, q1); |
192 | 0 | if(dist <= minDistance) { |
193 | 0 | minDistance = dist; |
194 | 0 | if(locs != nullptr) { |
195 | 0 | updateNearestLocationsLineLine(i, p0, p1, facetSeq, j, q0, q1, locs); |
196 | 0 | } |
197 | 0 | if(minDistance <= 0.0) return minDistance; |
198 | 0 | } |
199 | 0 | } |
200 | 0 | } |
201 | | |
202 | 0 | return minDistance; |
203 | 0 | } |
204 | | |
205 | | void |
206 | | FacetSequence::updateNearestLocationsLineLine(std::size_t i, const Coordinate& p0, const Coordinate& p1, |
207 | | const FacetSequence& facetSeq, |
208 | | std::size_t j, const Coordinate& q0, const Coordinate &q1, |
209 | | std::vector<GeometryLocation> *locs) const |
210 | 0 | { |
211 | 0 | LineSegment seg0(p0, p1); |
212 | 0 | LineSegment seg1(q0, q1); |
213 | |
|
214 | 0 | auto closestPts = seg0.closestPoints(seg1); |
215 | |
|
216 | 0 | locs->clear(); |
217 | 0 | locs->emplace_back(geom, i, closestPts[0]); |
218 | 0 | locs->emplace_back(facetSeq.geom, j, closestPts[1]); |
219 | 0 | } |
220 | | |
221 | | void |
222 | | FacetSequence::computeEnvelope() |
223 | 0 | { |
224 | 0 | env = Envelope(); |
225 | 0 | for(std::size_t i = start; i < end; i++) { |
226 | 0 | env.expandToInclude(pts->getAt(i)); |
227 | 0 | } |
228 | 0 | } |
229 | | |
230 | | const Envelope* |
231 | | FacetSequence::getEnvelope() const |
232 | 0 | { |
233 | 0 | return &env; |
234 | 0 | } |
235 | | |
236 | | const Coordinate* |
237 | | FacetSequence::getCoordinate(std::size_t index) const |
238 | 0 | { |
239 | 0 | return &(pts->getAt(start + index)); |
240 | 0 | } |
241 | | |