Quick Search:

View

Revision:

Diff

Diff from 201 to:

Annotations

Annotate by Age | Author | Mixed | None
/fisheye/browse/HibernateSpatial/trunk/hibernate-spatial-sqlserver/src/main/java/org/hibernatespatial/sqlserver/convertors/SqlServerGeometry.java

Annotated File View

maesenka
141
1 /*
maesenka
182
2  * $Id: SqlServerGeometry.java 201 2010-04-05 13:49:25Z maesenka $
maesenka
141
3  *
4  * This file is part of Hibernate Spatial, an extension to the
5  * hibernate ORM solution for geographic data.
6  *
maesenka
161
7  * Copyright © 2007-2010 Geovise BVBA
maesenka
141
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  * For more information, visit: http://www.hibernatespatial.org/
24  */
25
26 package org.hibernatespatial.sqlserver.convertors;
27
maesenka
145
28 import com.vividsolutions.jts.geom.Coordinate;
maesenka
141
29 import org.hibernatespatial.mgeom.MCoordinate;
30
31 import java.nio.ByteBuffer;
32 import java.nio.ByteOrder;
33
34 /**
maesenka
182
35  * A <code>SqlServerGeometry</code> represents the native SQL Server database object.
36  * <p/>
37  * <p>Instances are created by deserializing the byte array returned in the JDBC result set.
maesenka
201
38  * They present the structure of the SQL Server Geometry object as specified in <a href="http://download.microsoft.com/download/7/9/3/79326E29-1E2E-45EE-AA73-74043587B17D/%5BMS-SSCLRT%5D.pdf">Microsoft SQL Server CLR Types Serialization Formats</a> .
maesenka
182
39  *
maesenka
141
40  * @author Karel Maesen, Geovise BVBA.
41  */
maesenka
201
42 public class SqlServerGeometry {
maesenka
141
43
44     public static final byte SUPPORTED_VERSION = 1;
45
46     private static final byte hasZValuesMask = 1;
47     private static final byte hasMValuesMask = 2;
48     private static final byte isValidMask = 4;
49     private static final byte isSinglePointMask = 8;
50     private static final byte isSingleLineSegment = 16;
51
52     private ByteBuffer buffer;
53     private Integer srid;
54     private byte version;
55     private byte serializationPropertiesByte;
56     private int numberOfPoints;
maesenka
161
57     private double[] points;
maesenka
141
58     private double[] mValues;
59     private double[] zValues;
maesenka
145
60     private int numberOfFigures;
61     private Figure[] figures = null;
62     private int numberOfShapes;
63     private Shape[] shapes = null;
maesenka
141
64
65
maesenka
161
66     private SqlServerGeometry(byte[] bytes) {
maesenka
141
67         buffer = ByteBuffer.wrap(bytes);
68         buffer.order(ByteOrder.LITTLE_ENDIAN);
69     }
70
maesenka
161
71     SqlServerGeometry() {
maesenka
141
72     }
73
maesenka
159
74
maesenka
182
75     public static byte[] serialize(SqlServerGeometry sqlServerGeom) {
maesenka
161
76         int capacity = sqlServerGeom.calculateCapacity();
maesenka
141
77         ByteBuffer buffer = ByteBuffer.allocate(capacity);
78         buffer.order(ByteOrder.LITTLE_ENDIAN);
maesenka
161
79         buffer.putInt(sqlServerGeom.srid);
maesenka
159
80         buffer.put(SUPPORTED_VERSION);
maesenka
161
81         buffer.put(sqlServerGeom.serializationPropertiesByte);
82         if (!sqlServerGeom.isSinglePoint() && !sqlServerGeom.isSingleLineSegment()) {
83             buffer.putInt(sqlServerGeom.numberOfPoints);
maesenka
141
84         }
maesenka
161
85         for (int i = 0i < sqlServerGeom.getNumPoints(); i++) {
86             buffer.putDouble(sqlServerGeom.points[2 * i]);
87             buffer.putDouble(sqlServerGeom.points[2 * i + 1]);
maesenka
141
88         }
maesenka
161
89         if (sqlServerGeom.hasZValues()) {
90             for (int i = 0i < sqlServerGeom.zValues.lengthi++) {
91                 buffer.putDouble(sqlServerGeom.zValues[i]);
maesenka
141
92             }
93         }
maesenka
161
94         if (sqlServerGeom.hasMValues()) {
95             for (int i = 0i < sqlServerGeom.mValues.lengthi++) {
96                 buffer.putDouble(sqlServerGeom.mValues[i]);
maesenka
141
97             }
98         }
maesenka
161
99         if (sqlServerGeom.isSingleLineSegment() || sqlServerGeom.isSinglePoint())
maesenka
145
100             return buffer.array();
101
maesenka
182
102         //in all other cases, we continue to serialize shapes and figures
maesenka
161
103         buffer.putInt(sqlServerGeom.getNumFigures());
104         for (int i = 0i < sqlServerGeom.getNumFigures(); i++) {
105             sqlServerGeom.getFigure(i).store(buffer);
maesenka
145
106         }
107
maesenka
161
108         buffer.putInt(sqlServerGeom.getNumShapes());
109         for (int i = 0i < sqlServerGeom.getNumShapes(); i++) {
110             sqlServerGeom.getShape(i).store(buffer);
maesenka
145
111         }
112
maesenka
141
113         return buffer.array();
114     }
115
maesenka
182
116     public static SqlServerGeometry deserialize(byte[] bytes) {
maesenka
161
117         SqlServerGeometry result = new SqlServerGeometry(bytes);
maesenka
141
118         result.parse();
119         return result;
120     }
121
maesenka
201
122     Coordinate getCoordinate(int index) {
maesenka
148
123         Coordinate coordinate;
124         if (hasMValues()) {
125             coordinate = new MCoordinate();
126             ((MCoordinatecoordinate).m = mValues[index];
127         } else {
128             coordinate = new Coordinate();
129         }
maesenka
161
130         coordinate.x = points[2 * index];
131         coordinate.y = points[2 * index + 1];
maesenka
141
132         if (hasZValues()) coordinate.z = zValues[index];
133         return coordinate;
134     }
135
maesenka
201
136     boolean isParentShapeOf(int parentint child) {
maesenka
159
137         return getShape(child).parentOffset == parent;
138     }
139
maesenka
201
140     boolean isEmptyShape(int shapeIndex) {
maesenka
163
141         return getShape(shapeIndex).figureOffset == -1;
142     }
maesenka
156
143
maesenka
201
144     IndexRange getFiguresForShape(int shapeIndex) {
maesenka
161
145         int startIdx = getShape(shapeIndex).figureOffset;
maesenka
163
146         if (startIdx == -1return new IndexRange(-1, -1); //empty figures
maesenka
161
147         int endIdx = -1;
148         int nextShapeIdx = shapeIndex + 1;
149         if (nextShapeIdx == getNumShapes()) {
150             endIdx = getNumFigures();
151         } else {
152             endIdx = getShape(nextShapeIdx).figureOffset;
153         }
154         return new IndexRange(startIdxendIdx);
maesenka
156
155     }
156
maesenka
159
157     /**
maesenka
161
158      * Returns the range of indices in the point array for the specified figure.
maesenka
159
159      *
maesenka
156
160      * @param figureIndex index to shape in shape array
maesenka
161
161      * @return index range for
maesenka
156
162      */
maesenka
201
163     IndexRange getPointsForFigure(int figureIndex) {
maesenka
161
164         int start = getFigure(figureIndex).pointOffset;
165         int end = -1;
166         int nextFigure = figureIndex + 1;
167         if (nextFigure == getNumFigures()) {
168             end = getNumPoints();
169         } else {
170             end = getFigure(nextFigure).pointOffset;
maesenka
156
171         }
maesenka
161
172         return new IndexRange(startend);
maesenka
156
173     }
174
maesenka
201
175     boolean isFigureInteriorRing(int figureIdx) {
maesenka
156
176         return getFigure(figureIdx).isInteriorRing();
177     }
178
maesenka
201
179     OpenGisType getOpenGisTypeOfShape(int shpIdx) {
maesenka
156
180         return getShape(shpIdx).openGisType;
181     }
182
maesenka
201
183     Coordinate[] coordinateRange(IndexRange range) {
maesenka
161
184         Coordinate[] coordinates = createCoordinateArray(range.end - range.start);
185         for (int idx = range.starti = 0idx < range.endidx++, i++) {
maesenka
156
186             coordinates[i] = getCoordinate(idx);
187         }
188         return coordinates;
189     }
190
191     private Coordinate[] createCoordinateArray(int size) {
192         if (hasMValues()) {
193             return new MCoordinate[size];
194         } else {
195             return new Coordinate[size];
196         }
197     }
198
199
200     private Figure getFigure(int index) {
maesenka
145
201         return figures[index];
202     }
203
maesenka
156
204     private Shape getShape(int index) {
maesenka
145
205         return shapes[index];
206     }
207
maesenka
147
208     void setCoordinate(int indexCoordinate coordinate) {
maesenka
161
209         points[2 * index] = coordinate.x;
210         points[2 * index + 1] = coordinate.y;
maesenka
141
211         if (hasZValues()) {
212             zValues[index] = coordinate.z;
213         }
214         if (hasMValues()) {
215             mValues[index] = ((MCoordinatecoordinate).m;
216         }
217     }
218
maesenka
147
219     boolean isEmpty() {
maesenka
141
220         return this.numberOfPoints == 0;
221     }
222
maesenka
147
223     OpenGisType openGisType() {
maesenka
145
224         if (isValid() && isSinglePoint())
maesenka
141
225             return OpenGisType.POINT;
maesenka
145
226         if (isValid() && isSingleLineSegment())
227             return OpenGisType.LINESTRING;
228         return firstShapeOpenGisType();
maesenka
141
229     }
230
maesenka
147
231     void setHasZValues() {
maesenka
141
232         serializationPropertiesByte |= hasZValuesMask;
233     }
234
maesenka
159
235     void allocateZValueArray() {
maesenka
156
236         if (this.hasZValues())
237             this.zValues = new double[this.numberOfPoints];
238     }
239
maesenka
159
240     void allocateMValueArray() {
maesenka
156
241         if (this.hasMValues())
242             this.mValues = new double[this.numberOfPoints];
243     }
maesenka
145
244
maesenka
147
245     void setHasMValues() {
maesenka
141
246         serializationPropertiesByte |= hasMValuesMask;
247     }
248
maesenka
147
249     void setIsValid() {
maesenka
141
250         serializationPropertiesByte |= isValidMask;
251     }
252
maesenka
147
253     void setIsSinglePoint() {
maesenka
145
254         setNumberOfPoints(1);
maesenka
141
255         serializationPropertiesByte |= isSinglePointMask;
256     }
257
maesenka
147
258     void setIsSingleLineSegment() {
maesenka
141
259         serializationPropertiesByte |= isSingleLineSegment;
260     }
261
maesenka
147
262     int getNumPoints() {
maesenka
141
263         return this.numberOfPoints;
264     }
265
maesenka
147
266     void setNumberOfPoints(int num) {
maesenka
141
267         this.numberOfPoints = num;
maesenka
161
268         this.points = new double[2 * this.numberOfPoints];
maesenka
141
269     }
270
271     private void parse() {
272         srid = buffer.getInt();
273         version = buffer.get();
274         if (!isCompatible())
275             throw new IllegalStateException("Version mismatch. Expected version " + SUPPORTED_VERSION + ", but received version " + version);
276         serializationPropertiesByte = buffer.get();
277         determineNumberOfPoints();
278         readPoints();
279         if (hasZValues())
280             readZValues();
281         if (hasMValues())
282             readMValues();
maesenka
145
283
284         if (isSingleLineSegment() ||
285                 isSinglePoint()) {
maesenka
156
286             //generate figure and shape.
287             // These are assumed, not explicitly encoded in the
288             // serialized data. See specs.
289             setNumberOfFigures(1);
290             setFigure(0new Figure(FigureAttribute.Stroke0));
291             setNumberOfShapes(1);
292             OpenGisType gisType = isSinglePoint() ? OpenGisType.POINT : OpenGisType.LINESTRING;
maesenka
159
293             setShape(0new Shape(-10gisType));
maesenka
156
294             return;
maesenka
145
295         }
maesenka
156
296         //in all other cases, figures and shapes are
297         //explicitly encoded.
maesenka
145
298         readFigures();
299         readShapes();
300     }
301
302     private void readShapes() {
303         setNumberOfShapes(buffer.getInt());
304         for (int sIdx = 0sIdx < numberOfShapessIdx++) {
305             int parentOffset = buffer.getInt();
306             int figureOffset = buffer.getInt();
307             byte ogtByte = buffer.get();
308             OpenGisType type = OpenGisType.valueOf(ogtByte);
309             Shape shape = new Shape(parentOffsetfigureOffsettype);
310             setShape(sIdxshape);
311         }
312     }
313
314     private void readFigures() {
315         setNumberOfFigures(buffer.getInt());
316         for (int fIdx = 0fIdx < numberOfFiguresfIdx++) {
317             byte faByte = buffer.get();
318             int pointOffset = buffer.getInt();
319             FigureAttribute fa = FigureAttribute.valueOf(faByte);
320             Figure figure = new Figure(fapointOffset);
321             setFigure(fIdxfigure);
322         }
323     }
324
325     private OpenGisType firstShapeOpenGisType() {
326         if (shapes == null || shapes.length == 0)
327             return OpenGisType.INVALID_TYPE;
328         return shapes[0].openGisType;
maesenka
141
329     }
330
331     private int calculateCapacity() {
maesenka
145
332         int numPoints = getNumPoints();
333         int prefixSize = 6;
334
335         if (isSinglePoint() ||
336                 isSingleLineSegment()) {
337             int capacity = prefixSize + 16 * numPoints;
maesenka
141
338             if (hasZValues())
maesenka
145
339                 capacity += 8 * numPoints;
maesenka
141
340             if (hasMValues())
maesenka
145
341                 capacity += 8 * numPoints;
maesenka
141
342             return capacity;
343         }
maesenka
145
344
345         int pointSize = getPointByteSize();
346         int size = prefixSize + 3 * 4// prefix + 3 ints for points, shapes and figures
347         size += getNumPoints() * pointSize;
348         size += getNumFigures() * Figure.getByteSize();
349         size += getNumShapes() * Shape.getByteSize();
350         return size;
351     }
352
maesenka
148
353     int getNumShapes() {
maesenka
145
354         return this.numberOfShapes;
355     }
356
357     private int getPointByteSize() {
358         int size = 16//for X/Y values
359         if (hasMValues()) size += 8;
360         if (hasZValues()) size += 8;
361         return size;
362
maesenka
141
363     }
364
365     private void readPoints() {
maesenka
161
366         points = new double[2 * numberOfPoints];
maesenka
141
367         for (int i = 0i < numberOfPointsi++) {
maesenka
161
368             points[2 * i] = buffer.getDouble();
369             points[2 * i + 1] = buffer.getDouble();
maesenka
141
370         }
371     }
372
373     private void readZValues() {
374         zValues = new double[numberOfPoints];
375         for (int i = 0i < numberOfPointsi++) {
376             zValues[i] = buffer.getDouble();
377         }
378     }
379
380
381     private void readMValues() {
382         mValues = new double[numberOfPoints];
383         for (int i = 0i < numberOfPointsi++) {
384             mValues[i] = buffer.getDouble();
385         }
386     }
387
388     private void determineNumberOfPoints() {
389         if (isSinglePoint()) {
390             numberOfPoints = 1;
391             return;
392         }
393         if (isSingleLineSegment()) {
394             numberOfPoints = 2;
395             return;
396         }
397         numberOfPoints = buffer.getInt();
398     }
399
maesenka
145
400     boolean isCompatible() {
maesenka
141
401         return version == SUPPORTED_VERSION;
402     }
403
maesenka
145
404     void setSrid(Integer srid) {
maesenka
141
405         this.srid = (srid == null) ? -1 : srid;
406     }
407
maesenka
145
408     Integer getSrid() {
maesenka
141
409         return srid != -1 ? srid : null;
410     }
411
maesenka
145
412     boolean hasZValues() {
maesenka
141
413         return (serializationPropertiesByte & hasZValuesMask) != 0;
414     }
415
maesenka
145
416     boolean hasMValues() {
maesenka
141
417         return (serializationPropertiesByte & hasMValuesMask) != 0;
418     }
419
maesenka
145
420     boolean isValid() {
maesenka
141
421         return (serializationPropertiesByte & isValidMask) != 0;
422     }
423
maesenka
145
424     boolean isSinglePoint() {
maesenka
141
425         return (serializationPropertiesByte & isSinglePointMask) != 0;
426     }
427
maesenka
145
428     boolean isSingleLineSegment() {
maesenka
141
429         return (serializationPropertiesByte & isSingleLineSegment) != 0;
430     }
431
maesenka
145
432     void setNumberOfFigures(int num) {
433         numberOfFigures = num;
434         figures = new Figure[numberOfFigures];
435     }
436
437     void setFigure(int iFigure figure) {
438         figures[i] = figure;
439     }
440
441     void setNumberOfShapes(int num) {
442         numberOfShapes = num;
443         shapes = new Shape[numberOfShapes];
444     }
445
446     void setShape(int iShape shape) {
447         shapes[i] = shape;
448     }
449
450     int getNumFigures() {
451         return this.numberOfFigures;
452     }
453
maesenka
141
454
455 }
FishEye: Open Source License registered to Hibernate Spatial.
Your maintenance has expired. You can renew your license at http://www.atlassian.com/fisheye/renew
Atlassian FishEye, Subversion, CVS & Perforce analysis. (Version:1.5.2 Build:build-298 2008-05-26 ) - Administration - Page generated 2010-09-09 22:50 +0200