001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/model/spatialschema/MultiSurfaceImpl.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    
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 the MultiSurface interface from
046     *
047     *
048     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
049     * @author last edited by: $Author: mschneider $
050     *
051     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
052     */
053    public class MultiSurfaceImpl extends MultiPrimitiveImpl implements MultiSurface, Serializable {
054        /** Use serialVersionUID for interoperability. */
055        private final static long serialVersionUID = -6471121873087659850L;
056    
057        private static final ILogger LOG = LoggerFactory.getLogger( MultiSurfaceImpl.class );
058    
059        private double area = 0;
060    
061        /**
062         * Creates a new MultiSurfaceImpl object.
063         *
064         * @param crs
065         */
066        protected MultiSurfaceImpl( CoordinateSystem crs ) {
067            super( crs );
068        }
069    
070        /**
071         * Creates a new MultiSurfaceImpl object.
072         *
073         * @param surface
074         */
075        protected MultiSurfaceImpl( Surface[] surface ) {
076            super( surface[0].getCoordinateSystem() );
077    
078            for ( int i = 0; i < surface.length; i++ ) {
079                aggregate.add( surface[i] );
080            }
081    
082            setValid( false );
083        }
084    
085        /**
086         * Creates a new MultiSurfaceImpl object.
087         *
088         * @param surface
089         * @param crs
090         */
091        protected MultiSurfaceImpl( Surface[] surface, CoordinateSystem crs ) {
092            super( crs );
093    
094            for ( int i = 0; i < surface.length; i++ ) {
095                aggregate.add( surface[i] );
096            }
097    
098            setValid( false );
099        }
100    
101        /**
102         * adds an Surface to the aggregation
103         */
104        public void addSurface( Surface gms ) {
105            super.add( gms );
106        }
107    
108        /**
109         * inserts a Surface in the aggregation. all elements with an index equal or larger index will be moved. if index is
110         * larger then getSize() - 1 or smaller then 0 or gms equals null an exception will be thrown.
111         *
112         * @param gms
113         *            Surface to insert.
114         * @param index
115         *            position where to insert the new Surface
116         */
117        public void insertSurfaceAt( Surface gms, int index )
118                                throws GeometryException {
119            super.insertObjectAt( gms, index );
120        }
121    
122        /**
123         * sets the submitted Surface at the submitted index. the element at the position <code>index</code> will be
124         * removed. if index is larger then getSize() - 1 or smaller then 0 or gms equals null an exception will be thrown.
125         *
126         * @param gms
127         *            Surface to set.
128         * @param index
129         *            position where to set the new Surface
130         */
131        public void setSurfaceAt( Surface gms, int index )
132                                throws GeometryException {
133            setObjectAt( gms, index );
134        }
135    
136        /**
137         * removes the submitted Surface from the aggregation
138         *
139         * @return the removed Surface
140         */
141        public Surface removeSurface( Surface gms ) {
142            return (Surface) super.removeObject( gms );
143        }
144    
145        /**
146         * removes the Surface at the submitted index from the aggregation. if index is larger then getSize() - 1 or smaller
147         * then 0 an exception will be thrown.
148         *
149         * @return the removed Surface
150         */
151        public Surface removeSurfaceAt( int index )
152                                throws GeometryException {
153            return (Surface) super.removeObjectAt( index );
154        }
155    
156        /**
157         * returns the Surface at the submitted index.
158         */
159        public Surface getSurfaceAt( int index ) {
160            return (Surface) super.getPrimitiveAt( index );
161        }
162    
163        /**
164         * returns all Surfaces as array
165         */
166        public Surface[] getAllSurfaces() {
167            return aggregate.toArray( new Surface[getSize()] );
168        }
169    
170        /**
171         * calculates the bounding box / envelope of the aggregation
172         */
173        private void calculateEnvelope() {
174            Envelope bb = getSurfaceAt( 0 ).getEnvelope();
175    
176            double[] min = bb.getMin().getAsArray().clone();
177            double[] max = bb.getMax().getAsArray().clone();
178    
179            for ( int i = 1; i < getSize(); i++ ) {
180                double[] pos1 = getSurfaceAt( i ).getEnvelope().getMin().getAsArray();
181                double[] pos2 = getSurfaceAt( i ).getEnvelope().getMax().getAsArray();
182    
183                for ( int j = 0; j < pos1.length; j++ ) {
184                    if ( pos1[j] < min[j] ) {
185                        min[j] = pos1[j];
186                    } else if ( pos1[j] > max[j] ) {
187                        max[j] = pos1[j];
188                    }
189    
190                    if ( pos2[j] < min[j] ) {
191                        min[j] = pos2[j];
192                    } else if ( pos2[j] > max[j] ) {
193                        max[j] = pos2[j];
194                    }
195                }
196            }
197    
198            envelope = new EnvelopeImpl( new PositionImpl( min ), new PositionImpl( max ), this.crs );
199        }
200    
201        /**
202         * calculates the centroid and area of the aggregation
203         */
204        private void calculateCentroidArea() {
205    
206            area = 0;
207            int cnt = getCoordinateDimension();
208            try {
209                double[] cen = new double[cnt];
210    
211                for ( int i = 0; i < getSize(); i++ ) {
212                    double a = getSurfaceAt( i ).getArea();
213                    area = area + a;
214    
215                    double[] pos = getSurfaceAt( i ).getCentroid().getAsArray();
216    
217                    for ( int j = 0; j < cnt; j++ ) {
218                        cen[j] = cen[j] + ( pos[j] * a );
219                    }
220                }
221    
222                for ( int j = 0; j < cnt; j++ ) {
223                    cen[j] = cen[j] / area;
224                }
225    
226                centroid = new PointImpl( new PositionImpl( cen ), null );
227            } catch ( Exception e ) {
228                LOG.logError( "", e );
229            }
230        }
231    
232        /**
233         * calculates the centroid, area and envelope of the aggregation
234         */
235        @Override
236        protected void calculateParam() {
237            calculateEnvelope();
238            calculateCentroidArea();
239            setValid( true );
240        }
241    
242        /**
243         * returns the area of the multi surface. this is calculate as the sum of all containing surface areas.
244         *
245         * @return area
246         */
247        public double getArea() {
248            if ( !isValid() ) {
249                calculateParam();
250            }
251            return area;
252        }
253    
254        @Override
255        public Object clone() {
256            MultiSurface ms = null;
257    
258            try {
259                ms = new MultiSurfaceImpl( getCoordinateSystem() );
260    
261                for ( int i = 0; i < this.getSize(); i++ ) {
262                    SurfaceImpl si = (SurfaceImpl) getSurfaceAt( i );
263                    ms.add( (Surface) si.clone() );
264                }
265            } catch ( Exception ex ) {
266                LOG.logError( "MultiSurface_Impl.clone: ", ex );
267            }
268    
269            return ms;
270        }
271    
272        /**
273         * @return 2
274         */
275        @Override
276        public int getDimension() {
277            return 2;
278        }
279    
280        /**
281         * the dimension of the first contained surface.
282         */
283        @Override
284        public int getCoordinateDimension() {
285            return getSurfaceAt( 0 ).getCoordinateDimension();
286        }
287    }