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    }