001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_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 import java.util.List;
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
047 *
048 * @see org.deegree.model.spatialschema.Curve
049 *
050 * @author Andreas Poth
051 * @version $Revision: 23675 $ $Date: 2010-04-19 11:20:41 +0200 (Mo, 19 Apr 2010) $
052 */
053 public class CurveImpl extends OrientableCurveImpl implements Curve, GenericCurve {
054
055 private static final ILogger LOG = LoggerFactory.getLogger( CurveImpl.class );
056
057 /** Use serialVersionUID for interoperability. */
058 private final static long serialVersionUID = 4060425075179654976L;
059
060 protected ArrayList<CurveSegment> segments = null;
061
062 /**
063 * initialize the curve by submitting a spatial reference system and an array of curve segments. the orientation of
064 * the curve is '+'
065 *
066 * @param segments
067 * array of CurveSegment
068 * @throws GeometryException
069 */
070 protected CurveImpl( CurveSegment segments ) throws GeometryException {
071 this( '+', new CurveSegment[] { segments } );
072 }
073
074 /**
075 * initialize the curve by submitting a spatial reference system and an array of curve segments. the orientation of
076 * the curve is '+'
077 *
078 * @param segments
079 * array of CurveSegment
080 * @throws GeometryException
081 */
082 protected CurveImpl( CurveSegment[] segments ) throws GeometryException {
083 this( '+', segments );
084 }
085
086 /**
087 * initialize the curve by submitting a spatial reference system and an array of curve segments. the orientation of
088 * the curve is '+'
089 *
090 * @param segments
091 * array of CurveSegment
092 * @param crs
093 * @throws GeometryException
094 */
095 protected CurveImpl( CurveSegment[] segments, CoordinateSystem crs ) throws GeometryException {
096 this( '+', segments );
097 this.crs = crs;
098 }
099
100 /**
101 * initialize the curve by submitting a spatial reference system, an array of curve segments and the orientation of
102 * the curve
103 *
104 * @param segments
105 * array of CurveSegment
106 * @param orientation
107 * of the curve
108 * @throws GeometryException
109 */
110 protected CurveImpl( char orientation, CurveSegment[] segments ) throws GeometryException {
111 super( segments[0].getCoordinateSystem(), orientation );
112 this.segments = new ArrayList<CurveSegment>( segments.length );
113 for ( int i = 0; i < segments.length; i++ ) {
114 this.segments.add( segments[i] );
115 // TODO check if segments touch
116 if ( i > 0 ) {
117 if ( !segments[i - 1].getEndPoint().equals( segments[i].getStartPoint() ) ) {
118 String msg = "Topological error in Curve: end-point of segment " + ( i - 1 ) + ": "
119 + WKTAdapter.export( segments[i - 1].getEndPoint() )
120 + "doesn't match start-point of segment " + i + ": "
121 + WKTAdapter.export( segments[i].getStartPoint() ) + "!";
122 throw new GeometryException( msg );
123 }
124 }
125 }
126 setValid( false );
127 }
128
129 /**
130 * calculates the envelope of the Curve
131 */
132 private void calculateEnvelope() {
133 try {
134 Position[] positions = getAsLineString().getPositions();
135
136 double[] min = positions[0].getAsArray().clone();
137 double[] max = min.clone();
138
139 for ( int i = 1; i < positions.length; i++ ) {
140 double[] pos = positions[i].getAsArray();
141
142 for ( int j = 0; j < pos.length; j++ ) {
143 if ( pos[j] < min[j] ) {
144 min[j] = pos[j];
145 } else if ( pos[j] > max[j] ) {
146 max[j] = pos[j];
147 }
148 }
149 }
150
151 envelope = new EnvelopeImpl( new PositionImpl( min ), new PositionImpl( max ), this.crs );
152 } catch ( GeometryException e ) {
153 // do nothing
154 }
155 }
156
157 /**
158 * calculates the boundary of the Curve
159 */
160 private void calculateBoundary() {
161 boundary = new CurveBoundaryImpl( getCoordinateSystem(), getStartPoint().getPosition(),
162 getEndPoint().getPosition() );
163 }
164
165 /**
166 * calculates the centroid of the Curve
167 */
168 private void calculateCentroid() {
169 Position[] positions = null;
170 try {
171 positions = getAsLineString().getPositions();
172 } catch ( GeometryException e ) {
173 LOG.logError( e.getMessage(), e );
174 }
175 if ( positions != null ) {
176
177 double[] cen = new double[positions[0].getAsArray().length];
178
179 for ( int i = 0; i < positions.length; i++ ) {
180 double[] pos = positions[i].getAsArray();
181
182 for ( int j = 0; j < pos.length; j++ ) {
183 cen[j] += ( pos[j] / positions.length );
184 }
185 }
186
187 centroid = new PointImpl( new PositionImpl( cen ), null );
188 }
189 }
190
191 @Override
192 protected void calculateParam() {
193 calculateCentroid();
194 calculateEnvelope();
195 calculateBoundary();
196 setValid( true );
197 }
198
199 /**
200 * returns the boundary of the curve
201 */
202 public CurveBoundary getCurveBoundary() {
203 return (CurveBoundary) boundary;
204 }
205
206 /**
207 * The operation "dimension" shall return the inherent dimension of this Geometry, which shall be less than or equal
208 * to the coordinate dimension. The dimension of a collection of geometric objects shall be the largest dimension of
209 * any of its pieces. Points are 0-dimensional, curves are 1-dimensional, surfaces are 2-dimensional, and solids are
210 * 3-dimensional.
211 */
212 public int getDimension() {
213 return 1;
214 }
215
216 /**
217 * The operation "coordinateDimension" shall return the dimension of the coordinates that define this Geometry,
218 * which must be the same as the coordinate dimension of the coordinate reference system for this Geometry.
219 */
220 public int getCoordinateDimension() {
221 return getStartPoint().getPosition().getCoordinateDimension();
222 }
223
224 /**
225 * The Boolean valued operation "intersects" shall return TRUE if this Geometry intersects another Geometry. Within
226 * a Complex, the Primitives do not intersect one another. In general, topologically structured data uses shared
227 * geometric objects to capture intersection information.
228 * <p>
229 * </p>
230 * dummy implementation
231 */
232 @Override
233 public boolean intersects( Geometry gmo ) {
234 boolean inter = false;
235
236 try {
237 for ( int i = 0; i < segments.size(); i++ ) {
238 CurveSegment cs = getCurveSegmentAt( i );
239
240 if ( cs.intersects( gmo ) ) {
241 inter = true;
242 break;
243 }
244 }
245 } catch ( Exception e ) {
246 LOG.logError( e.getMessage(), e );
247 }
248
249 return inter;
250 }
251
252 /**
253 * returns the length of the curve in units of the related spatial reference system
254 */
255 public double getLength() {
256 double d = 0;
257 for ( int i = 0; i < segments.size(); i++ ) {
258 d += segments.get( i ).getLength();
259 }
260 return d;
261 }
262
263 /**
264 * returns the number of segments building the curve
265 */
266 public int getNumberOfCurveSegments() {
267 return segments.size();
268 }
269
270 /**
271 * returns the first point of the curve. if the curve doesn't contain a segment or the first segment doesn't contain
272 * a point null will be returned
273 */
274 public Point getStartPoint() {
275 if ( getNumberOfCurveSegments() == 0 ) {
276 return null;
277 }
278
279 Point gmp = null;
280
281 try {
282 gmp = getCurveSegmentAt( 0 ).getStartPoint();
283 } catch ( GeometryException e ) {
284 LOG.logError( "", e );
285 }
286
287 return gmp;
288 }
289
290 /**
291 * returns the last point of the curve.if the curve doesn't contain a segment or the last segment doesn't contain a
292 * point null will be returned
293 */
294 public Point getEndPoint() {
295 if ( getNumberOfCurveSegments() == 0 ) {
296 return null;
297 }
298
299 Point gmp = null;
300
301 try {
302 gmp = getCurveSegmentAt( getNumberOfCurveSegments() - 1 ).getEndPoint();
303 } catch ( GeometryException e ) {
304 LOG.logError( "", e );
305 }
306
307 return gmp;
308 }
309
310 /**
311 * returns the curve as LineString. if there isn't a curve segment within the curve null will be returned
312 */
313 public LineString getAsLineString()
314 throws GeometryException {
315 if ( getNumberOfCurveSegments() == 0 ) {
316 return null;
317 }
318
319 Position[] tmp = null;
320
321 // normal orientaton
322 if ( getOrientation() == '+' ) {
323 int cnt = 0;
324
325 for ( int i = 0; i < getNumberOfCurveSegments(); i++ ) {
326 cnt += getCurveSegmentAt( i ).getNumberOfPoints();
327 }
328
329 tmp = new Position[cnt];
330
331 int k = 0;
332
333 for ( int i = 0; i < getNumberOfCurveSegments(); i++ ) {
334 Position[] gmps = getCurveSegmentAt( i ).getPositions();
335
336 for ( int j = 0; j < gmps.length; j++ ) {
337 tmp[k++] = gmps[j];
338 }
339 }
340 } else {
341 // inverse orientation
342 int cnt = 0;
343
344 for ( int i = getNumberOfCurveSegments() - 1; i >= 0; i-- ) {
345 cnt += getCurveSegmentAt( i ).getNumberOfPoints();
346 }
347
348 tmp = new Position[cnt];
349
350 int k = 0;
351
352 for ( int i = getNumberOfCurveSegments() - 1; i >= 0; i-- ) {
353 Position[] gmps = getCurveSegmentAt( i ).getPositions();
354
355 for ( int j = gmps.length - 1; j >= 0; j-- ) {
356 tmp[k++] = gmps[j];
357 }
358 }
359 }
360
361 return new LineStringImpl( tmp, this.crs );
362 }
363
364 /**
365 * returns the curve segment at the submitted index
366 *
367 * @param index
368 * index of the curve segment that should be returned
369 * @exception GeometryException
370 * a exception will be thrown if <tt>index</tt> is smaller than '0' or larger than
371 * <tt>getNumberOfCurveSegments()-1</tt>
372 */
373 public CurveSegment getCurveSegmentAt( int index )
374 throws GeometryException {
375 if ( ( index < 0 ) || ( index > getNumberOfCurveSegments() - 1 ) ) {
376 throw new GeometryException( "invalid index/position to get a segment!" );
377 }
378
379 return segments.get( index );
380 }
381
382 /**
383 *
384 * @return all segments of a Curve
385 * @throws GeometryException
386 */
387 public CurveSegment[] getCurveSegments()
388 throws GeometryException {
389 return segments.toArray( new CurveSegment[segments.size()] );
390 }
391
392 /**
393 * @return true if no segment is within the curve
394 */
395 @Override
396 public boolean isEmpty() {
397 return ( getNumberOfCurveSegments() == 0 );
398 }
399
400 /**
401 * translate each point of the curve with the values of the submitted double array.
402 */
403 @Override
404 public void translate( double[] d ) {
405 try {
406 for ( int i = 0; i < segments.size(); i++ ) {
407 Position[] pos = getCurveSegmentAt( i ).getPositions();
408
409 for ( int j = 0; j < pos.length; j++ ) {
410 pos[j].translate( d );
411 }
412 }
413 } catch ( Exception e ) {
414 LOG.logError( e.getLocalizedMessage(), e );
415 }
416 setValid( false );
417 }
418
419 /**
420 * checks if this curve is completely equal to the submitted geometry
421 *
422 * @param other
423 * object to compare to
424 */
425 @Override
426 public boolean equals( Object other ) {
427 if ( envelope == null ) {
428 calculateEnvelope();
429 }
430 if ( !super.equals( other ) ) {
431 return false;
432 }
433
434 if ( !( other instanceof CurveImpl ) ) {
435 return false;
436 }
437
438 if ( !envelope.equals( ( (Geometry) other ).getEnvelope() ) ) {
439 return false;
440 }
441
442 if ( segments.size() != ( (Curve) other ).getNumberOfCurveSegments() ) {
443 return false;
444 }
445
446 try {
447 for ( int i = 0; i < segments.size(); i++ ) {
448 if ( !getCurveSegmentAt( i ).equals( ( (Curve) other ).getCurveSegmentAt( i ) ) ) {
449 return false;
450 }
451 }
452 } catch ( Exception e ) {
453 return false;
454 }
455
456 return true;
457 }
458
459 @Override
460 public Geometry union( Geometry other ) {
461 if ( other instanceof Curve ) {
462 Geometry result = null;
463 try {
464 Position[] p1 = getAsLineString().getPositions();
465 Position[] p2 = ( (Curve) other ).getAsLineString().getPositions();
466 List<Position> list = null;
467 if ( p1[0].equals( p2[0] ) ) {
468 list = new ArrayList<Position>( p1.length + p2.length - 1);
469 for ( int i = p1.length-1; i > 0; i-- ) {
470 list.add( p1[i] );
471 }
472 for ( Position position : p2 ) {
473 list.add( position );
474 }
475 } else if ( p1[0].equals( p2[p2.length - 1] ) ) {
476 list = new ArrayList<Position>( p1.length + p2.length - 1);
477 for ( Position position : p2 ) {
478 list.add( position );
479 }
480 for ( int i = 1; i < p1.length; i++ ) {
481 list.add( p1[i] );
482 }
483 } else if ( p1[p1.length - 1].equals( p2[0] ) ) {
484 list = new ArrayList<Position>( p1.length + p2.length - 1);
485 for ( Position position : p1 ) {
486 list.add( position );
487 }
488 for ( int i = 1; i < p2.length; i++ ) {
489 list.add( p2[i] );
490 }
491 } else if ( p1[p1.length - 1].equals( p2[p2.length - 1] ) ) {
492 list = new ArrayList<Position>( p1.length + p2.length - 1);
493 for ( Position position : p1 ) {
494 list.add( position );
495 }
496 for ( int i = p2.length-2; i >= 0; i-- ) {
497 list.add( p2[i] );
498 }
499 } else {
500 // curves not touching at start or end point
501 result = GeometryFactory.createMultiCurve( new Curve[] { this, (Curve) other } );
502 }
503 if ( result == null ) {
504 // curves touching at start or end point
505 result = GeometryFactory.createCurve( list.toArray( new Position[list.size()] ), crs );
506 }
507 } catch ( GeometryException e ) {
508 throw new RuntimeException( e );
509 }
510 return result;
511 } else {
512 return super.union( other );
513 }
514 }
515
516 @Override
517 public Object clone() {
518 CurveImpl c = null;
519 try {
520 CurveSegment[] cs = new CurveSegment[getNumberOfCurveSegments()];
521 for ( int i = 0; i < segments.size(); i++ ) {
522 cs[i] = (CurveSegment) ( (CurveSegmentImpl) segments.get( i ) ).clone();
523 }
524 c = new CurveImpl( getOrientation(), cs );
525 c.crs = crs;
526 } catch ( Exception ex ) {
527 LOG.logError( "CurveImpl.clone: ", ex );
528 }
529 return c;
530 }
531
532 @Override
533 public String toString() {
534 String ret = null;
535 ret = "segments = " + segments + "\n";
536 ret += ( "envelope = " + envelope + "\n" );
537 return ret;
538 }
539 }