001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/model/spatialschema/GeometryFactory.java $
002 /*---------------- FILE HEADER ------------------------------------------
003
004 This file is part of deegree.
005 Copyright (C) 2001-2007 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: 7987 $, $Date: 2007-08-12 20:37:59 +0200 (So, 12 Aug 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,
398 CoordinateSystem crs )
399 throws GeometryException {
400 CurveSegment[] e = exteriorRing.getCurveSegments();
401 CurveSegment[][] i = null;
402 if ( interiorRings != null ) {
403 i = new CurveSegment[interiorRings.length][];
404 for ( int j = 0; j < i.length; j++ ) {
405 i[j] = interiorRings[j].getCurveSegments();
406 }
407 }
408 return createSurfacePatch( e, i, crs );
409 }
410
411 /**
412 * creates a Curve from a wkb.
413 *
414 * @param wkb
415 * byte stream that contains the wkb information
416 * @param crs
417 * CS_CoordinateSystem spatial reference system of the curve
418 * @return the Curve defined by the WKB and the given CRS
419 * @throws GeometryException
420 * if the wkb is not known or invalid
421 *
422 */
423 public static Curve createCurve( byte[] wkb, CoordinateSystem crs )
424 throws GeometryException {
425 int wkbType = -1;
426 int numPoints = -1;
427 Position[] points = null;
428 double x = 0;
429 double y = 0;
430
431 byte byteorder = wkb[0];
432
433 if ( byteorder == 0 ) {
434 wkbType = ByteUtils.readBEInt( wkb, 1 );
435 } else {
436 wkbType = ByteUtils.readLEInt( wkb, 1 );
437 }
438
439 // check if it's realy a linestrin/curve
440 if ( wkbType != 2 ) {
441 throw new GeometryException( "invalid byte stream for Curve" );
442 }
443
444 // read number of points
445 if ( byteorder == 0 ) {
446 numPoints = ByteUtils.readBEInt( wkb, 5 );
447 } else {
448 numPoints = ByteUtils.readLEInt( wkb, 5 );
449 }
450
451 int offset = 9;
452
453 points = new Position[numPoints];
454
455 // read the i-th point depending on the byteorde
456 if ( byteorder == 0 ) {
457 for ( int i = 0; i < numPoints; i++ ) {
458 x = ByteUtils.readBEDouble( wkb, offset );
459 offset += 8;
460 y = ByteUtils.readBEDouble( wkb, offset );
461 offset += 8;
462 points[i] = new PositionImpl( x, y );
463 }
464 } else {
465 for ( int i = 0; i < numPoints; i++ ) {
466 x = ByteUtils.readLEDouble( wkb, offset );
467 offset += 8;
468 y = ByteUtils.readLEDouble( wkb, offset );
469 offset += 8;
470 points[i] = new PositionImpl( x, y );
471 }
472 }
473
474 CurveSegment[] segment = new CurveSegment[1];
475
476 segment[0] = createCurveSegment( points, crs );
477
478 return createCurve( segment );
479 }
480
481 /**
482 * creates a Surface composed of one SurfacePatch from array(s) of Position
483 *
484 * @param exteriorRing
485 * exterior ring of the patch
486 * @param interiorRings
487 * interior rings of the patch
488 * @param si
489 * SurfaceInterpolation
490 * @param crs
491 * CS_CoordinateSystem spatial reference system of the surface patch
492 * @return a Surface composed of one SurfacePatch from array(s) of Position
493 * @throws GeometryException
494 * if the implicite orientation is not '+' or '-', or the rings aren't closed
495 */
496 public static Surface createSurface( Position[] exteriorRing, Position[][] interiorRings, SurfaceInterpolation si,
497 CoordinateSystem crs )
498 throws GeometryException {
499 SurfacePatch sp = new PolygonImpl( si, exteriorRing, interiorRings, crs );
500 return createSurface( sp );
501 }
502
503 /**
504 * creates a Surface from an array of SurfacePatch.
505 *
506 * @param patch
507 * patches that build the surface
508 * @return a Surface from an array of SurfacePatch.
509 * @throws GeometryException
510 * if implicite the orientation is not '+' or '-'
511 */
512 public static Surface createSurface( SurfacePatch patch )
513 throws GeometryException {
514 return new SurfaceImpl( patch );
515 }
516
517 /**
518 * creates a Surface from an array of SurfacePatch.
519 *
520 * @param patches
521 * patches that build the surface
522 *
523 * @return a Surface from an array of SurfacePatch.
524 * @throws GeometryException
525 * if implicite the orientation is not '+' or '-'
526 */
527 public static Surface createSurface( SurfacePatch[] patches )
528 throws GeometryException {
529 return new SurfaceImpl( patches );
530 }
531
532 /**
533 * creates a Surface from an array of SurfacePatch.
534 *
535 * @param patches
536 * patches that build the surface
537 * @param crs
538 *
539 * @return a Surface from an array of SurfacePatch.
540 * @throws GeometryException
541 * if implicite the orientation is not '+' or '-'
542 */
543 public static Surface createSurface( SurfacePatch[] patches, CoordinateSystem crs )
544 throws GeometryException {
545 return new SurfaceImpl( patches, crs );
546 }
547
548 /**
549 * creates a Surface from a wkb.
550 *
551 * @param wkb
552 * byte stream that contains the wkb information
553 * @param crs
554 * CS_CoordinateSystem spatial reference system of the curve
555 * @param si
556 * SurfaceInterpolation
557 * @return a Surface from a wkb.
558 * @throws GeometryException
559 * if the implicite orientation is not '+' or '-' or the wkb is not known or invalid
560 */
561 public static Surface createSurface( byte[] wkb, CoordinateSystem crs, SurfaceInterpolation si )
562 throws GeometryException {
563 int wkbtype = -1;
564 int numRings = 0;
565 int numPoints = 0;
566 int offset = 0;
567 double x = 0;
568 double y = 0;
569
570 Position[] externalBoundary = null;
571 Position[][] internalBoundaries = null;
572
573 byte byteorder = wkb[offset++];
574
575 if ( byteorder == 0 ) {
576 wkbtype = ByteUtils.readBEInt( wkb, offset );
577 } else {
578 wkbtype = ByteUtils.readLEInt( wkb, offset );
579 }
580
581 offset += 4;
582
583 if ( wkbtype == 6 ) {
584 return null;
585 }
586
587 // is the geometry respresented by wkb a polygon?
588 if ( wkbtype != 3 ) {
589 throw new GeometryException( "invalid byte stream for Surface " + wkbtype );
590 }
591
592 // read number of rings of the polygon
593 if ( byteorder == 0 ) {
594 numRings = ByteUtils.readBEInt( wkb, offset );
595 } else {
596 numRings = ByteUtils.readLEInt( wkb, offset );
597 }
598
599 offset += 4;
600
601 // read number of points of the external ring
602 if ( byteorder == 0 ) {
603 numPoints = ByteUtils.readBEInt( wkb, offset );
604 } else {
605 numPoints = ByteUtils.readLEInt( wkb, offset );
606 }
607
608 offset += 4;
609
610 // allocate memory for the external boundary
611 externalBoundary = new Position[numPoints];
612
613 if ( byteorder == 0 ) {
614 // read points of the external boundary from the byte[]
615 for ( int i = 0; i < numPoints; i++ ) {
616 x = ByteUtils.readBEDouble( wkb, offset );
617 offset += 8;
618 y = ByteUtils.readBEDouble( wkb, offset );
619 offset += 8;
620 externalBoundary[i] = new PositionImpl( x, y );
621 }
622 } else {
623 // read points of the external boundary from the byte[]
624 for ( int i = 0; i < numPoints; i++ ) {
625 x = ByteUtils.readLEDouble( wkb, offset );
626 offset += 8;
627 y = ByteUtils.readLEDouble( wkb, offset );
628 offset += 8;
629 externalBoundary[i] = new PositionImpl( x, y );
630 }
631 }
632
633 // only if numRings is larger then one there internal rings
634 if ( numRings > 1 ) {
635 internalBoundaries = new Position[numRings - 1][];
636 }
637
638 if ( byteorder == 0 ) {
639 for ( int j = 1; j < numRings; j++ ) {
640 // read number of points of the j-th internal ring
641 numPoints = ByteUtils.readBEInt( wkb, offset );
642 offset += 4;
643
644 // allocate memory for the j-th internal boundary
645 internalBoundaries[j - 1] = new Position[numPoints];
646
647 // read points of the external boundary from the byte[]
648 for ( int i = 0; i < numPoints; i++ ) {
649 x = ByteUtils.readBEDouble( wkb, offset );
650 offset += 8;
651 y = ByteUtils.readBEDouble( wkb, offset );
652 offset += 8;
653 internalBoundaries[j - 1][i] = new PositionImpl( x, y );
654 }
655 }
656 } else {
657 for ( int j = 1; j < numRings; j++ ) {
658 // read number of points of the j-th internal ring
659 numPoints = ByteUtils.readLEInt( wkb, offset );
660 offset += 4;
661
662 // allocate memory for the j-th internal boundary
663 internalBoundaries[j - 1] = new Position[numPoints];
664
665 // read points of the external boundary from the byte[]
666 for ( int i = 0; i < numPoints; i++ ) {
667 x = ByteUtils.readLEDouble( wkb, offset );
668 offset += 8;
669 y = ByteUtils.readLEDouble( wkb, offset );
670 offset += 8;
671 internalBoundaries[j - 1][i] = new PositionImpl( x, y );
672 }
673 }
674 }
675
676 SurfacePatch patch = createSurfacePatch( externalBoundary, internalBoundaries, si, crs );
677
678 return createSurface( patch );
679 }
680
681 /**
682 * Creates a <tt>Surface</tt> from a <tt>Envelope</tt>.
683 * <p>
684 *
685 * @param bbox
686 * envelope to be converted
687 * @param crs
688 * spatial reference system of the surface
689 * @return corresponding surface
690 *
691 * @throws GeometryException
692 * if the implicite orientation is not '+' or '-'
693 */
694 public static Surface createSurface( Envelope bbox, CoordinateSystem crs )
695 throws GeometryException {
696
697 Position min = bbox.getMin();
698 Position max = bbox.getMax();
699 Position[] exteriorRing = null;
700 if ( min.getCoordinateDimension() == 2 ) {
701 exteriorRing = new Position[] { min, new PositionImpl( min.getX(), max.getY() ), max,
702 new PositionImpl( max.getX(), min.getY() ), min };
703 } else {
704 exteriorRing = new Position[] {
705 min,
706 new PositionImpl( min.getX(), max.getY(),
707 min.getZ() + ( ( max.getZ() - min.getZ() ) * 0.5 ) ),
708 max,
709 new PositionImpl( max.getX(), min.getY(),
710 min.getZ() + ( ( max.getZ() - min.getZ() ) * 0.5 ) ), min };
711 }
712
713 return createSurface( exteriorRing, null, new SurfaceInterpolationImpl(), crs );
714 }
715
716 /**
717 * Creates a <tt>GM_Surface</tt> from the ordinates of the exterior ring and the the interior
718 * rings
719 * <p>
720 *
721 * @param exterior
722 * ring
723 * @param interior
724 * ring
725 * @param dim
726 * of the surface
727 * @param crs
728 * spatial reference system of the surface
729 * @return corresponding surface
730 * @throws GeometryException
731 * if the implicite orientation is not '+' or '-'
732 *
733 */
734 public static Surface createSurface( double[] exterior, double[][] interior, int dim, CoordinateSystem crs )
735 throws GeometryException {
736
737 // get exterior ring
738 Position[] ext = new Position[exterior.length / dim];
739 int i = 0;
740 int k = 0;
741 while ( i < exterior.length - 1 ) {
742 double[] o = new double[dim];
743 for ( int j = 0; j < dim; j++ ) {
744 o[j] = exterior[i++];
745 }
746 ext[k++] = GeometryFactory.createPosition( o );
747 }
748
749 // get interior rings if available
750 Position[][] in = null;
751 if ( interior != null && interior.length > 0 ) {
752 in = new Position[interior.length][];
753 for ( int j = 0; j < in.length; j++ ) {
754 in[j] = new Position[interior[j].length / dim];
755 i = 0;
756 while ( i < interior[j].length ) {
757 double[] o = new double[dim];
758 for ( int z = 0; z < dim; z++ ) {
759 o[z] = interior[j][i++];
760 }
761 in[j][i / dim - 1] = GeometryFactory.createPosition( o );
762 }
763 }
764 }
765
766 // default - linear - interpolation
767 SurfaceInterpolation si = new SurfaceInterpolationImpl();
768 return GeometryFactory.createSurface( ext, in, si, crs );
769 }
770
771 /**
772 * creates a MultiPoint from an array of Point.
773 *
774 * @param points
775 * array of Points
776 * @return a MultiPoint from an array of Point.
777 *
778 */
779 public static MultiPoint createMultiPoint( Point[] points ) {
780 return new MultiPointImpl( points );
781 }
782
783 /**
784 * creates a MultiPoint from an array of Point.
785 *
786 * @param points
787 * array of Points
788 * @param crs
789 * @return a MultiPoint from an array of Point.
790 */
791 public static MultiPoint createMultiPoint( Point[] points, CoordinateSystem crs ) {
792 return new MultiPointImpl( points, crs );
793 }
794
795 /**
796 * creates a MultiPoint from a wkb.
797 *
798 * @param wkb
799 * byte stream that contains the wkb information
800 * @param crs
801 * CS_CoordinateSystem spatial reference system of the curve
802 * @return the MultiPoint defined by the WKB and the given CRS
803 * @throws GeometryException
804 * if the wkb is not known or invalid
805 *
806 */
807 public static MultiPoint createMultiPoint( byte[] wkb, CoordinateSystem crs )
808 throws GeometryException {
809 Point[] points = null;
810 int wkbType = -1;
811 int numPoints = -1;
812 double x = 0;
813 double y = 0;
814 byte byteorder = wkb[0];
815
816 // read wkbType
817 if ( byteorder == 0 ) {
818 wkbType = ByteUtils.readBEInt( wkb, 1 );
819 } else {
820 wkbType = ByteUtils.readLEInt( wkb, 1 );
821 }
822
823 // if the geometry isn't a multipoint throw exception
824 if ( wkbType != 4 ) {
825 throw new GeometryException( "Invalid byte stream for MultiPoint" );
826 }
827
828 // read number of points
829 if ( byteorder == 0 ) {
830 numPoints = ByteUtils.readBEInt( wkb, 5 );
831 } else {
832 numPoints = ByteUtils.readLEInt( wkb, 5 );
833 }
834
835 points = new Point[numPoints];
836
837 int offset = 9;
838
839 Object[] o = new Object[3];
840 o[2] = crs;
841
842 // read all points
843 for ( int i = 0; i < numPoints; i++ ) {
844 // byteorder of the i-th point
845 byteorder = wkb[offset];
846
847 // wkbType of the i-th geometry
848 if ( byteorder == 0 ) {
849 wkbType = ByteUtils.readBEInt( wkb, offset + 1 );
850 } else {
851 wkbType = ByteUtils.readLEInt( wkb, offset + 1 );
852 }
853
854 // if the geometry isn't a point throw exception
855 if ( wkbType != 1 ) {
856 throw new GeometryException( "Invalid byte stream for Point as " + "part of a multi point" );
857 }
858
859 // read the i-th point depending on the byteorde
860 if ( byteorder == 0 ) {
861 x = ByteUtils.readBEDouble( wkb, offset + 5 );
862 y = ByteUtils.readBEDouble( wkb, offset + 13 );
863 } else {
864 x = ByteUtils.readLEDouble( wkb, offset + 5 );
865 y = ByteUtils.readLEDouble( wkb, offset + 13 );
866 }
867
868 offset += 21;
869
870 points[i] = new PointImpl( x, y, crs );
871 }
872
873 return createMultiPoint( points );
874 }
875
876 /**
877 * creates a MultiCurve from an array of Curves.
878 *
879 * @param curves
880 * @return a MultiCurve from an array of Curves.
881 */
882 public static MultiCurve createMultiCurve( Curve[] curves ) {
883 return new MultiCurveImpl( curves );
884 }
885
886 /**
887 * creates a MultiCurve from an array of Curves.
888 *
889 * @param curves
890 * @param crs
891 * @return a MultiCurve from an array of Curves.
892 */
893 public static MultiCurve createMultiCurve( Curve[] curves, CoordinateSystem crs ) {
894 return new MultiCurveImpl( curves, crs );
895 }
896
897 /**
898 * creates a MultiCurve from a wkb.
899 *
900 * @param wkb
901 * byte stream that contains the wkb information
902 * @param crs
903 * CS_CoordinateSystem spatial reference system of the curve
904 * @return the MultiCurve defined by the WKB and the given CRS
905 * @throws GeometryException
906 * if the wkb is not known or invalid
907 */
908 public static MultiCurve createMultiCurve( byte[] wkb, CoordinateSystem crs )
909 throws GeometryException {
910 int wkbType = -1;
911 int numPoints = -1;
912 int numParts = -1;
913 double x = 0;
914 double y = 0;
915 Position[][] points = null;
916 int offset = 0;
917 byte byteorder = wkb[offset++];
918
919 if ( byteorder == 0 ) {
920 wkbType = ByteUtils.readBEInt( wkb, offset );
921 } else {
922 wkbType = ByteUtils.readLEInt( wkb, offset );
923 }
924
925 offset += 4;
926
927 // check if it's realy a linestring
928 if ( wkbType != 5 ) {
929 throw new GeometryException( "Invalid byte stream for MultiCurve" );
930 }
931
932 // read number of linestrings
933 if ( byteorder == 0 ) {
934 numParts = ByteUtils.readBEInt( wkb, offset );
935 } else {
936 numParts = ByteUtils.readLEInt( wkb, offset );
937 }
938
939 offset += 4;
940
941 points = new Position[numParts][];
942
943 // for every linestring
944 for ( int j = 0; j < numParts; j++ ) {
945 byteorder = wkb[offset++];
946
947 if ( byteorder == 0 ) {
948 wkbType = ByteUtils.readBEInt( wkb, offset );
949 } else {
950 wkbType = ByteUtils.readLEInt( wkb, offset );
951 }
952
953 offset += 4;
954
955 // check if it's realy a linestring
956 if ( wkbType != 2 ) {
957 throw new GeometryException( "Invalid byte stream for Curve as " + " part of a MultiCurve." );
958 }
959
960 // read number of points
961 if ( byteorder == 0 ) {
962 numPoints = ByteUtils.readBEInt( wkb, offset );
963 } else {
964 numPoints = ByteUtils.readLEInt( wkb, offset );
965 }
966
967 offset += 4;
968
969 points[j] = new Position[numPoints];
970
971 // read the i-th point depending on the byteorde
972 if ( byteorder == 0 ) {
973 for ( int i = 0; i < numPoints; i++ ) {
974 x = ByteUtils.readBEDouble( wkb, offset );
975 offset += 8;
976 y = ByteUtils.readBEDouble( wkb, offset );
977 offset += 8;
978 points[j][i] = new PositionImpl( x, y );
979 }
980 } else {
981 for ( int i = 0; i < numPoints; i++ ) {
982 x = ByteUtils.readLEDouble( wkb, offset );
983 offset += 8;
984 y = ByteUtils.readLEDouble( wkb, offset );
985 offset += 8;
986 points[j][i] = new PositionImpl( x, y );
987 }
988 }
989 }
990
991 CurveSegment[] segment = new CurveSegment[1];
992 Curve[] curves = new Curve[numParts];
993
994 for ( int i = 0; i < numParts; i++ ) {
995 segment[0] = createCurveSegment( points[i], crs );
996 curves[i] = createCurve( segment );
997 }
998
999 return createMultiCurve( curves );
1000 }
1001
1002 /**
1003 * creates a MultiSurface from an array of surfaces
1004 *
1005 * @param surfaces
1006 * @return a MultiSurface from an array of surfaces
1007 */
1008 public static MultiSurface createMultiSurface( Surface[] surfaces ) {
1009 return new MultiSurfaceImpl( surfaces );
1010 }
1011
1012 /**
1013 * creates a MultiSurface from an array of surfaces
1014 *
1015 * @param surfaces
1016 * @param crs
1017 * @return a MultiSurface from an array of surfaces
1018 */
1019 public static MultiSurface createMultiSurface( Surface[] surfaces, CoordinateSystem crs ) {
1020 return new MultiSurfaceImpl( surfaces, crs );
1021 }
1022
1023 /**
1024 * creates a MultiSurface from a wkb
1025 *
1026 * @param wkb
1027 * geometry in Well-Known Binary (WKB) format
1028 * @param crs
1029 * spatial reference system of the geometry
1030 * @param si
1031 * surface interpolation
1032 * @return the MultiSurface defined by the WKB and the given CRS
1033 * @throws GeometryException
1034 * if the wkb is not known or invalid
1035 */
1036 public static MultiSurface createMultiSurface( byte[] wkb, CoordinateSystem crs, SurfaceInterpolation si )
1037 throws GeometryException {
1038 int wkbtype = -1;
1039 int numPoly = 0;
1040 int numRings = 0;
1041 int numPoints = 0;
1042 int offset = 0;
1043 double x = 0;
1044 double y = 0;
1045 Position[] externalBoundary = null;
1046 Position[][] internalBoundaries = null;
1047 byte byteorder = wkb[offset++];
1048
1049 if ( byteorder == 0 ) {
1050 wkbtype = ByteUtils.readBEInt( wkb, offset );
1051 } else {
1052 wkbtype = ByteUtils.readLEInt( wkb, offset );
1053 }
1054
1055 offset += 4;
1056
1057 // is the wkbmetry a multipolygon?
1058 if ( wkbtype != 6 ) {
1059 throw new GeometryException( "Invalid byte stream for MultiSurface" );
1060 }
1061
1062 // read number of polygons on the byte[]
1063 if ( byteorder == 0 ) {
1064 numPoly = ByteUtils.readBEInt( wkb, offset );
1065 } else {
1066 numPoly = ByteUtils.readLEInt( wkb, offset );
1067 }
1068
1069 offset += 4;
1070
1071 ArrayList<Surface> list = new ArrayList<Surface>( numPoly );
1072
1073 for ( int ip = 0; ip < numPoly; ip++ ) {
1074 byteorder = wkb[offset];
1075 offset++;
1076
1077 if ( byteorder == 0 ) {
1078 wkbtype = ByteUtils.readBEInt( wkb, offset );
1079 } else {
1080 wkbtype = ByteUtils.readLEInt( wkb, offset );
1081 }
1082
1083 offset += 4;
1084
1085 // is the geometry respresented by wkb a polygon?
1086 if ( wkbtype != 3 ) {
1087 throw new GeometryException( "invalid byte stream for Surface " + wkbtype );
1088 }
1089
1090 // read number of rings of the polygon
1091 if ( byteorder == 0 ) {
1092 numRings = ByteUtils.readBEInt( wkb, offset );
1093 } else {
1094 numRings = ByteUtils.readLEInt( wkb, offset );
1095 }
1096
1097 offset += 4;
1098
1099 // read number of points of the external ring
1100 if ( byteorder == 0 ) {
1101 numPoints = ByteUtils.readBEInt( wkb, offset );
1102 } else {
1103 numPoints = ByteUtils.readLEInt( wkb, offset );
1104 }
1105
1106 offset += 4;
1107
1108 // allocate memory for the external boundary
1109 externalBoundary = new Position[numPoints];
1110
1111 if ( byteorder == 0 ) {
1112 // read points of the external boundary from the byte[]
1113 for ( int i = 0; i < numPoints; i++ ) {
1114 x = ByteUtils.readBEDouble( wkb, offset );
1115 offset += 8;
1116 y = ByteUtils.readBEDouble( wkb, offset );
1117 offset += 8;
1118 externalBoundary[i] = new PositionImpl( x, y );
1119 }
1120 } else {
1121 // read points of the external boundary from the byte[]
1122 for ( int i = 0; i < numPoints; i++ ) {
1123 x = ByteUtils.readLEDouble( wkb, offset );
1124 offset += 8;
1125 y = ByteUtils.readLEDouble( wkb, offset );
1126 offset += 8;
1127 externalBoundary[i] = new PositionImpl( x, y );
1128 }
1129 }
1130
1131 // only if numRings is larger then one there internal rings
1132 if ( numRings > 1 ) {
1133 internalBoundaries = new Position[numRings - 1][];
1134 }
1135
1136 if ( byteorder == 0 ) {
1137 for ( int j = 1; j < numRings; j++ ) {
1138 // read number of points of the j-th internal ring
1139 numPoints = ByteUtils.readBEInt( wkb, offset );
1140 offset += 4;
1141
1142 // allocate memory for the j-th internal boundary
1143 internalBoundaries[j - 1] = new Position[numPoints];
1144
1145 // read points of the external boundary from the byte[]
1146 for ( int i = 0; i < numPoints; i++ ) {
1147 x = ByteUtils.readBEDouble( wkb, offset );
1148 offset += 8;
1149 y = ByteUtils.readBEDouble( wkb, offset );
1150 offset += 8;
1151 internalBoundaries[j - 1][i] = new PositionImpl( x, y );
1152 }
1153 }
1154 } else {
1155 for ( int j = 1; j < numRings; j++ ) {
1156 // read number of points of the j-th internal ring
1157 numPoints = ByteUtils.readLEInt( wkb, offset );
1158 offset += 4;
1159
1160 // allocate memory for the j-th internal boundary
1161 internalBoundaries[j - 1] = new Position[numPoints];
1162
1163 // read points of the external boundary from the byte[]
1164 for ( int i = 0; i < numPoints; i++ ) {
1165 x = ByteUtils.readLEDouble( wkb, offset );
1166 offset += 8;
1167 y = ByteUtils.readLEDouble( wkb, offset );
1168 offset += 8;
1169 internalBoundaries[j - 1][i] = new PositionImpl( x, y );
1170 }
1171 }
1172 }
1173
1174 SurfacePatch patch = createSurfacePatch( externalBoundary, internalBoundaries, si, crs );
1175
1176 list.add( createSurface( patch ) );
1177 }
1178
1179 MultiSurface multisurface = new MultiSurfaceImpl( crs );
1180
1181 for ( int i = 0; i < list.size(); i++ ) {
1182 multisurface.addSurface( list.get( i ) );
1183 }
1184
1185 return multisurface;
1186 }
1187
1188 }