    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    }