LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/mssqlspatial - ogrmssqlgeometryvalidator.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 0 260 0.0 %
Date: 2024-05-04 12:52:34 Functions: 0 31 0.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  MSSQL Spatial driver
       4             :  * Purpose:  Implements OGRMSSQLGeometryValidator class to create valid
       5             :  *SqlGeometries. Author:   Tamas Szekeres, szekerest at gmail.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2010, Tamas Szekeres
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "cpl_conv.h"
      30             : #include "ogr_mssqlspatial.h"
      31             : 
      32             : /************************************************************************/
      33             : /*                   OGRMSSQLGeometryValidator()                        */
      34             : /************************************************************************/
      35             : 
      36           0 : OGRMSSQLGeometryValidator::OGRMSSQLGeometryValidator(OGRGeometry *poGeom,
      37           0 :                                                      int geomColumnType)
      38             : {
      39           0 :     poOriginalGeometry = poGeom;
      40           0 :     poValidGeometry = nullptr;
      41           0 :     nGeomColumnType = geomColumnType;
      42           0 :     bIsValid = IsValid(poGeom);
      43           0 : }
      44             : 
      45             : /************************************************************************/
      46             : /*                      ~OGRMSSQLGeometryValidator()                    */
      47             : /************************************************************************/
      48             : 
      49           0 : OGRMSSQLGeometryValidator::~OGRMSSQLGeometryValidator()
      50             : {
      51           0 :     if (poValidGeometry)
      52           0 :         delete poValidGeometry;
      53           0 : }
      54             : 
      55             : /************************************************************************/
      56             : /*                         IsValidLatLon()                             */
      57             : /************************************************************************/
      58             : 
      59           0 : static double MakeValidLatitude(double latitude)
      60             : {
      61           0 :     if (latitude < -90)
      62           0 :         return -90;
      63             : 
      64           0 :     if (latitude > 90.0)
      65           0 :         return 90.0;
      66             : 
      67           0 :     return latitude;
      68             : }
      69             : 
      70           0 : static double MakeValidLongitude(double longitude)
      71             : {
      72           0 :     if (longitude < -15069.0)
      73           0 :         return -15069.0;
      74             : 
      75           0 :     if (longitude > 15069.0)
      76           0 :         return 15069.0;
      77             : 
      78           0 :     return longitude;
      79             : }
      80             : 
      81           0 : bool OGRMSSQLGeometryValidator::IsValidLatLon(double longitude, double latitude)
      82             : {
      83           0 :     if (MakeValidLatitude(latitude) != latitude)
      84             :     {
      85           0 :         if (poValidGeometry == nullptr)
      86           0 :             CPLError(CE_Warning, CPLE_NotSupported,
      87             :                      "Latitude values must be between -90 and 90 degrees");
      88           0 :         return false;
      89             :     }
      90           0 :     if (MakeValidLongitude(longitude) != longitude)
      91             :     {
      92           0 :         if (poValidGeometry == nullptr)
      93           0 :             CPLError(
      94             :                 CE_Warning, CPLE_NotSupported,
      95             :                 "Longitude values must be between -15069 and 15069 degrees");
      96           0 :         return false;
      97             :     }
      98           0 :     return true;
      99             : }
     100             : 
     101             : /************************************************************************/
     102             : /*                         IsValidCircularZ()                           */
     103             : /************************************************************************/
     104             : 
     105           0 : bool OGRMSSQLGeometryValidator::IsValidCircularZ(double z1, double z2)
     106             : {
     107           0 :     if (z1 != z2)
     108             :     {
     109           0 :         if (poValidGeometry == nullptr)
     110           0 :             CPLError(CE_Warning, CPLE_NotSupported,
     111             :                      "Circular arc segments with Z values must have equal Z "
     112             :                      "value for all 3 points");
     113           0 :         return false;
     114             :     }
     115           0 :     return true;
     116             : }
     117             : 
     118             : /************************************************************************/
     119             : /*                         IsValidPolygonRingCount()                    */
     120             : /************************************************************************/
     121             : 
     122           0 : bool OGRMSSQLGeometryValidator::IsValidPolygonRingCount(const OGRCurve *poGeom)
     123             : {
     124           0 :     if (poGeom->getNumPoints() < 4)
     125             :     {
     126           0 :         if (poValidGeometry == nullptr)
     127           0 :             CPLError(
     128             :                 CE_Warning, CPLE_NotSupported,
     129             :                 "Each ring of a polygon must contain at least four points");
     130           0 :         return false;
     131             :     }
     132           0 :     return true;
     133             : }
     134             : 
     135             : /************************************************************************/
     136             : /*                         IsValidPolygonRingClosed()                   */
     137             : /************************************************************************/
     138             : 
     139           0 : bool OGRMSSQLGeometryValidator::IsValidPolygonRingClosed(const OGRCurve *poGeom)
     140             : {
     141           0 :     if (poGeom->get_IsClosed() == FALSE)
     142             :     {
     143           0 :         if (poValidGeometry == nullptr)
     144           0 :             CPLError(CE_Warning, CPLE_NotSupported,
     145             :                      "Each ring of a polygon must have the same start and end "
     146             :                      "points.");
     147           0 :         return false;
     148             :     }
     149           0 :     return true;
     150             : }
     151             : 
     152             : /************************************************************************/
     153             : /*                         ValidatePoint()                              */
     154             : /************************************************************************/
     155             : 
     156           0 : bool OGRMSSQLGeometryValidator::IsValid(const OGRPoint *poGeom)
     157             : {
     158           0 :     if (poGeom->IsEmpty())
     159           0 :         return true;
     160             : 
     161           0 :     if (nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY)
     162           0 :         return IsValidLatLon(poGeom->getX(), poGeom->getY());
     163             : 
     164           0 :     return true;
     165             : }
     166             : 
     167           0 : void OGRMSSQLGeometryValidator::MakeValid(OGRPoint *poGeom)
     168             : {
     169           0 :     if (poGeom->IsEmpty())
     170           0 :         return;
     171             : 
     172           0 :     if (nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY)
     173             :     {
     174           0 :         poGeom->setX(MakeValidLongitude(poGeom->getX()));
     175           0 :         poGeom->setY(MakeValidLatitude(poGeom->getY()));
     176             :     }
     177             : }
     178             : 
     179             : /************************************************************************/
     180             : /*                     ValidateMultiPoint()                             */
     181             : /************************************************************************/
     182             : 
     183           0 : bool OGRMSSQLGeometryValidator::IsValid(const OGRMultiPoint *poGeom)
     184             : {
     185           0 :     if (nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY)
     186             :     {
     187           0 :         for (const auto point : *poGeom)
     188             :         {
     189           0 :             if (!IsValid(point))
     190           0 :                 return false;
     191             :         }
     192             :     }
     193           0 :     return true;
     194             : }
     195             : 
     196           0 : void OGRMSSQLGeometryValidator::MakeValid(OGRMultiPoint *poGeom)
     197             : {
     198           0 :     if (nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY)
     199             :     {
     200           0 :         for (auto point : *poGeom)
     201             :         {
     202           0 :             MakeValid(point);
     203             :         }
     204             :     }
     205           0 : }
     206             : 
     207             : /************************************************************************/
     208             : /*                         ValidateSimpleCurve()                        */
     209             : /************************************************************************/
     210             : 
     211           0 : bool OGRMSSQLGeometryValidator::IsValid(const OGRSimpleCurve *poGeom)
     212             : {
     213           0 :     if (nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY)
     214             :     {
     215           0 :         const int numPoints = poGeom->getNumPoints();
     216           0 :         for (int i = 0; i < numPoints; i++)
     217             :         {
     218           0 :             if (!IsValidLatLon(poGeom->getX(i), poGeom->getY(i)))
     219           0 :                 return false;
     220             :         }
     221             :     }
     222           0 :     return true;
     223             : }
     224             : 
     225           0 : void OGRMSSQLGeometryValidator::MakeValid(OGRSimpleCurve *poGeom)
     226             : {
     227           0 :     if (nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY)
     228             :     {
     229           0 :         const int numPoints = poGeom->getNumPoints();
     230           0 :         for (int i = 0; i < numPoints; i++)
     231             :         {
     232           0 :             poGeom->setPoint(i, MakeValidLongitude(poGeom->getX(i)),
     233             :                              MakeValidLatitude(poGeom->getY(i)));
     234             :         }
     235             :     }
     236           0 : }
     237             : 
     238             : /************************************************************************/
     239             : /*                         ValidateCircularString()                     */
     240             : /************************************************************************/
     241             : 
     242           0 : bool OGRMSSQLGeometryValidator::IsValid(const OGRCircularString *poGeom)
     243             : {
     244           0 :     if (!IsValid(poGeom->toSimpleCurve()))
     245           0 :         return false;
     246             : 
     247           0 :     if (poGeom->Is3D())
     248             :     {
     249           0 :         const int numPoints = poGeom->getNumPoints();
     250           0 :         for (int i = 1; i < numPoints; i++)
     251             :         {
     252           0 :             if (!IsValidCircularZ(poGeom->getZ(i), poGeom->getZ(0)))
     253             :             {
     254           0 :                 return false;
     255             :             }
     256             :         }
     257             :     }
     258           0 :     return true;
     259             : }
     260             : 
     261           0 : void OGRMSSQLGeometryValidator::MakeValid(OGRCircularString *poGeom)
     262             : {
     263           0 :     MakeValid(poGeom->toSimpleCurve());
     264             : 
     265           0 :     if (poGeom->Is3D())
     266             :     {
     267           0 :         const int numPoints = poGeom->getNumPoints();
     268           0 :         for (int i = 1; i < numPoints; i++)
     269             :         {
     270           0 :             poGeom->setZ(i, poGeom->getZ(0));
     271             :         }
     272             :     }
     273           0 : }
     274             : 
     275             : /************************************************************************/
     276             : /*                         ValidateCompoundCurve()                      */
     277             : /************************************************************************/
     278             : 
     279           0 : bool OGRMSSQLGeometryValidator::IsValid(const OGRCompoundCurve *poGeom)
     280             : {
     281           0 :     for (const auto poCurve : *poGeom)
     282             :     {
     283           0 :         switch (wkbFlatten(poCurve->getGeometryType()))
     284             :         {
     285           0 :             case wkbLineString:
     286           0 :                 if (!IsValid(poCurve->toLineString()))
     287           0 :                     return false;
     288           0 :                 break;
     289             : 
     290           0 :             case wkbCircularString:
     291           0 :                 if (!IsValid(poCurve->toCircularString()))
     292           0 :                     return false;
     293           0 :                 break;
     294             : 
     295           0 :             default:
     296           0 :                 break;
     297             :         }
     298             :     }
     299           0 :     return true;
     300             : }
     301             : 
     302           0 : void OGRMSSQLGeometryValidator::MakeValid(OGRCompoundCurve *poGeom)
     303             : {
     304           0 :     for (auto poCurve : *poGeom)
     305             :     {
     306           0 :         switch (wkbFlatten(poCurve->getGeometryType()))
     307             :         {
     308           0 :             case wkbLineString:
     309           0 :                 MakeValid(poCurve->toLineString());
     310           0 :                 break;
     311             : 
     312           0 :             case wkbCircularString:
     313           0 :                 MakeValid(poCurve->toCircularString());
     314           0 :                 break;
     315             : 
     316           0 :             default:
     317           0 :                 break;
     318             :         }
     319             :     }
     320           0 : }
     321             : 
     322             : /************************************************************************/
     323             : /*                     ValidateMultiLineString()                        */
     324             : /************************************************************************/
     325             : 
     326           0 : bool OGRMSSQLGeometryValidator::IsValid(const OGRMultiLineString *poGeom)
     327             : {
     328           0 :     if (nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY)
     329             :     {
     330           0 :         for (const auto part : *poGeom)
     331             :         {
     332           0 :             if (!IsValid(part))
     333           0 :                 return false;
     334             :         }
     335             :     }
     336           0 :     return true;
     337             : }
     338             : 
     339           0 : void OGRMSSQLGeometryValidator::MakeValid(OGRMultiLineString *poGeom)
     340             : {
     341           0 :     if (nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY)
     342             :     {
     343           0 :         for (auto part : *poGeom)
     344             :         {
     345           0 :             MakeValid(part);
     346             :         }
     347             :     }
     348           0 : }
     349             : 
     350             : /************************************************************************/
     351             : /*                         ValidatePolygon()                            */
     352             : /************************************************************************/
     353             : 
     354           0 : void OGRMSSQLGeometryValidator::MakeValid(OGRPolygon *poGeom)
     355             : {
     356           0 :     OGRMSSQLGeometryValidator::MakeValid(poGeom->toCurvePolygon());
     357             : 
     358           0 :     poGeom->closeRings();
     359           0 : }
     360             : 
     361             : /************************************************************************/
     362             : /*                         ValidateCurvePolygon()                       */
     363             : /************************************************************************/
     364             : 
     365           0 : bool OGRMSSQLGeometryValidator::IsValid(const OGRCurvePolygon *poGeom)
     366             : {
     367           0 :     if (poGeom->IsEmpty())
     368           0 :         return true;
     369             : 
     370           0 :     for (const auto part : *poGeom)
     371             :     {
     372           0 :         if (!IsValid(part))
     373           0 :             return false;
     374             : 
     375           0 :         if (!IsValidPolygonRingCount(part))
     376           0 :             return false;
     377             : 
     378           0 :         if (!IsValidPolygonRingClosed(part))
     379           0 :             return false;
     380             :     }
     381             : 
     382           0 :     return true;
     383             : }
     384             : 
     385           0 : void OGRMSSQLGeometryValidator::MakeValid(OGRCurvePolygon *poGeom)
     386             : {
     387           0 :     if (poGeom->IsEmpty())
     388           0 :         return;
     389             : 
     390           0 :     for (auto part : *poGeom)
     391             :     {
     392           0 :         MakeValid(part);
     393             :     }
     394             : }
     395             : 
     396             : /************************************************************************/
     397             : /*                         ValidateMultiPolygon()                       */
     398             : /************************************************************************/
     399             : 
     400           0 : bool OGRMSSQLGeometryValidator::IsValid(const OGRMultiPolygon *poGeom)
     401             : {
     402           0 :     for (const auto part : *poGeom)
     403             :     {
     404           0 :         if (!IsValid(part))
     405           0 :             return false;
     406             :     }
     407           0 :     return true;
     408             : }
     409             : 
     410           0 : void OGRMSSQLGeometryValidator::MakeValid(OGRMultiPolygon *poGeom)
     411             : {
     412           0 :     for (auto part : *poGeom)
     413             :     {
     414           0 :         MakeValid(part);
     415             :     }
     416           0 : }
     417             : 
     418             : /************************************************************************/
     419             : /*                     ValidateGeometryCollection()                     */
     420             : /************************************************************************/
     421             : 
     422           0 : bool OGRMSSQLGeometryValidator::IsValid(const OGRGeometryCollection *poGeom)
     423             : {
     424           0 :     for (const auto part : *poGeom)
     425             :     {
     426           0 :         if (!IsValid(part))
     427           0 :             return false;
     428             :     }
     429           0 :     return true;
     430             : }
     431             : 
     432           0 : void OGRMSSQLGeometryValidator::MakeValid(OGRGeometryCollection *poGeom)
     433             : {
     434           0 :     for (auto part : *poGeom)
     435             :     {
     436           0 :         MakeValid(part);
     437             :     }
     438           0 : }
     439             : 
     440             : /************************************************************************/
     441             : /*                         ValidateGeometry()                           */
     442             : /************************************************************************/
     443             : 
     444           0 : bool OGRMSSQLGeometryValidator::IsValid(const OGRGeometry *poGeom)
     445             : {
     446           0 :     if (!poGeom)
     447           0 :         return false;
     448             : 
     449           0 :     switch (wkbFlatten(poGeom->getGeometryType()))
     450             :     {
     451           0 :         case wkbPoint:
     452           0 :             return IsValid(poGeom->toPoint());
     453           0 :         case wkbLineString:
     454           0 :             return IsValid(poGeom->toSimpleCurve());
     455           0 :         case wkbPolygon:
     456           0 :             return IsValid(poGeom->toPolygon());
     457           0 :         case wkbCurvePolygon:
     458           0 :             return IsValid(poGeom->toCurvePolygon());
     459           0 :         case wkbMultiPoint:
     460           0 :             return IsValid(poGeom->toMultiPoint());
     461           0 :         case wkbMultiLineString:
     462           0 :             return IsValid(poGeom->toMultiLineString());
     463           0 :         case wkbCircularString:
     464           0 :             return IsValid(poGeom->toCircularString());
     465           0 :         case wkbCompoundCurve:
     466           0 :             return IsValid(poGeom->toCompoundCurve());
     467           0 :         case wkbMultiPolygon:
     468           0 :             return IsValid(poGeom->toMultiPolygon());
     469           0 :         case wkbGeometryCollection:
     470           0 :             return IsValid(poGeom->toGeometryCollection());
     471           0 :         default:
     472           0 :             break;
     473             :     }
     474           0 :     return false;
     475             : }
     476             : 
     477           0 : void OGRMSSQLGeometryValidator::MakeValid(OGRGeometry *poGeom)
     478             : {
     479           0 :     if (!poGeom)
     480           0 :         return;
     481             : 
     482           0 :     switch (wkbFlatten(poGeom->getGeometryType()))
     483             :     {
     484           0 :         case wkbPoint:
     485           0 :             MakeValid(poGeom->toPoint());
     486           0 :             break;
     487           0 :         case wkbLineString:
     488           0 :             MakeValid(poGeom->toSimpleCurve());
     489           0 :             break;
     490           0 :         case wkbPolygon:
     491           0 :             MakeValid(poGeom->toPolygon());
     492           0 :             break;
     493           0 :         case wkbCurvePolygon:
     494           0 :             MakeValid(poGeom->toCurvePolygon());
     495           0 :             break;
     496           0 :         case wkbMultiPoint:
     497           0 :             MakeValid(poGeom->toMultiPoint());
     498           0 :             break;
     499           0 :         case wkbMultiLineString:
     500           0 :             MakeValid(poGeom->toMultiLineString());
     501           0 :             break;
     502           0 :         case wkbCircularString:
     503           0 :             MakeValid(poGeom->toCircularString());
     504           0 :             break;
     505           0 :         case wkbCompoundCurve:
     506           0 :             MakeValid(poGeom->toCompoundCurve());
     507           0 :             break;
     508           0 :         case wkbMultiPolygon:
     509           0 :             MakeValid(poGeom->toMultiPolygon());
     510           0 :             break;
     511           0 :         case wkbGeometryCollection:
     512           0 :             MakeValid(poGeom->toGeometryCollection());
     513           0 :             break;
     514           0 :         default:
     515           0 :             break;
     516             :     }
     517             : }
     518             : 
     519           0 : bool OGRMSSQLGeometryValidator::ValidateGeometry(OGRGeometry *poGeom)
     520             : {
     521           0 :     if (poValidGeometry != nullptr)
     522             :     {
     523           0 :         delete poValidGeometry;
     524           0 :         poValidGeometry = nullptr;
     525             :     }
     526             : 
     527           0 :     if (!IsValid(poGeom))
     528             :     {
     529           0 :         poValidGeometry = poGeom->clone();
     530           0 :         MakeValid(poValidGeometry);
     531           0 :         return false;
     532             :     }
     533           0 :     return true;
     534             : }
     535             : 
     536             : /************************************************************************/
     537             : /*                      GetValidGeometryRef()                           */
     538             : /************************************************************************/
     539           0 : OGRGeometry *OGRMSSQLGeometryValidator::GetValidGeometryRef()
     540             : {
     541           0 :     if (bIsValid || poOriginalGeometry == nullptr)
     542           0 :         return poOriginalGeometry;
     543             : 
     544           0 :     if (poValidGeometry)
     545             :     {
     546           0 :         CPLError(CE_Warning, CPLE_NotSupported,
     547             :                  "Invalid geometry has been converted from %s to %s.",
     548           0 :                  poOriginalGeometry->getGeometryName(),
     549           0 :                  poValidGeometry->getGeometryName());
     550             :     }
     551             :     else
     552             :     {
     553           0 :         CPLError(CE_Warning, CPLE_NotSupported,
     554             :                  "Invalid geometry has been converted from %s to null.",
     555           0 :                  poOriginalGeometry->getGeometryName());
     556             :     }
     557             : 
     558           0 :     return poValidGeometry;
     559             : }

Generated by: LCOV version 1.14