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