001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/model/spatialschema/GeometryFactory.java $
002 /*---------------- FILE HEADER ------------------------------------------
003
004 This file is part of deegree.
005 Copyright (C) 2001-2008 by:
006 EXSE, Department of Geography, University of Bonn
007 http://www.giub.uni-bonn.de/deegree/
008 lat/lon GmbH
009 http://www.lat-lon.de
010
011 This library is free software; you can redistribute it and/or
012 modify it under the terms of the GNU Lesser General Public
013 License as published by the Free Software Foundation; either
014 version 2.1 of the License, or (at your option) any later version.
015
016 This library is distributed in the hope that it will be useful,
017 but WITHOUT ANY WARRANTY; without even the implied warranty of
018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019 Lesser General Public License for more details.
020
021 You should have received a copy of the GNU Lesser General Public
022 License along with this library; if not, write to the Free Software
023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024
025 Contact:
026
027 Andreas Poth
028 lat/lon GmbH
029 Aennchenstr. 19
030 53115 Bonn
031 Germany
032 E-Mail: poth@lat-lon.de
033
034 Prof. Dr. Klaus Greve
035 Department of Geography
036 University of Bonn
037 Meckenheimer Allee 166
038 53115 Bonn
039 Germany
040 E-Mail: greve@giub.uni-bonn.de
041
042
043 ---------------------------------------------------------------------------*/
044 package org.deegree.model.spatialschema;
045
046 import java.util.ArrayList;
047
048 import org.deegree.framework.util.StringTools;
049 import org.deegree.model.crs.CoordinateSystem;
050
051 /**
052 * Factory to create geometry instances.
053 *
054 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
055 * @version $Revision: 9343 $, $Date: 2007-12-27 14:30:32 +0100 (Do, 27 Dez 2007) $
056 *
057 */
058 public final class GeometryFactory {
059
060 private GeometryFactory() {
061 // Hidden default constructor.
062 }
063
064 /**
065 * creates a Envelope object out from two corner coordinates
066 *
067 * @param minx
068 * lower x-axis coordinate
069 * @param miny
070 * lower y-axis coordinate
071 * @param maxx
072 * upper x-axis coordinate
073 * @param maxy
074 * upper y-axis coordinate
075 * @param crs
076 * The coordinate system
077 * @return an Envelope with given parameters
078 */
079 public static Envelope createEnvelope( double minx, double miny, double maxx, double maxy, CoordinateSystem crs ) {
080 Position min = createPosition( minx, miny );
081 Position max = createPosition( maxx, maxy );
082 return new EnvelopeImpl( min, max, crs );
083 }
084
085 /**
086 * creates a Envelope object out from two corner coordinates
087 *
088 * @param min
089 * lower point
090 * @param max
091 * upper point
092 * @param crs
093 * The coordinate system
094 * @return an Envelope with given parameters
095 */
096 public static Envelope createEnvelope( Position min, Position max, CoordinateSystem crs ) {
097 return new EnvelopeImpl( min, max, crs );
098 }
099
100 /**
101 * creates an Envelope from a comma seperated String; e.g.: 10,34,15,48
102 *
103 * @param bbox
104 * the boundingbox of the created Envelope
105 * @param crs
106 * The coordinate system
107 * @return an Envelope with given parameters
108 */
109 public static Envelope createEnvelope( String bbox, CoordinateSystem crs ) {
110 double[] d = StringTools.toArrayDouble( bbox, "," );
111 return createEnvelope( d[0], d[1], d[2], d[3], crs );
112 }
113
114 /**
115 * creates a Position from two coordinates.
116 *
117 * @param x
118 * coordinate on the x-axis
119 * @param y
120 * coordinate on the y-axis
121 * @return a Position defining position x, y
122 */
123 public static Position createPosition( double x, double y ) {
124 return new PositionImpl( x, y );
125 }
126
127 /**
128 * creates a Position from three coordinates.
129 *
130 * @param x
131 * coordinate on the x-axis
132 * @param y
133 * coordinate on the y-axis
134 * @param z
135 * coordinate on the z-axis
136 * @return a Position defining position x, y, z
137 */
138 public static Position createPosition( double x, double y, double z ) {
139 return new PositionImpl( new double[] { x, y, z } );
140 }
141
142 /**
143 * creates a Position from an array of double.
144 *
145 * @param p
146 * list of points
147 * @return the Position defined by the array.
148 */
149 public static Position createPosition( double[] p ) {
150 return new PositionImpl( p );
151 }
152
153 /**
154 * creates a Point from two coordinates.
155 *
156 * @param x
157 * x coordinate
158 * @param y
159 * y coordinate
160 * @param crs
161 * spatial reference system of the point geometry
162 * @return a Position defining position x, y in the given CRS
163 */
164 public static Point createPoint( double x, double y, CoordinateSystem crs ) {
165 return new PointImpl( x, y, crs );
166 }
167
168 /**
169 * creates a Point from two coordinates.
170 *
171 * @param x
172 * x coordinate
173 * @param y
174 * y coordinate
175 * @param z
176 * coordinate on the z-axis
177 * @param crs
178 * spatial reference system of the point geometry
179 * @return a Position defining position x, y, z in the given CRS
180 */
181 public static Point createPoint( double x, double y, double z, CoordinateSystem crs ) {
182 return new PointImpl( x, y, z, crs );
183 }
184
185 /**
186 * creates a Point from a position.
187 *
188 * @param position
189 * position
190 * @param crs
191 * spatial reference system of the point geometry
192 * @return the Position defined by the array in the given CRS
193 */
194 public static Point createPoint( Position position, CoordinateSystem crs ) {
195 return new PointImpl( position, crs );
196 }
197
198 /**
199 * creates a Point from a wkb.
200 *
201 * @param wkb
202 * geometry in Well-Known Binary (WKB) format
203 * @param srs
204 * spatial reference system of the geometry
205 * @return the Position defined by the WKB and the given CRS
206 * @throws GeometryException
207 * if the wkb is not known or invalid
208 */
209 public static Point createPoint( byte[] wkb, CoordinateSystem srs )
210 throws GeometryException {
211 int wkbType = -1;
212 double x = 0;
213 double y = 0;
214
215 byte byteorder = wkb[0];
216
217 if ( byteorder == 0 ) {
218 wkbType = ByteUtils.readBEInt( wkb, 1 );
219 } else {
220 wkbType = ByteUtils.readLEInt( wkb, 1 );
221 }
222
223 if ( wkbType != 1 ) {
224 throw new GeometryException( "invalid byte stream" );
225 }
226
227 if ( byteorder == 0 ) {
228 x = ByteUtils.readBEDouble( wkb, 5 );
229 y = ByteUtils.readBEDouble( wkb, 13 );
230 } else {
231 x = ByteUtils.readLEDouble( wkb, 5 );
232 y = ByteUtils.readLEDouble( wkb, 13 );
233 }
234
235 return new PointImpl( x, y, srs );
236 }
237
238 /**
239 * creates a CurveSegment from an array of points.
240 *
241 * @param points
242 * array of Point
243 * @param crs
244 * CS_CoordinateSystem spatial reference system of the curve
245 * @return A curve defined by the given Points in the CRS.
246 * @throws GeometryException
247 * if the point array is empty
248 */
249 public static CurveSegment createCurveSegment( Position[] points, CoordinateSystem crs )
250 throws GeometryException {
251 return new LineStringImpl( points, crs );
252 }
253
254 /**
255 * creates a Curve from an array of Positions.
256 *
257 * @param positions
258 * positions
259 * @param crs
260 * spatial reference system of the geometry
261 * @return A curve defined by the given Points in the CRS.
262 * @throws GeometryException
263 * if the point array is empty
264 */
265 public static Curve createCurve( Position[] positions, CoordinateSystem crs )
266 throws GeometryException {
267 CurveSegment[] cs = new CurveSegment[1];
268 cs[0] = createCurveSegment( positions, crs );
269 return new CurveImpl( cs );
270 }
271
272 /**
273 * creates a Curve from one curve segment.
274 *
275 * @param segment
276 * CurveSegments
277 * @return a new CurveSegment
278 * @throws GeometryException
279 * if the segment is null
280 */
281 public static Curve createCurve( CurveSegment segment )
282 throws GeometryException {
283 return new CurveImpl( new CurveSegment[] { segment } );
284 }
285
286 /**
287 * creates a Curve from an array of curve segments.
288 *
289 * @param segments
290 * array of CurveSegments
291 * @return a new CurveSegment
292 * @throws GeometryException
293 * if the segment is null or has no values
294 *
295 */
296 public static Curve createCurve( CurveSegment[] segments )
297 throws GeometryException {
298 return new CurveImpl( segments );
299 }
300
301 /**
302 * creates a Curve from an array of curve segments.
303 *
304 * @param segments
305 * array of CurveSegments
306 * @param crs
307 * @return a new CurveSegment
308 * @throws GeometryException
309 * if the segment is null or has no values
310 *
311 */
312 public static Curve createCurve( CurveSegment[] segments, CoordinateSystem crs )
313 throws GeometryException {
314 return new CurveImpl( segments, crs );
315 }
316
317 /**
318 * creates a GM_Curve from an array of ordinates
319 *
320 * TODO: If resources are available, think about good programming style.
321 *
322 * @param ord
323 * the ordinates
324 * @param dim
325 * the dimension of the ordinates
326 * @param crs
327 * the spatial reference system of the geometry
328 *
329 * @return the Curve defined by the given parameters
330 * @throws GeometryException
331 * if the ord array is empty
332 */
333 public static Curve createCurve( double[] ord, int dim, CoordinateSystem crs )
334 throws GeometryException {
335 Position[] pos = new Position[ord.length / dim];
336 int i = 0;
337 while ( i < ord.length ) {
338 double[] o = new double[dim];
339 for ( int j = 0; j < dim; j++ ) {
340 o[j] = ord[i++];
341 }
342 pos[i / dim - 1] = GeometryFactory.createPosition( o );
343 }
344 return GeometryFactory.createCurve( pos, crs );
345 }
346
347 /**
348 * creates a SurfacePatch from array(s) of Position
349 *
350 * @param exteriorRing
351 * exterior ring of the patch
352 * @param interiorRings
353 * interior rings of the patch
354 * @param si
355 * SurfaceInterpolation
356 * @param crs
357 * CS_CoordinateSystem spatial reference system of the surface patch
358 * @return a Surfacepatch defined by the given Parameters
359 * @throws GeometryException
360 */
361 public static SurfacePatch createSurfacePatch( Position[] exteriorRing, Position[][] interiorRings,
362 SurfaceInterpolation si, CoordinateSystem crs )
363 throws GeometryException {
364 return new PolygonImpl( si, exteriorRing, interiorRings, crs );
365 }
366
367 /**
368 *
369 * @param exteriorRing
370 * @param interiorRings
371 * @param crs
372 * @return
373 * @throws GeometryException
374 */
375 public static SurfacePatch createSurfacePatch( CurveSegment[] exteriorRing, CurveSegment[][] interiorRings,
376 CoordinateSystem crs )
377 throws GeometryException {
378 Ring eRing = new RingImpl( exteriorRing, crs, '+' );
379 Ring[] iRings = null;
380 if ( interiorRings != null ) {
381 iRings = new Ring[interiorRings.length];
382 for ( int i = 0; i < iRings.length; i++ ) {
383 iRings[i] = new RingImpl( interiorRings[i], crs, '+' );
384 }
385 }
386 return new PolygonImpl( eRing, iRings, crs );
387 }
388
389 /**
390 *
391 * @param exteriorRing
392 * @param interiorRings
393 * @param crs
394 * @return
395 * @throws GeometryException
396 */
397 public static SurfacePatch createSurfacePatch( Curve exteriorRing, Curve[] interiorRings, CoordinateSystem crs )
398 throws GeometryException {
399 CurveSegment[] e = exteriorRing.getCurveSegments();
400 CurveSegment[][] i = null;
401 if ( interiorRings != null ) {
402 i = new CurveSegment[interiorRings.length][];
403 for ( int j = 0; j < i.length; j++ ) {
404 i[j] = interiorRings[j].getCurveSegments();
405 }
406 }
407 return createSurfacePatch( e, i, crs );
408 }
409
410 /**
411 * creates a Curve from a wkb.
412 *
413 * @param wkb
414 * byte stream that contains the wkb information
415 * @param crs
416 * CS_CoordinateSystem spatial reference system of the curve
417 * @return the Curve defined by the WKB and the given CRS
418 * @throws GeometryException
419 * if the wkb is not known or invalid
420 *
421 */
422 public static Curve createCurve( byte[] wkb, CoordinateSystem crs )
423 throws GeometryException {
424 int wkbType = -1;
425 int numPoints = -1;
426 Position[] points = null;
427 double x = 0;
428 double y = 0;
429
430 byte byteorder = wkb[0];
431
432 if ( byteorder == 0 ) {
433 wkbType = ByteUtils.readBEInt( wkb, 1 );
434 } else {
435 wkbType = ByteUtils.readLEInt( wkb, 1 );
436 }
437
438 // check if it's realy a linestrin/curve
439 if ( wkbType != 2 ) {
440 throw new GeometryException( "invalid byte stream for Curve" );
441 }
442
443 // read number of points
444 if ( byteorder == 0 ) {
445 numPoints = ByteUtils.readBEInt( wkb, 5 );
446 } else {
447 numPoints = ByteUtils.readLEInt( wkb, 5 );
448 }
449
450 int offset = 9;
451
452 points = new Position[numPoints];
453
454 // read the i-th point depending on the byteorde
455 if ( byteorder == 0 ) {
456 for ( int i = 0; i < numPoints; i++ ) {
457 x = ByteUtils.readBEDouble( wkb, offset );
458 offset += 8;
459 y = ByteUtils.readBEDouble( wkb, offset );
460 offset += 8;
461 points[i] = new PositionImpl( x, y );
462 }
463 } else {
464 for ( int i = 0; i < numPoints; i++ ) {
465 x = ByteUtils.readLEDouble( wkb, offset );
466 offset += 8;
467 y = ByteUtils.readLEDouble( wkb, offset );
468 offset += 8;
469 points[i] = new PositionImpl( x, y );
470 }
471 }
472
473 CurveSegment[] segment = new CurveSegment[1];
474
475 segment[0] = createCurveSegment( points, crs );
476
477 return createCurve( segment );
478 }
479
480 /**
481 * creates a Surface composed of one SurfacePatch from array(s) of Position
482 *
483 * @param exteriorRing
484 * exterior ring of the patch
485 * @param interiorRings
486 * interior rings of the patch
487 * @param si
488 * SurfaceInterpolation
489 * @param crs
490 * CS_CoordinateSystem spatial reference system of the surface patch
491 * @return a Surface composed of one SurfacePatch from array(s) of Position
492 * @throws GeometryException
493 * if the implicite orientation is not '+' or '-', or the rings aren't closed
494 */
495 public static Surface createSurface( Position[] exteriorRing, Position[][] interiorRings, SurfaceInterpolation si,
496 CoordinateSystem crs )
497 throws GeometryException {
498 SurfacePatch sp = new PolygonImpl( si, exteriorRing, interiorRings, crs );
499 return createSurface( sp );
500 }
501
502 /**
503 * creates a Surface from an array of SurfacePatch.
504 *
505 * @param patch
506 * patches that build the surface
507 * @return a Surface from an array of SurfacePatch.
508 * @throws GeometryException
509 * if implicite the orientation is not '+' or '-'
510 */
511 public static Surface createSurface( SurfacePatch patch )
512 throws GeometryException {
513 return new SurfaceImpl( patch );
514 }
515
516 /**
517 * creates a Surface from an array of SurfacePatch.
518 *
519 * @param patches
520 * patches that build the surface
521 *
522 * @return a Surface from an array of SurfacePatch.
523 * @throws GeometryException
524 * if implicite the orientation is not '+' or '-'
525 */
526 public static Surface createSurface( SurfacePatch[] patches )
527 throws GeometryException {
528 return new SurfaceImpl( patches );
529 }
530
531 /**
532 * creates a Surface from an array of SurfacePatch.
533 *
534 * @param patches
535 * patches that build the surface
536 * @param crs
537 *
538 * @return a Surface from an array of SurfacePatch.
539 * @throws GeometryException
540 * if implicite the orientation is not '+' or '-'
541 */
542 public static Surface createSurface( SurfacePatch[] patches, CoordinateSystem crs )
543 throws GeometryException {
544 return new SurfaceImpl( patches, crs );
545 }
546
547 /**
548 * creates a Surface from a wkb.
549 *
550 * @param wkb
551 * byte stream that contains the wkb information
552 * @param crs
553 * CS_CoordinateSystem spatial reference system of the curve
554 * @param si
555 * SurfaceInterpolation
556 * @return a Surface from a wkb.
557 * @throws GeometryException
558 * if the implicite orientation is not '+' or '-' or the wkb is not known or invalid
559 */
560 public static Surface createSurface( byte[] wkb, CoordinateSystem crs, SurfaceInterpolation si )
561 throws GeometryException {
562 int wkbtype = -1;
563 int numRings = 0;
564 int numPoints = 0;
565 int offset = 0;
566 double x = 0;
567 double y = 0;
568
569 Position[] externalBoundary = null;
570 Position[][] internalBoundaries = null;
571
572 byte byteorder = wkb[offset++];
573
574 if ( byteorder == 0 ) {
575 wkbtype = ByteUtils.readBEInt( wkb, offset );
576 } else {
577 wkbtype = ByteUtils.readLEInt( wkb, offset );
578 }
579
580 offset += 4;
581
582 if ( wkbtype == 6 ) {
583 return null;
584 }
585
586 // is the geometry respresented by wkb a polygon?
587 if ( wkbtype != 3 ) {
588 throw new GeometryException( "invalid byte stream for Surface " + wkbtype );
589 }
590
591 // read number of rings of the polygon
592 if ( byteorder == 0 ) {
593 numRings = ByteUtils.readBEInt( wkb, offset );
594 } else {
595 numRings = ByteUtils.readLEInt( wkb, offset );
596 }
597
598 offset += 4;
599
600 // read number of points of the external ring
601 if ( byteorder == 0 ) {
602 numPoints = ByteUtils.readBEInt( wkb, offset );
603 } else {
604 numPoints = ByteUtils.readLEInt( wkb, offset );
605 }
606
607 offset += 4;
608
609 // allocate memory for the external boundary
610 externalBoundary = new Position[numPoints];
611
612 if ( byteorder == 0 ) {
613 // read points of the external boundary from the byte[]
614 for ( int i = 0; i < numPoints; i++ ) {
615 x = ByteUtils.readBEDouble( wkb, offset );
616 offset += 8;
617 y = ByteUtils.readBEDouble( wkb, offset );
618 offset += 8;
619 externalBoundary[i] = new PositionImpl( x, y );
620 }
621 } else {
622 // read points of the external boundary from the byte[]
623 for ( int i = 0; i < numPoints; i++ ) {
624 x = ByteUtils.readLEDouble( wkb, offset );
625 offset += 8;
626 y = ByteUtils.readLEDouble( wkb, offset );
627 offset += 8;
628 externalBoundary[i] = new PositionImpl( x, y );
629 }
630 }
631
632 // only if numRings is larger then one there internal rings
633 if ( numRings > 1 ) {
634 internalBoundaries = new Position[numRings - 1][];
635 }
636
637 if ( byteorder == 0 ) {
638 for ( int j = 1; j < numRings; j++ ) {
639 // read number of points of the j-th internal ring
640 numPoints = ByteUtils.readBEInt( wkb, offset );
641 offset += 4;
642
643 // allocate memory for the j-th internal boundary
644 internalBoundaries[j - 1] = new Position[numPoints];
645
646 // read points of the external boundary from the byte[]
647 for ( int i = 0; i < numPoints; i++ ) {
648 x = ByteUtils.readBEDouble( wkb, offset );
649 offset += 8;
650 y = ByteUtils.readBEDouble( wkb, offset );
651 offset += 8;
652 internalBoundaries[j - 1][i] = new PositionImpl( x, y );
653 }
654 }
655 } else {
656 for ( int j = 1; j < numRings; j++ ) {
657 // read number of points of the j-th internal ring
658 numPoints = ByteUtils.readLEInt( wkb, offset );
659 offset += 4;
660
661 // allocate memory for the j-th internal boundary
662 internalBoundaries[j - 1] = new Position[numPoints];
663
664 // read points of the external boundary from the byte[]
665 for ( int i = 0; i < numPoints; i++ ) {
666 x = ByteUtils.readLEDouble( wkb, offset );
667 offset += 8;
668 y = ByteUtils.readLEDouble( wkb, offset );
669 offset += 8;
670 internalBoundaries[j - 1][i] = new PositionImpl( x, y );
671 }
672 }
673 }
674
675 SurfacePatch patch = createSurfacePatch( externalBoundary, internalBoundaries, si, crs );
676
677 return createSurface( patch );
678 }
679
680 /**
681 * Creates a <tt>Surface</tt> from a <tt>Envelope</tt>.
682 * <p>
683 *
684 * @param bbox
685 * envelope to be converted
686 * @param crs
687 * spatial reference system of the surface
688 * @return corresponding surface
689 *
690 * @throws GeometryException
691 * if the implicite orientation is not '+' or '-'
692 */
693 public static Surface createSurface( Envelope bbox, CoordinateSystem crs )
694 throws GeometryException {
695
696 Position min = bbox.getMin();
697 Position max = bbox.getMax();
698 Position[] exteriorRing = null;
699 if ( min.getCoordinateDimension() == 2 ) {
700 exteriorRing = new Position[] { min, new PositionImpl( min.getX(), max.getY() ), max,
701 new PositionImpl( max.getX(), min.getY() ), min };
702 } else {
703 exteriorRing = new Position[] {
704 min,
705 new PositionImpl( min.getX(), max.getY(),
706 min.getZ() + ( ( max.getZ() - min.getZ() ) * 0.5 ) ),
707 max,
708 new PositionImpl( max.getX(), min.getY(),
709 min.getZ() + ( ( max.getZ() - min.getZ() ) * 0.5 ) ), min };
710 }
711
712 return createSurface( exteriorRing, null, new SurfaceInterpolationImpl(), crs );
713 }
714
715 /**
716 * Creates a <tt>GM_Surface</tt> from the ordinates of the exterior ring and the the interior
717 * rings
718 * <p>
719 *
720 * @param exterior
721 * ring
722 * @param interior
723 * ring
724 * @param dim
725 * of the surface
726 * @param crs
727 * spatial reference system of the surface
728 * @return corresponding surface
729 * @throws GeometryException
730 * if the implicite orientation is not '+' or '-'
731 *
732 */
733 public static Surface createSurface( double[] exterior, double[][] interior, int dim, CoordinateSystem crs )
734 throws GeometryException {
735
736 // get exterior ring
737 Position[] ext = new Position[exterior.length / dim];
738 int i = 0;
739 int k = 0;
740 while ( i < exterior.length - 1 ) {
741 double[] o = new double[dim];
742 for ( int j = 0; j < dim; j++ ) {
743 o[j] = exterior[i++];
744 }
745 ext[k++] = GeometryFactory.createPosition( o );
746 }
747
748 // get interior rings if available
749 Position[][] in = null;
750 if ( interior != null && interior.length > 0 ) {
751 in = new Position[interior.length][];
752 for ( int j = 0; j < in.length; j++ ) {
753 in[j] = new Position[interior[j].length / dim];
754 i = 0;
755 while ( i < interior[j].length ) {
756 double[] o = new double[dim];
757 for ( int z = 0; z < dim; z++ ) {
758 o[z] = interior[j][i++];
759 }
760 in[j][i / dim - 1] = GeometryFactory.createPosition( o );
761 }
762 }
763 }
764
765 // default - linear - interpolation
766 SurfaceInterpolation si = new SurfaceInterpolationImpl();
767 return GeometryFactory.createSurface( ext, in, si, crs );
768 }
769
770 /**
771 * creates a MultiPoint from an array of Point.
772 *
773 * @param points
774 * array of Points
775 * @return a MultiPoint from an array of Point.
776 *
777 */
778 public static MultiPoint createMultiPoint( Point[] points ) {
779 return new MultiPointImpl( points );
780 }
781
782 /**
783 * creates a MultiPoint from an array of Point.
784 *
785 * @param points
786 * array of Points
787 * @param crs
788 * @return a MultiPoint from an array of Point.
789 */
790 public static MultiPoint createMultiPoint( Point[] points, CoordinateSystem crs ) {
791 return new MultiPointImpl( points, crs );
792 }
793
794 /**
795 * creates a MultiPoint from a wkb.
796 *
797 * @param wkb
798 * byte stream that contains the wkb information
799 * @param crs
800 * CS_CoordinateSystem spatial reference system of the curve
801 * @return the MultiPoint defined by the WKB and the given CRS
802 * @throws GeometryException
803 * if the wkb is not known or invalid
804 *
805 */
806 public static MultiPoint createMultiPoint( byte[] wkb, CoordinateSystem crs )
807 throws GeometryException {
808 Point[] points = null;
809 int wkbType = -1;
810 int numPoints = -1;
811 double x = 0;
812 double y = 0;
813 byte byteorder = wkb[0];
814
815 // read wkbType
816 if ( byteorder == 0 ) {
817 wkbType = ByteUtils.readBEInt( wkb, 1 );
818 } else {
819 wkbType = ByteUtils.readLEInt( wkb, 1 );
820 }
821
822 // if the geometry isn't a multipoint throw exception
823 if ( wkbType != 4 ) {
824 throw new GeometryException( "Invalid byte stream for MultiPoint" );
825 }
826
827 // read number of points
828 if ( byteorder == 0 ) {
829 numPoints = ByteUtils.readBEInt( wkb, 5 );
830 } else {
831 numPoints = ByteUtils.readLEInt( wkb, 5 );
832 }
833
834 points = new Point[numPoints];
835
836 int offset = 9;
837
838 Object[] o = new Object[3];
839 o[2] = crs;
840
841 // read all points
842 for ( int i = 0; i < numPoints; i++ ) {
843 // byteorder of the i-th point
844 byteorder = wkb[offset];
845
846 // wkbType of the i-th geometry
847 if ( byteorder == 0 ) {
848 wkbType = ByteUtils.readBEInt( wkb, offset + 1 );
849 } else {
850 wkbType = ByteUtils.readLEInt( wkb, offset + 1 );
851 }
852
853 // if the geometry isn't a point throw exception
854 if ( wkbType != 1 ) {
855 throw new GeometryException( "Invalid byte stream for Point as " + "part of a multi point" );
856 }
857
858 // read the i-th point depending on the byteorde
859 if ( byteorder == 0 ) {
860 x = ByteUtils.readBEDouble( wkb, offset + 5 );
861 y = ByteUtils.readBEDouble( wkb, offset + 13 );
862 } else {
863 x = ByteUtils.readLEDouble( wkb, offset + 5 );
864 y = ByteUtils.readLEDouble( wkb, offset + 13 );
865 }
866
867 offset += 21;
868
869 points[i] = new PointImpl( x, y, crs );
870 }
871
872 return createMultiPoint( points );
873 }
874
875 /**
876 * creates a MultiCurve from an array of Curves.
877 *
878 * @param curves
879 * @return a MultiCurve from an array of Curves.
880 */
881 public static MultiCurve createMultiCurve( Curve[] curves ) {
882 return new MultiCurveImpl( curves );
883 }
884
885 /**
886 * creates a MultiCurve from an array of Curves.
887 *
888 * @param curves
889 * @param crs
890 * @return a MultiCurve from an array of Curves.
891 */
892 public static MultiCurve createMultiCurve( Curve[] curves, CoordinateSystem crs ) {
893 return new MultiCurveImpl( curves, crs );
894 }
895
896 /**
897 * creates a MultiCurve from a wkb.
898 *
899 * @param wkb
900 * byte stream that contains the wkb information
901 * @param crs
902 * CS_CoordinateSystem spatial reference system of the curve
903 * @return the MultiCurve defined by the WKB and the given CRS
904 * @throws GeometryException
905 * if the wkb is not known or invalid
906 */
907 public static MultiCurve createMultiCurve( byte[] wkb, CoordinateSystem crs )
908 throws GeometryException {
909 int wkbType = -1;
910 int numPoints = -1;
911 int numParts = -1;
912 double x = 0;
913 double y = 0;
914 Position[][] points = null;
915 int offset = 0;
916 byte byteorder = wkb[offset++];
917
918 if ( byteorder == 0 ) {
919 wkbType = ByteUtils.readBEInt( wkb, offset );
920 } else {
921 wkbType = ByteUtils.readLEInt( wkb, offset );
922 }
923
924 offset += 4;
925
926 // check if it's realy a linestring
927 if ( wkbType != 5 ) {
928 throw new GeometryException( "Invalid byte stream for MultiCurve" );
929 }
930
931 // read number of linestrings
932 if ( byteorder == 0 ) {
933 numParts = ByteUtils.readBEInt( wkb, offset );
934 } else {
935 numParts = ByteUtils.readLEInt( wkb, offset );
936 }
937
938 offset += 4;
939
940 points = new Position[numParts][];
941
942 // for every linestring
943 for ( int j = 0; j < numParts; j++ ) {
944 byteorder = wkb[offset++];
945
946 if ( byteorder == 0 ) {
947 wkbType = ByteUtils.readBEInt( wkb, offset );
948 } else {
949 wkbType = ByteUtils.readLEInt( wkb, offset );
950 }
951
952 offset += 4;
953
954 // check if it's realy a linestring
955 if ( wkbType != 2 ) {
956 throw new GeometryException( "Invalid byte stream for Curve as " + " part of a MultiCurve." );
957 }
958
959 // read number of points
960 if ( byteorder == 0 ) {
961 numPoints = ByteUtils.readBEInt( wkb, offset );
962 } else {
963 numPoints = ByteUtils.readLEInt( wkb, offset );
964 }
965
966 offset += 4;
967
968 points[j] = new Position[numPoints];
969
970 // read the i-th point depending on the byteorde
971 if ( byteorder == 0 ) {
972 for ( int i = 0; i < numPoints; i++ ) {
973 x = ByteUtils.readBEDouble( wkb, offset );
974 offset += 8;
975 y = ByteUtils.readBEDouble( wkb, offset );
976 offset += 8;
977 points[j][i] = new PositionImpl( x, y );
978 }
979 } else {
980 for ( int i = 0; i < numPoints; i++ ) {
981 x = ByteUtils.readLEDouble( wkb, offset );
982 offset += 8;
983 y = ByteUtils.readLEDouble( wkb, offset );
984 offset += 8;
985 points[j][i] = new PositionImpl( x, y );
986 }
987 }
988 }
989
990 CurveSegment[] segment = new CurveSegment[1];
991 Curve[] curves = new Curve[numParts];
992
993 for ( int i = 0; i < numParts; i++ ) {
994 segment[0] = createCurveSegment( points[i], crs );
995 curves[i] = createCurve( segment );
996 }
997
998 return createMultiCurve( curves );
999 }
1000
1001 /**
1002 * creates a MultiSurface from an array of surfaces
1003 *
1004 * @param surfaces
1005 * @return a MultiSurface from an array of surfaces
1006 */
1007 public static MultiSurface createMultiSurface( Surface[] surfaces ) {
1008 return new MultiSurfaceImpl( surfaces );
1009 }
1010
1011 /**
1012 * creates a MultiSurface from an array of surfaces
1013 *
1014 * @param surfaces
1015 * @param crs
1016 * @return a MultiSurface from an array of surfaces
1017 */
1018 public static MultiSurface createMultiSurface( Surface[] surfaces, CoordinateSystem crs ) {
1019 return new MultiSurfaceImpl( surfaces, crs );
1020 }
1021
1022 /**
1023 * creates a MultiSurface from a wkb
1024 *
1025 * @param wkb
1026 * geometry in Well-Known Binary (WKB) format
1027 * @param crs
1028 * spatial reference system of the geometry
1029 * @param si
1030 * surface interpolation
1031 * @return the MultiSurface defined by the WKB and the given CRS
1032 * @throws GeometryException
1033 * if the wkb is not known or invalid
1034 */
1035 public static MultiSurface createMultiSurface( byte[] wkb, CoordinateSystem crs, SurfaceInterpolation si )
1036 throws GeometryException {
1037 int wkbtype = -1;
1038 int numPoly = 0;
1039 int numRings = 0;
1040 int numPoints = 0;
1041 int offset = 0;
1042 double x = 0;
1043 double y = 0;
1044 Position[] externalBoundary = null;
1045 Position[][] internalBoundaries = null;
1046 byte byteorder = wkb[offset++];
1047
1048 if ( byteorder == 0 ) {
1049 wkbtype = ByteUtils.readBEInt( wkb, offset );
1050 } else {
1051 wkbtype = ByteUtils.readLEInt( wkb, offset );
1052 }
1053
1054 offset += 4;
1055
1056 // is the wkbmetry a multipolygon?
1057 if ( wkbtype != 6 ) {
1058 throw new GeometryException( "Invalid byte stream for MultiSurface" );
1059 }
1060
1061 // read number of polygons on the byte[]
1062 if ( byteorder == 0 ) {
1063 numPoly = ByteUtils.readBEInt( wkb, offset );
1064 } else {
1065 numPoly = ByteUtils.readLEInt( wkb, offset );
1066 }
1067
1068 offset += 4;
1069
1070 ArrayList<Surface> list = new ArrayList<Surface>( numPoly );
1071
1072 for ( int ip = 0; ip < numPoly; ip++ ) {
1073 byteorder = wkb[offset];
1074 offset++;
1075
1076 if ( byteorder == 0 ) {
1077 wkbtype = ByteUtils.readBEInt( wkb, offset );
1078 } else {
1079 wkbtype = ByteUtils.readLEInt( wkb, offset );
1080 }
1081
1082 offset += 4;
1083
1084 // is the geometry respresented by wkb a polygon?
1085 if ( wkbtype != 3 ) {
1086 throw new GeometryException( "invalid byte stream for Surface " + wkbtype );
1087 }
1088
1089 // read number of rings of the polygon
1090 if ( byteorder == 0 ) {
1091 numRings = ByteUtils.readBEInt( wkb, offset );
1092 } else {
1093 numRings = ByteUtils.readLEInt( wkb, offset );
1094 }
1095
1096 offset += 4;
1097
1098 // read number of points of the external ring
1099 if ( byteorder == 0 ) {
1100 numPoints = ByteUtils.readBEInt( wkb, offset );
1101 } else {
1102 numPoints = ByteUtils.readLEInt( wkb, offset );
1103 }
1104
1105 offset += 4;
1106
1107 // allocate memory for the external boundary
1108 externalBoundary = new Position[numPoints];
1109
1110 if ( byteorder == 0 ) {
1111 // read points of the external boundary from the byte[]
1112 for ( int i = 0; i < numPoints; i++ ) {
1113 x = ByteUtils.readBEDouble( wkb, offset );
1114 offset += 8;
1115 y = ByteUtils.readBEDouble( wkb, offset );
1116 offset += 8;
1117 externalBoundary[i] = new PositionImpl( x, y );
1118 }
1119 } else {
1120 // read points of the external boundary from the byte[]
1121 for ( int i = 0; i < numPoints; i++ ) {
1122 x = ByteUtils.readLEDouble( wkb, offset );
1123 offset += 8;
1124 y = ByteUtils.readLEDouble( wkb, offset );
1125 offset += 8;
1126 externalBoundary[i] = new PositionImpl( x, y );
1127 }
1128 }
1129
1130 // only if numRings is larger then one there internal rings
1131 if ( numRings > 1 ) {
1132 internalBoundaries = new Position[numRings - 1][];
1133 }
1134
1135 if ( byteorder == 0 ) {
1136 for ( int j = 1; j < numRings; j++ ) {
1137 // read number of points of the j-th internal ring
1138 numPoints = ByteUtils.readBEInt( wkb, offset );
1139 offset += 4;
1140
1141 // allocate memory for the j-th internal boundary
1142 internalBoundaries[j - 1] = new Position[numPoints];
1143
1144 // read points of the external boundary from the byte[]
1145 for ( int i = 0; i < numPoints; i++ ) {
1146 x = ByteUtils.readBEDouble( wkb, offset );
1147 offset += 8;
1148 y = ByteUtils.readBEDouble( wkb, offset );
1149 offset += 8;
1150 internalBoundaries[j - 1][i] = new PositionImpl( x, y );
1151 }
1152 }
1153 } else {
1154 for ( int j = 1; j < numRings; j++ ) {
1155 // read number of points of the j-th internal ring
1156 numPoints = ByteUtils.readLEInt( wkb, offset );
1157 offset += 4;
1158
1159 // allocate memory for the j-th internal boundary
1160 internalBoundaries[j - 1] = new Position[numPoints];
1161
1162 // read points of the external boundary from the byte[]
1163 for ( int i = 0; i < numPoints; i++ ) {
1164 x = ByteUtils.readLEDouble( wkb, offset );
1165 offset += 8;
1166 y = ByteUtils.readLEDouble( wkb, offset );
1167 offset += 8;
1168 internalBoundaries[j - 1][i] = new PositionImpl( x, y );
1169 }
1170 }
1171 }
1172
1173 SurfacePatch patch = createSurfacePatch( externalBoundary, internalBoundaries, si, crs );
1174
1175 list.add( createSurface( patch ) );
1176 }
1177
1178 MultiSurface multisurface = new MultiSurfaceImpl( crs );
1179
1180 for ( int i = 0; i < list.size(); i++ ) {
1181 multisurface.addSurface( list.get( i ) );
1182 }
1183
1184 return multisurface;
1185 }
1186
1187 }