LCOV - code coverage report
Current view: top level - ogr - ogrmultipoint.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 150 173 86.7 %
Date: 2026-06-02 13:52:01 Functions: 10 10 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  The OGRMultiPoint class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999, Frank Warmerdam
       9             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "ogr_geometry.h"
      16             : 
      17             : #include <cstddef>
      18             : #include <cstdio>
      19             : #include <cstring>
      20             : #include <new>
      21             : 
      22             : #include "cpl_conv.h"
      23             : #include "cpl_error.h"
      24             : #include "cpl_vsi.h"
      25             : #include "ogr_core.h"
      26             : #include "ogr_p.h"
      27             : 
      28             : /************************************************************************/
      29             : /*                OGRMultiPoint( const OGRMultiPoint& )                 */
      30             : /************************************************************************/
      31             : 
      32             : /**
      33             :  * \brief Copy constructor.
      34             :  */
      35             : 
      36             : OGRMultiPoint::OGRMultiPoint(const OGRMultiPoint &) = default;
      37             : 
      38             : /************************************************************************/
      39             : /*                   operator=( const OGRMultiPoint&)                   */
      40             : /************************************************************************/
      41             : 
      42             : /**
      43             :  * \brief Assignment operator.
      44             :  */
      45             : 
      46           5 : OGRMultiPoint &OGRMultiPoint::operator=(const OGRMultiPoint &other)
      47             : {
      48           5 :     if (this != &other)
      49             :     {
      50           4 :         OGRGeometryCollection::operator=(other);
      51             :     }
      52           5 :     return *this;
      53             : }
      54             : 
      55             : /************************************************************************/
      56             : /*                               clone()                                */
      57             : /************************************************************************/
      58             : 
      59         792 : OGRMultiPoint *OGRMultiPoint::clone() const
      60             : 
      61             : {
      62         792 :     return new (std::nothrow) OGRMultiPoint(*this);
      63             : }
      64             : 
      65             : /************************************************************************/
      66             : /*                          getGeometryType()                           */
      67             : /************************************************************************/
      68             : 
      69       15910 : OGRwkbGeometryType OGRMultiPoint::getGeometryType() const
      70             : 
      71             : {
      72       15910 :     if ((flags & OGR_G_3D) && (flags & OGR_G_MEASURED))
      73        3129 :         return wkbMultiPointZM;
      74       12781 :     else if (flags & OGR_G_MEASURED)
      75         350 :         return wkbMultiPointM;
      76       12431 :     else if (flags & OGR_G_3D)
      77        6025 :         return wkbMultiPoint25D;
      78             :     else
      79        6406 :         return wkbMultiPoint;
      80             : }
      81             : 
      82             : /************************************************************************/
      83             : /*                            getDimension()                            */
      84             : /************************************************************************/
      85             : 
      86           2 : int OGRMultiPoint::getDimension() const
      87             : 
      88             : {
      89           2 :     return 0;
      90             : }
      91             : 
      92             : /************************************************************************/
      93             : /*                          getGeometryName()                           */
      94             : /************************************************************************/
      95             : 
      96        2087 : const char *OGRMultiPoint::getGeometryName() const
      97             : 
      98             : {
      99        2087 :     return "MULTIPOINT";
     100             : }
     101             : 
     102             : /************************************************************************/
     103             : /*                        isCompatibleSubType()                         */
     104             : /************************************************************************/
     105             : 
     106       13593 : bool OGRMultiPoint::isCompatibleSubType(OGRwkbGeometryType eGeomType) const
     107             : {
     108       13593 :     return wkbFlatten(eGeomType) == wkbPoint;
     109             : }
     110             : 
     111             : /************************************************************************/
     112             : /*                            exportToWkt()                             */
     113             : /*                                                                      */
     114             : /*      Translate this structure into its well known text format        */
     115             : /*      equivalent.                                                     */
     116             : /************************************************************************/
     117             : 
     118         226 : std::string OGRMultiPoint::exportToWkt(const OGRWktOptions &opts,
     119             :                                        OGRErr *err) const
     120             : {
     121             :     try
     122             :     {
     123         452 :         std::string wkt = getGeometryName();
     124         226 :         wkt += wktTypeString(opts.variant);
     125             : 
     126         226 :         bool first(true);
     127             :         // OGRMultiPoint has a begin()/end().
     128         642 :         for (const OGRPoint *poPoint : this)
     129             :         {
     130         416 :             if (poPoint->IsEmpty())
     131          13 :                 continue;
     132             : 
     133         403 :             if (first)
     134         181 :                 wkt += '(';
     135             :             else
     136         222 :                 wkt += ',';
     137         403 :             first = false;
     138             : 
     139         403 :             if (opts.variant == wkbVariantIso)
     140         226 :                 wkt += '(';
     141             : 
     142         806 :             wkt += OGRMakeWktCoordinateM(
     143             :                 poPoint->getX(), poPoint->getY(), poPoint->getZ(),
     144         403 :                 poPoint->getM(), poPoint->Is3D(),
     145         806 :                 poPoint->IsMeasured() && (opts.variant == wkbVariantIso), opts);
     146             : 
     147         403 :             if (opts.variant == wkbVariantIso)
     148         226 :                 wkt += ')';
     149             :         }
     150             : 
     151         226 :         if (err)
     152         204 :             *err = OGRERR_NONE;
     153         226 :         if (first)
     154          45 :             wkt += "EMPTY";
     155             :         else
     156         181 :             wkt += ')';
     157         226 :         return wkt;
     158             :     }
     159           0 :     catch (const std::bad_alloc &e)
     160             :     {
     161           0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
     162           0 :         if (err)
     163           0 :             *err = OGRERR_FAILURE;
     164           0 :         return std::string();
     165             :     }
     166             : }
     167             : 
     168             : /************************************************************************/
     169             : /*                           importFromWkt()                            */
     170             : /************************************************************************/
     171             : 
     172         654 : OGRErr OGRMultiPoint::importFromWkt(const char **ppszInput)
     173             : 
     174             : {
     175         654 :     const char *pszInputBefore = *ppszInput;
     176         654 :     int bHasZ = FALSE;
     177         654 :     int bHasM = FALSE;
     178         654 :     bool bIsEmpty = false;
     179         654 :     OGRErr eErr = importPreambleFromWkt(ppszInput, &bHasZ, &bHasM, &bIsEmpty);
     180         654 :     flags = 0;
     181         654 :     if (eErr != OGRERR_NONE)
     182           5 :         return eErr;
     183         649 :     if (bHasZ)
     184          92 :         flags |= OGR_G_3D;
     185         649 :     if (bHasM)
     186          64 :         flags |= OGR_G_MEASURED;
     187         649 :     if (bIsEmpty)
     188          65 :         return OGRERR_NONE;
     189             : 
     190         584 :     char szToken[OGR_WKT_TOKEN_MAX] = {};
     191         584 :     const char *pszInput = *ppszInput;
     192             : 
     193         584 :     const char *pszPreScan = OGRWktReadToken(pszInput, szToken);
     194         584 :     OGRWktReadToken(pszPreScan, szToken);
     195             : 
     196             :     // Do we have an inner bracket?
     197         584 :     if (EQUAL(szToken, "(") || EQUAL(szToken, "EMPTY"))
     198             :     {
     199         206 :         *ppszInput = pszInputBefore;
     200         206 :         return importFromWkt_Bracketed(ppszInput, bHasM, bHasZ);
     201             :     }
     202             : 
     203             :     /* -------------------------------------------------------------------- */
     204             :     /*      Read the point list.                                            */
     205             :     /* -------------------------------------------------------------------- */
     206         378 :     OGRRawPoint *paoPoints = nullptr;
     207         378 :     double *padfZ = nullptr;
     208         378 :     double *padfM = nullptr;
     209         378 :     int flagsFromInput = flags;
     210         378 :     int nMaxPoint = 0;
     211         378 :     int nPointCount = 0;
     212             : 
     213         378 :     pszInput = OGRWktReadPointsM(pszInput, &paoPoints, &padfZ, &padfM,
     214             :                                  &flagsFromInput, &nMaxPoint, &nPointCount);
     215         378 :     if (pszInput == nullptr)
     216             :     {
     217          11 :         CPLFree(paoPoints);
     218          11 :         CPLFree(padfZ);
     219          11 :         CPLFree(padfM);
     220          11 :         return OGRERR_CORRUPT_DATA;
     221             :     }
     222         367 :     if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
     223             :     {
     224         175 :         flags |= OGR_G_3D;
     225         175 :         bHasZ = TRUE;
     226             :     }
     227         367 :     if ((flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED))
     228             :     {
     229           1 :         flags |= OGR_G_MEASURED;
     230           1 :         bHasM = TRUE;
     231             :     }
     232             : 
     233             :     /* -------------------------------------------------------------------- */
     234             :     /*      Transform raw points into point objects.                        */
     235             :     /* -------------------------------------------------------------------- */
     236        1063 :     for (int iGeom = 0; iGeom < nPointCount; iGeom++)
     237             :     {
     238             :         OGRPoint *poPoint =
     239         696 :             new OGRPoint(paoPoints[iGeom].x, paoPoints[iGeom].y);
     240         696 :         if (bHasM)
     241             :         {
     242           7 :             if (padfM != nullptr)
     243           7 :                 poPoint->setM(padfM[iGeom]);
     244             :             else
     245           0 :                 poPoint->setM(0.0);
     246             :         }
     247         696 :         if (bHasZ)
     248             :         {
     249         392 :             if (padfZ != nullptr)
     250         392 :                 poPoint->setZ(padfZ[iGeom]);
     251             :             else
     252           0 :                 poPoint->setZ(0.0);
     253             :         }
     254             : 
     255         696 :         eErr = addGeometryDirectly(poPoint);
     256         696 :         if (eErr != OGRERR_NONE)
     257             :         {
     258           0 :             CPLFree(paoPoints);
     259           0 :             CPLFree(padfZ);
     260           0 :             CPLFree(padfM);
     261           0 :             delete poPoint;
     262           0 :             return eErr;
     263             :         }
     264             :     }
     265             : 
     266         367 :     CPLFree(paoPoints);
     267         367 :     CPLFree(padfZ);
     268         367 :     CPLFree(padfM);
     269             : 
     270         367 :     *ppszInput = pszInput;
     271             : 
     272         367 :     return OGRERR_NONE;
     273             : }
     274             : 
     275             : /************************************************************************/
     276             : /*                      importFromWkt_Bracketed()                       */
     277             : /*                                                                      */
     278             : /*      This operates similar to importFromWkt(), but reads a format    */
     279             : /*      with brackets around each point.  This is the form defined      */
     280             : /*      in the BNF of the SFSQL spec.  It is called from                */
     281             : /*      importFromWkt().                                                */
     282             : /************************************************************************/
     283             : 
     284         206 : OGRErr OGRMultiPoint::importFromWkt_Bracketed(const char **ppszInput, int bHasM,
     285             :                                               int bHasZ)
     286             : 
     287             : {
     288             :     /* -------------------------------------------------------------------- */
     289             :     /*      Skip MULTIPOINT keyword.                                        */
     290             :     /* -------------------------------------------------------------------- */
     291         206 :     char szToken[OGR_WKT_TOKEN_MAX] = {};
     292         206 :     const char *pszInput = *ppszInput;
     293         206 :     pszInput = OGRWktReadToken(pszInput, szToken);
     294             : 
     295         206 :     if (bHasZ || bHasM)
     296             :     {
     297             :         // Skip Z, M or ZM.
     298          84 :         pszInput = OGRWktReadToken(pszInput, szToken);
     299             :     }
     300             : 
     301             :     /* -------------------------------------------------------------------- */
     302             :     /*      Read points till we get to the closing bracket.                 */
     303             :     /* -------------------------------------------------------------------- */
     304             : 
     305         206 :     OGRRawPoint *paoPoints = nullptr;
     306         206 :     double *padfZ = nullptr;
     307         206 :     double *padfM = nullptr;
     308             : 
     309        1322 :     while ((pszInput = OGRWktReadToken(pszInput, szToken)) != nullptr &&
     310         661 :            (EQUAL(szToken, "(") || EQUAL(szToken, ",")))
     311             :     {
     312         458 :         const char *pszNext = OGRWktReadToken(pszInput, szToken);
     313         458 :         if (EQUAL(szToken, "EMPTY"))
     314             :         {
     315          17 :             OGRPoint *poGeom = new OGRPoint(0.0, 0.0);
     316          17 :             poGeom->empty();
     317          17 :             const OGRErr eErr = addGeometryDirectly(poGeom);
     318          17 :             if (eErr != OGRERR_NONE)
     319             :             {
     320           0 :                 CPLFree(paoPoints);
     321           0 :                 delete poGeom;
     322           3 :                 return eErr;
     323             :             }
     324             : 
     325          17 :             pszInput = pszNext;
     326             : 
     327          17 :             continue;
     328             :         }
     329             : 
     330         441 :         int flagsFromInput = flags;
     331         441 :         int nMaxPoint = 0;
     332         441 :         int nPointCount = 0;
     333         441 :         pszInput = OGRWktReadPointsM(pszInput, &paoPoints, &padfZ, &padfM,
     334             :                                      &flagsFromInput, &nMaxPoint, &nPointCount);
     335             : 
     336         441 :         if (pszInput == nullptr || nPointCount != 1)
     337             :         {
     338           3 :             CPLFree(paoPoints);
     339           3 :             CPLFree(padfZ);
     340           3 :             CPLFree(padfM);
     341           3 :             return OGRERR_CORRUPT_DATA;
     342             :         }
     343         438 :         if ((flagsFromInput & OGR_G_3D) && !(flags & OGR_G_3D))
     344             :         {
     345           4 :             flags |= OGR_G_3D;
     346           4 :             bHasZ = TRUE;
     347             :         }
     348         438 :         if ((flagsFromInput & OGR_G_MEASURED) && !(flags & OGR_G_MEASURED))
     349             :         {
     350           0 :             flags |= OGR_G_MEASURED;
     351           0 :             bHasM = TRUE;
     352             :         }
     353             : 
     354         438 :         OGRPoint *poPoint = new OGRPoint(paoPoints[0].x, paoPoints[0].y);
     355         438 :         if (bHasM)
     356             :         {
     357          88 :             if (padfM != nullptr)
     358          88 :                 poPoint->setM(padfM[0]);
     359             :             else
     360           0 :                 poPoint->setM(0.0);
     361             :         }
     362         438 :         if (bHasZ)
     363             :         {
     364         123 :             if (padfZ != nullptr)
     365         123 :                 poPoint->setZ(padfZ[0]);
     366             :             else
     367           0 :                 poPoint->setZ(0.0);
     368             :         }
     369             : 
     370         438 :         const OGRErr eErr = addGeometryDirectly(poPoint);
     371         438 :         if (eErr != OGRERR_NONE)
     372             :         {
     373           0 :             CPLFree(paoPoints);
     374           0 :             CPLFree(padfZ);
     375           0 :             CPLFree(padfM);
     376           0 :             delete poPoint;
     377           0 :             return eErr;
     378             :         }
     379             :     }
     380             : 
     381             :     /* -------------------------------------------------------------------- */
     382             :     /*      Cleanup.                                                        */
     383             :     /* -------------------------------------------------------------------- */
     384         203 :     CPLFree(paoPoints);
     385         203 :     CPLFree(padfZ);
     386         203 :     CPLFree(padfM);
     387             : 
     388         203 :     if (!EQUAL(szToken, ")"))
     389           6 :         return OGRERR_CORRUPT_DATA;
     390             : 
     391         197 :     *ppszInput = pszInput;
     392             : 
     393         197 :     return OGRERR_NONE;
     394             : }
     395             : 
     396             : /************************************************************************/
     397             : /*                          hasCurveGeometry()                          */
     398             : /************************************************************************/
     399             : 
     400        3207 : bool OGRMultiPoint::hasCurveGeometry(int /* bLookForNonLinear */) const
     401             : {
     402        3207 :     return FALSE;
     403             : }

Generated by: LCOV version 1.14