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
|