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 }