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