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 }