001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/model/spatialschema/RingImpl.java $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 004 This file is part of deegree. 005 Copyright (C) 2001-2008 by: 006 EXSE, Department of Geography, University of Bonn 007 http://www.giub.uni-bonn.de/deegree/ 008 lat/lon GmbH 009 http://www.lat-lon.de 010 011 This library is free software; you can redistribute it and/or 012 modify it under the terms of the GNU Lesser General Public 013 License as published by the Free Software Foundation; either 014 version 2.1 of the License, or (at your option) any later version. 015 016 This library is distributed in the hope that it will be useful, 017 but WITHOUT ANY WARRANTY; without even the implied warranty of 018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 019 Lesser General Public License for more details. 020 021 You should have received a copy of the GNU Lesser General Public 022 License along with this library; if not, write to the Free Software 023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 024 025 Contact: 026 027 Andreas Poth 028 lat/lon GmbH 029 Aennchenstr. 19 030 53177 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.io.Serializable; 047 import java.util.Arrays; 048 049 import org.deegree.framework.log.ILogger; 050 import org.deegree.framework.log.LoggerFactory; 051 import org.deegree.model.crs.CoordinateSystem; 052 053 /** 054 * default implementation of the Ring interface of the 055 * 056 * 057 * @version $Revision: 9343 $ 058 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a> 059 * @author last edited by: $Author: apoth $ 060 * 061 * @version 1.0. $Revision: 9343 $, $Date: 2007-12-27 14:30:32 +0100 (Do, 27 Dez 2007) $ 062 * 063 * @since 2.0 064 */ 065 public class RingImpl extends OrientableCurveImpl implements Ring, Serializable { 066 /** Use serialVersionUID for interoperability. */ 067 private final static long serialVersionUID = 9157144642050604928L; 068 069 private static final ILogger LOG = LoggerFactory.getLogger( RingImpl.class ); 070 071 private CurveSegment[] segments; 072 073 private SurfacePatch sp = null; 074 075 private int nop = 0; 076 077 private Position[] allPos; 078 079 /** 080 * Constructor, with an array and CoordinateSystem 081 * 082 * @param points 083 * @param crs 084 * @throws GeometryException 085 */ 086 public RingImpl( Position[] points, CoordinateSystem crs ) throws GeometryException { 087 super( crs ); 088 Position[][] tmp = new Position[1][]; 089 tmp[0] = points; 090 setPositions( tmp ); 091 } 092 093 /** 094 * Constructor, with an array, CoordinateSystem and Orientation 095 * 096 * @param points 097 * @param crs 098 * @param orientation 099 * @throws GeometryException 100 */ 101 public RingImpl( Position[] points, CoordinateSystem crs, char orientation ) throws GeometryException { 102 super( crs, orientation ); 103 Position[][] tmp = new Position[1][]; 104 tmp[0] = points; 105 setPositions( tmp ); 106 } 107 108 /** 109 * Constructor, with curve segments, CoordinateSystem and Orientation 110 * 111 * @param segments 112 * @param crs 113 * @param orientation 114 * @throws GeometryException 115 */ 116 public RingImpl( CurveSegment[] segments, CoordinateSystem crs, char orientation ) throws GeometryException { 117 super( crs, orientation ); 118 Position[][] tmp = new Position[segments.length][]; 119 for ( int i = 0; i < segments.length; i++ ) { 120 tmp[i] = segments[i].getPositions(); 121 } 122 setPositions( tmp ); 123 } 124 125 /** 126 * calculates the envelope 127 */ 128 private void calculateEnvelope() { 129 double[] min = allPos[0].getAsArray().clone(); 130 double[] max = min.clone(); 131 132 for ( int k = 1; k < allPos.length; k++ ) { 133 double[] pos = allPos[k].getAsArray(); 134 135 for ( int j = 0; j < pos.length; j++ ) { 136 if ( pos[j] < min[j] ) { 137 min[j] = pos[j]; 138 } else if ( pos[j] > max[j] ) { 139 max[j] = pos[j]; 140 } 141 } 142 } 143 144 envelope = new EnvelopeImpl( new PositionImpl( min ), new PositionImpl( max ), this.crs ); 145 } 146 147 /** 148 * Ring must be closed, so isCycle returns TRUE. 149 */ 150 public boolean isCycle() { 151 return true; 152 } 153 154 /** 155 * Ring is a PrimitiveBoundary, so isSimple returns TRUE. 156 */ 157 public boolean isSimple() { 158 return true; 159 } 160 161 /** 162 * The operation "dimension" shall return the inherent dimension of this Geometry, which shall 163 * be less than or equal to the coordinate dimension. The dimension of a collection of geometric 164 * objects shall be the largest dimension of any of its pieces. Points are 0-dimensional, curves 165 * are 1-dimensional, surfaces are 2-dimensional, and solids are 3-dimensional. 166 */ 167 public int getDimension() { 168 return 1; 169 } 170 171 /** 172 * The operation "coordinateDimension" shall return the dimension of the coordinates that define 173 * this Geometry, which must be the same as the coordinate dimension of the coordinate reference 174 * system for this Geometry. 175 */ 176 public int getCoordinateDimension() { 177 return getPositions()[0].getCoordinateDimension(); 178 } 179 180 /** 181 * gets the Ring as a Array of positions. 182 */ 183 public Position[] getPositions() { 184 if ( getOrientation() == '-' ) { 185 Position[] temp = new Position[allPos.length]; 186 187 for ( int i = 0; i < allPos.length; i++ ) { 188 temp[i] = allPos[( allPos.length - 1 ) - i]; 189 } 190 191 return temp; 192 } 193 return allPos; 194 } 195 196 /** 197 * sets the Ring as a ArrayList of points 198 */ 199 protected void setPositions( Position[][] positions ) 200 throws GeometryException { 201 202 segments = new CurveSegment[positions.length]; 203 for ( int i = 0; i < positions.length; i++ ) { 204 segments[i] = new LineStringImpl( positions[i], getCoordinateSystem() ); 205 } 206 207 nop = 0; 208 for ( int i = 0; i < positions.length; i++ ) { 209 nop += positions[i].length; 210 } 211 allPos = new Position[nop]; 212 int k = 0; 213 for ( int i = 0; i < positions.length; i++ ) { 214 for ( int j = 0; j < positions[i].length; j++ ) { 215 allPos[k++] = positions[i][j]; 216 } 217 } 218 219 // checks if the ring has more than 3 elements [!(points.length > 3)] 220 if ( nop < 3 ) { 221 throw new GeometryException( "invalid length of a Ring!" ); 222 } 223 224 // checks if the startpoint = endpoint of the ring 225 if ( !allPos[0].equals( allPos[allPos.length - 1] ) ) { 226 throw new GeometryException( "StartPoint of ring isn't equal to EndPoint!" ); 227 } 228 229 setValid( false ); 230 } 231 232 /** 233 * returns the Ring as one CurveSegment 234 */ 235 public CurveSegment getAsCurveSegment() 236 throws GeometryException { 237 return new LineStringImpl( allPos, getCoordinateSystem() ); 238 } 239 240 /** 241 * returns the Ring as a CurveSegments 242 * 243 * @return curve segments 244 */ 245 public CurveSegment[] getCurveSegments() { 246 return segments; 247 } 248 249 /** 250 * returns the CurveBoundary of the Ring. For a CurveBoundary is defines as the first and the 251 * last point of a Curve the CurveBoundary of a Ring contains two indentical point (because a 252 * Ring is closed) 253 */ 254 public CurveBoundary getCurveBoundary() { 255 return (CurveBoundary) boundary; 256 } 257 258 /** 259 * checks if this curve segment is completly equal to the submitted geometry 260 * 261 * @param other 262 * object to compare to 263 */ 264 public boolean equals( Object other ) { 265 if ( !super.equals( other ) || !( other instanceof RingImpl ) ) { 266 return false; 267 } 268 269 if ( !envelope.equals( ( (Geometry) other ).getEnvelope() ) ) { 270 return false; 271 } 272 273 Position[] p2 = ( (Ring) other ).getPositions(); 274 275 if ( !Arrays.equals( allPos, p2 ) ) { 276 return false; 277 } 278 279 return true; 280 } 281 282 /** 283 * returns a shallow copy of the geometry 284 */ 285 public Object clone() { 286 Ring r = null; 287 try { 288 CurveSegment[] segments = getCurveSegments(); 289 for ( int i = 0; i < segments.length; i++ ) { 290 segments[i] = new LineStringImpl( segments[i].getPositions(), getCoordinateSystem() ); 291 } 292 r = new RingImpl( segments, getCoordinateSystem(), getOrientation() ); 293 } catch ( Exception ex ) { 294 LOG.logError( ex.getMessage(), ex ); 295 } 296 297 return r; 298 } 299 300 /** 301 * The Boolean valued operation "intersects" shall return TRUE if this Geometry intersects 302 * another Geometry. Within a Complex, the Primitives do not intersect one another. In general, 303 * topologically structured data uses shared geometric objects to capture intersection 304 * information. 305 * 306 * @param gmo 307 * @return true if intersects 308 */ 309 public boolean intersects( Geometry gmo ) { 310 boolean inter = false; 311 312 try { 313 // TODO 314 // use segments 315 CurveSegment sp = new LineStringImpl( allPos, crs ); 316 317 if ( gmo instanceof Point ) { 318 double tolerance = ( (Point) gmo ).getTolerance(); 319 inter = LinearIntersects.intersects( ( (Point) gmo ).getPosition(), sp, tolerance ); 320 } else if ( gmo instanceof Curve ) { 321 Curve curve = new CurveImpl( new CurveSegment[] { sp } ); 322 inter = LinearIntersects.intersects( (Curve) gmo, curve ); 323 } else if ( gmo instanceof Surface ) { 324 Curve curve = new CurveImpl( new CurveSegment[] { sp } ); 325 inter = LinearIntersects.intersects( curve, (Surface) gmo ); 326 } else if ( gmo instanceof MultiPrimitive ) { 327 inter = intersectsAggregate( (MultiPrimitive) gmo ); 328 } 329 } catch ( Exception e ) { 330 LOG.logError( e.getMessage(), e ); 331 } 332 333 return inter; 334 } 335 336 /** 337 * the operations returns true if the submitted multi primitive intersects with the curve 338 * segment 339 */ 340 private boolean intersectsAggregate( Aggregate mprim ) 341 throws Exception { 342 boolean inter = false; 343 344 int cnt = mprim.getSize(); 345 346 for ( int i = 0; i < cnt; i++ ) { 347 if ( intersects( mprim.getObjectAt( i ) ) ) { 348 inter = true; 349 break; 350 } 351 } 352 353 return inter; 354 } 355 356 /** 357 * The Boolean valued operation "contains" shall return TRUE if this Geometry contains another 358 * Geometry. 359 * <p> 360 * </p> 361 * At the moment the operation just works with point geometries 362 */ 363 public boolean contains( Geometry gmo ) { 364 365 try { 366 if ( sp == null ) { 367 sp = new PolygonImpl( new SurfaceInterpolationImpl(), allPos, null, crs ); 368 } 369 return sp.contains( gmo ); 370 } catch ( Exception e ) { 371 LOG.logError( e.getMessage(), e ); 372 } 373 374 return false; 375 } 376 377 /** 378 * The Boolean valued operation "contains" shall return TRUE if this Geometry contains a single 379 * point given by a coordinate. 380 * 381 * @param position 382 * @return true if Ring contains passed position 383 */ 384 public boolean contains( Position position ) { 385 return contains( new PointImpl( position, null ) ); 386 } 387 388 /** 389 * calculates the centroid of the ring 390 */ 391 protected void calculateCentroid() { 392 double[] cen = new double[getCoordinateDimension()]; 393 394 for ( int k = 0; k < allPos.length; k++ ) { 395 for ( int j = 0; j < getCoordinateDimension(); j++ ) { 396 cen[j] += ( allPos[k].getAsArray()[j] / allPos.length ); 397 } 398 } 399 400 centroid = new PointImpl( new PositionImpl( cen ), crs ); 401 } 402 403 /** 404 * calculates the centroid and the envelope of the ring 405 */ 406 protected void calculateParam() { 407 calculateCentroid(); 408 calculateEnvelope(); 409 setValid( true ); 410 } 411 412 /** 413 * 414 * @return string representation 415 */ 416 public String toString() { 417 String ret = null; 418 ret = "segements = " + segments.length + "\n"; 419 ret += ( "envelope = " + envelope + "\n" ); 420 return ret; 421 } 422 }