svn-gvsig-desktop / branches / Fmap_GisPlanet / libraries / libFMap / src / com / iver / cit / gvsig / fmap / drivers / WKBParser.java @ 1841
History | View | Annotate | Download (10.4 KB)
1 | 1755 | fjp | /*
|
---|---|---|---|
2 | * WKBParser.java
|
||
3 | * Based in
|
||
4 | * PostGIS extension for PostgreSQL JDBC driver - Binary Parser
|
||
5 | *
|
||
6 | * NOTA: Es posible que lo mejor sea crear un PostGisGeometry que implemente
|
||
7 | * la interfaz IGeometry, y as? nos sirve de base para tener IGeometries
|
||
8 | * que encapsulan otras posibles geometr?as. Por ejemplo, un JTSGeometry.
|
||
9 | * De esta forma, un driver no necesitar?a reescribirse.
|
||
10 | *
|
||
11 | * (C) 2005 Markus Schaber, schabios@logi-track.com
|
||
12 | *
|
||
13 | * This library is free software; you can redistribute it and/or modify it under
|
||
14 | * the terms of the GNU Lesser General Public License as published by the Free
|
||
15 | * Software Foundation, either version 2.1 of the License.
|
||
16 | *
|
||
17 | * This library is distributed in the hope that it will be useful, but WITHOUT
|
||
18 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||
19 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||
20 | * details.
|
||
21 | *
|
||
22 | * You should have received a copy of the GNU Lesser General Public License
|
||
23 | * along with this library; if not, write to the Free Software Foundation, Inc.,
|
||
24 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA or visit the web at
|
||
25 | * http://www.gnu.org.
|
||
26 | *
|
||
27 | * $Id$
|
||
28 | */
|
||
29 | package com.iver.cit.gvsig.fmap.drivers; |
||
30 | |||
31 | import org.postgis.Geometry; |
||
32 | import org.postgis.GeometryCollection; |
||
33 | import org.postgis.LineString; |
||
34 | import org.postgis.LinearRing; |
||
35 | import org.postgis.MultiLineString; |
||
36 | import org.postgis.MultiPoint; |
||
37 | import org.postgis.MultiPolygon; |
||
38 | import org.postgis.Point; |
||
39 | import org.postgis.Polygon; |
||
40 | import org.postgis.binary.ByteGetter; |
||
41 | import org.postgis.binary.ValueGetter; |
||
42 | import org.postgis.binary.ByteGetter.BinaryByteGetter; |
||
43 | import org.postgis.binary.ByteGetter.StringByteGetter; |
||
44 | |||
45 | import com.iver.cit.gvsig.fmap.core.FGeometryCollection; |
||
46 | import com.iver.cit.gvsig.fmap.core.FMultiPoint2D; |
||
47 | import com.iver.cit.gvsig.fmap.core.FPoint2D; |
||
48 | import com.iver.cit.gvsig.fmap.core.FPoint3D; |
||
49 | import com.iver.cit.gvsig.fmap.core.FPolygon2D; |
||
50 | import com.iver.cit.gvsig.fmap.core.FPolyline2D; |
||
51 | import com.iver.cit.gvsig.fmap.core.GeneralPathX; |
||
52 | import com.iver.cit.gvsig.fmap.core.IGeometry; |
||
53 | import com.iver.cit.gvsig.fmap.core.ShapeFactory; |
||
54 | |||
55 | /**
|
||
56 | * Parse binary representation of geometries. Currently, only text rep (hexed)
|
||
57 | * implementation is tested.
|
||
58 | *
|
||
59 | * It should be easy to add char[] and CharSequence ByteGetter instances,
|
||
60 | * although the latter one is not compatible with older jdks.
|
||
61 | *
|
||
62 | * I did not implement real unsigned 32-bit integers or emulate them with long,
|
||
63 | * as both java Arrays and Strings currently can have only 2^31-1 elements
|
||
64 | * (bytes), so we cannot even get or build Geometries with more than approx.
|
||
65 | * 2^28 coordinates (8 bytes each).
|
||
66 | *
|
||
67 | * @author markus.schaber@logi-track.com
|
||
68 | *
|
||
69 | */
|
||
70 | public class WKBParser { |
||
71 | |||
72 | private boolean gHaveM, gHaveZ, gHaveS; // M, Z y SRID |
||
73 | /**
|
||
74 | * Get the appropriate ValueGetter for my endianness
|
||
75 | *
|
||
76 | * @param bytes The appropriate Byte Getter
|
||
77 | *
|
||
78 | * @return the ValueGetter
|
||
79 | */
|
||
80 | public static ValueGetter valueGetterForEndian(ByteGetter bytes) { |
||
81 | if (bytes.get(0) == ValueGetter.XDR.NUMBER) { // XDR |
||
82 | return new ValueGetter.XDR(bytes); |
||
83 | } else if (bytes.get(0) == ValueGetter.NDR.NUMBER) { |
||
84 | return new ValueGetter.NDR(bytes); |
||
85 | } else {
|
||
86 | throw new IllegalArgumentException("Unknown Endian type:" + bytes.get(0)); |
||
87 | } |
||
88 | } |
||
89 | |||
90 | /**
|
||
91 | * Parse a hex encoded geometry
|
||
92 | *
|
||
93 | * Is synchronized to protect offset counter. (Unfortunately, Java does not
|
||
94 | * have neither call by reference nor multiple return values.)
|
||
95 | */
|
||
96 | public synchronized IGeometry parse(String value) { |
||
97 | StringByteGetter bytes = new ByteGetter.StringByteGetter(value);
|
||
98 | return parseGeometry(valueGetterForEndian(bytes));
|
||
99 | } |
||
100 | |||
101 | /**
|
||
102 | * Parse a binary encoded geometry.
|
||
103 | *
|
||
104 | * Is synchronized to protect offset counter. (Unfortunately, Java does not
|
||
105 | * have neither call by reference nor multiple return values.)
|
||
106 | */
|
||
107 | public synchronized IGeometry parse(byte[] value) { |
||
108 | BinaryByteGetter bytes = new ByteGetter.BinaryByteGetter(value);
|
||
109 | return parseGeometry(valueGetterForEndian(bytes));
|
||
110 | } |
||
111 | |||
112 | protected void parseTypeAndSRID(ValueGetter data) |
||
113 | { |
||
114 | byte endian = data.getByte(); //skip and test endian flag |
||
115 | if (endian != data.endian) {
|
||
116 | throw new IllegalArgumentException("Endian inconsistency!"); |
||
117 | } |
||
118 | int typeword = data.getInt();
|
||
119 | |||
120 | int realtype = typeword & 0x1FFFFFFF; //cut off high flag bits |
||
121 | |||
122 | gHaveZ = (typeword & 0x80000000) != 0; |
||
123 | gHaveM = (typeword & 0x40000000) != 0; |
||
124 | gHaveS = (typeword & 0x20000000) != 0; |
||
125 | |||
126 | int srid = -1; |
||
127 | |||
128 | if (gHaveS) {
|
||
129 | srid = data.getInt(); |
||
130 | } |
||
131 | |||
132 | } |
||
133 | |||
134 | /** Parse a geometry starting at offset. */
|
||
135 | protected IGeometry parseGeometry(ValueGetter data) {
|
||
136 | byte endian = data.getByte(); //skip and test endian flag |
||
137 | if (endian != data.endian) {
|
||
138 | throw new IllegalArgumentException("Endian inconsistency!"); |
||
139 | } |
||
140 | int typeword = data.getInt();
|
||
141 | |||
142 | int realtype = typeword & 0x1FFFFFFF; //cut off high flag bits |
||
143 | |||
144 | boolean haveZ = (typeword & 0x80000000) != 0; |
||
145 | boolean haveM = (typeword & 0x40000000) != 0; |
||
146 | boolean haveS = (typeword & 0x20000000) != 0; |
||
147 | |||
148 | int srid = -1; |
||
149 | |||
150 | if (haveS) {
|
||
151 | srid = data.getInt(); |
||
152 | } |
||
153 | IGeometry result1; |
||
154 | switch (realtype) {
|
||
155 | case Geometry.POINT :
|
||
156 | result1 = ShapeFactory.createPoint2D(parsePoint(data, haveZ, haveM)); |
||
157 | break;
|
||
158 | case Geometry.LINESTRING :
|
||
159 | result1 = ShapeFactory.createGeometry(parseLineString(data, haveZ, haveM)); |
||
160 | break;
|
||
161 | case Geometry.POLYGON :
|
||
162 | result1 = ShapeFactory.createGeometry(parsePolygon(data, haveZ, haveM)); |
||
163 | break;
|
||
164 | case Geometry.MULTIPOINT :
|
||
165 | result1 = parseMultiPoint(data); |
||
166 | break;
|
||
167 | case Geometry.MULTILINESTRING :
|
||
168 | result1 = ShapeFactory.createGeometry(parseMultiLineString(data)); |
||
169 | break;
|
||
170 | case Geometry.MULTIPOLYGON :
|
||
171 | result1 = ShapeFactory.createGeometry(parseMultiPolygon(data)); |
||
172 | break;
|
||
173 | case Geometry.GEOMETRYCOLLECTION :
|
||
174 | result1 = parseCollection(data); |
||
175 | break;
|
||
176 | default :
|
||
177 | throw new IllegalArgumentException("Unknown Geometry Type!"); |
||
178 | } |
||
179 | |||
180 | /*Geometry result = result1;
|
||
181 | |||
182 | if (haveS) {
|
||
183 | result.setSrid(srid);
|
||
184 | } */
|
||
185 | return result1;
|
||
186 | } |
||
187 | |||
188 | private FPoint2D parsePoint(ValueGetter data, boolean haveZ, boolean haveM) { |
||
189 | double X = data.getDouble();
|
||
190 | double Y = data.getDouble();
|
||
191 | FPoint2D result; |
||
192 | if (haveZ) {
|
||
193 | double Z = data.getDouble();
|
||
194 | result = new FPoint3D(X, Y, Z);
|
||
195 | } else {
|
||
196 | result = new FPoint2D(X, Y);
|
||
197 | } |
||
198 | |||
199 | if (haveM) {
|
||
200 | System.err.println("M no soportado. (WKBParser de gvSIG, dentro de parsePoint)"); |
||
201 | double m = data.getDouble();
|
||
202 | // result.setM(m);
|
||
203 | } |
||
204 | |||
205 | return result;
|
||
206 | } |
||
207 | |||
208 | /** Parse an Array of "full" Geometries */
|
||
209 | private void parseGeometryArray(ValueGetter data, IGeometry[] container) { |
||
210 | for (int i = 0; i < container.length; i++) { |
||
211 | container[i] = parseGeometry(data); |
||
212 | } |
||
213 | } |
||
214 | |||
215 | /**
|
||
216 | * Parse an Array of "slim" Points (without endianness and type, part of
|
||
217 | * LinearRing and Linestring, but not MultiPoint!
|
||
218 | *
|
||
219 | * @param haveZ
|
||
220 | * @param haveM
|
||
221 | */
|
||
222 | private FPoint2D[] parsePointArray(ValueGetter data, boolean haveZ, boolean haveM) { |
||
223 | int count = data.getInt();
|
||
224 | FPoint2D[] result = new FPoint2D[count]; |
||
225 | for (int i = 0; i < count; i++) { |
||
226 | result[i] = parsePoint(data, haveZ, haveM); |
||
227 | } |
||
228 | return result;
|
||
229 | } |
||
230 | |||
231 | private FMultiPoint2D parseMultiPoint(ValueGetter data) {
|
||
232 | FPoint2D[] points = new FPoint2D[data.getInt()]; |
||
233 | for (int i=0; i < points.length; i++) |
||
234 | { |
||
235 | parseTypeAndSRID(data); |
||
236 | parsePoint(data, gHaveZ, gHaveM); |
||
237 | } |
||
238 | return new FMultiPoint2D(points); |
||
239 | } |
||
240 | |||
241 | private FPolyline2D parseLineString(ValueGetter data, boolean haveZ, boolean haveM) { |
||
242 | FPoint2D[] points = parsePointArray(data, haveZ, haveM);
|
||
243 | GeneralPathX gp = new GeneralPathX();
|
||
244 | gp.moveTo(points[0].getX(), points[0].getY()); |
||
245 | for (int i = 1; i< points.length; i++) |
||
246 | { |
||
247 | gp.lineTo(points[i].getX(), points[i].getY()); |
||
248 | } |
||
249 | return new FPolyline2D(gp); |
||
250 | } |
||
251 | |||
252 | private FPolygon2D parseLinearRing(ValueGetter data, boolean haveZ, boolean haveM) { |
||
253 | FPoint2D[] points = parsePointArray(data, haveZ, haveM);
|
||
254 | GeneralPathX gp = new GeneralPathX();
|
||
255 | gp.moveTo(points[0].getX(), points[0].getY()); |
||
256 | for (int i = 1; i< points.length; i++) |
||
257 | { |
||
258 | gp.lineTo(points[i].getX(), points[i].getY()); |
||
259 | } |
||
260 | return new FPolygon2D(gp); |
||
261 | } |
||
262 | |||
263 | private FPolygon2D parsePolygon(ValueGetter data, boolean haveZ, boolean haveM) { |
||
264 | int count = data.getInt();
|
||
265 | FPolygon2D[] rings = new FPolygon2D[count]; |
||
266 | for (int i = 0; i < count; i++) { |
||
267 | rings[i] = parseLinearRing(data, haveZ, haveM); |
||
268 | } |
||
269 | return rings[0]; //new FPolygon2D(rings[0]); |
||
270 | } |
||
271 | |||
272 | private FPolyline2D parseMultiLineString(ValueGetter data) {
|
||
273 | int count = data.getInt();
|
||
274 | FPolyline2D[] strings = new FPolyline2D[count]; |
||
275 | for (int i=0; i < strings.length; i++) |
||
276 | { |
||
277 | parseTypeAndSRID(data); |
||
278 | strings[i] = parseLineString(data, gHaveZ, gHaveM); |
||
279 | } |
||
280 | |||
281 | // parseGeometryArray(data, strings);
|
||
282 | return strings[0]; //new MultiLineString(strings); |
||
283 | } |
||
284 | |||
285 | private FPolygon2D parseMultiPolygon(ValueGetter data) {
|
||
286 | int count = data.getInt();
|
||
287 | FPolygon2D[] polys = new FPolygon2D[count]; |
||
288 | for (int i=0; i < polys.length; i++) |
||
289 | { |
||
290 | parseTypeAndSRID(data); |
||
291 | polys[i] = parsePolygon(data, gHaveZ, gHaveM); |
||
292 | } |
||
293 | |||
294 | // parseGeometryArray(data, polys);
|
||
295 | return polys[0]; //new MultiPolygon(polys); |
||
296 | } |
||
297 | |||
298 | private FGeometryCollection parseCollection(ValueGetter data) {
|
||
299 | int count = data.getInt();
|
||
300 | IGeometry[] geoms = new IGeometry[count]; |
||
301 | parseGeometryArray(data, geoms); |
||
302 | return new FGeometryCollection(geoms); |
||
303 | } |
||
304 | } |