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