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