1 /**********************************************************************
2 *
3 * GEOS - Geometry Engine Open Source
4 * http://geos.osgeo.org
5 *
6 * Copyright (C) 2001-2002 Vivid Solutions Inc.
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: original (by strk)
16 *
17 **********************************************************************/
18
19 #include <geos/constants.h>
20 #include <geos/operation/overlay/ElevationMatrix.h>
21 #include <geos/util/IllegalArgumentException.h>
22 #include <geos/geom/Geometry.h>
23 #include <geos/geom/Coordinate.h>
24 #include <geos/geom/CoordinateSequence.h>
25
26 #include <cassert>
27 #include <cmath>
28 #include <iostream>
29 #include <sstream>
30 #include <string>
31
32 #ifndef GEOS_DEBUG
33 #define GEOS_DEBUG 0
34 #endif
35 #define PARANOIA_LEVEL 0
36
37 #ifdef _MSC_VER
38 #pragma warning(disable:4355)
39 #endif
40
41 using namespace std;
42 using namespace geos::geom;
43
44 namespace geos {
45 namespace operation { // geos.operation
46 namespace overlay { // geos.operation.overlay
47
ElevationMatrixFilter(ElevationMatrix & newEm)48 ElevationMatrixFilter::ElevationMatrixFilter(ElevationMatrix& newEm):
49 em(newEm)
50 { }
51
52 void
filter_rw(Coordinate * c) const53 ElevationMatrixFilter::filter_rw(Coordinate* c) const
54 {
55 #if GEOS_DEBUG
56 cerr << "ElevationMatrixFilter::filter_rw(" << c->toString() << ") called"
57 << endl;
58 #endif
59
60 // already has a Z value, nothing to do
61 if(! std::isnan(c->z)) {
62 return;
63 }
64
65 double p_avgElevation = em.getAvgElevation();
66
67 try {
68 const ElevationMatrixCell& emc = em.getCell(*c);
69 c->z = emc.getAvg();
70 if(std::isnan(c->z)) {
71 c->z = p_avgElevation;
72 }
73 #if GEOS_DEBUG
74 cerr << " z set to " << c->z << endl;
75 #endif
76 }
77 catch(const util::IllegalArgumentException& /* ex */) {
78 c->z = avgElevation;
79 }
80 }
81
82 void
filter_ro(const Coordinate * c)83 ElevationMatrixFilter::filter_ro(const Coordinate* c)
84 {
85 #if GEOS_DEBUG
86 cerr << "ElevationMatrixFilter::filter_ro(" << c->toString() << ") called"
87 << endl;
88 #endif
89 em.add(*c);
90 }
91
92
ElevationMatrix(const Envelope & newEnv,unsigned int newRows,unsigned int newCols)93 ElevationMatrix::ElevationMatrix(const Envelope& newEnv,
94 unsigned int newRows, unsigned int newCols):
95 filter(*this),
96 env(newEnv), cols(newCols), rows(newRows),
97 avgElevationComputed(false),
98 avgElevation(DoubleNotANumber),
99 cells(newRows * newCols)
100 {
101 cellwidth = env.getWidth() / cols;
102 cellheight = env.getHeight() / rows;
103 if(! cellwidth) {
104 cols = 1;
105 }
106 if(! cellheight) {
107 rows = 1;
108 }
109 }
110
111 void
add(const Geometry * geom)112 ElevationMatrix::add(const Geometry* geom)
113 {
114 #if GEOS_DEBUG
115 cerr << "ElevationMatrix::add(Geometry *) called" << endl;
116 #endif // GEOS_DEBUG
117
118 // Cannot add Geometries to an ElevationMatrix after it's average
119 // elevation has been computed
120 assert(!avgElevationComputed);
121
122 //ElevationMatrixFilter filter(this);
123 geom->apply_ro(&filter);
124
125 }
126
127 #if 0
128 void
129 ElevationMatrix::add(const CoordinateSequence* cs)
130 {
131 unsigned int ncoords = cs->getSize();
132 for(unsigned int i = 0; i < ncoords; i++) {
133 add(cs->getAt(i));
134 }
135 }
136 #endif
137
138 void
add(const Coordinate & c)139 ElevationMatrix::add(const Coordinate& c)
140 {
141 if(std::isnan(c.z)) {
142 return;
143 }
144 try {
145 ElevationMatrixCell& emc = getCell(c);
146 emc.add(c);
147 }
148 catch(const util::IllegalArgumentException& exp) {
149 // coordinate do not overlap matrix
150 cerr << "ElevationMatrix::add(" << c.toString()
151 << "): Coordinate does not overlap grid extent: "
152 << exp.what() << endl;
153 return;
154 }
155 }
156
157 ElevationMatrixCell&
getCell(const Coordinate & c)158 ElevationMatrix::getCell(const Coordinate& c)
159 {
160 int col, row;
161
162 if(! cellwidth) {
163 col = 0;
164 }
165 else {
166 double xoffset = c.x - env.getMinX();
167 col = (int)(xoffset / cellwidth);
168 if(col == (int)cols) {
169 col = cols - 1;
170 }
171 }
172 if(! cellheight) {
173 row = 0;
174 }
175 else {
176 double yoffset = c.y - env.getMinY();
177 row = (int)(yoffset / cellheight);
178 if(row == (int)rows) {
179 row = rows - 1;
180 }
181 }
182 int celloffset = (cols * row) + col;
183
184 if(celloffset < 0 || celloffset >= (int)(cols * rows)) {
185 ostringstream s;
186 s << "ElevationMatrix::getCell got a Coordinate out of grid extent (" << env.toString() << ") - cols:" << cols <<
187 " rows:" << rows;
188 throw util::IllegalArgumentException(s.str());
189 }
190
191 return cells[celloffset];
192 }
193
194 const ElevationMatrixCell&
getCell(const Coordinate & c) const195 ElevationMatrix::getCell(const Coordinate& c) const
196 {
197 return (const ElevationMatrixCell&)
198 ((ElevationMatrix*)this)->getCell(c);
199 }
200
201 double
getAvgElevation() const202 ElevationMatrix::getAvgElevation() const
203 {
204 if(avgElevationComputed) {
205 return avgElevation;
206 }
207 double ztot = 0;
208 int zvals = 0;
209 for(unsigned int r = 0; r < rows; r++) {
210 for(unsigned int c = 0; c < cols; c++) {
211 const ElevationMatrixCell& cell = cells[(r * cols) + c];
212 double e = cell.getAvg();
213 if(!std::isnan(e)) {
214 zvals++;
215 ztot += e;
216 }
217 }
218 }
219 if(zvals) {
220 avgElevation = ztot / zvals;
221 }
222 else {
223 avgElevation = DoubleNotANumber;
224 }
225
226 avgElevationComputed = true;
227
228 return avgElevation;
229 }
230
231 string
print() const232 ElevationMatrix::print() const
233 {
234 ostringstream ret;
235 ret << "Cols:" << cols << " Rows:" << rows << " AvgElevation:" << getAvgElevation() << endl;
236 for(unsigned int r = 0; r < rows; r++) {
237 for(unsigned int c = 0; c < cols; c++) {
238 ret << cells[(r * cols) + c].print() << '\t';
239 }
240 ret << endl;
241 }
242 return ret.str();
243 }
244
245 void
elevate(Geometry * g) const246 ElevationMatrix::elevate(Geometry* g) const
247 {
248
249 // Nothing to do if no elevation info in matrix
250 if(std::isnan(getAvgElevation())) {
251 return;
252 }
253
254 g->apply_rw(&filter);
255 }
256
257 } // namespace geos.operation.overlay
258 } // namespace geos.operation
259 } // namespace geos;
260