001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_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    }