in src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSpatialDatatype.java [1895:2107]
int determineWkbCapacity() {
int totalSize = 0;
totalSize += BYTE_ORDER_SIZE; // byte order
totalSize += INTERNAL_TYPE_SIZE; // internal type size
switch (internalType) {
case POINT:
// Handle special case where POINT EMPTY
if (numberOfPoints == 0) {
totalSize += NUMBER_OF_SHAPES_SIZE; // number of points
}
totalSize += numberOfPoints * WKB_POINT_SIZE;
break;
case LINESTRING:
totalSize += NUMBER_OF_SHAPES_SIZE; // number of points
totalSize += numberOfPoints * WKB_POINT_SIZE;
break;
case POLYGON:
totalSize += NUMBER_OF_SHAPES_SIZE; // number of rings
totalSize += figures.length * 4 + (numberOfPoints * WKB_POINT_SIZE);
break;
case MULTIPOINT:
totalSize += NUMBER_OF_SHAPES_SIZE; // number of points
totalSize += numberOfFigures * WKB_POINT_HEADER_SIZE;
totalSize += numberOfPoints * WKB_POINT_SIZE;
break;
case MULTILINESTRING:
totalSize += NUMBER_OF_SHAPES_SIZE; // number of LineStrings
totalSize += numberOfFigures * WKB_HEADER_SIZE;
totalSize += numberOfPoints * WKB_POINT_SIZE;
break;
case MULTIPOLYGON:
totalSize += NUMBER_OF_SHAPES_SIZE; // number of polygons
totalSize += (numberOfShapes - 1) * WKB_HEADER_SIZE;
for (int i = 1; i < shapes.length; i++) {
if (i == shapes.length - 1) { // last element
totalSize += LINEAR_RING_HEADER_SIZE * (figures.length - shapes[i].getFigureOffset());
} else {
int nextFigureOffset = shapes[i + 1].getFigureOffset();
totalSize += LINEAR_RING_HEADER_SIZE * (nextFigureOffset - shapes[i].getFigureOffset());
}
}
totalSize += numberOfPoints * WKB_POINT_SIZE;
break;
case GEOMETRYCOLLECTION:
totalSize += NUMBER_OF_SHAPES_SIZE; // number of shapes
int actualNumberOfPoints = numberOfPoints;
for (Segment s : segments) {
if (s.getSegmentType() == SEGMENT_FIRST_ARC || s.getSegmentType() == SEGMENT_FIRST_LINE) {
totalSize += WKB_HEADER_SIZE;
actualNumberOfPoints++;
}
}
int numberOfCompositeCurves = 0;
for (Figure f : figures) {
if (f.getFiguresAttribute() == FA_COMPOSITE_CURVE) {
numberOfCompositeCurves++;
}
}
if (numberOfCompositeCurves > 1) {
actualNumberOfPoints = actualNumberOfPoints - (numberOfCompositeCurves - 1);
}
if (numberOfSegments > 0) {
actualNumberOfPoints--;
}
// start from 1
for (int i = 1; i < shapes.length; i++) {
if (shapes[i].getOpenGISType() == InternalSpatialDatatype.POINT.getTypeCode()) {
/*
* empty points are actually considered an empty multipoint in WKB. In this case, the figure
* offset will be -1, so adjust accordingly.
*/
if (shapes[i].getFigureOffset() == -1) {
totalSize += WKB_HEADER_SIZE;
} else {
totalSize += WKB_POINT_HEADER_SIZE;
}
} else if (shapes[i].getOpenGISType() == InternalSpatialDatatype.POLYGON.getTypeCode()) {
if (shapes[i].getFigureOffset() != -1) {
if (i == shapes.length - 1) { // last element
totalSize += LINEAR_RING_HEADER_SIZE * (figures.length - shapes[i].getFigureOffset());
} else {
/*
* the logic below handles cases where we have something like:
* GEOMETRYCOLLECTION(POLYGON(0 1, 0 2, 0 3), POLYGON EMPTY, POLYGON EMPTY) In this
* case, in order to find out how many figures there are in the first polygon, we need
* to look ahead to the next shape (POLYGON EMPTY) to find out how many figures are in
* this polygon. However, if the shape is empty, the figure index is going to be -1. If
* that happens, we need to keep looking ahead until we find a shape that isn't empty.
* If the last shape is also empty, then we can calculate the number of figures in the
* current polygon by doing (number of all the figures) - (current figure index).
*/
int figureIndexEnd = -1;
int localCurrentShapeIndex = i;
while (figureIndexEnd == -1 && localCurrentShapeIndex < shapes.length - 1) {
figureIndexEnd = shapes[localCurrentShapeIndex + 1].getFigureOffset();
localCurrentShapeIndex++;
}
if (figureIndexEnd == -1) {
figureIndexEnd = numberOfFigures;
}
totalSize += LINEAR_RING_HEADER_SIZE * (figureIndexEnd - shapes[i].getFigureOffset());
}
}
totalSize += WKB_HEADER_SIZE;
} else if (shapes[i].getOpenGISType() == InternalSpatialDatatype.CURVEPOLYGON.getTypeCode()) {
if (shapes[i].getFigureOffset() != -1) {
if (i == shapes.length - 1) { // last element
totalSize += WKB_HEADER_SIZE * (figures.length - shapes[i].getFigureOffset());
} else {
int figureIndexEnd = -1;
int localCurrentShapeIndex = i;
while (figureIndexEnd == -1 && localCurrentShapeIndex < shapes.length - 1) {
figureIndexEnd = shapes[localCurrentShapeIndex + 1].getFigureOffset();
localCurrentShapeIndex++;
}
if (figureIndexEnd == -1) {
figureIndexEnd = numberOfFigures;
}
totalSize += WKB_HEADER_SIZE * (figureIndexEnd - shapes[i].getFigureOffset());
}
}
totalSize += WKB_HEADER_SIZE;
} else {
totalSize += WKB_HEADER_SIZE;
}
}
totalSize += actualNumberOfPoints * WKB_POINT_SIZE;
break;
case CIRCULARSTRING:
totalSize += NUMBER_OF_SHAPES_SIZE; // number of points
totalSize += numberOfPoints * WKB_POINT_SIZE;
break;
case COMPOUNDCURVE:
totalSize += NUMBER_OF_SHAPES_SIZE; // number of curves
actualNumberOfPoints = numberOfPoints;
/*
* Segments are exclusively used by COMPOUNDCURVE. However, by extension GEOMETRYCOLLECTION or
* CURVEPOLYGON can have them beacuse they can contain COMPOUNDCURVE inside. If a geometric shape
* contains any number of COMPOUNDCURVEs, we need to calculate the actual number of points involved in
* the geometric shape. This is because some points in the compound curve shapes are being used across
* two segments. For example, let's say we have a COMPOUNDCURVE(CIRCULARSTRING(1 0, 0 1, 9 6, 8 7, -1
* 0), CIRCULARSTRING(-1 0, 7 9, -10 2)). This compoundcurve contains a CIRCULARSTRING that spans across
* 5 points, and another CIRCULARSTRING that spans across 3 points. In WKB format this would be
* considered as 8 points. However, the existing Geometry/Geography object will have their CLR sent from
* SQL Server as only having 7 points. This is because compoundcurves have a rule that all the segments
* have to be connected to each other (if the user tried to create a compoundcurve that doesn't link
* from one segment to the next, it will throw an error). Therefore, in order to convert from CLR to
* WKB, we need to find out the "true" number of points that exist in this geometric object, and the
* below logic handles the calculation.
*/
for (Segment s : segments) {
if (s.getSegmentType() == SEGMENT_FIRST_ARC || s.getSegmentType() == SEGMENT_FIRST_LINE) {
totalSize += WKB_HEADER_SIZE;
actualNumberOfPoints++;
}
}
if (numberOfSegments > 0) {
actualNumberOfPoints--;
}
totalSize += actualNumberOfPoints * WKB_POINT_SIZE;
break;
case CURVEPOLYGON:
totalSize += NUMBER_OF_SHAPES_SIZE; // number of shapes
actualNumberOfPoints = numberOfPoints;
for (Segment s : segments) {
if (s.getSegmentType() == SEGMENT_FIRST_ARC || s.getSegmentType() == SEGMENT_FIRST_LINE) {
totalSize += WKB_HEADER_SIZE;
actualNumberOfPoints++;
}
}
numberOfCompositeCurves = 0;
/*
* Since CURVEPOLYGONs can have COMPOUNDCURVEs inside, we need to account for them as well. However,
* COMPOUNDCURVEs inside CURVEPOLYGONs are treated differently than when they are on their own, because
* each compound curve (represented by f.getFiguresAttribute() == FA_COMPOSITE_CURVE) needs to wrap
* around to itself, which means that for every composite curve, the actual number of pointsdecreases by
* one. The below logic accounts for this.
*/
for (Figure f : figures) {
totalSize += WKB_HEADER_SIZE;
if (f.getFiguresAttribute() == FA_COMPOSITE_CURVE) {
numberOfCompositeCurves++;
}
}
if (numberOfCompositeCurves > 1) {
actualNumberOfPoints = actualNumberOfPoints - (numberOfCompositeCurves - 1);
}
if (numberOfSegments > 0) {
actualNumberOfPoints--;
}
totalSize += actualNumberOfPoints * WKB_POINT_SIZE;
break;
case FULLGLOBE:
totalSize = 5; // create a variable for this later?
break;
default:
break;
}
return totalSize;
}