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