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 }