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