Complete Note#1 in the http://wiki.osgeo.org/wiki/GEOS_Provenance_Review to get out...
[geos.git] / src / operation / overlay / validate / OverlayResultValidator.cpp
blobfa422b9dc8d9c39bd252d276554d08a0dc571e8d
1 /**********************************************************************
3 * GEOS - Geometry Engine Open Source
4 * http://geos.osgeo.org
6 * Copyright (C) 2006 Refractions Research Inc.
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.
13 ***********************************************************************
15 * Last port: operation/overlay/validate/OverlayResultValidator.java rev. 1.4 (JTS-1.10)
17 **********************************************************************/
19 #include <geos/operation/overlay/validate/OverlayResultValidator.h>
20 #include <geos/operation/overlay/validate/FuzzyPointLocator.h>
21 #include <geos/operation/overlay/validate/OffsetPointGenerator.h>
22 #include <geos/operation/overlay/snap/GeometrySnapper.h>
23 #include <geos/geom/CoordinateSequence.h>
24 #include <geos/geom/MultiPoint.h>
25 #include <geos/geom/GeometryFactory.h>
26 #include <geos/geom/CoordinateSequenceFactory.h>
28 #include <cassert>
29 #include <functional>
30 #include <vector>
31 #include <memory> // for auto_ptr
32 #include <algorithm> // for std::min etc.
34 #ifndef GEOS_DEBUG
35 #define GEOS_DEBUG 0
36 #endif
38 #if GEOS_DEBUG
39 #include <iomanip> // for setprecision
40 #endif
42 #define COMPUTE_Z 1
43 #define USE_ELEVATION_MATRIX 1
44 #define USE_INPUT_AVGZ 0
46 using namespace std;
47 using namespace geos::geom;
48 using namespace geos::geomgraph;
49 using namespace geos::algorithm;
51 namespace geos {
52 namespace operation { // geos.operation
53 namespace overlay { // geos.operation.overlay
54 namespace validate { // geos.operation.overlay.validate
56 namespace { // anonymous namespace
58 bool
59 isArea(const Geometry& g)
61 GeometryTypeId type = g.getGeometryTypeId();
62 if ( type == GEOS_POLYGON ) return true;
63 if ( type == GEOS_MULTIPOLYGON ) return true;
64 #if GEOS_DEBUG
65 cerr << "OverlayResultValidator: one of the geoms being checked is not a POLYGON or MULTIPOLYGON, blindly returning a positive answer (is valid)" << endl;
66 #endif
67 return false;
70 auto_ptr<MultiPoint>
71 toMultiPoint(vector<Coordinate>& coords)
73 const GeometryFactory& gf = *(GeometryFactory::getDefaultInstance());
74 const CoordinateSequenceFactory& csf =
75 *(gf.getCoordinateSequenceFactory());
77 auto_ptr< vector<Coordinate> > nc ( new vector<Coordinate>(coords) );
78 auto_ptr<CoordinateSequence> cs(csf.create(nc.release()));
80 auto_ptr<MultiPoint> mp ( gf.createMultiPoint(*cs) );
82 return mp;
85 } // anonymous namespace
88 /* static public */
89 bool
90 OverlayResultValidator::isValid(const Geometry& geom0, const Geometry& geom1,
91 OverlayOp::OpCode opCode,
92 const Geometry& result)
94 OverlayResultValidator validator(geom0, geom1, result);
95 return validator.isValid(opCode);
98 /*public*/
99 OverlayResultValidator::OverlayResultValidator(
100 const Geometry& geom0,
101 const Geometry& geom1,
102 const Geometry& result)
104 boundaryDistanceTolerance(
105 computeBoundaryDistanceTolerance(geom0, geom1)
107 g0(geom0),
108 g1(geom1),
109 gres(result),
110 fpl0(g0, boundaryDistanceTolerance),
111 fpl1(g1, boundaryDistanceTolerance),
112 fplres(gres, boundaryDistanceTolerance),
113 invalidLocation()
117 /*public*/
118 bool
119 OverlayResultValidator::isValid(OverlayOp::OpCode overlayOp)
121 // The check only works for areal geoms
122 #if 0 // now that FuzzyPointLocator extracts polygonal geoms,
123 // there should be no problem here
124 if ( ! isArea(g0) ) return true;
125 if ( ! isArea(g1) ) return true;
126 if ( ! isArea(gres) ) return true;
127 #endif
129 addTestPts(g0);
130 addTestPts(g1);
131 addTestPts(gres);
133 if (! testValid(overlayOp) )
135 #if GEOS_DEBUG
136 cerr << "OverlayResultValidator:" << endl
137 << "Points:" << *toMultiPoint(testCoords) << endl
138 << "Geom0: " << g0 << endl
139 << "Geom1: " << g1 << endl
140 << "Reslt: " << gres << endl
141 << "Locat: " << getInvalidLocation()
142 << endl;
143 #endif
144 return false;
148 return true;
151 /*private*/
152 void
153 OverlayResultValidator::addTestPts(const Geometry& g)
155 OffsetPointGenerator ptGen(g, 5 * boundaryDistanceTolerance);
156 auto_ptr< vector<geom::Coordinate> > pts = ptGen.getPoints();
157 testCoords.insert(testCoords.end(), pts->begin(), pts->end());
160 /*private*/
161 void
162 OverlayResultValidator::addVertices(const Geometry& g)
164 // TODO: optimize this by not copying coordinates
165 // and pre-allocating memory
166 auto_ptr<CoordinateSequence> cs ( g.getCoordinates() );
167 const vector<Coordinate>* coords = cs->toVector();
168 testCoords.insert(testCoords.end(), coords->begin(), coords->end());
171 /*private*/
172 bool
173 OverlayResultValidator::testValid(OverlayOp::OpCode overlayOp)
175 for (size_t i=0, n=testCoords.size(); i<n; ++i)
177 Coordinate& pt = testCoords[i];
178 if (! testValid(overlayOp, pt)) {
179 invalidLocation = pt;
180 return false;
183 return true;
186 /*private*/
187 bool
188 OverlayResultValidator::testValid(OverlayOp::OpCode overlayOp,
189 const Coordinate& pt)
191 std::vector<geom::Location::Value> location(3);
193 location[0] = fpl0.getLocation(pt);
194 location[1] = fpl1.getLocation(pt);
195 location[2] = fplres.getLocation(pt);
197 #if GEOS_DEBUG
198 cerr << setprecision(10) << "Point " << pt << endl
199 << "Loc0: " << location[0] << endl
200 << "Loc1: " << location[1] << endl
201 << "Locr: " << location[2] << endl;
202 #endif
205 * If any location is on the Boundary, can't deduce anything,
206 * so just return true
208 if ( find(location.begin(), location.end(), Location::BOUNDARY) != location.end() )
210 #if GEOS_DEBUG
211 cerr << "OverlayResultValidator: testpoint " << pt << " is on the boundary, blindly returning a positive answer (is valid)" << endl;
212 #endif
213 return true;
216 return isValidResult(overlayOp, location);
219 /* private */
220 bool
221 OverlayResultValidator::isValidResult(OverlayOp::OpCode overlayOp,
222 std::vector<geom::Location::Value>& location)
224 bool expectedInterior = OverlayOp::isResultOfOp(location[0],
225 location[1], overlayOp);
227 bool resultInInterior = (location[2] == Location::INTERIOR);
229 bool isValid = ! (expectedInterior ^ resultInInterior);
231 return isValid;
234 /*private static*/
235 double
236 OverlayResultValidator::computeBoundaryDistanceTolerance(
237 const geom::Geometry& g0, const geom::Geometry& g1)
239 using geos::operation::overlay::snap::GeometrySnapper;
241 return (std::min)(GeometrySnapper::computeSizeBasedSnapTolerance(g0),
242 GeometrySnapper::computeSizeBasedSnapTolerance(g1));
245 } // namespace geos.operation.overlay.validate
246 } // namespace geos.operation.overlay
247 } // namespace geos.operation
248 } // namespace geos
250 /**********************************************************************
251 * $Log$
252 **********************************************************************/