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