001 //$HeadURL: http://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/model/spatialschema/RingImpl.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.io.Serializable;
039 import java.util.Arrays;
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 the Ring interface of the
047 *
048 *
049 * @version $Revision: 29966 $
050 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
051 * @author last edited by: $Author: apoth $
052 *
053 * @version 1.0. $Revision: 29966 $, $Date: 2011-03-09 15:19:04 +0100 (Wed, 09 Mar 2011) $
054 *
055 * @since 2.0
056 */
057 public class RingImpl extends OrientableCurveImpl implements Ring, Serializable {
058 /** Use serialVersionUID for interoperability. */
059 private final static long serialVersionUID = 9157144642050604928L;
060
061 private static final ILogger LOG = LoggerFactory.getLogger( RingImpl.class );
062
063 private SurfacePatch sp = null;
064
065 private int nop = 0;
066
067 private Position[] allPos;
068
069 /**
070 * Constructor, with an array and CoordinateSystem
071 *
072 * @param points
073 * @param crs
074 * @throws GeometryException
075 */
076 protected RingImpl( Position[] points, CoordinateSystem crs ) throws GeometryException {
077 super( crs );
078 Position[][] tmp = new Position[1][];
079 tmp[0] = points;
080 setPositions( tmp );
081 }
082
083 /**
084 * Constructor, with an array, CoordinateSystem and Orientation
085 *
086 * @param points
087 * @param crs
088 * @param orientation
089 * @throws GeometryException
090 */
091 protected RingImpl( Position[] points, CoordinateSystem crs, char orientation ) throws GeometryException {
092 super( crs, orientation );
093 Position[][] tmp = new Position[1][];
094 tmp[0] = points;
095 setPositions( tmp );
096 }
097
098 /**
099 * Constructor, with curve segments, CoordinateSystem and Orientation
100 *
101 * @param segments
102 * @param crs
103 * @param orientation
104 * @throws GeometryException
105 */
106 protected RingImpl( CurveSegment[] segments, CoordinateSystem crs, char orientation ) throws GeometryException {
107 super( crs, orientation );
108 Position[][] tmp = new Position[segments.length][];
109 for ( int i = 0; i < segments.length; i++ ) {
110 tmp[i] = segments[i].getPositions();
111 }
112 setPositions( tmp );
113 }
114
115 /**
116 * calculates the envelope
117 */
118 private void calculateEnvelope() {
119 double[] min = allPos[0].getAsArray().clone();
120 double[] max = min.clone();
121
122 for ( int k = 1; k < allPos.length; k++ ) {
123 double[] pos = allPos[k].getAsArray();
124
125 for ( int j = 0; j < pos.length; j++ ) {
126 if ( pos[j] < min[j] ) {
127 min[j] = pos[j];
128 } else if ( pos[j] > max[j] ) {
129 max[j] = pos[j];
130 }
131 }
132 }
133
134 envelope = new EnvelopeImpl( new PositionImpl( min ), new PositionImpl( max ), this.crs );
135 }
136
137 /**
138 * Ring must be closed, so isCycle returns TRUE.
139 */
140 public boolean isCycle() {
141 return true;
142 }
143
144 /**
145 * Ring is a PrimitiveBoundary, so isSimple returns TRUE.
146 */
147 public boolean isSimple() {
148 return true;
149 }
150
151 /**
152 * The operation "dimension" shall return the inherent dimension of this Geometry, which shall be less than or equal
153 * to the coordinate dimension. The dimension of a collection of geometric objects shall be the largest dimension of
154 * any of its pieces. Points are 0-dimensional, curves are 1-dimensional, surfaces are 2-dimensional, and solids are
155 * 3-dimensional.
156 */
157 public int getDimension() {
158 return 1;
159 }
160
161 /**
162 * The operation "coordinateDimension" shall return the dimension of the coordinates that define this Geometry,
163 * which must be the same as the coordinate dimension of the coordinate reference system for this Geometry.
164 */
165 public int getCoordinateDimension() {
166 return getPositions()[0].getCoordinateDimension();
167 }
168
169 /**
170 * gets the Ring as a Array of positions.
171 */
172 public Position[] getPositions() {
173 if ( getOrientation() == '-' ) {
174 Position[] temp = new Position[allPos.length];
175
176 for ( int i = 0; i < allPos.length; i++ ) {
177 temp[i] = allPos[( allPos.length - 1 ) - i];
178 }
179
180 return temp;
181 }
182 return allPos;
183 }
184
185 /**
186 * sets the Ring as a ArrayList of points
187 *
188 * @param positions
189 * @throws GeometryException
190 */
191 protected void setPositions( Position[][] positions )
192 throws GeometryException {
193
194 nop = 0;
195 for ( int i = 0; i < positions.length; i++ ) {
196 nop += positions[i].length;
197 }
198 allPos = new Position[nop];
199 int k = 0;
200 for ( int i = 0; i < positions.length; i++ ) {
201 for ( int j = 0; j < positions[i].length; j++ ) {
202 allPos[k++] = positions[i][j];
203 }
204 }
205
206 // checks if the ring has more than 3 elements [!(points.length > 3)]
207 if ( nop < 3 ) {
208 throw new GeometryException( "invalid length of a Ring!" );
209 }
210
211 // checks if the startpoint = endpoint of the ring
212 if ( !allPos[0].equals( allPos[allPos.length - 1] ) ) {
213 throw new GeometryException( "StartPoint of ring isn't equal to EndPoint!" );
214 }
215
216 setValid( false );
217 }
218
219 /**
220 * returns the Ring as one CurveSegment
221 */
222 public CurveSegment getAsCurveSegment()
223 throws GeometryException {
224 return new LineStringImpl( allPos, getCoordinateSystem() );
225 }
226
227 /**
228 * returns the Ring as a CurveSegments
229 *
230 * @return curve segments
231 */
232 public CurveSegment[] getCurveSegments() {
233 try {
234 return new CurveSegment[] { getAsCurveSegment() };
235 } catch ( GeometryException e ) {
236 LOG.logError( e );
237 return null;
238 }
239 }
240
241 /**
242 * returns the CurveBoundary of the Ring. For a CurveBoundary is defines as the first and the last point of a Curve
243 * the CurveBoundary of a Ring contains two indentical point (because a Ring is closed)
244 */
245 public CurveBoundary getCurveBoundary() {
246 return (CurveBoundary) boundary;
247 }
248
249 @Override
250 public boolean equals( Object other ) {
251 if ( !super.equals( other ) || !( other instanceof RingImpl ) ) {
252 return false;
253 }
254
255 if ( !envelope.equals( ( (Geometry) other ).getEnvelope() ) ) {
256 return false;
257 }
258
259 Position[] p2 = ( (Ring) other ).getPositions();
260
261 if ( !Arrays.equals( allPos, p2 ) ) {
262 return false;
263 }
264
265 return true;
266 }
267
268 @Override
269 public Object clone() {
270 Ring r = null;
271 try {
272 CurveSegment[] segments = getCurveSegments();
273 for ( int i = 0; i < segments.length; i++ ) {
274 segments[i] = new LineStringImpl( segments[i].getPositions(), getCoordinateSystem() );
275 }
276 r = new RingImpl( segments, getCoordinateSystem(), getOrientation() );
277 } catch ( Exception ex ) {
278 LOG.logError( ex.getMessage(), ex );
279 }
280
281 return r;
282 }
283
284 @Override
285 public boolean intersects( Geometry gmo ) {
286 boolean inter = false;
287
288 try {
289 // TODO
290 // use segments
291 CurveSegment sp = new LineStringImpl( allPos, crs );
292
293 if ( gmo instanceof Point ) {
294 double tolerance = ( (Point) gmo ).getTolerance();
295 inter = LinearIntersects.intersects( ( (Point) gmo ).getPosition(), sp, tolerance );
296 } else if ( gmo instanceof Curve ) {
297 Curve curve = new CurveImpl( new CurveSegment[] { sp } );
298 inter = LinearIntersects.intersects( (Curve) gmo, curve );
299 } else if ( gmo instanceof Surface ) {
300 Curve curve = new CurveImpl( new CurveSegment[] { sp } );
301 inter = LinearIntersects.intersects( curve, (Surface) gmo );
302 } else if ( gmo instanceof MultiPrimitive ) {
303 inter = intersectsAggregate( (MultiPrimitive) gmo );
304 }
305 } catch ( Exception e ) {
306 LOG.logError( e.getMessage(), e );
307 }
308
309 return inter;
310 }
311
312 /**
313 * the operations returns true if the submitted multi primitive intersects with the curve segment
314 */
315 private boolean intersectsAggregate( Aggregate mprim )
316 throws Exception {
317 boolean inter = false;
318
319 int cnt = mprim.getSize();
320
321 for ( int i = 0; i < cnt; i++ ) {
322 if ( intersects( mprim.getObjectAt( i ) ) ) {
323 inter = true;
324 break;
325 }
326 }
327
328 return inter;
329 }
330
331 /**
332 * The Boolean valued operation "contains" shall return TRUE if this Geometry contains another Geometry.
333 * <p>
334 * </p>
335 * At the moment the operation just works with point geometries
336 */
337 @Override
338 public boolean contains( Geometry gmo ) {
339
340 try {
341 if ( sp == null ) {
342 sp = new PolygonImpl( new SurfaceInterpolationImpl(), allPos, null, crs );
343 }
344 return sp.contains( gmo );
345 } catch ( Exception e ) {
346 LOG.logError( e.getMessage(), e );
347 }
348
349 return false;
350 }
351
352 @Override
353 public boolean contains( Position position ) {
354 return contains( new PointImpl( position, null ) );
355 }
356
357 /**
358 * calculates the centroid of the ring
359 */
360 protected void calculateCentroid() {
361 double[] cen = new double[getCoordinateDimension()];
362
363 for ( int k = 0; k < allPos.length; k++ ) {
364 for ( int j = 0; j < getCoordinateDimension(); j++ ) {
365 cen[j] += ( allPos[k].getAsArray()[j] / allPos.length );
366 }
367 }
368
369 centroid = new PositionImpl( cen );
370 }
371
372 @Override
373 protected void calculateParam() {
374 calculateCentroid();
375 calculateEnvelope();
376 setValid( true );
377 }
378
379 @Override
380 public String toString() {
381 String ret = null;
382 ret = "positions = " + allPos.length + "\n";
383 ret += ( "envelope = " + envelope + "\n" );
384 return ret;
385 }
386 }