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