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

Generated by: LCOV version 1.14