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 }