001    //$HeadURL$
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.model.crs.CoordinateSystem;
041    
042    /**
043     * Default implementation of {@link MultiGeometry}.
044     *
045     * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </a>
046     * @author last edited by: $Author:$
047     *
048     * @version $Revision:$, $Date:$
049     */
050    public class MultiGeometryImpl extends AggregateImpl implements MultiGeometry, Serializable {
051    
052        private static final long serialVersionUID = 1449961950954331996L;
053    
054        // = highest dimension of all member geometries
055        private int dimension;
056    
057        /**
058         * Creates an empty {@link MultiGeometryImpl} instance with a given {@link CoordinateSystem}.
059         *
060         * @param crs
061         *            coordinate system
062         */
063        protected MultiGeometryImpl( CoordinateSystem crs ) {
064            super( crs );
065        }
066    
067        /**
068         * Creates a {@link MultiGeometryImpl} with a given {@link CoordinateSystem} that contains the provided
069         * {@link Geometry} objects.
070         *
071         * @param members
072         *            geometries contained in the {@link MultiGeometry}
073         * @param crs
074         *            coordinate system
075         */
076        protected MultiGeometryImpl( Geometry[] members, CoordinateSystem crs ) {
077            super( crs );
078            for ( int i = 0; i < members.length; i++ ) {
079                aggregate.add( members[i] );
080            }
081        }
082    
083        /**
084         * The operation "coordinateDimension" shall return the dimension of the coordinates that define this Geometry,
085         * which must be the same as the coordinate dimension of the coordinate reference system for this Geometry.
086         *
087         * @return the actual dimension
088         */
089        public int getCoordinateDimension() {
090            if ( crs != null ) {
091                return crs.getDimension();
092            }
093            return 2;
094        }
095    
096        /**
097         * Returns the dimension of the aggregation, i.e. the maximum dimension of all member geometries.
098         *
099         * @return the maximum dimension of all member geometries
100         */
101        public int getDimension() {
102            if ( !isValid() ) {
103                calculateParam();
104            }
105            return dimension;
106        }
107    
108        /**
109         * Calculates the value of the following member variables:
110         * <ul>
111         * <li>{@link #dimension}</li>
112         * <li>{@link #envelope}</li>
113         * <li>{@link #centroid}</li>
114         * </ul>
115         */
116        @Override
117        protected synchronized void calculateParam() {
118            if ( aggregate.size() == 0 ) {
119                throw new RuntimeException( "Cannot calculate params for empty MultiGeometry." );
120            }
121            dimension = calculateDimension();
122            envelope = calculateEnvelope();
123            centroid = calculateCentroid();
124            setValid( true );
125        }
126    
127        private int calculateDimension() {
128            int dimension = -1;
129            for ( Geometry member : aggregate ) {
130                if ( member.getDimension() > dimension ) {
131                    dimension = member.getDimension();
132                }
133            }
134            return dimension;
135        }
136    
137        private Envelope calculateEnvelope() {
138    
139            double[] min;
140            double[] max;
141            Geometry firstMember = getObjectAt( 0 );
142            if ( firstMember instanceof Point ) {
143                min = ( (Point) firstMember ).getAsArray().clone();
144                max = ( (Point) firstMember ).getAsArray().clone();
145            } else {
146                System.out.println( "Object at 0: " + getObjectAt( 0 ).getClass().getName() );
147                Envelope bb = getObjectAt( 0 ).getEnvelope();
148                min = bb.getMin().getAsArray().clone();
149                max = bb.getMax().getAsArray().clone();
150            }
151    
152            for ( int i = 1; i < getSize(); i++ ) {
153                double[] pos1 = getObjectAt( i ).getEnvelope().getMin().getAsArray();
154                double[] pos2 = getObjectAt( i ).getEnvelope().getMax().getAsArray();
155    
156                for ( int j = 0; j < pos1.length; j++ ) {
157                    if ( pos1[j] < min[j] ) {
158                        min[j] = pos1[j];
159                    } else if ( pos1[j] > max[j] ) {
160                        max[j] = pos1[j];
161                    }
162    
163                    if ( pos2[j] < min[j] ) {
164                        min[j] = pos2[j];
165                    } else if ( pos2[j] > max[j] ) {
166                        max[j] = pos2[j];
167                    }
168                }
169            }
170            return new EnvelopeImpl( new PositionImpl( min ), new PositionImpl( max ), this.crs );
171        }
172    
173        private Point calculateCentroid() {
174            int dim = getCoordinateDimension();
175            double[] centroid = new double[dim];
176            for ( Geometry member : aggregate ) {
177                double[] pos = member.getCentroid().getAsArray();
178                for ( int i = 0; i < dim; i++ ) {
179                    centroid[i] = centroid[i] + pos[i];
180                }
181            }
182            for ( int i = 0; i < dim; i++ ) {
183                centroid[i] = centroid[i] / aggregate.size();
184            }
185            return new PointImpl( new PositionImpl( centroid ), crs );
186        }
187    }