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