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