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