LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/mssqlspatial - ogrmssqlgeometrywriter.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 0 345 0.0 %
Date: 2025-05-31 00:00:17 Functions: 0 16 0.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  MSSQL Spatial driver
       4             :  * Purpose:  Implements OGRMSSQLGeometryWriter class to write native
       5             :  *SqlGeometries. Author:   Tamas Szekeres, szekerest at gmail.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2016, Tamas Szekeres
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_conv.h"
      14             : #include "ogr_mssqlspatial.h"
      15             : 
      16             : /*   SqlGeometry/SqlGeography serialization format
      17             : 
      18             : Simple Point (SerializationProps & IsSinglePoint)
      19             :   [SRID][0x01][SerializationProps][Point][z][m]
      20             : 
      21             : Simple Line Segment (SerializationProps & IsSingleLineSegment)
      22             :   [SRID][0x01][SerializationProps][Point1][Point2][z1][z2][m1][m2]
      23             : 
      24             : Complex Geometries
      25             :   [SRID][VersionAttribute][SerializationProps][NumPoints][Point1]..[PointN][z1]..[zN][m1]..[mN]
      26             :   [NumFigures][Figure]..[Figure][NumShapes][Shape]..[Shape]
      27             : 
      28             : Complex Geometries (FigureAttribute == Curve)
      29             :   [SRID][VersionAttribute][SerializationProps][NumPoints][Point1]..[PointN][z1]..[zN][m1]..[mN]
      30             :   [NumFigures][Figure]..[Figure][NumShapes][Shape]..[Shape][NumSegments][SegmentType]..[SegmentType]
      31             : 
      32             : VersionAttribute (1 byte)
      33             :   0x01 = Katmai (MSSQL2008+)
      34             :   0x02 = Denali (MSSQL2012+)
      35             : 
      36             : SRID
      37             :   Spatial Reference Id (4 bytes)
      38             : 
      39             : SerializationProps (bitmask) 1 byte
      40             :   0x01 = HasZValues
      41             :   0x02 = HasMValues
      42             :   0x04 = IsValid
      43             :   0x08 = IsSinglePoint
      44             :   0x10 = IsSingleLineSegment
      45             :   0x20 = IsLargerThanAHemisphere
      46             : 
      47             : Point (2-4)x8 bytes, size depends on SerializationProps & HasZValues &
      48             : HasMValues [x][y]                  - SqlGeometry [latitude][longitude]   -
      49             : SqlGeography
      50             : 
      51             : Figure
      52             :   [FigureAttribute][PointOffset]
      53             : 
      54             : FigureAttribute - Katmai (1 byte)
      55             :   0x00 = Interior Ring
      56             :   0x01 = Stroke
      57             :   0x02 = Exterior Ring
      58             : 
      59             : FigureAttribute - Denali (1 byte)
      60             :   0x00 = None
      61             :   0x01 = Line
      62             :   0x02 = Arc
      63             :   0x03 = Curve
      64             : 
      65             : Shape
      66             :   [ParentFigureOffset][FigureOffset][ShapeType]
      67             : 
      68             : ShapeType (1 byte)
      69             :   0x00 = Unknown
      70             :   0x01 = Point
      71             :   0x02 = LineString
      72             :   0x03 = Polygon
      73             :   0x04 = MultiPoint
      74             :   0x05 = MultiLineString
      75             :   0x06 = MultiPolygon
      76             :   0x07 = GeometryCollection
      77             :   -- Denali
      78             :   0x08 = CircularString
      79             :   0x09 = CompoundCurve
      80             :   0x0A = CurvePolygon
      81             :   0x0B = FullGlobe
      82             : 
      83             : SegmentType (1 byte)
      84             :   0x00 = Line
      85             :   0x01 = Arc
      86             :   0x02 = FirstLine
      87             :   0x03 = FirstArc
      88             : 
      89             : */
      90             : 
      91             : /************************************************************************/
      92             : /*                         Geometry writer macros                       */
      93             : /************************************************************************/
      94             : 
      95             : #define WriteInt32(nPos, value)                                                \
      96             :     (*(reinterpret_cast<unsigned int *>(pszData + (nPos))) = value)
      97             : 
      98             : #define WriteByte(nPos, value) (pszData[nPos] = value)
      99             : 
     100             : #define WriteDouble(nPos, value)                                               \
     101             :     (*(reinterpret_cast<double *>(pszData + (nPos))) = value)
     102             : 
     103             : #define ParentOffset(iShape) (nShapePos + (iShape)*9)
     104             : #define FigureOffset(iShape) (nShapePos + (iShape)*9 + 4)
     105             : #define ShapeType(iShape) (nShapePos + (iShape)*9 + 8)
     106             : #define SegmentType(iSegment) (nSegmentPos + (iSegment))
     107             : 
     108             : #define FigureAttribute(iFigure) (nFigurePos + (iFigure)*5)
     109             : #define PointOffset(iFigure) (nFigurePos + (iFigure)*5 + 1)
     110             : 
     111             : #define WriteX(iPoint, value) (WriteDouble(nPointPos + 16 * (iPoint), value))
     112             : #define WriteY(iPoint, value)                                                  \
     113             :     (WriteDouble(nPointPos + 16 * (iPoint) + 8, value))
     114             : #define WriteZ(iPoint, value)                                                  \
     115             :     (WriteDouble(nPointPos + 16 * nNumPoints + 8 * (iPoint), value))
     116             : #define WriteM(iPoint, value)                                                  \
     117             :     (WriteDouble(nPointPos + 24 * nNumPoints + 8 * (iPoint), value))
     118             : 
     119             : /************************************************************************/
     120             : /*                   OGRMSSQLGeometryWriter()                           */
     121             : /************************************************************************/
     122             : 
     123           0 : OGRMSSQLGeometryWriter::OGRMSSQLGeometryWriter(OGRGeometry *poGeometry,
     124           0 :                                                int nGeomColumnType, int nSRS)
     125             : {
     126           0 :     nColType = nGeomColumnType;
     127           0 :     nSRSId = nSRS;
     128           0 :     poGeom2 = poGeometry;
     129             : 
     130           0 :     chProps = 0;
     131             : 
     132             :     /* calculate required buffer length and the attributes */
     133           0 :     nPointSize = 16;
     134           0 :     if (poGeom2->getCoordinateDimension() == 3)
     135             :     {
     136           0 :         chProps |= SP_HASZVALUES;
     137           0 :         nPointSize += 8;
     138             :     }
     139             : 
     140           0 :     if (poGeom2->IsMeasured())
     141             :     {
     142           0 :         chProps |= SP_HASMVALUES;
     143           0 :         nPointSize += 8;
     144             :     }
     145             : 
     146           0 :     iPoint = 0;
     147           0 :     nNumPoints = 0;
     148           0 :     iFigure = 0;
     149           0 :     nNumFigures = 0;
     150           0 :     iShape = 0;
     151           0 :     nNumShapes = 0;
     152           0 :     iSegment = 0;
     153           0 :     nNumSegments = 0;
     154             : 
     155             :     /* calculate points figures, shapes and segments*/
     156           0 :     chVersion = VA_KATMAI;
     157           0 :     TrackGeometry(poGeom2);
     158           0 :     ++nNumShapes;
     159             : 
     160           0 :     OGRwkbGeometryType geomType = wkbFlatten(poGeom2->getGeometryType());
     161             : 
     162           0 :     if (nNumPoints == 1 && geomType == wkbPoint)
     163             :     {
     164             :         /* writing a single point */
     165           0 :         chProps |= SP_ISSINGLEPOINT | SP_ISVALID;
     166           0 :         nPointPos = 6;
     167           0 :         nLen = nPointPos + nPointSize;
     168             :     }
     169           0 :     else if (nNumPoints == 2 && geomType == wkbLineString)
     170             :     {
     171             :         /* writing a single line */
     172           0 :         chProps |= SP_ISSINGLELINESEGMENT | SP_ISVALID;
     173           0 :         nPointPos = 6;
     174           0 :         nLen = nPointPos + nPointSize * 2;
     175             :     }
     176             :     else
     177             :     {
     178             :         /* complex geometry */
     179           0 :         nPointPos = 10;
     180           0 :         nFigurePos = nPointPos + nPointSize * nNumPoints + 4;
     181           0 :         nShapePos = nFigurePos + 5 * nNumFigures + 4;
     182           0 :         nSegmentPos = nShapePos + 9 * nNumShapes + 4;
     183           0 :         if (nNumSegments > 0)
     184           0 :             nLen = nSegmentPos + nNumSegments;
     185             :         else
     186           0 :             nLen = nShapePos + 9 * nNumShapes;
     187             :     }
     188           0 : }
     189             : 
     190             : /************************************************************************/
     191             : /*                         WritePoint()                                 */
     192             : /************************************************************************/
     193             : 
     194           0 : void OGRMSSQLGeometryWriter::WritePoint(OGRPoint *poGeom)
     195             : {
     196           0 :     if ((chProps & SP_HASZVALUES) && (chProps & SP_HASMVALUES))
     197           0 :         WritePoint(poGeom->getX(), poGeom->getY(), poGeom->getZ(),
     198             :                    poGeom->getM());
     199           0 :     else if (chProps & SP_HASZVALUES)
     200           0 :         WritePoint(poGeom->getX(), poGeom->getY(), poGeom->getZ());
     201           0 :     else if (chProps & SP_HASMVALUES)
     202           0 :         WritePoint(poGeom->getX(), poGeom->getY(), poGeom->getM());
     203             :     else
     204           0 :         WritePoint(poGeom->getX(), poGeom->getY());
     205           0 : }
     206             : 
     207           0 : void OGRMSSQLGeometryWriter::WritePoint(double x, double y)
     208             : {
     209           0 :     if (nColType == MSSQLCOLTYPE_GEOGRAPHY)
     210             :     {
     211           0 :         WriteY(iPoint, x);
     212           0 :         WriteX(iPoint, y);
     213             :     }
     214             :     else
     215             :     {
     216           0 :         WriteX(iPoint, x);
     217           0 :         WriteY(iPoint, y);
     218             :     }
     219           0 :     ++iPoint;
     220           0 : }
     221             : 
     222           0 : void OGRMSSQLGeometryWriter::WritePoint(double x, double y, double z)
     223             : {
     224           0 :     WriteZ(iPoint, z);
     225           0 :     WritePoint(x, y);
     226           0 : }
     227             : 
     228           0 : void OGRMSSQLGeometryWriter::WritePoint(double x, double y, double z, double m)
     229             : {
     230           0 :     WriteZ(iPoint, z);
     231           0 :     WriteM(iPoint, m);
     232           0 :     WritePoint(x, y);
     233           0 : }
     234             : 
     235             : /************************************************************************/
     236             : /*                         WriteSimpleCurve()                           */
     237             : /************************************************************************/
     238             : 
     239           0 : void OGRMSSQLGeometryWriter::WriteSimpleCurve(OGRSimpleCurve *poGeom,
     240             :                                               int iStartIndex, int nCount,
     241             :                                               bool bReversePoints)
     242             : {
     243           0 :     if (bReversePoints && iStartIndex == 0)
     244             :     {
     245           0 :         poGeom->reversePoints();
     246             :     }
     247             : 
     248           0 :     if ((chProps & SP_HASZVALUES) && (chProps & SP_HASMVALUES))
     249             :     {
     250           0 :         for (int i = iStartIndex; i < iStartIndex + nCount; i++)
     251           0 :             WritePoint(poGeom->getX(i), poGeom->getY(i), poGeom->getZ(i),
     252           0 :                        poGeom->getM(i));
     253             :     }
     254           0 :     else if (chProps & SP_HASZVALUES)
     255             :     {
     256           0 :         for (int i = iStartIndex; i < iStartIndex + nCount; i++)
     257           0 :             WritePoint(poGeom->getX(i), poGeom->getY(i), poGeom->getZ(i));
     258             :     }
     259           0 :     else if (chProps & SP_HASMVALUES)
     260             :     {
     261           0 :         for (int i = iStartIndex; i < iStartIndex + nCount; i++)
     262           0 :             WritePoint(poGeom->getX(i), poGeom->getY(i), poGeom->getM(i));
     263             :     }
     264             :     else
     265             :     {
     266           0 :         for (int i = iStartIndex; i < iStartIndex + nCount; i++)
     267           0 :             WritePoint(poGeom->getX(i), poGeom->getY(i));
     268             :     }
     269           0 : }
     270             : 
     271           0 : void OGRMSSQLGeometryWriter::WriteSimpleCurve(OGRSimpleCurve *poGeom,
     272             :                                               int iStartIndex,
     273             :                                               bool bReversePoints)
     274             : {
     275           0 :     WriteSimpleCurve(poGeom, iStartIndex, poGeom->getNumPoints() - iStartIndex,
     276             :                      bReversePoints);
     277           0 : }
     278             : 
     279           0 : void OGRMSSQLGeometryWriter::WriteSimpleCurve(OGRSimpleCurve *poGeom,
     280             :                                               bool bReversePoints)
     281             : {
     282           0 :     WriteSimpleCurve(poGeom, 0, poGeom->getNumPoints(), bReversePoints);
     283           0 : }
     284             : 
     285             : /************************************************************************/
     286             : /*                         WriteCompoundCurve()                         */
     287             : /************************************************************************/
     288             : 
     289           0 : void OGRMSSQLGeometryWriter::WriteCompoundCurve(OGRCompoundCurve *poGeom)
     290             : {
     291             :     OGRSimpleCurve *poSubGeom;
     292           0 :     WriteByte(FigureAttribute(iFigure), FA_CURVE);
     293           0 :     WriteInt32(PointOffset(iFigure), iPoint);
     294           0 :     for (int i = 0; i < poGeom->getNumCurves(); i++)
     295             :     {
     296           0 :         poSubGeom = poGeom->getCurve(i)->toSimpleCurve();
     297           0 :         switch (wkbFlatten(poSubGeom->getGeometryType()))
     298             :         {
     299           0 :             case wkbLineString:
     300           0 :                 if (i == 0)
     301           0 :                     WriteSimpleCurve(poSubGeom, false);
     302             :                 else
     303           0 :                     WriteSimpleCurve(poSubGeom, 1, false);
     304           0 :                 for (int j = 1; j < poSubGeom->getNumPoints(); j++)
     305             :                 {
     306           0 :                     if (j == 1)
     307           0 :                         WriteByte(SegmentType(iSegment++), SMT_FIRSTLINE);
     308             :                     else
     309           0 :                         WriteByte(SegmentType(iSegment++), SMT_LINE);
     310             :                 }
     311           0 :                 break;
     312             : 
     313           0 :             case wkbCircularString:
     314           0 :                 if (i == 0)
     315           0 :                     WriteSimpleCurve(poSubGeom, false);
     316             :                 else
     317           0 :                     WriteSimpleCurve(poSubGeom, 1, false);
     318           0 :                 for (int j = 2; j < poSubGeom->getNumPoints(); j += 2)
     319             :                 {
     320           0 :                     if (j == 2)
     321           0 :                         WriteByte(SegmentType(iSegment++), SMT_FIRSTARC);
     322             :                     else
     323           0 :                         WriteByte(SegmentType(iSegment++), SMT_ARC);
     324             :                 }
     325           0 :                 break;
     326             : 
     327           0 :             default:
     328           0 :                 break;
     329             :         }
     330             :     }
     331           0 : }
     332             : 
     333             : /************************************************************************/
     334             : /*                         WriteCurve()                                 */
     335             : /************************************************************************/
     336             : 
     337           0 : void OGRMSSQLGeometryWriter::WriteCurve(OGRCurve *poGeom, bool bReversePoints)
     338             : {
     339           0 :     switch (wkbFlatten(poGeom->getGeometryType()))
     340             :     {
     341           0 :         case wkbLineString:
     342             :         case wkbLinearRing:
     343           0 :             WriteByte(FigureAttribute(iFigure), FA_LINE);
     344           0 :             WriteInt32(PointOffset(iFigure), iPoint);
     345           0 :             WriteSimpleCurve(poGeom->toSimpleCurve(), bReversePoints);
     346           0 :             ++iFigure;
     347           0 :             break;
     348             : 
     349           0 :         case wkbCircularString:
     350           0 :             WriteByte(FigureAttribute(iFigure), FA_ARC);
     351           0 :             WriteInt32(PointOffset(iFigure), iPoint);
     352           0 :             WriteSimpleCurve(poGeom->toSimpleCurve(), bReversePoints);
     353           0 :             ++iFigure;
     354           0 :             break;
     355             : 
     356           0 :         case wkbCompoundCurve:
     357           0 :             WriteCompoundCurve(poGeom->toCompoundCurve());
     358           0 :             ++iFigure;
     359           0 :             break;
     360             : 
     361           0 :         default:
     362           0 :             break;
     363             :     }
     364           0 : }
     365             : 
     366             : /************************************************************************/
     367             : /*                         WritePolygon()                               */
     368             : /************************************************************************/
     369             : 
     370           0 : void OGRMSSQLGeometryWriter::WritePolygon(OGRPolygon *poGeom)
     371             : {
     372             :     int r;
     373           0 :     OGRLinearRing *poRing = poGeom->getExteriorRing();
     374             : 
     375           0 :     if (poRing == nullptr)
     376           0 :         return;
     377             : 
     378           0 :     if (chVersion == VA_KATMAI)
     379           0 :         WriteByte(FigureAttribute(iFigure), FA_EXTERIORRING);
     380             :     else
     381           0 :         WriteByte(FigureAttribute(iFigure), FA_LINE);
     382             : 
     383           0 :     WriteInt32(PointOffset(iFigure), iPoint);
     384           0 :     WriteSimpleCurve(poRing, poRing->isClockwise() &&
     385           0 :                                  nColType == MSSQLCOLTYPE_GEOGRAPHY);
     386           0 :     ++iFigure;
     387           0 :     for (r = 0; r < poGeom->getNumInteriorRings(); r++)
     388             :     {
     389             :         /* write interior rings */
     390           0 :         poRing = poGeom->getInteriorRing(r);
     391           0 :         if (chVersion == VA_KATMAI)
     392           0 :             WriteByte(FigureAttribute(iFigure), FA_INTERIORRING);
     393             :         else
     394           0 :             WriteByte(FigureAttribute(iFigure), FA_LINE);
     395             : 
     396           0 :         WriteInt32(PointOffset(iFigure), iPoint);
     397           0 :         WriteSimpleCurve(poRing, !poRing->isClockwise() &&
     398           0 :                                      nColType == MSSQLCOLTYPE_GEOGRAPHY);
     399           0 :         ++iFigure;
     400             :     }
     401             : }
     402             : 
     403             : /************************************************************************/
     404             : /*                         WriteCurvePolygon()                          */
     405             : /************************************************************************/
     406             : 
     407           0 : void OGRMSSQLGeometryWriter::WriteCurvePolygon(OGRCurvePolygon *poGeom)
     408             : {
     409           0 :     if (poGeom->getExteriorRingCurve() == nullptr)
     410           0 :         return;
     411             : 
     412           0 :     WriteCurve(poGeom->getExteriorRingCurve(),
     413           0 :                poGeom->getExteriorRingCurve()->isClockwise() &&
     414           0 :                    nColType == MSSQLCOLTYPE_GEOGRAPHY);
     415           0 :     for (int r = 0; r < poGeom->getNumInteriorRings(); r++)
     416             :     {
     417             :         /* write interior rings */
     418           0 :         WriteCurve(poGeom->getInteriorRingCurve(r),
     419           0 :                    !poGeom->getInteriorRingCurve(r)->isClockwise() &&
     420           0 :                        nColType == MSSQLCOLTYPE_GEOGRAPHY);
     421             :     }
     422             : }
     423             : 
     424             : /************************************************************************/
     425             : /*                         WriteGeometryCollection()                    */
     426             : /************************************************************************/
     427             : 
     428           0 : void OGRMSSQLGeometryWriter::WriteGeometryCollection(
     429             :     OGRGeometryCollection *poGeom, int iParent)
     430             : {
     431           0 :     for (int i = 0; i < poGeom->getNumGeometries(); i++)
     432           0 :         WriteGeometry(poGeom->getGeometryRef(i), iParent);
     433           0 : }
     434             : 
     435             : /************************************************************************/
     436             : /*                         WriteGeometry()                              */
     437             : /************************************************************************/
     438             : 
     439           0 : void OGRMSSQLGeometryWriter::WriteGeometry(OGRGeometry *poGeom, int iParent)
     440             : {
     441             :     /* write shape */
     442           0 :     int iCurrentFigure = iFigure;
     443           0 :     int iCurrentShape = iShape;
     444           0 :     WriteInt32(ParentOffset(iShape), iParent);
     445             : 
     446           0 :     iParent = iShape;
     447             : 
     448           0 :     switch (wkbFlatten(poGeom->getGeometryType()))
     449             :     {
     450           0 :         case wkbPoint:
     451           0 :             WriteByte(ShapeType(iShape++), ST_POINT);
     452           0 :             if (!poGeom->IsEmpty())
     453             :             {
     454           0 :                 if (chVersion == VA_KATMAI)
     455           0 :                     WriteByte(FigureAttribute(iFigure), FA_STROKE);
     456             :                 else
     457           0 :                     WriteByte(FigureAttribute(iFigure), FA_LINE);
     458           0 :                 WriteInt32(PointOffset(iFigure), iPoint);
     459           0 :                 WritePoint(poGeom->toPoint());
     460           0 :                 ++iFigure;
     461             :             }
     462           0 :             break;
     463             : 
     464           0 :         case wkbLineString:
     465           0 :             WriteByte(ShapeType(iShape++), ST_LINESTRING);
     466           0 :             if (!poGeom->IsEmpty())
     467             :             {
     468           0 :                 if (chVersion == VA_KATMAI)
     469           0 :                     WriteByte(FigureAttribute(iFigure), FA_STROKE);
     470             :                 else
     471           0 :                     WriteByte(FigureAttribute(iFigure), FA_LINE);
     472           0 :                 WriteInt32(PointOffset(iFigure), iPoint);
     473           0 :                 WriteSimpleCurve(poGeom->toSimpleCurve(), false);
     474           0 :                 ++iFigure;
     475             :             }
     476           0 :             break;
     477             : 
     478           0 :         case wkbCircularString:
     479           0 :             WriteByte(ShapeType(iShape++), ST_CIRCULARSTRING);
     480           0 :             if (!poGeom->IsEmpty())
     481             :             {
     482           0 :                 if (chVersion == VA_KATMAI)
     483           0 :                     WriteByte(FigureAttribute(iFigure), FA_STROKE);
     484             :                 else
     485           0 :                     WriteByte(FigureAttribute(iFigure), FA_ARC);
     486           0 :                 WriteInt32(PointOffset(iFigure), iPoint);
     487           0 :                 WriteSimpleCurve(poGeom->toSimpleCurve(), false);
     488           0 :                 ++iFigure;
     489             :             }
     490           0 :             break;
     491             : 
     492           0 :         case wkbCompoundCurve:
     493           0 :             WriteByte(ShapeType(iShape++), ST_COMPOUNDCURVE);
     494           0 :             if (!poGeom->IsEmpty())
     495             :             {
     496           0 :                 WriteCompoundCurve(poGeom->toCompoundCurve());
     497           0 :                 ++iFigure;
     498             :             }
     499           0 :             break;
     500             : 
     501           0 :         case wkbPolygon:
     502           0 :             WriteByte(ShapeType(iShape++), ST_POLYGON);
     503           0 :             WritePolygon(poGeom->toPolygon());
     504           0 :             break;
     505             : 
     506           0 :         case wkbCurvePolygon:
     507           0 :             WriteByte(ShapeType(iShape++), ST_CURVEPOLYGON);
     508           0 :             WriteCurvePolygon(poGeom->toCurvePolygon());
     509           0 :             break;
     510             : 
     511           0 :         case wkbMultiPoint:
     512           0 :             WriteByte(ShapeType(iShape++), ST_MULTIPOINT);
     513           0 :             WriteGeometryCollection(poGeom->toGeometryCollection(), iParent);
     514           0 :             break;
     515             : 
     516           0 :         case wkbMultiLineString:
     517           0 :             WriteByte(ShapeType(iShape++), ST_MULTILINESTRING);
     518           0 :             WriteGeometryCollection(poGeom->toGeometryCollection(), iParent);
     519           0 :             break;
     520             : 
     521           0 :         case wkbMultiPolygon:
     522           0 :             WriteByte(ShapeType(iShape++), ST_MULTIPOLYGON);
     523           0 :             WriteGeometryCollection(poGeom->toGeometryCollection(), iParent);
     524           0 :             break;
     525             : 
     526           0 :         case wkbGeometryCollection:
     527           0 :             WriteByte(ShapeType(iShape++), ST_GEOMETRYCOLLECTION);
     528           0 :             WriteGeometryCollection(poGeom->toGeometryCollection(), iParent);
     529           0 :             break;
     530             : 
     531           0 :         default:
     532           0 :             return;
     533             :     }
     534             :     // check if new figures have been added to shape
     535           0 :     WriteInt32(FigureOffset(iCurrentShape),
     536             :                iFigure == iCurrentFigure ? 0xFFFFFFFF : iCurrentFigure);
     537             : }
     538             : 
     539             : /************************************************************************/
     540             : /*                         TrackGeometry()                              */
     541             : /************************************************************************/
     542             : 
     543           0 : void OGRMSSQLGeometryWriter::TrackGeometry(OGRGeometry *poGeom)
     544             : {
     545           0 :     switch (wkbFlatten(poGeom->getGeometryType()))
     546             :     {
     547           0 :         case wkbPoint:
     548           0 :             if (!poGeom->IsEmpty())
     549             :             {
     550           0 :                 ++nNumFigures;
     551           0 :                 ++nNumPoints;
     552             :             }
     553           0 :             break;
     554             : 
     555           0 :         case wkbLineString:
     556           0 :             if (!poGeom->IsEmpty())
     557             :             {
     558           0 :                 ++nNumFigures;
     559           0 :                 nNumPoints += poGeom->toLineString()->getNumPoints();
     560             :             }
     561           0 :             break;
     562             : 
     563           0 :         case wkbCircularString:
     564           0 :             chVersion = VA_DENALI;
     565           0 :             if (!poGeom->IsEmpty())
     566             :             {
     567           0 :                 ++nNumFigures;
     568           0 :                 nNumPoints += poGeom->toCircularString()->getNumPoints();
     569             :             }
     570           0 :             break;
     571             : 
     572           0 :         case wkbCompoundCurve:
     573             :         {
     574             :             int c;
     575           0 :             chVersion = VA_DENALI;
     576           0 :             if (!poGeom->IsEmpty())
     577             :             {
     578           0 :                 OGRCompoundCurve *g = poGeom->toCompoundCurve();
     579             :                 OGRCurve *poSubGeom;
     580           0 :                 ++nNumFigures;
     581           0 :                 for (int i = 0; i < g->getNumCurves(); i++)
     582             :                 {
     583           0 :                     poSubGeom = g->getCurve(i);
     584           0 :                     switch (wkbFlatten(poSubGeom->getGeometryType()))
     585             :                     {
     586           0 :                         case wkbLineString:
     587           0 :                             c = poSubGeom->toLineString()->getNumPoints();
     588           0 :                             if (c > 1)
     589             :                             {
     590           0 :                                 if (i == 0)
     591           0 :                                     nNumPoints += c;
     592             :                                 else
     593           0 :                                     nNumPoints += c - 1;
     594           0 :                                 nNumSegments += c - 1;
     595             :                             }
     596           0 :                             break;
     597             : 
     598           0 :                         case wkbCircularString:
     599           0 :                             c = poSubGeom->toCircularString()->getNumPoints();
     600           0 :                             if (c > 2)
     601             :                             {
     602           0 :                                 if (i == 0)
     603           0 :                                     nNumPoints += c;
     604             :                                 else
     605           0 :                                     nNumPoints += c - 1;
     606           0 :                                 nNumSegments += static_cast<int>((c - 1) / 2);
     607             :                             }
     608           0 :                             break;
     609             : 
     610           0 :                         default:
     611           0 :                             break;
     612             :                     }
     613             :                 }
     614             :             }
     615             :         }
     616           0 :         break;
     617             : 
     618           0 :         case wkbPolygon:
     619             :         {
     620           0 :             OGRPolygon *g = poGeom->toPolygon();
     621           0 :             for (auto &&poIter : *g)
     622           0 :                 TrackGeometry(poIter);
     623             :         }
     624           0 :         break;
     625             : 
     626           0 :         case wkbCurvePolygon:
     627             :         {
     628           0 :             chVersion = VA_DENALI;
     629           0 :             OGRCurvePolygon *g = poGeom->toCurvePolygon();
     630           0 :             for (auto &&poIter : *g)
     631           0 :                 TrackGeometry(poIter);
     632             :         }
     633           0 :         break;
     634             : 
     635           0 :         case wkbMultiPoint:
     636             :         case wkbMultiLineString:
     637             :         case wkbMultiPolygon:
     638             :         case wkbGeometryCollection:
     639             :         {
     640           0 :             OGRGeometryCollection *g = poGeom->toGeometryCollection();
     641           0 :             for (auto &&poMember : *g)
     642             :             {
     643           0 :                 TrackGeometry(poMember);
     644           0 :                 ++nNumShapes;
     645             :             }
     646             :         }
     647           0 :         break;
     648             : 
     649           0 :         default:
     650           0 :             break;
     651             :     }
     652           0 : }
     653             : 
     654             : /************************************************************************/
     655             : /*                         WriteSqlGeometry()                           */
     656             : /************************************************************************/
     657             : 
     658           0 : OGRErr OGRMSSQLGeometryWriter::WriteSqlGeometry(unsigned char *pszBuffer,
     659             :                                                 int nBufLen)
     660             : {
     661           0 :     pszData = pszBuffer;
     662             : 
     663           0 :     if (nBufLen < nLen)
     664           0 :         return OGRERR_FAILURE;
     665             : 
     666           0 :     OGRwkbGeometryType geomType = wkbFlatten(poGeom2->getGeometryType());
     667             : 
     668           0 :     if (nNumPoints == 1 && geomType == wkbPoint)
     669             :     {
     670             :         /* writing a single point */
     671           0 :         OGRPoint *g = poGeom2->toPoint();
     672           0 :         WriteInt32(0, nSRSId);
     673           0 :         WriteByte(4, VA_KATMAI);
     674           0 :         WriteByte(5, chProps);
     675           0 :         WritePoint(g);
     676             :     }
     677           0 :     else if (nNumPoints == 2 && geomType == wkbLineString)
     678             :     {
     679             :         /* writing a single line */
     680           0 :         OGRLineString *g = poGeom2->toLineString();
     681           0 :         WriteInt32(0, nSRSId);
     682           0 :         WriteByte(4, VA_KATMAI);
     683           0 :         WriteByte(5, chProps);
     684             : 
     685           0 :         if ((chProps & SP_HASZVALUES) && (chProps & SP_HASMVALUES))
     686             :         {
     687           0 :             WritePoint(g->getX(0), g->getY(0), g->getZ(0), g->getM(0));
     688           0 :             WritePoint(g->getX(1), g->getY(1), g->getZ(1), g->getM(1));
     689             :         }
     690           0 :         else if (chProps & SP_HASZVALUES)
     691             :         {
     692           0 :             WritePoint(g->getX(0), g->getY(0), g->getZ(0));
     693           0 :             WritePoint(g->getX(1), g->getY(1), g->getZ(1));
     694             :         }
     695           0 :         else if (chProps & SP_HASMVALUES)
     696             :         {
     697           0 :             WritePoint(g->getX(0), g->getY(0), g->getM(0));
     698           0 :             WritePoint(g->getX(1), g->getY(1), g->getM(1));
     699             :         }
     700             :         else
     701             :         {
     702           0 :             WritePoint(g->getX(0), g->getY(0));
     703           0 :             WritePoint(g->getX(1), g->getY(1));
     704           0 :         }
     705             :     }
     706             :     else
     707             :     {
     708             :         /* complex geometry */
     709           0 :         if (poGeom2->IsValid())
     710           0 :             chProps |= SP_ISVALID;
     711             : 
     712           0 :         WriteInt32(0, nSRSId);
     713           0 :         WriteByte(4, chVersion);
     714           0 :         WriteByte(5, chProps);
     715           0 :         WriteInt32(nPointPos - 4, nNumPoints);
     716           0 :         WriteInt32(nFigurePos - 4, nNumFigures);
     717           0 :         WriteInt32(nShapePos - 4, nNumShapes);
     718           0 :         if (nNumSegments > 0)
     719           0 :             WriteInt32(nSegmentPos - 4, nNumSegments);
     720             : 
     721           0 :         WriteGeometry(poGeom2, 0xFFFFFFFF);
     722             :     }
     723           0 :     return OGRERR_NONE;
     724             : }
     725             : 
     726             : #undef ParentOffset
     727             : #undef FigureOffset
     728             : #undef ShapeType
     729             : #undef SegmentType
     730             : 
     731             : #undef FigureAttribute
     732             : #undef PointOffset
     733             : #undef NextPointOffset

Generated by: LCOV version 1.14