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 }