/src/geos/src/coverage/CoverageEdge.cpp
Line | Count | Source |
1 | | /********************************************************************** |
2 | | * |
3 | | * GEOS - Geometry Engine Open Source |
4 | | * http://geos.osgeo.org |
5 | | * |
6 | | * Copyright (C) 2022 Paul Ramsey <pramsey@cleverelephant.ca> |
7 | | * Copyright (c) 2022 Martin Davis. |
8 | | * |
9 | | * This is free software; you can redistribute and/or modify it under |
10 | | * the terms of the GNU Lesser General Public Licence as published |
11 | | * by the Free Software Foundation. |
12 | | * See the COPYING file for more information. |
13 | | * |
14 | | **********************************************************************/ |
15 | | |
16 | | #include <geos/coverage/CoverageEdge.h> |
17 | | |
18 | | #include <geos/geom/Coordinate.h> |
19 | | #include <geos/geom/GeometryFactory.h> |
20 | | #include <geos/geom/LinearRing.h> |
21 | | #include <geos/geom/LineSegment.h> |
22 | | #include <geos/util/IllegalStateException.h> |
23 | | |
24 | | |
25 | | using geos::geom::Coordinate; |
26 | | using geos::geom::GeometryFactory; |
27 | | using geos::geom::LinearRing; |
28 | | using geos::geom::LineSegment; |
29 | | using geos::geom::MultiLineString; |
30 | | using geos::geom::LineString; |
31 | | using geos::geom::CoordinateSequence; |
32 | | |
33 | | |
34 | | namespace geos { // geos |
35 | | namespace coverage { // geos.coverage |
36 | | |
37 | | /* public static */ |
38 | | std::unique_ptr<CoverageEdge> |
39 | | CoverageEdge::createEdge(const CoordinateSequence& ring) |
40 | 0 | { |
41 | 0 | auto pts = extractEdgePoints(ring, 0, ring.getSize() - 1); |
42 | 0 | return detail::make_unique<CoverageEdge>(std::move(pts), true); |
43 | 0 | } |
44 | | |
45 | | /* public static */ |
46 | | std::unique_ptr<CoverageEdge> |
47 | | CoverageEdge::createEdge(const CoordinateSequence& ring, |
48 | | std::size_t start, std::size_t end) |
49 | 0 | { |
50 | 0 | auto pts = extractEdgePoints(ring, start, end); |
51 | 0 | return detail::make_unique<CoverageEdge>(std::move(pts), false); |
52 | 0 | } |
53 | | |
54 | | /* public static */ |
55 | | std::unique_ptr<MultiLineString> |
56 | | CoverageEdge::createLines( |
57 | | const std::vector<CoverageEdge*>& edges, |
58 | | const GeometryFactory* geomFactory) |
59 | 0 | { |
60 | 0 | std::vector<std::unique_ptr<LineString>> lines; |
61 | 0 | for (const CoverageEdge* edge : edges) { |
62 | 0 | auto cs = edge->getCoordinates()->clone(); |
63 | 0 | auto ls = geomFactory->createLineString(std::move(cs)); |
64 | 0 | lines.push_back(std::move(ls)); |
65 | 0 | } |
66 | 0 | return geomFactory->createMultiLineString(std::move(lines)); |
67 | 0 | } |
68 | | |
69 | | /* public */ |
70 | | std::unique_ptr<LineString> |
71 | | CoverageEdge::toLineString(const GeometryFactory* geomFactory) |
72 | 0 | { |
73 | 0 | const CoordinateSequence* cs = getCoordinates(); |
74 | 0 | return geomFactory->createLineString(cs->clone()); |
75 | 0 | } |
76 | | |
77 | | /* private static */ |
78 | | std::unique_ptr<CoordinateSequence> |
79 | | CoverageEdge::extractEdgePoints(const CoordinateSequence& ring, |
80 | | std::size_t start, std::size_t end) |
81 | 0 | { |
82 | 0 | auto pts = detail::make_unique<CoordinateSequence>(); |
83 | 0 | std::size_t size = start < end |
84 | 0 | ? end - start + 1 |
85 | 0 | : ring.getSize() - start + end; |
86 | 0 | std::size_t iring = start; |
87 | 0 | for (std::size_t i = 0; i < size; i++) { |
88 | 0 | pts->add(ring.getAt(iring)); |
89 | 0 | iring += 1; |
90 | 0 | if (iring >= ring.getSize()) |
91 | 0 | iring = 1; |
92 | 0 | } |
93 | 0 | return pts; |
94 | 0 | } |
95 | | |
96 | | |
97 | | /* public static */ |
98 | | LineSegment |
99 | | CoverageEdge::key(const CoordinateSequence& ring) |
100 | 0 | { |
101 | | // find lowest vertex index |
102 | 0 | std::size_t indexLow = 0; |
103 | 0 | for (std::size_t i = 1; i < ring.size() - 1; i++) { |
104 | 0 | if (ring.getAt(indexLow).compareTo(ring.getAt(i)) < 0) |
105 | 0 | indexLow = i; |
106 | 0 | } |
107 | 0 | const Coordinate& key0 = ring.getAt(indexLow); |
108 | | // find distinct adjacent vertices |
109 | 0 | const Coordinate& adj0 = findDistinctPoint(ring, indexLow, true, key0); |
110 | 0 | const Coordinate& adj1 = findDistinctPoint(ring, indexLow, false, key0); |
111 | 0 | const Coordinate& key1 = adj0.compareTo(adj1) < 0 ? adj0 : adj1; |
112 | 0 | return LineSegment(key0, key1); |
113 | 0 | } |
114 | | |
115 | | |
116 | | /* public static */ |
117 | | LineSegment |
118 | | CoverageEdge::key(const CoordinateSequence& ring, |
119 | | std::size_t start, std::size_t end) |
120 | 0 | { |
121 | | //-- endpoints are distinct in a line edge |
122 | 0 | const Coordinate& end0 = ring.getAt(start); |
123 | 0 | const Coordinate& end1 = ring.getAt(end); |
124 | 0 | bool isForward = 0 > end0.compareTo(end1); |
125 | 0 | const Coordinate* key0; |
126 | 0 | const Coordinate* key1; |
127 | 0 | if (isForward) { |
128 | 0 | key0 = &end0; |
129 | 0 | key1 = &findDistinctPoint(ring, start, true, *key0); |
130 | 0 | } |
131 | 0 | else { |
132 | 0 | key0 = &end1; |
133 | 0 | key1 = &findDistinctPoint(ring, end, false, *key0); |
134 | 0 | } |
135 | 0 | return LineSegment(*key0, *key1); |
136 | 0 | } |
137 | | |
138 | | /* private static */ |
139 | | const Coordinate& |
140 | | CoverageEdge::findDistinctPoint( |
141 | | const CoordinateSequence& pts, |
142 | | std::size_t index, |
143 | | bool isForward, |
144 | | const Coordinate& pt) |
145 | 0 | { |
146 | 0 | std::size_t i = index; |
147 | 0 | std::size_t endIndex = pts.size()-1; |
148 | 0 | do { |
149 | 0 | if (! pts.getAt(i).equals2D(pt)) { |
150 | 0 | return pts.getAt(i); |
151 | 0 | } |
152 | | // increment index with wrapping |
153 | 0 | if (isForward) { |
154 | 0 | i = (i == endIndex) ? 0 : (i+1); |
155 | 0 | } |
156 | 0 | else { |
157 | 0 | i = (i == 0) ? endIndex : (i-1); |
158 | 0 | } |
159 | |
|
160 | 0 | } while (i != index); |
161 | 0 | throw util::IllegalStateException("Edge does not contain distinct points"); |
162 | 0 | } |
163 | | |
164 | | |
165 | | |
166 | | // /* public */ |
167 | | // std::string toString() |
168 | | // { |
169 | | // return WKTWriter::toLineString(pts); |
170 | | // } |
171 | | |
172 | | |
173 | | |
174 | | } // namespace geos.coverage |
175 | | } // namespace geos |