1 : /******************************************************************************
2 : * $Id: ogrmssqlgeometryvalidator.cpp 21933 2011-03-11 16:50:10Z tamas $
3 : *
4 : * Project: MSSQL Spatial driver
5 : * Purpose: Implements OGRMSSQLGeometryValidator class to create valid SqlGeometries.
6 : * Author: Tamas Szekeres, szekerest at gmail.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, Tamas Szekeres
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_conv.h"
31 : #include "ogr_mssqlspatial.h"
32 :
33 : CPL_CVSID("$Id: ogrmssqlgeometryvalidator.cpp 21933 2011-03-11 16:50:10Z tamas $");
34 :
35 : /************************************************************************/
36 : /* OGRMSSQLGeometryValidator() */
37 : /************************************************************************/
38 :
39 0 : OGRMSSQLGeometryValidator::OGRMSSQLGeometryValidator(OGRGeometry *poGeom)
40 : {
41 0 : poOriginalGeometry = poGeom;
42 0 : poValidGeometry = NULL;
43 0 : bIsValid = ValidateGeometry(poGeom);
44 0 : }
45 :
46 : /************************************************************************/
47 : /* ~OGRMSSQLGeometryValidator() */
48 : /************************************************************************/
49 :
50 0 : OGRMSSQLGeometryValidator::~OGRMSSQLGeometryValidator()
51 : {
52 0 : if (poValidGeometry)
53 0 : delete poValidGeometry;
54 0 : }
55 :
56 : /************************************************************************/
57 : /* ValidatePoint() */
58 : /************************************************************************/
59 :
60 0 : int OGRMSSQLGeometryValidator::ValidatePoint(OGRPoint* poGeom)
61 : {
62 0 : return TRUE;
63 : }
64 :
65 : /************************************************************************/
66 : /* ValidateMultiPoint() */
67 : /************************************************************************/
68 :
69 0 : int OGRMSSQLGeometryValidator::ValidateMultiPoint(OGRMultiPoint* poGeom)
70 : {
71 0 : return TRUE;
72 : }
73 :
74 : /************************************************************************/
75 : /* ValidateLineString() */
76 : /************************************************************************/
77 :
78 0 : int OGRMSSQLGeometryValidator::ValidateLineString(OGRLineString * poGeom)
79 : {
80 0 : OGRPoint* poPoint0 = NULL;
81 : int i;
82 0 : int bResult = FALSE;
83 :
84 0 : for (i = 0; i < poGeom->getNumPoints(); i++)
85 : {
86 0 : if (poPoint0 == NULL)
87 : {
88 0 : poPoint0 = new OGRPoint();
89 0 : poGeom->getPoint(i, poPoint0);
90 0 : continue;
91 : }
92 :
93 0 : if (poPoint0->getX() == poGeom->getX(i) && poPoint0->getY() == poGeom->getY(i))
94 0 : continue;
95 :
96 0 : bResult = TRUE;
97 0 : break;
98 : }
99 :
100 0 : if (!bResult)
101 : {
102 0 : if (poValidGeometry)
103 0 : delete poValidGeometry;
104 :
105 0 : poValidGeometry = NULL;
106 :
107 : // create a compatible geometry
108 0 : if (poPoint0 != NULL)
109 : {
110 : CPLError( CE_Warning, CPLE_NotSupported,
111 0 : "Linestring has no distinct points constructing point geometry instead." );
112 :
113 : // create a point
114 0 : poValidGeometry = poPoint0;
115 0 : poPoint0 = NULL;
116 : }
117 : else
118 : {
119 : CPLError( CE_Warning, CPLE_NotSupported,
120 0 : "Linestring has no points. Removing the geometry from the output." );
121 : }
122 : }
123 :
124 0 : if (poPoint0)
125 0 : delete poPoint0;
126 :
127 0 : return bResult;
128 : }
129 :
130 : /************************************************************************/
131 : /* ValidateLinearRing() */
132 : /************************************************************************/
133 :
134 0 : int OGRMSSQLGeometryValidator::ValidateLinearRing(OGRLinearRing * poGeom)
135 : {
136 0 : OGRPoint* poPoint0 = NULL;
137 0 : OGRPoint* poPoint1 = NULL;
138 : int i;
139 0 : int bResult = FALSE;
140 :
141 0 : poGeom->closeRings();
142 :
143 0 : for (i = 0; i < poGeom->getNumPoints(); i++)
144 : {
145 0 : if (poPoint0 == NULL)
146 : {
147 0 : poPoint0 = new OGRPoint();
148 0 : poGeom->getPoint(i, poPoint0);
149 0 : continue;
150 : }
151 :
152 0 : if (poPoint0->getX() == poGeom->getX(i) && poPoint0->getY() == poGeom->getY(i))
153 0 : continue;
154 :
155 0 : if (poPoint1 == NULL)
156 : {
157 0 : poPoint1 = new OGRPoint();
158 0 : poGeom->getPoint(i, poPoint1);
159 0 : continue;
160 : }
161 :
162 0 : if (poPoint1->getX() == poGeom->getX(i) && poPoint1->getY() == poGeom->getY(i))
163 0 : continue;
164 :
165 0 : bResult = TRUE;
166 0 : break;
167 : }
168 :
169 0 : if (!bResult)
170 : {
171 0 : if (poValidGeometry)
172 0 : delete poValidGeometry;
173 :
174 0 : poValidGeometry = NULL;
175 :
176 : // create a compatible geometry
177 0 : if (poPoint1 != NULL)
178 : {
179 : CPLError( CE_Warning, CPLE_NotSupported,
180 0 : "Linear ring has only 2 distinct points constructing linestring geometry instead." );
181 :
182 : // create a linestring
183 0 : poValidGeometry = new OGRLineString();
184 0 : ((OGRLineString*)poValidGeometry)->setNumPoints( 2 );
185 0 : ((OGRLineString*)poValidGeometry)->addPoint(poPoint0);
186 0 : ((OGRLineString*)poValidGeometry)->addPoint(poPoint1);
187 : }
188 0 : else if (poPoint0 != NULL)
189 : {
190 : CPLError( CE_Warning, CPLE_NotSupported,
191 0 : "Linear ring has no distinct points constructing point geometry instead." );
192 :
193 : // create a point
194 0 : poValidGeometry = poPoint0;
195 0 : poPoint0 = NULL;
196 : }
197 : else
198 : {
199 : CPLError( CE_Warning, CPLE_NotSupported,
200 0 : "Linear ring has no points. Removing the geometry from the output." );
201 : }
202 : }
203 :
204 0 : if (poPoint0)
205 0 : delete poPoint0;
206 :
207 0 : if (poPoint1)
208 0 : delete poPoint1;
209 :
210 0 : return bResult;
211 : }
212 :
213 : /************************************************************************/
214 : /* ValidateMultiLineString() */
215 : /************************************************************************/
216 :
217 0 : int OGRMSSQLGeometryValidator::ValidateMultiLineString(OGRMultiLineString * poGeom)
218 : {
219 : int i, j;
220 : OGRGeometry* poLineString;
221 0 : OGRGeometryCollection* poGeometries = NULL;
222 :
223 0 : for (i = 0; i < poGeom->getNumGeometries(); i++)
224 : {
225 0 : poLineString = poGeom->getGeometryRef(i);
226 0 : if (poLineString->getGeometryType() != wkbLineString && poLineString->getGeometryType() != wkbLineString25D)
227 : {
228 : // non linestring geometry
229 0 : if (!poGeometries)
230 : {
231 0 : poGeometries = new OGRGeometryCollection();
232 0 : for (j = 0; j < i; j++)
233 0 : poGeometries->addGeometry(poGeom->getGeometryRef(j));
234 : }
235 0 : if (ValidateGeometry(poLineString))
236 0 : poGeometries->addGeometry(poLineString);
237 : else
238 0 : poGeometries->addGeometry(poValidGeometry);
239 :
240 0 : continue;
241 : }
242 :
243 0 : if (!ValidateLineString((OGRLineString*)poLineString))
244 : {
245 : // non valid linestring
246 0 : if (!poGeometries)
247 : {
248 0 : poGeometries = new OGRGeometryCollection();
249 0 : for (j = 0; j < i; j++)
250 0 : poGeometries->addGeometry(poGeom->getGeometryRef(j));
251 : }
252 :
253 0 : poGeometries->addGeometry(poValidGeometry);
254 0 : continue;
255 : }
256 :
257 0 : if (poGeometries)
258 0 : poGeometries->addGeometry(poLineString);
259 : }
260 :
261 0 : if (poGeometries)
262 : {
263 0 : if (poValidGeometry)
264 0 : delete poValidGeometry;
265 :
266 0 : poValidGeometry = poGeometries;
267 : }
268 :
269 0 : return (poValidGeometry == NULL);
270 : }
271 :
272 : /************************************************************************/
273 : /* ValidatePolygon() */
274 : /************************************************************************/
275 :
276 0 : int OGRMSSQLGeometryValidator::ValidatePolygon(OGRPolygon* poGeom)
277 : {
278 : int i,j;
279 0 : OGRLinearRing* poRing = poGeom->getExteriorRing();
280 : OGRGeometry* poInteriorRing;
281 :
282 0 : if (poRing == NULL)
283 0 : return FALSE;
284 :
285 0 : OGRGeometryCollection* poGeometries = NULL;
286 :
287 0 : if (!ValidateLinearRing(poRing))
288 : {
289 0 : if (poGeom->getNumInteriorRings() > 0)
290 : {
291 0 : poGeometries = new OGRGeometryCollection();
292 0 : poGeometries->addGeometryDirectly(poValidGeometry);
293 : }
294 : }
295 :
296 0 : for (i = 0; i < poGeom->getNumInteriorRings(); i++)
297 : {
298 0 : poInteriorRing = poGeom->getInteriorRing(i);
299 0 : if (!ValidateLinearRing((OGRLinearRing*)poInteriorRing))
300 : {
301 0 : if (!poGeometries)
302 : {
303 0 : poGeometries = new OGRGeometryCollection();
304 0 : poGeometries->addGeometry(poRing);
305 0 : for (j = 0; j < i; j++)
306 0 : poGeometries->addGeometry(poGeom->getInteriorRing(j));
307 : }
308 :
309 0 : poGeometries->addGeometry(poValidGeometry);
310 0 : continue;
311 : }
312 :
313 0 : if (poGeometries)
314 0 : poGeometries->addGeometry(poInteriorRing);
315 : }
316 :
317 0 : if (poGeometries)
318 : {
319 0 : if (poValidGeometry)
320 0 : delete poValidGeometry;
321 :
322 0 : poValidGeometry = poGeometries;
323 : }
324 :
325 0 : return (poValidGeometry == NULL);
326 : }
327 :
328 : /************************************************************************/
329 : /* ValidateMultiPolygon() */
330 : /************************************************************************/
331 :
332 0 : int OGRMSSQLGeometryValidator::ValidateMultiPolygon(OGRMultiPolygon* poGeom)
333 : {
334 : int i, j;
335 : OGRGeometry* poPolygon;
336 0 : OGRGeometryCollection* poGeometries = NULL;
337 :
338 0 : for (i = 0; i < poGeom->getNumGeometries(); i++)
339 : {
340 0 : poPolygon = poGeom->getGeometryRef(i);
341 0 : if (poPolygon->getGeometryType() != wkbPolygon && poPolygon->getGeometryType() != wkbPolygon25D)
342 : {
343 : // non polygon geometry
344 0 : if (!poGeometries)
345 : {
346 0 : poGeometries = new OGRGeometryCollection();
347 0 : for (j = 0; j < i; j++)
348 0 : poGeometries->addGeometry(poGeom->getGeometryRef(j));
349 : }
350 0 : if (ValidateGeometry(poPolygon))
351 0 : poGeometries->addGeometry(poPolygon);
352 : else
353 0 : poGeometries->addGeometry(poValidGeometry);
354 :
355 0 : continue;
356 : }
357 :
358 0 : if (!ValidatePolygon((OGRPolygon*)poPolygon))
359 : {
360 : // non valid polygon
361 0 : if (!poGeometries)
362 : {
363 0 : poGeometries = new OGRGeometryCollection();
364 0 : for (j = 0; j < i; j++)
365 0 : poGeometries->addGeometry(poGeom->getGeometryRef(j));
366 : }
367 :
368 0 : poGeometries->addGeometry(poValidGeometry);
369 0 : continue;
370 : }
371 :
372 0 : if (poGeometries)
373 0 : poGeometries->addGeometry(poPolygon);
374 : }
375 :
376 0 : if (poGeometries)
377 : {
378 0 : if (poValidGeometry)
379 0 : delete poValidGeometry;
380 :
381 0 : poValidGeometry = poGeometries;
382 : }
383 :
384 0 : return poValidGeometry == NULL;
385 : }
386 :
387 : /************************************************************************/
388 : /* ValidateGeometryCollection() */
389 : /************************************************************************/
390 :
391 0 : int OGRMSSQLGeometryValidator::ValidateGeometryCollection(OGRGeometryCollection* poGeom)
392 : {
393 : int i, j;
394 : OGRGeometry* poGeometry;
395 0 : OGRGeometryCollection* poGeometries = NULL;
396 :
397 0 : for (i = 0; i < poGeom->getNumGeometries(); i++)
398 : {
399 0 : poGeometry = poGeom->getGeometryRef(i);
400 :
401 0 : if (!ValidateGeometry(poGeometry))
402 : {
403 : // non valid geometry
404 0 : if (!poGeometries)
405 : {
406 0 : poGeometries = new OGRGeometryCollection();
407 0 : for (j = 0; j < i; j++)
408 0 : poGeometries->addGeometry(poGeom->getGeometryRef(j));
409 : }
410 :
411 0 : if (poValidGeometry)
412 0 : poGeometries->addGeometry(poValidGeometry);
413 0 : continue;
414 : }
415 :
416 0 : if (poGeometries)
417 0 : poGeometries->addGeometry(poGeometry);
418 : }
419 :
420 0 : if (poGeometries)
421 : {
422 0 : if (poValidGeometry)
423 0 : delete poValidGeometry;
424 :
425 0 : poValidGeometry = poGeometries;
426 : }
427 :
428 0 : return (poValidGeometry == NULL);
429 : }
430 :
431 : /************************************************************************/
432 : /* ValidateGeometry() */
433 : /************************************************************************/
434 :
435 0 : int OGRMSSQLGeometryValidator::ValidateGeometry(OGRGeometry* poGeom)
436 : {
437 0 : if (!poGeom)
438 0 : return FALSE;
439 :
440 0 : switch (poGeom->getGeometryType())
441 : {
442 : case wkbPoint:
443 : case wkbPoint25D:
444 0 : return ValidatePoint((OGRPoint*)poGeom);
445 : case wkbLineString:
446 : case wkbLineString25D:
447 0 : return ValidateLineString((OGRLineString*)poGeom);
448 : case wkbPolygon:
449 : case wkbPolygon25D:
450 0 : return ValidatePolygon((OGRPolygon*)poGeom);
451 : case wkbMultiPoint:
452 : case wkbMultiPoint25D:
453 0 : return ValidateMultiPoint((OGRMultiPoint*)poGeom);
454 : case wkbMultiLineString:
455 : case wkbMultiLineString25D:
456 0 : return ValidateMultiLineString((OGRMultiLineString*)poGeom);
457 : case wkbMultiPolygon:
458 : case wkbMultiPolygon25D:
459 0 : return ValidateMultiPolygon((OGRMultiPolygon*)poGeom);
460 : case wkbGeometryCollection:
461 : case wkbGeometryCollection25D:
462 0 : return ValidateGeometryCollection((OGRGeometryCollection*)poGeom);
463 : case wkbLinearRing:
464 0 : return ValidateLinearRing((OGRLinearRing*)poGeom);
465 : default:
466 0 : return FALSE;
467 : }
468 : }
469 :
470 : /************************************************************************/
471 : /* GetValidGeometryRef() */
472 : /************************************************************************/
473 0 : OGRGeometry* OGRMSSQLGeometryValidator::GetValidGeometryRef()
474 : {
475 0 : if (bIsValid || poOriginalGeometry == NULL)
476 0 : return poOriginalGeometry;
477 :
478 0 : if (poValidGeometry)
479 : {
480 : CPLError( CE_Warning, CPLE_NotSupported,
481 : "Invalid geometry has been converted from %s to %s.",
482 0 : poOriginalGeometry->getGeometryName(),
483 0 : poValidGeometry->getGeometryName() );
484 : }
485 : else
486 : {
487 : CPLError( CE_Warning, CPLE_NotSupported,
488 : "Invalid geometry has been converted from %s to null.",
489 0 : poOriginalGeometry->getGeometryName());
490 : }
491 :
492 0 : return poValidGeometry;
493 : }
494 :
495 :
|