001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_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: 19316 $, $Date: 2009-08-24 18:14:33 +0200 (Mo, 24. Aug 2009) $
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 while ( arc <= end ) {
466 arc += 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 }
478 return createCurve( list.toArray( new Position[list.size()] ), crs );
479 }
480
481 /**
482 * creates a Curve from a wkb.
483 *
484 * @param wkb
485 * byte stream that contains the wkb information
486 * @param crs
487 * CS_CoordinateSystem spatial reference system of the curve
488 * @return the Curve defined by the WKB and the given CRS
489 * @throws GeometryException
490 * if the wkb is not known or invalid
491 *
492 */
493 public static Curve createCurve( byte[] wkb, CoordinateSystem crs )
494 throws GeometryException {
495 int wkbType = -1;
496 int numPoints = -1;
497 Position[] points = null;
498 double x = 0;
499 double y = 0;
500
501 byte byteorder = wkb[0];
502
503 if ( byteorder == 0 ) {
504 wkbType = ByteUtils.readBEInt( wkb, 1 );
505 } else {
506 wkbType = ByteUtils.readLEInt( wkb, 1 );
507 }
508
509 // check if it's realy a linestrin/curve
510 if ( wkbType != 2 ) {
511 throw new GeometryException( "invalid byte stream for Curve" );
512 }
513
514 // read number of points
515 if ( byteorder == 0 ) {
516 numPoints = ByteUtils.readBEInt( wkb, 5 );
517 } else {
518 numPoints = ByteUtils.readLEInt( wkb, 5 );
519 }
520
521 int offset = 9;
522
523 points = new Position[numPoints];
524
525 // read the i-th point depending on the byteorde
526 if ( byteorder == 0 ) {
527 for ( int i = 0; i < numPoints; i++ ) {
528 x = ByteUtils.readBEDouble( wkb, offset );
529 offset += 8;
530 y = ByteUtils.readBEDouble( wkb, offset );
531 offset += 8;
532 points[i] = new PositionImpl( x, y );
533 }
534 } else {
535 for ( int i = 0; i < numPoints; i++ ) {
536 x = ByteUtils.readLEDouble( wkb, offset );
537 offset += 8;
538 y = ByteUtils.readLEDouble( wkb, offset );
539 offset += 8;
540 points[i] = new PositionImpl( x, y );
541 }
542 }
543
544 CurveSegment[] segment = new CurveSegment[1];
545
546 segment[0] = createCurveSegment( points, crs );
547
548 return createCurve( segment );
549 }
550
551 /**
552 * creates a surface in form of an ellipse. If <code>radiusX</code> == <code>radiusY</code> a circle will be created
553 *
554 * @param centerX
555 * @param centerY
556 * @param radiusX
557 * @param radiusY
558 * @param nSeg
559 * number of segments the ellipse will have
560 * @param crs
561 * @throws GeometryException
562 */
563 public static Surface createSurfaceAsEllipse( double centerX, double centerY, double radiusX, double radiusY,
564 int nSeg, CoordinateSystem crs )
565 throws GeometryException {
566 double x;
567 double _x = 0;
568 double _y = 0;
569 double y = 0;
570 double __x = 0;
571 double __y = 0;
572
573 List<Position> list = new ArrayList<Position>();
574 for ( int i = 0; i < nSeg; i++ ) {
575 x = radiusX * Math.sin( ( (double) i / (double) nSeg ) * ( Math.PI * 2.0 ) );
576 y = radiusY * Math.cos( ( (double) i / (double) nSeg ) * ( Math.PI * 2.0 ) );
577 if ( i > 0 ) {
578 list.add( GeometryFactory.createPosition( centerX + _x, centerY + -_y ) );
579 } else {
580 // Save the first point coordinate to link it with the last one
581 __x = x;
582 __y = y;
583 }
584 // Save the actual point coordinate to link it with the next one
585 _x = x;
586 _y = y;
587 }
588 list.add( GeometryFactory.createPosition( centerX + _x, centerY + -y ) );
589 list.add( GeometryFactory.createPosition( centerX + __x, centerY + -__y ) );
590 return createSurface( list.toArray( new Position[list.size()] ), null, new SurfaceInterpolationImpl(), crs );
591 }
592
593 /**
594 * creates a Surface composed of one SurfacePatch from array(s) of Position
595 *
596 * @param exteriorRing
597 * exterior ring of the patch
598 * @param interiorRings
599 * interior rings of the patch
600 * @param si
601 * SurfaceInterpolation
602 * @param crs
603 * CS_CoordinateSystem spatial reference system of the surface patch
604 * @return a Surface composed of one SurfacePatch from array(s) of Position
605 * @throws GeometryException
606 * if the implicite orientation is not '+' or '-', or the rings aren't closed
607 */
608 public static Surface createSurface( Position[] exteriorRing, Position[][] interiorRings, SurfaceInterpolation si,
609 CoordinateSystem crs )
610 throws GeometryException {
611 SurfacePatch sp = new PolygonImpl( si, exteriorRing, interiorRings, crs );
612 return createSurface( sp );
613 }
614
615 /**
616 * creates a Surface from an array of SurfacePatch.
617 *
618 * @param patch
619 * patches that build the surface
620 * @return a Surface from an array of SurfacePatch.
621 * @throws GeometryException
622 * if implicite the orientation is not '+' or '-'
623 */
624 public static Surface createSurface( SurfacePatch patch )
625 throws GeometryException {
626 return new SurfaceImpl( patch );
627 }
628
629 /**
630 * creates a Surface from an array of SurfacePatch.
631 *
632 * @param patches
633 * patches that build the surface
634 *
635 * @return a Surface from an array of SurfacePatch.
636 * @throws GeometryException
637 * if implicite the orientation is not '+' or '-'
638 */
639 public static Surface createSurface( SurfacePatch[] patches )
640 throws GeometryException {
641 return new SurfaceImpl( patches );
642 }
643
644 /**
645 * creates a Surface from an array of SurfacePatch.
646 *
647 * @param patches
648 * patches that build the surface
649 * @param crs
650 *
651 * @return a Surface from an array of SurfacePatch.
652 * @throws GeometryException
653 * if implicite the orientation is not '+' or '-'
654 */
655 public static Surface createSurface( SurfacePatch[] patches, CoordinateSystem crs )
656 throws GeometryException {
657 return new SurfaceImpl( patches, crs );
658 }
659
660 /**
661 * creates a Surface from a wkb.
662 *
663 * @param wkb
664 * byte stream that contains the wkb information
665 * @param crs
666 * CS_CoordinateSystem spatial reference system of the curve
667 * @param si
668 * SurfaceInterpolation
669 * @return a Surface from a wkb.
670 * @throws GeometryException
671 * if the implicite orientation is not '+' or '-' or the wkb is not known or invalid
672 */
673 public static Surface createSurface( byte[] wkb, CoordinateSystem crs, SurfaceInterpolation si )
674 throws GeometryException {
675 int wkbtype = -1;
676 int numRings = 0;
677 int numPoints = 0;
678 int offset = 0;
679 double x = 0;
680 double y = 0;
681
682 Position[] externalBoundary = null;
683 Position[][] internalBoundaries = null;
684
685 byte byteorder = wkb[offset++];
686
687 if ( byteorder == 0 ) {
688 wkbtype = ByteUtils.readBEInt( wkb, offset );
689 } else {
690 wkbtype = ByteUtils.readLEInt( wkb, offset );
691 }
692
693 offset += 4;
694
695 if ( wkbtype == 6 ) {
696 return null;
697 }
698
699 // is the geometry respresented by wkb a polygon?
700 if ( wkbtype != 3 ) {
701 throw new GeometryException( "invalid byte stream for Surface " + wkbtype );
702 }
703
704 // read number of rings of the polygon
705 if ( byteorder == 0 ) {
706 numRings = ByteUtils.readBEInt( wkb, offset );
707 } else {
708 numRings = ByteUtils.readLEInt( wkb, offset );
709 }
710
711 offset += 4;
712
713 // read number of points of the external ring
714 if ( byteorder == 0 ) {
715 numPoints = ByteUtils.readBEInt( wkb, offset );
716 } else {
717 numPoints = ByteUtils.readLEInt( wkb, offset );
718 }
719
720 offset += 4;
721
722 // allocate memory for the external boundary
723 externalBoundary = new Position[numPoints];
724
725 if ( byteorder == 0 ) {
726 // read points of the external boundary from the byte[]
727 for ( int i = 0; i < numPoints; i++ ) {
728 x = ByteUtils.readBEDouble( wkb, offset );
729 offset += 8;
730 y = ByteUtils.readBEDouble( wkb, offset );
731 offset += 8;
732 externalBoundary[i] = new PositionImpl( x, y );
733 }
734 } else {
735 // read points of the external boundary from the byte[]
736 for ( int i = 0; i < numPoints; i++ ) {
737 x = ByteUtils.readLEDouble( wkb, offset );
738 offset += 8;
739 y = ByteUtils.readLEDouble( wkb, offset );
740 offset += 8;
741 externalBoundary[i] = new PositionImpl( x, y );
742 }
743 }
744
745 // only if numRings is larger then one there internal rings
746 if ( numRings > 1 ) {
747 internalBoundaries = new Position[numRings - 1][];
748 }
749
750 if ( byteorder == 0 ) {
751 for ( int j = 1; j < numRings; j++ ) {
752 // read number of points of the j-th internal ring
753 numPoints = ByteUtils.readBEInt( wkb, offset );
754 offset += 4;
755
756 // allocate memory for the j-th internal boundary
757 internalBoundaries[j - 1] = new Position[numPoints];
758
759 // read points of the external boundary from the byte[]
760 for ( int i = 0; i < numPoints; i++ ) {
761 x = ByteUtils.readBEDouble( wkb, offset );
762 offset += 8;
763 y = ByteUtils.readBEDouble( wkb, offset );
764 offset += 8;
765 internalBoundaries[j - 1][i] = new PositionImpl( x, y );
766 }
767 }
768 } else {
769 for ( int j = 1; j < numRings; j++ ) {
770 // read number of points of the j-th internal ring
771 numPoints = ByteUtils.readLEInt( wkb, offset );
772 offset += 4;
773
774 // allocate memory for the j-th internal boundary
775 internalBoundaries[j - 1] = new Position[numPoints];
776
777 // read points of the external boundary from the byte[]
778 for ( int i = 0; i < numPoints; i++ ) {
779 x = ByteUtils.readLEDouble( wkb, offset );
780 offset += 8;
781 y = ByteUtils.readLEDouble( wkb, offset );
782 offset += 8;
783 internalBoundaries[j - 1][i] = new PositionImpl( x, y );
784 }
785 }
786 }
787
788 SurfacePatch patch = createSurfacePatch( externalBoundary, internalBoundaries, si, crs );
789
790 return createSurface( patch );
791 }
792
793 /**
794 * Creates a <tt>Surface</tt> from a <tt>Envelope</tt>.
795 * <p>
796 *
797 * @param bbox
798 * envelope to be converted
799 * @param crs
800 * spatial reference system of the surface
801 * @return corresponding surface
802 *
803 * @throws GeometryException
804 * if the implicite orientation is not '+' or '-'
805 */
806 public static Surface createSurface( Envelope bbox, CoordinateSystem crs )
807 throws GeometryException {
808
809 Position min = bbox.getMin();
810 Position max = bbox.getMax();
811 Position[] exteriorRing = null;
812 if ( min.getCoordinateDimension() == 2 ) {
813 exteriorRing = new Position[] { min, new PositionImpl( min.getX(), max.getY() ), max,
814 new PositionImpl( max.getX(), min.getY() ), min };
815 } else {
816 exteriorRing = new Position[] {
817 min,
818 new PositionImpl( min.getX(), max.getY(),
819 min.getZ() + ( ( max.getZ() - min.getZ() ) * 0.5 ) ),
820 max,
821 new PositionImpl( max.getX(), min.getY(),
822 min.getZ() + ( ( max.getZ() - min.getZ() ) * 0.5 ) ), min };
823 }
824
825 return createSurface( exteriorRing, null, new SurfaceInterpolationImpl(), crs );
826 }
827
828 /**
829 * Creates a <tt>GM_Surface</tt> from the ordinates of the exterior ring and the the interior rings
830 * <p>
831 *
832 * @param exterior
833 * ring
834 * @param interior
835 * ring
836 * @param dim
837 * of the surface
838 * @param crs
839 * spatial reference system of the surface
840 * @return corresponding surface
841 * @throws GeometryException
842 * if the implicite orientation is not '+' or '-'
843 *
844 */
845 public static Surface createSurface( double[] exterior, double[][] interior, int dim, CoordinateSystem crs )
846 throws GeometryException {
847
848 // get exterior ring
849 Position[] ext = new Position[exterior.length / dim];
850 int i = 0;
851 int k = 0;
852 while ( i < exterior.length - 1 ) {
853 double[] o = new double[dim];
854 for ( int j = 0; j < dim; j++ ) {
855 o[j] = exterior[i++];
856 }
857 ext[k++] = GeometryFactory.createPosition( o );
858 }
859
860 // get interior rings if available
861 Position[][] in = null;
862 if ( interior != null && interior.length > 0 ) {
863 in = new Position[interior.length][];
864 for ( int j = 0; j < in.length; j++ ) {
865 in[j] = new Position[interior[j].length / dim];
866 i = 0;
867 while ( i < interior[j].length ) {
868 double[] o = new double[dim];
869 for ( int z = 0; z < dim; z++ ) {
870 o[z] = interior[j][i++];
871 }
872 in[j][i / dim - 1] = GeometryFactory.createPosition( o );
873 }
874 }
875 }
876
877 // default - linear - interpolation
878 SurfaceInterpolation si = new SurfaceInterpolationImpl();
879 return GeometryFactory.createSurface( ext, in, si, crs );
880 }
881
882 /**
883 * Creates a {@link MultiGeometry} from an array of {@link Geometry} objects.
884 *
885 * @param members
886 * member geometries
887 * @param crs
888 * coordinate system
889 * @return {@link MultiGeometry} that contains all given members
890 */
891 public static MultiGeometry createMultiGeometry( Geometry[] members, CoordinateSystem crs ) {
892 return new MultiGeometryImpl( members, crs );
893 }
894
895 /**
896 * Creates a {@link MultiGeometry} from an array of {@link Geometry} objects.
897 *
898 * @param wkb
899 * wkb information
900 * @param crs
901 * coordinate system
902 * @return {@link MultiGeometry} that contains all given members
903 * @throws GeometryException
904 * if the wkb is not known or invalid
905 */
906 public static MultiGeometry createMultiGeometry( byte[] wkb, CoordinateSystem crs )
907 throws GeometryException {
908 throw new GeometryException( "Generation of MultiGeometry instances from WKB is not implemented yet." );
909 }
910
911 /**
912 * creates a MultiPoint from an array of Point.
913 *
914 * @param points
915 * array of Points
916 * @return a MultiPoint from an array of Point.
917 *
918 */
919 public static MultiPoint createMultiPoint( Point[] points ) {
920 return new MultiPointImpl( points );
921 }
922
923 /**
924 * creates a MultiPoint from an array of Point.
925 *
926 * @param points
927 * array of Points
928 * @param crs
929 * @return a MultiPoint from an array of Point.
930 */
931 public static MultiPoint createMultiPoint( Point[] points, CoordinateSystem crs ) {
932 return new MultiPointImpl( points, crs );
933 }
934
935 /**
936 * creates a MultiPoint from a wkb.
937 *
938 * @param wkb
939 * byte stream that contains the wkb information
940 * @param crs
941 * CS_CoordinateSystem spatial reference system of the curve
942 * @return the MultiPoint defined by the WKB and the given CRS
943 * @throws GeometryException
944 * if the wkb is not known or invalid
945 *
946 */
947 public static MultiPoint createMultiPoint( byte[] wkb, CoordinateSystem crs )
948 throws GeometryException {
949 Point[] points = null;
950 int wkbType = -1;
951 int numPoints = -1;
952 double x = 0;
953 double y = 0;
954 byte byteorder = wkb[0];
955
956 // read wkbType
957 if ( byteorder == 0 ) {
958 wkbType = ByteUtils.readBEInt( wkb, 1 );
959 } else {
960 wkbType = ByteUtils.readLEInt( wkb, 1 );
961 }
962
963 // if the geometry isn't a multipoint throw exception
964 if ( wkbType != 4 ) {
965 throw new GeometryException( "Invalid byte stream for MultiPoint" );
966 }
967
968 // read number of points
969 if ( byteorder == 0 ) {
970 numPoints = ByteUtils.readBEInt( wkb, 5 );
971 } else {
972 numPoints = ByteUtils.readLEInt( wkb, 5 );
973 }
974
975 points = new Point[numPoints];
976
977 int offset = 9;
978
979 Object[] o = new Object[3];
980 o[2] = crs;
981
982 // read all points
983 for ( int i = 0; i < numPoints; i++ ) {
984 // byteorder of the i-th point
985 byteorder = wkb[offset];
986
987 // wkbType of the i-th geometry
988 if ( byteorder == 0 ) {
989 wkbType = ByteUtils.readBEInt( wkb, offset + 1 );
990 } else {
991 wkbType = ByteUtils.readLEInt( wkb, offset + 1 );
992 }
993
994 // if the geometry isn't a point throw exception
995 if ( wkbType != 1 ) {
996 throw new GeometryException( "Invalid byte stream for Point as " + "part of a multi point" );
997 }
998
999 // read the i-th point depending on the byteorde
1000 if ( byteorder == 0 ) {
1001 x = ByteUtils.readBEDouble( wkb, offset + 5 );
1002 y = ByteUtils.readBEDouble( wkb, offset + 13 );
1003 } else {
1004 x = ByteUtils.readLEDouble( wkb, offset + 5 );
1005 y = ByteUtils.readLEDouble( wkb, offset + 13 );
1006 }
1007
1008 offset += 21;
1009
1010 points[i] = new PointImpl( x, y, crs );
1011 }
1012
1013 return createMultiPoint( points );
1014 }
1015
1016 /**
1017 * creates a MultiCurve from an array of Curves.
1018 *
1019 * @param curves
1020 * @return a MultiCurve from an array of Curves.
1021 */
1022 public static MultiCurve createMultiCurve( Curve[] curves ) {
1023 return new MultiCurveImpl( curves );
1024 }
1025
1026 /**
1027 * creates a MultiCurve from an array of Curves.
1028 *
1029 * @param curves
1030 * @param crs
1031 * @return a MultiCurve from an array of Curves.
1032 */
1033 public static MultiCurve createMultiCurve( Curve[] curves, CoordinateSystem crs ) {
1034 return new MultiCurveImpl( curves, crs );
1035 }
1036
1037 /**
1038 * creates a MultiCurve from a wkb.
1039 *
1040 * @param wkb
1041 * byte stream that contains the wkb information
1042 * @param crs
1043 * CS_CoordinateSystem spatial reference system of the curve
1044 * @return the MultiCurve defined by the WKB and the given CRS
1045 * @throws GeometryException
1046 * if the wkb is not known or invalid
1047 */
1048 public static MultiCurve createMultiCurve( byte[] wkb, CoordinateSystem crs )
1049 throws GeometryException {
1050 int wkbType = -1;
1051 int numPoints = -1;
1052 int numParts = -1;
1053 double x = 0;
1054 double y = 0;
1055 Position[][] points = null;
1056 int offset = 0;
1057 byte byteorder = wkb[offset++];
1058
1059 if ( byteorder == 0 ) {
1060 wkbType = ByteUtils.readBEInt( wkb, offset );
1061 } else {
1062 wkbType = ByteUtils.readLEInt( wkb, offset );
1063 }
1064
1065 offset += 4;
1066
1067 // check if it's realy a linestring
1068 if ( wkbType != 5 ) {
1069 throw new GeometryException( "Invalid byte stream for MultiCurve" );
1070 }
1071
1072 // read number of linestrings
1073 if ( byteorder == 0 ) {
1074 numParts = ByteUtils.readBEInt( wkb, offset );
1075 } else {
1076 numParts = ByteUtils.readLEInt( wkb, offset );
1077 }
1078
1079 offset += 4;
1080
1081 points = new Position[numParts][];
1082
1083 // for every linestring
1084 for ( int j = 0; j < numParts; j++ ) {
1085 byteorder = wkb[offset++];
1086
1087 if ( byteorder == 0 ) {
1088 wkbType = ByteUtils.readBEInt( wkb, offset );
1089 } else {
1090 wkbType = ByteUtils.readLEInt( wkb, offset );
1091 }
1092
1093 offset += 4;
1094
1095 // check if it's realy a linestring
1096 if ( wkbType != 2 ) {
1097 throw new GeometryException( "Invalid byte stream for Curve as " + " part of a MultiCurve." );
1098 }
1099
1100 // read number of points
1101 if ( byteorder == 0 ) {
1102 numPoints = ByteUtils.readBEInt( wkb, offset );
1103 } else {
1104 numPoints = ByteUtils.readLEInt( wkb, offset );
1105 }
1106
1107 offset += 4;
1108
1109 points[j] = new Position[numPoints];
1110
1111 // read the i-th point depending on the byteorde
1112 if ( byteorder == 0 ) {
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 points[j][i] = new PositionImpl( x, y );
1119 }
1120 } else {
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 points[j][i] = new PositionImpl( x, y );
1127 }
1128 }
1129 }
1130
1131 CurveSegment[] segment = new CurveSegment[1];
1132 Curve[] curves = new Curve[numParts];
1133
1134 for ( int i = 0; i < numParts; i++ ) {
1135 segment[0] = createCurveSegment( points[i], crs );
1136 curves[i] = createCurve( segment );
1137 }
1138
1139 return createMultiCurve( curves );
1140 }
1141
1142 /**
1143 * creates a MultiSurface from an array of surfaces
1144 *
1145 * @param surfaces
1146 * @return a MultiSurface from an array of surfaces
1147 */
1148 public static MultiSurface createMultiSurface( Surface[] surfaces ) {
1149 return new MultiSurfaceImpl( surfaces );
1150 }
1151
1152 /**
1153 * creates a MultiSurface from an array of surfaces
1154 *
1155 * @param surfaces
1156 * @param crs
1157 * @return a MultiSurface from an array of surfaces
1158 */
1159 public static MultiSurface createMultiSurface( Surface[] surfaces, CoordinateSystem crs ) {
1160 return new MultiSurfaceImpl( surfaces, crs );
1161 }
1162
1163 /**
1164 * creates a MultiSurface from a wkb
1165 *
1166 * @param wkb
1167 * geometry in Well-Known Binary (WKB) format
1168 * @param crs
1169 * spatial reference system of the geometry
1170 * @param si
1171 * surface interpolation
1172 * @return the MultiSurface defined by the WKB and the given CRS
1173 * @throws GeometryException
1174 * if the wkb is not known or invalid
1175 */
1176 public static MultiSurface createMultiSurface( byte[] wkb, CoordinateSystem crs, SurfaceInterpolation si )
1177 throws GeometryException {
1178 int wkbtype = -1;
1179 int numPoly = 0;
1180 int numRings = 0;
1181 int numPoints = 0;
1182 int offset = 0;
1183 double x = 0;
1184 double y = 0;
1185 Position[] externalBoundary = null;
1186 Position[][] internalBoundaries = null;
1187 byte byteorder = wkb[offset++];
1188
1189 if ( byteorder == 0 ) {
1190 wkbtype = ByteUtils.readBEInt( wkb, offset );
1191 } else {
1192 wkbtype = ByteUtils.readLEInt( wkb, offset );
1193 }
1194
1195 offset += 4;
1196
1197 // is the wkbmetry a multipolygon?
1198 if ( wkbtype != 6 ) {
1199 throw new GeometryException( "Invalid byte stream for MultiSurface" );
1200 }
1201
1202 // read number of polygons on the byte[]
1203 if ( byteorder == 0 ) {
1204 numPoly = ByteUtils.readBEInt( wkb, offset );
1205 } else {
1206 numPoly = ByteUtils.readLEInt( wkb, offset );
1207 }
1208
1209 offset += 4;
1210
1211 ArrayList<Surface> list = new ArrayList<Surface>( numPoly );
1212
1213 for ( int ip = 0; ip < numPoly; ip++ ) {
1214 byteorder = wkb[offset];
1215 offset++;
1216
1217 if ( byteorder == 0 ) {
1218 wkbtype = ByteUtils.readBEInt( wkb, offset );
1219 } else {
1220 wkbtype = ByteUtils.readLEInt( wkb, offset );
1221 }
1222
1223 offset += 4;
1224
1225 // is the geometry respresented by wkb a polygon?
1226 if ( wkbtype != 3 ) {
1227 throw new GeometryException( "invalid byte stream for Surface " + wkbtype );
1228 }
1229
1230 // read number of rings of the polygon
1231 if ( byteorder == 0 ) {
1232 numRings = ByteUtils.readBEInt( wkb, offset );
1233 } else {
1234 numRings = ByteUtils.readLEInt( wkb, offset );
1235 }
1236
1237 offset += 4;
1238
1239 // read number of points of the external ring
1240 if ( byteorder == 0 ) {
1241 numPoints = ByteUtils.readBEInt( wkb, offset );
1242 } else {
1243 numPoints = ByteUtils.readLEInt( wkb, offset );
1244 }
1245
1246 offset += 4;
1247
1248 // allocate memory for the external boundary
1249 externalBoundary = new Position[numPoints];
1250
1251 if ( byteorder == 0 ) {
1252 // read points of the external boundary from the byte[]
1253 for ( int i = 0; i < numPoints; i++ ) {
1254 x = ByteUtils.readBEDouble( wkb, offset );
1255 offset += 8;
1256 y = ByteUtils.readBEDouble( wkb, offset );
1257 offset += 8;
1258 externalBoundary[i] = new PositionImpl( x, y );
1259 }
1260 } else {
1261 // read points of the external boundary from the byte[]
1262 for ( int i = 0; i < numPoints; i++ ) {
1263 x = ByteUtils.readLEDouble( wkb, offset );
1264 offset += 8;
1265 y = ByteUtils.readLEDouble( wkb, offset );
1266 offset += 8;
1267 externalBoundary[i] = new PositionImpl( x, y );
1268 }
1269 }
1270
1271 // only if numRings is larger then one there internal rings
1272 if ( numRings > 1 ) {
1273 internalBoundaries = new Position[numRings - 1][];
1274 }
1275
1276 if ( byteorder == 0 ) {
1277 for ( int j = 1; j < numRings; j++ ) {
1278 // read number of points of the j-th internal ring
1279 numPoints = ByteUtils.readBEInt( wkb, offset );
1280 offset += 4;
1281
1282 // allocate memory for the j-th internal boundary
1283 internalBoundaries[j - 1] = new Position[numPoints];
1284
1285 // read points of the external boundary from the byte[]
1286 for ( int i = 0; i < numPoints; i++ ) {
1287 x = ByteUtils.readBEDouble( wkb, offset );
1288 offset += 8;
1289 y = ByteUtils.readBEDouble( wkb, offset );
1290 offset += 8;
1291 internalBoundaries[j - 1][i] = new PositionImpl( x, y );
1292 }
1293 }
1294 } else {
1295 for ( int j = 1; j < numRings; j++ ) {
1296 // read number of points of the j-th internal ring
1297 numPoints = ByteUtils.readLEInt( wkb, offset );
1298 offset += 4;
1299
1300 // allocate memory for the j-th internal boundary
1301 internalBoundaries[j - 1] = new Position[numPoints];
1302
1303 // read points of the external boundary from the byte[]
1304 for ( int i = 0; i < numPoints; i++ ) {
1305 x = ByteUtils.readLEDouble( wkb, offset );
1306 offset += 8;
1307 y = ByteUtils.readLEDouble( wkb, offset );
1308 offset += 8;
1309 internalBoundaries[j - 1][i] = new PositionImpl( x, y );
1310 }
1311 }
1312 }
1313
1314 SurfacePatch patch = createSurfacePatch( externalBoundary, internalBoundaries, si, crs );
1315
1316 list.add( createSurface( patch ) );
1317 }
1318
1319 MultiSurface multisurface = new MultiSurfaceImpl( crs );
1320
1321 for ( int i = 0; i < list.size(); i++ ) {
1322 multisurface.addSurface( list.get( i ) );
1323 }
1324
1325 return multisurface;
1326 }
1327
1328 }