All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.geolatte.geom.codec.db.sqlserver.SqlServerGeometry Maven / Gradle / Ivy

Go to download

This geoLatte-geom library offers a geometry model that conforms to the OGC Simple Features for SQL specification.

The newest version!
/*
 * This file is part of the GeoLatte project.
 *
 *     GeoLatte is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     GeoLatte is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Lesser General Public License for more details.
 *
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with GeoLatte.  If not, see .
 *
 * Copyright (C) 2010 - 2013 and Ownership of code is shared by:
 * Qmino bvba - Romeinsestraat 18 - 3001 Heverlee  (http://www.qmino.com)
 * Geovise bvba - Generaal Eisenhowerlei 9 - 2140 Antwerpen (http://www.geovise.com)
 */

package org.geolatte.geom.codec.db.sqlserver;

import org.geolatte.geom.Position;
import org.geolatte.geom.PositionSequence;
import org.geolatte.geom.PositionSequenceBuilder;
import org.geolatte.geom.PositionSequenceBuilders;
import org.geolatte.geom.crs.*;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import static org.geolatte.geom.crs.CoordinateReferenceSystems.hasMeasureAxis;
import static org.geolatte.geom.crs.CoordinateReferenceSystems.hasVerticalAxis;

/**
 * A SqlServerGeometry represents the native SQL Server database object.
 *
 * 

Instances are created by deserializing the byte array returned in the JDBC result set. * They present the structure of the SQL Server Geometry object as specified in Microsoft SQL Server CLR Types Serialization Formats . * * @author Karel Maesen, Geovise BVBA. */ public class SqlServerGeometry { public static final byte SUPPORTED_VERSION = 1; private static final CoordinateReferenceSystem DEFAULT_CRS = CoordinateReferenceSystems.mkProjected(CrsId.valueOf(0), Unit.METER); private static final byte hasZValuesMask = 1; private static final byte hasMValuesMask = 2; private static final byte isValidMask = 4; private static final byte isSinglePointMask = 8; private static final byte isSingleLineSegment = 16; private ByteBuffer buffer; private Integer srid = 0; private CoordinateReferenceSystem crs = DEFAULT_CRS; private byte version; private byte serializationPropertiesByte; private int numberOfPoints; private double[] points; private double[] mValues; private double[] zValues; private int numberOfFigures; private Figure[] figures = null; private int numberOfShapes; private Shape[] shapes = null; private SqlServerGeometry(byte[] bytes) { buffer = ByteBuffer.wrap(bytes); buffer.order(ByteOrder.LITTLE_ENDIAN); } SqlServerGeometry() { } public static byte[] serialize(SqlServerGeometry sqlServerGeom) { int capacity = sqlServerGeom.calculateCapacity(); ByteBuffer buffer = ByteBuffer.allocate(capacity); buffer.order(ByteOrder.LITTLE_ENDIAN); buffer.putInt(sqlServerGeom.srid); buffer.put(SUPPORTED_VERSION); buffer.put(sqlServerGeom.serializationPropertiesByte); if (!sqlServerGeom.isSinglePoint() && !sqlServerGeom.isSingleLineSegment()) { buffer.putInt(sqlServerGeom.numberOfPoints); } for (int i = 0; i < sqlServerGeom.getNumPoints(); i++) { buffer.putDouble(sqlServerGeom.points[2 * i]); buffer.putDouble(sqlServerGeom.points[2 * i + 1]); } if (sqlServerGeom.hasZValues()) { for (int i = 0; i < sqlServerGeom.zValues.length; i++) { buffer.putDouble(sqlServerGeom.zValues[i]); } } if (sqlServerGeom.hasMValues()) { for (int i = 0; i < sqlServerGeom.mValues.length; i++) { buffer.putDouble(sqlServerGeom.mValues[i]); } } if (sqlServerGeom.isSingleLineSegment() || sqlServerGeom.isSinglePoint()) { return buffer.array(); } //in all other cases, we continue to serialize shapes and figures buffer.putInt(sqlServerGeom.getNumFigures()); for (int i = 0; i < sqlServerGeom.getNumFigures(); i++) { sqlServerGeom.getFigure(i).store(buffer); } buffer.putInt(sqlServerGeom.getNumShapes()); for (int i = 0; i < sqlServerGeom.getNumShapes(); i++) { sqlServerGeom.getShape(i).store(buffer); } return buffer.array(); } public static SqlServerGeometry deserialize(byte[] bytes) { SqlServerGeometry result = new SqlServerGeometry(bytes); result.parse(); return result; }

void copyCoordinate(int index, double[] coords, CoordinateReferenceSystem

crs) { coords[0] = points[2 * index]; coords[1] = points[2 * index + 1]; int idx = 2; if (hasZValues()) { assert (hasVerticalAxis(crs)); coords[idx++] = zValues[index]; } if (hasMValues()) { assert (CoordinateReferenceSystems.hasMeasureAxis(crs)); coords[idx] = mValues[index]; } } void setCoordinateReferenceSystem(CoordinateReferenceSystem crs) { this.crs = crs; this.srid = crs.getCrsId().getCode(); } boolean isParentShapeOf(int parent, int child) { return getShape(child).parentOffset == parent; } boolean isEmptyShape(int shapeIndex) { return getShape(shapeIndex).figureOffset == -1; } IndexRange getFiguresForShape(int shapeIndex) { int startIdx = getShape(shapeIndex).figureOffset; if (startIdx == -1) { return new IndexRange(-1, -1); //empty figures } int endIdx = -1; int nextShapeIdx = shapeIndex + 1; if (nextShapeIdx == getNumShapes()) { endIdx = getNumFigures(); } else { endIdx = getShape(nextShapeIdx).figureOffset; } return new IndexRange(startIdx, endIdx); } /** * Returns the range of indices in the point array for the specified figure. * * @param figureIndex index to shape in shape array * @return index range for */ IndexRange getPointsForFigure(int figureIndex) { int start = getFigure(figureIndex).pointOffset; int end = -1; int nextFigure = figureIndex + 1; if (nextFigure == getNumFigures()) { end = getNumPoints(); } else { end = getFigure(nextFigure).pointOffset; } return new IndexRange(start, end); } boolean isFigureInteriorRing(int figureIdx) { return getFigure(figureIdx).isInteriorRing(); } OpenGisType getOpenGisTypeOfShape(int shpIdx) { return getShape(shpIdx).openGisType; } CoordinateReferenceSystem getCRS(int srid, boolean hasZValues, boolean hasMValues) { CoordinateReferenceSystem crs = CrsRegistry.getCoordinateReferenceSystemForEPSG(srid, DEFAULT_CRS); return CoordinateReferenceSystems.adjustTo(crs, hasZValues, hasMValues); } PositionSequence coordinateRange(IndexRange range) { crs = getCRS(getSrid(), hasZValues(), hasMValues()); PositionSequenceBuilder psBuilder = PositionSequenceBuilders.fixedSized(range.end - range.start, crs.getPositionClass()); double[] coordinates = new double[crs.getCoordinateDimension()]; for (int idx = range.start, i = 0; idx < range.end; idx++, i++) { copyCoordinate(idx, coordinates, crs); psBuilder.add(coordinates); } return psBuilder.toPositionSequence(); } private Figure getFigure(int index) { return figures[index]; } private Shape getShape(int index) { return shapes[index]; } void setCoordinate(int index, PositionSequence positions) { points[2 * index] = positions.getPositionN(index).getCoordinate(0); points[2 * index + 1] = positions.getPositionN(index).getCoordinate(1); if (hasZValues()) { //TODO ensure this conditions is satisfied if (!hasVerticalAxis(crs)) throw new IllegalStateException(); zValues[index] = positions.getPositionN(index).getCoordinate(2); } if (hasMValues()) { if (!hasMeasureAxis(crs)) throw new IllegalStateException(); int idx = hasZValues() ? 3 : 2; mValues[index] = positions.getPositionN(index).getCoordinate(idx); } } boolean isEmpty() { return this.numberOfPoints == 0; } OpenGisType openGisType() { if (isValid() && isSinglePoint()) { return OpenGisType.POINT; } if (isValid() && isSingleLineSegment()) { return OpenGisType.LINESTRING; } return firstShapeOpenGisType(); } void setHasZValues() { serializationPropertiesByte |= hasZValuesMask; } void allocateZValueArray() { if (this.hasZValues()) { this.zValues = new double[this.numberOfPoints]; } } void allocateMValueArray() { if (this.hasMValues()) { this.mValues = new double[this.numberOfPoints]; } } void setHasMValues() { serializationPropertiesByte |= hasMValuesMask; } void setIsValid() { serializationPropertiesByte |= isValidMask; } void setIsSinglePoint() { setNumberOfPoints(1); serializationPropertiesByte |= isSinglePointMask; } void setIsSingleLineSegment() { serializationPropertiesByte |= isSingleLineSegment; } int getNumPoints() { return this.numberOfPoints; } void setNumberOfPoints(int num) { this.numberOfPoints = num; this.points = new double[2 * this.numberOfPoints]; } private void parse() { srid = buffer.getInt(); version = buffer.get(); if (!isCompatible()) { throw new IllegalStateException("Version mismatch. Expected version " + SUPPORTED_VERSION + ", but received version " + version); } serializationPropertiesByte = buffer.get(); determineNumberOfPoints(); readPoints(); if (hasZValues()) { readZValues(); } if (hasMValues()) { readMValues(); } if (isSingleLineSegment() || isSinglePoint()) { //generate figure and shape. // These are assumed, not explicitly encoded in the // serialized data. See specs. setNumberOfFigures(1); setFigure(0, new Figure(FigureAttribute.Stroke, 0)); setNumberOfShapes(1); OpenGisType gisType = isSinglePoint() ? OpenGisType.POINT : OpenGisType.LINESTRING; setShape(0, new Shape(-1, 0, gisType)); return; } //in all other cases, figures and shapes are //explicitly encoded. readFigures(); readShapes(); } private void readShapes() { setNumberOfShapes(buffer.getInt()); for (int sIdx = 0; sIdx < numberOfShapes; sIdx++) { int parentOffset = buffer.getInt(); int figureOffset = buffer.getInt(); byte ogtByte = buffer.get(); OpenGisType type = OpenGisType.valueOf(ogtByte); Shape shape = new Shape(parentOffset, figureOffset, type); setShape(sIdx, shape); } } private void readFigures() { setNumberOfFigures(buffer.getInt()); for (int fIdx = 0; fIdx < numberOfFigures; fIdx++) { byte faByte = buffer.get(); int pointOffset = buffer.getInt(); FigureAttribute fa = FigureAttribute.valueOf(faByte); Figure figure = new Figure(fa, pointOffset); setFigure(fIdx, figure); } } private OpenGisType firstShapeOpenGisType() { if (shapes == null || shapes.length == 0) { return OpenGisType.INVALID_TYPE; } return shapes[0].openGisType; } private int calculateCapacity() { int numPoints = getNumPoints(); int prefixSize = 6; if (isSinglePoint() || isSingleLineSegment()) { int capacity = prefixSize + 16 * numPoints; if (hasZValues()) { capacity += 8 * numPoints; } if (hasMValues()) { capacity += 8 * numPoints; } return capacity; } int pointSize = getPointByteSize(); int size = prefixSize + 3 * 4; // prefix + 3 ints for points, shapes and figures size += getNumPoints() * pointSize; size += getNumFigures() * Figure.getByteSize(); size += getNumShapes() * Shape.getByteSize(); return size; } int getNumShapes() { return this.numberOfShapes; } private int getPointByteSize() { int size = 16; //for X/Y values if (hasMValues()) { size += 8; } if (hasZValues()) { size += 8; } return size; } private void readPoints() { points = new double[2 * numberOfPoints]; for (int i = 0; i < numberOfPoints; i++) { points[2 * i] = buffer.getDouble(); points[2 * i + 1] = buffer.getDouble(); } } private void readZValues() { zValues = new double[numberOfPoints]; for (int i = 0; i < numberOfPoints; i++) { zValues[i] = buffer.getDouble(); } } private void readMValues() { mValues = new double[numberOfPoints]; for (int i = 0; i < numberOfPoints; i++) { mValues[i] = buffer.getDouble(); } } private void determineNumberOfPoints() { if (isSinglePoint()) { numberOfPoints = 1; return; } if (isSingleLineSegment()) { numberOfPoints = 2; return; } numberOfPoints = buffer.getInt(); } boolean isCompatible() { return version == SUPPORTED_VERSION; } void setSrid(Integer srid) { this.srid = (srid == null) ? 0 : srid; } Integer getSrid() { return srid; } boolean hasZValues() { return (serializationPropertiesByte & hasZValuesMask) != 0; } boolean hasMValues() { return (serializationPropertiesByte & hasMValuesMask) != 0; } boolean isValid() { return (serializationPropertiesByte & isValidMask) != 0; } boolean isSinglePoint() { return (serializationPropertiesByte & isSinglePointMask) != 0; } boolean isSingleLineSegment() { return (serializationPropertiesByte & isSingleLineSegment) != 0; } void setNumberOfFigures(int num) { numberOfFigures = num; figures = new Figure[numberOfFigures]; } void setFigure(int i, Figure figure) { figures[i] = figure; } void setNumberOfShapes(int num) { numberOfShapes = num; shapes = new Shape[numberOfShapes]; } void setShape(int i, Shape shape) { shapes[i] = shape; } int getNumFigures() { return this.numberOfFigures; } CoordinateReferenceSystem getCoordinateReferenceSystem() { return this.crs; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy