001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/model/spatialschema/CurveImpl.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 org.deegree.framework.log.ILogger; 042 import org.deegree.framework.log.LoggerFactory; 043 import org.deegree.model.crs.CoordinateSystem; 044 045 /** 046 * default implementation of 047 * 048 * @see org.deegree.model.spatialschema.Curve 049 * 050 * @author Andreas Poth 051 * @version $Revision: 23675 $ $Date: 2010-04-19 11:20:41 +0200 (Mo, 19 Apr 2010) $ 052 */ 053 public class CurveImpl extends OrientableCurveImpl implements Curve, GenericCurve { 054 055 private static final ILogger LOG = LoggerFactory.getLogger( CurveImpl.class ); 056 057 /** Use serialVersionUID for interoperability. */ 058 private final static long serialVersionUID = 4060425075179654976L; 059 060 protected ArrayList<CurveSegment> segments = null; 061 062 /** 063 * initialize the curve by submitting a spatial reference system and an array of curve segments. the orientation of 064 * the curve is '+' 065 * 066 * @param segments 067 * array of CurveSegment 068 * @throws GeometryException 069 */ 070 protected CurveImpl( CurveSegment segments ) throws GeometryException { 071 this( '+', new CurveSegment[] { segments } ); 072 } 073 074 /** 075 * initialize the curve by submitting a spatial reference system and an array of curve segments. the orientation of 076 * the curve is '+' 077 * 078 * @param segments 079 * array of CurveSegment 080 * @throws GeometryException 081 */ 082 protected CurveImpl( CurveSegment[] segments ) throws GeometryException { 083 this( '+', segments ); 084 } 085 086 /** 087 * initialize the curve by submitting a spatial reference system and an array of curve segments. the orientation of 088 * the curve is '+' 089 * 090 * @param segments 091 * array of CurveSegment 092 * @param crs 093 * @throws GeometryException 094 */ 095 protected CurveImpl( CurveSegment[] segments, CoordinateSystem crs ) throws GeometryException { 096 this( '+', segments ); 097 this.crs = crs; 098 } 099 100 /** 101 * initialize the curve by submitting a spatial reference system, an array of curve segments and the orientation of 102 * the curve 103 * 104 * @param segments 105 * array of CurveSegment 106 * @param orientation 107 * of the curve 108 * @throws GeometryException 109 */ 110 protected CurveImpl( char orientation, CurveSegment[] segments ) throws GeometryException { 111 super( segments[0].getCoordinateSystem(), orientation ); 112 this.segments = new ArrayList<CurveSegment>( segments.length ); 113 for ( int i = 0; i < segments.length; i++ ) { 114 this.segments.add( segments[i] ); 115 // TODO check if segments touch 116 if ( i > 0 ) { 117 if ( !segments[i - 1].getEndPoint().equals( segments[i].getStartPoint() ) ) { 118 String msg = "Topological error in Curve: end-point of segment " + ( i - 1 ) + ": " 119 + WKTAdapter.export( segments[i - 1].getEndPoint() ) 120 + "doesn't match start-point of segment " + i + ": " 121 + WKTAdapter.export( segments[i].getStartPoint() ) + "!"; 122 throw new GeometryException( msg ); 123 } 124 } 125 } 126 setValid( false ); 127 } 128 129 /** 130 * calculates the envelope of the Curve 131 */ 132 private void calculateEnvelope() { 133 try { 134 Position[] positions = getAsLineString().getPositions(); 135 136 double[] min = positions[0].getAsArray().clone(); 137 double[] max = min.clone(); 138 139 for ( int i = 1; i < positions.length; i++ ) { 140 double[] pos = positions[i].getAsArray(); 141 142 for ( int j = 0; j < pos.length; j++ ) { 143 if ( pos[j] < min[j] ) { 144 min[j] = pos[j]; 145 } else if ( pos[j] > max[j] ) { 146 max[j] = pos[j]; 147 } 148 } 149 } 150 151 envelope = new EnvelopeImpl( new PositionImpl( min ), new PositionImpl( max ), this.crs ); 152 } catch ( GeometryException e ) { 153 // do nothing 154 } 155 } 156 157 /** 158 * calculates the boundary of the Curve 159 */ 160 private void calculateBoundary() { 161 boundary = new CurveBoundaryImpl( getCoordinateSystem(), getStartPoint().getPosition(), 162 getEndPoint().getPosition() ); 163 } 164 165 /** 166 * calculates the centroid of the Curve 167 */ 168 private void calculateCentroid() { 169 Position[] positions = null; 170 try { 171 positions = getAsLineString().getPositions(); 172 } catch ( GeometryException e ) { 173 LOG.logError( e.getMessage(), e ); 174 } 175 if ( positions != null ) { 176 177 double[] cen = new double[positions[0].getAsArray().length]; 178 179 for ( int i = 0; i < positions.length; i++ ) { 180 double[] pos = positions[i].getAsArray(); 181 182 for ( int j = 0; j < pos.length; j++ ) { 183 cen[j] += ( pos[j] / positions.length ); 184 } 185 } 186 187 centroid = new PointImpl( new PositionImpl( cen ), null ); 188 } 189 } 190 191 @Override 192 protected void calculateParam() { 193 calculateCentroid(); 194 calculateEnvelope(); 195 calculateBoundary(); 196 setValid( true ); 197 } 198 199 /** 200 * returns the boundary of the curve 201 */ 202 public CurveBoundary getCurveBoundary() { 203 return (CurveBoundary) boundary; 204 } 205 206 /** 207 * The operation "dimension" shall return the inherent dimension of this Geometry, which shall be less than or equal 208 * to the coordinate dimension. The dimension of a collection of geometric objects shall be the largest dimension of 209 * any of its pieces. Points are 0-dimensional, curves are 1-dimensional, surfaces are 2-dimensional, and solids are 210 * 3-dimensional. 211 */ 212 public int getDimension() { 213 return 1; 214 } 215 216 /** 217 * The operation "coordinateDimension" shall return the dimension of the coordinates that define this Geometry, 218 * which must be the same as the coordinate dimension of the coordinate reference system for this Geometry. 219 */ 220 public int getCoordinateDimension() { 221 return getStartPoint().getPosition().getCoordinateDimension(); 222 } 223 224 /** 225 * The Boolean valued operation "intersects" shall return TRUE if this Geometry intersects another Geometry. Within 226 * a Complex, the Primitives do not intersect one another. In general, topologically structured data uses shared 227 * geometric objects to capture intersection information. 228 * <p> 229 * </p> 230 * dummy implementation 231 */ 232 @Override 233 public boolean intersects( Geometry gmo ) { 234 boolean inter = false; 235 236 try { 237 for ( int i = 0; i < segments.size(); i++ ) { 238 CurveSegment cs = getCurveSegmentAt( i ); 239 240 if ( cs.intersects( gmo ) ) { 241 inter = true; 242 break; 243 } 244 } 245 } catch ( Exception e ) { 246 LOG.logError( e.getMessage(), e ); 247 } 248 249 return inter; 250 } 251 252 /** 253 * returns the length of the curve in units of the related spatial reference system 254 */ 255 public double getLength() { 256 double d = 0; 257 for ( int i = 0; i < segments.size(); i++ ) { 258 d += segments.get( i ).getLength(); 259 } 260 return d; 261 } 262 263 /** 264 * returns the number of segments building the curve 265 */ 266 public int getNumberOfCurveSegments() { 267 return segments.size(); 268 } 269 270 /** 271 * returns the first point of the curve. if the curve doesn't contain a segment or the first segment doesn't contain 272 * a point null will be returned 273 */ 274 public Point getStartPoint() { 275 if ( getNumberOfCurveSegments() == 0 ) { 276 return null; 277 } 278 279 Point gmp = null; 280 281 try { 282 gmp = getCurveSegmentAt( 0 ).getStartPoint(); 283 } catch ( GeometryException e ) { 284 LOG.logError( "", e ); 285 } 286 287 return gmp; 288 } 289 290 /** 291 * returns the last point of the curve.if the curve doesn't contain a segment or the last segment doesn't contain a 292 * point null will be returned 293 */ 294 public Point getEndPoint() { 295 if ( getNumberOfCurveSegments() == 0 ) { 296 return null; 297 } 298 299 Point gmp = null; 300 301 try { 302 gmp = getCurveSegmentAt( getNumberOfCurveSegments() - 1 ).getEndPoint(); 303 } catch ( GeometryException e ) { 304 LOG.logError( "", e ); 305 } 306 307 return gmp; 308 } 309 310 /** 311 * returns the curve as LineString. if there isn't a curve segment within the curve null will be returned 312 */ 313 public LineString getAsLineString() 314 throws GeometryException { 315 if ( getNumberOfCurveSegments() == 0 ) { 316 return null; 317 } 318 319 Position[] tmp = null; 320 321 // normal orientaton 322 if ( getOrientation() == '+' ) { 323 int cnt = 0; 324 325 for ( int i = 0; i < getNumberOfCurveSegments(); i++ ) { 326 cnt += getCurveSegmentAt( i ).getNumberOfPoints(); 327 } 328 329 tmp = new Position[cnt]; 330 331 int k = 0; 332 333 for ( int i = 0; i < getNumberOfCurveSegments(); i++ ) { 334 Position[] gmps = getCurveSegmentAt( i ).getPositions(); 335 336 for ( int j = 0; j < gmps.length; j++ ) { 337 tmp[k++] = gmps[j]; 338 } 339 } 340 } else { 341 // inverse orientation 342 int cnt = 0; 343 344 for ( int i = getNumberOfCurveSegments() - 1; i >= 0; i-- ) { 345 cnt += getCurveSegmentAt( i ).getNumberOfPoints(); 346 } 347 348 tmp = new Position[cnt]; 349 350 int k = 0; 351 352 for ( int i = getNumberOfCurveSegments() - 1; i >= 0; i-- ) { 353 Position[] gmps = getCurveSegmentAt( i ).getPositions(); 354 355 for ( int j = gmps.length - 1; j >= 0; j-- ) { 356 tmp[k++] = gmps[j]; 357 } 358 } 359 } 360 361 return new LineStringImpl( tmp, this.crs ); 362 } 363 364 /** 365 * returns the curve segment at the submitted index 366 * 367 * @param index 368 * index of the curve segment that should be returned 369 * @exception GeometryException 370 * a exception will be thrown if <tt>index</tt> is smaller than '0' or larger than 371 * <tt>getNumberOfCurveSegments()-1</tt> 372 */ 373 public CurveSegment getCurveSegmentAt( int index ) 374 throws GeometryException { 375 if ( ( index < 0 ) || ( index > getNumberOfCurveSegments() - 1 ) ) { 376 throw new GeometryException( "invalid index/position to get a segment!" ); 377 } 378 379 return segments.get( index ); 380 } 381 382 /** 383 * 384 * @return all segments of a Curve 385 * @throws GeometryException 386 */ 387 public CurveSegment[] getCurveSegments() 388 throws GeometryException { 389 return segments.toArray( new CurveSegment[segments.size()] ); 390 } 391 392 /** 393 * @return true if no segment is within the curve 394 */ 395 @Override 396 public boolean isEmpty() { 397 return ( getNumberOfCurveSegments() == 0 ); 398 } 399 400 /** 401 * translate each point of the curve with the values of the submitted double array. 402 */ 403 @Override 404 public void translate( double[] d ) { 405 try { 406 for ( int i = 0; i < segments.size(); i++ ) { 407 Position[] pos = getCurveSegmentAt( i ).getPositions(); 408 409 for ( int j = 0; j < pos.length; j++ ) { 410 pos[j].translate( d ); 411 } 412 } 413 } catch ( Exception e ) { 414 LOG.logError( e.getLocalizedMessage(), e ); 415 } 416 setValid( false ); 417 } 418 419 /** 420 * checks if this curve is completely equal to the submitted geometry 421 * 422 * @param other 423 * object to compare to 424 */ 425 @Override 426 public boolean equals( Object other ) { 427 if ( envelope == null ) { 428 calculateEnvelope(); 429 } 430 if ( !super.equals( other ) ) { 431 return false; 432 } 433 434 if ( !( other instanceof CurveImpl ) ) { 435 return false; 436 } 437 438 if ( !envelope.equals( ( (Geometry) other ).getEnvelope() ) ) { 439 return false; 440 } 441 442 if ( segments.size() != ( (Curve) other ).getNumberOfCurveSegments() ) { 443 return false; 444 } 445 446 try { 447 for ( int i = 0; i < segments.size(); i++ ) { 448 if ( !getCurveSegmentAt( i ).equals( ( (Curve) other ).getCurveSegmentAt( i ) ) ) { 449 return false; 450 } 451 } 452 } catch ( Exception e ) { 453 return false; 454 } 455 456 return true; 457 } 458 459 @Override 460 public Geometry union( Geometry other ) { 461 if ( other instanceof Curve ) { 462 Geometry result = null; 463 try { 464 Position[] p1 = getAsLineString().getPositions(); 465 Position[] p2 = ( (Curve) other ).getAsLineString().getPositions(); 466 List<Position> list = null; 467 if ( p1[0].equals( p2[0] ) ) { 468 list = new ArrayList<Position>( p1.length + p2.length - 1); 469 for ( int i = p1.length-1; i > 0; i-- ) { 470 list.add( p1[i] ); 471 } 472 for ( Position position : p2 ) { 473 list.add( position ); 474 } 475 } else if ( p1[0].equals( p2[p2.length - 1] ) ) { 476 list = new ArrayList<Position>( p1.length + p2.length - 1); 477 for ( Position position : p2 ) { 478 list.add( position ); 479 } 480 for ( int i = 1; i < p1.length; i++ ) { 481 list.add( p1[i] ); 482 } 483 } else if ( p1[p1.length - 1].equals( p2[0] ) ) { 484 list = new ArrayList<Position>( p1.length + p2.length - 1); 485 for ( Position position : p1 ) { 486 list.add( position ); 487 } 488 for ( int i = 1; i < p2.length; i++ ) { 489 list.add( p2[i] ); 490 } 491 } else if ( p1[p1.length - 1].equals( p2[p2.length - 1] ) ) { 492 list = new ArrayList<Position>( p1.length + p2.length - 1); 493 for ( Position position : p1 ) { 494 list.add( position ); 495 } 496 for ( int i = p2.length-2; i >= 0; i-- ) { 497 list.add( p2[i] ); 498 } 499 } else { 500 // curves not touching at start or end point 501 result = GeometryFactory.createMultiCurve( new Curve[] { this, (Curve) other } ); 502 } 503 if ( result == null ) { 504 // curves touching at start or end point 505 result = GeometryFactory.createCurve( list.toArray( new Position[list.size()] ), crs ); 506 } 507 } catch ( GeometryException e ) { 508 throw new RuntimeException( e ); 509 } 510 return result; 511 } else { 512 return super.union( other ); 513 } 514 } 515 516 @Override 517 public Object clone() { 518 CurveImpl c = null; 519 try { 520 CurveSegment[] cs = new CurveSegment[getNumberOfCurveSegments()]; 521 for ( int i = 0; i < segments.size(); i++ ) { 522 cs[i] = (CurveSegment) ( (CurveSegmentImpl) segments.get( i ) ).clone(); 523 } 524 c = new CurveImpl( getOrientation(), cs ); 525 c.crs = crs; 526 } catch ( Exception ex ) { 527 LOG.logError( "CurveImpl.clone: ", ex ); 528 } 529 return c; 530 } 531 532 @Override 533 public String toString() { 534 String ret = null; 535 ret = "segments = " + segments + "\n"; 536 ret += ( "envelope = " + envelope + "\n" ); 537 return ret; 538 } 539 }