    001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/model/spatialschema/CurveImpl.java $
    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.util.ArrayList;
    039    import java.util.List;
    040
    041    import org.deegree.framework.log.ILogger;
    042    import org.deegree.framework.log.LoggerFactory;
    043    import org.deegree.model.crs.CoordinateSystem;
    044
    045    /**
    046     * default implementation of
    047     *
    048     * @see org.deegree.model.spatialschema.Curve
    049     *
    050     * @author Andreas Poth
    051     * @version $Revision: 23675 $ $Date: 2010-04-19 11:20:41 +0200 (Mo, 19. Apr 2010) $
    052     */
    053    public class CurveImpl extends OrientableCurveImpl implements Curve, GenericCurve {
    054
    055        private static final ILogger LOG = LoggerFactory.getLogger( CurveImpl.class );
    056
    057        /** Use serialVersionUID for interoperability. */
    058        private final static long serialVersionUID = 4060425075179654976L;
    059
    060        protected ArrayList<CurveSegment> segments = null;
    061
    062        /**
    063         * initialize the curve by submitting a spatial reference system and an array of curve segments. the orientation of
    064         * the curve is '+'
    065         *
    066         * @param segments
    067         *            array of CurveSegment
    068         * @throws GeometryException
    069         */
    070        protected CurveImpl( CurveSegment segments ) throws GeometryException {
    071            this( '+', new CurveSegment[] { segments } );
    072        }
    073
    074        /**
    075         * initialize the curve by submitting a spatial reference system and an array of curve segments. the orientation of
    076         * the curve is '+'
    077         *
    078         * @param segments
    079         *            array of CurveSegment
    080         * @throws GeometryException
    081         */
    082        protected CurveImpl( CurveSegment[] segments ) throws GeometryException {
    083            this( '+', segments );
    084        }
    085
    086        /**
    087         * initialize the curve by submitting a spatial reference system and an array of curve segments. the orientation of
    088         * the curve is '+'
    089         *
    090         * @param segments
    091         *            array of CurveSegment
    092         * @param crs
    093         * @throws GeometryException
    094         */
    095        protected CurveImpl( CurveSegment[] segments, CoordinateSystem crs ) throws GeometryException {
    096            this( '+', segments );
    097            this.crs = crs;
    098        }
    099
    100        /**
    101         * initialize the curve by submitting a spatial reference system, an array of curve segments and the orientation of
    102         * the curve
    103         *
    104         * @param segments
    105         *            array of CurveSegment
    106         * @param orientation
    107         *            of the curve
    108         * @throws GeometryException
    109         */
    110        protected CurveImpl( char orientation, CurveSegment[] segments ) throws GeometryException {
    111            super( segments[0].getCoordinateSystem(), orientation );
    112            this.segments = new ArrayList<CurveSegment>( segments.length );
    113            for ( int i = 0; i < segments.length; i++ ) {
    114                this.segments.add( segments[i] );
    115                // TODO check if segments touch
    116                if ( i > 0 ) {
    117                    if ( !segments[i - 1].getEndPoint().equals( segments[i].getStartPoint() ) ) {
    118                        String msg = "Topological error in Curve: end-point of segment " + ( i - 1 ) + ": "
    119                                     + WKTAdapter.export( segments[i - 1].getEndPoint() )
    120                                     + "doesn't match start-point of segment " + i + ": "
    121                                     + WKTAdapter.export( segments[i].getStartPoint() ) + "!";
    122                        throw new GeometryException( msg );
    123                    }
    124                }
    125            }
    126            setValid( false );
    127        }
    128
    129        /**
    130         * calculates the envelope of the Curve
    131         */
    132        private void calculateEnvelope() {
    133            try {
    134                Position[] positions = getAsLineString().getPositions();
    135
    136                double[] min = positions[0].getAsArray().clone();
    137                double[] max = min.clone();
    138
    139                for ( int i = 1; i < positions.length; i++ ) {
    140                    double[] pos = positions[i].getAsArray();
    141
    142                    for ( int j = 0; j < pos.length; j++ ) {
    143                        if ( pos[j] < min[j] ) {
    144                            min[j] = pos[j];
    145                        } else if ( pos[j] > max[j] ) {
    146                            max[j] = pos[j];
    147                        }
    148                    }
    149                }
    150
    151                envelope = new EnvelopeImpl( new PositionImpl( min ), new PositionImpl( max ), this.crs );
    152            } catch ( GeometryException e ) {
    153                // do nothing
    154            }
    155        }
    156
    157        /**
    158         * calculates the boundary of the Curve
    159         */
    160        private void calculateBoundary() {
    161            boundary = new CurveBoundaryImpl( getCoordinateSystem(), getStartPoint().getPosition(),
    162                                              getEndPoint().getPosition() );
    163        }
    164
    165        /**
    166         * calculates the centroid of the Curve
    167         */
    168        private void calculateCentroid() {
    169            Position[] positions = null;
    170            try {
    171                positions = getAsLineString().getPositions();
    172            } catch ( GeometryException e ) {
    173                LOG.logError( e.getMessage(), e );
    174            }
    175            if ( positions != null ) {
    176
    177                double[] cen = new double[positions[0].getAsArray().length];
    178
    179                for ( int i = 0; i < positions.length; i++ ) {
    180                    double[] pos = positions[i].getAsArray();
    181
    182                    for ( int j = 0; j < pos.length; j++ ) {
    183                        cen[j] += ( pos[j] / positions.length );
    184                    }
    185                }
    186
    187                centroid = new PointImpl( new PositionImpl( cen ), null );
    188            }
    189        }
    190
    191        @Override
    192        protected void calculateParam() {
    193            calculateCentroid();
    194            calculateEnvelope();
    195            calculateBoundary();
    196            setValid( true );
    197        }
    198
    199        /**
    200         * returns the boundary of the curve
    201         */
    202        public CurveBoundary getCurveBoundary() {
    203            return (CurveBoundary) boundary;
    204        }
    205
    206        /**
    207         * The operation "dimension" shall return the inherent dimension of this Geometry, which shall be less than or equal
    208         * to the coordinate dimension. The dimension of a collection of geometric objects shall be the largest dimension of
    209         * any of its pieces. Points are 0-dimensional, curves are 1-dimensional, surfaces are 2-dimensional, and solids are
    210         * 3-dimensional.
    211         */
    212        public int getDimension() {
    213            return 1;
    214        }
    215
    216        /**
    217         * The operation "coordinateDimension" shall return the dimension of the coordinates that define this Geometry,
    218         * which must be the same as the coordinate dimension of the coordinate reference system for this Geometry.
    219         */
    220        public int getCoordinateDimension() {
    221            return getStartPoint().getPosition().getCoordinateDimension();
    222        }
    223
    224        /**
    225         * The Boolean valued operation "intersects" shall return TRUE if this Geometry intersects another Geometry. Within
    226         * a Complex, the Primitives do not intersect one another. In general, topologically structured data uses shared
    227         * geometric objects to capture intersection information.
    228         * <p>
    229         * </p>
    230         * dummy implementation
    231         */
    232        @Override
    233        public boolean intersects( Geometry gmo ) {
    234            boolean inter = false;
    235
    236            try {
    237                for ( int i = 0; i < segments.size(); i++ ) {
    238                    CurveSegment cs = getCurveSegmentAt( i );
    239
    240                    if ( cs.intersects( gmo ) ) {
    241                        inter = true;
    242                        break;
    243                    }
    244                }
    245            } catch ( Exception e ) {
    246                LOG.logError( e.getMessage(), e );
    247            }
    248
    249            return inter;
    250        }
    251
    252        /**
    253         * returns the length of the curve in units of the related spatial reference system
    254         */
    255        public double getLength() {
    256            double d = 0;
    257            for ( int i = 0; i < segments.size(); i++ ) {
    258                d += segments.get( i ).getLength();
    259            }
    260            return d;
    261        }
    262
    263        /**
    264         * returns the number of segments building the curve
    265         */
    266        public int getNumberOfCurveSegments() {
    267            return segments.size();
    268        }
    269
    270        /**
    271         * returns the first point of the curve. if the curve doesn't contain a segment or the first segment doesn't contain
    272         * a point null will be returned
    273         */
    274        public Point getStartPoint() {
    275            if ( getNumberOfCurveSegments() == 0 ) {
    276                return null;
    277            }
    278
    279            Point gmp = null;
    280
    281            try {
    282                gmp = getCurveSegmentAt( 0 ).getStartPoint();
    283            } catch ( GeometryException e ) {
    284                LOG.logError( "", e );
    285            }
    286
    287            return gmp;
    288        }
    289
    290        /**
    291         * returns the last point of the curve.if the curve doesn't contain a segment or the last segment doesn't contain a
    292         * point null will be returned
    293         */
    294        public Point getEndPoint() {
    295            if ( getNumberOfCurveSegments() == 0 ) {
    296                return null;
    297            }
    298
    299            Point gmp = null;
    300
    301            try {
    302                gmp = getCurveSegmentAt( getNumberOfCurveSegments() - 1 ).getEndPoint();
    303            } catch ( GeometryException e ) {
    304                LOG.logError( "", e );
    305            }
    306
    307            return gmp;
    308        }
    309
    310        /**
    311         * returns the curve as LineString. if there isn't a curve segment within the curve null will be returned
    312         */
    313        public LineString getAsLineString()
    314                                throws GeometryException {
    315            if ( getNumberOfCurveSegments() == 0 ) {
    316                return null;
    317            }
    318
    319            Position[] tmp = null;
    320
    321            // normal orientaton
    322            if ( getOrientation() == '+' ) {
    323                int cnt = 0;
    324
    325                for ( int i = 0; i < getNumberOfCurveSegments(); i++ ) {
    326                    cnt += getCurveSegmentAt( i ).getNumberOfPoints();
    327                }
    328
    329                tmp = new Position[cnt];
    330
    331                int k = 0;
    332
    333                for ( int i = 0; i < getNumberOfCurveSegments(); i++ ) {
    334                    Position[] gmps = getCurveSegmentAt( i ).getPositions();
    335
    336                    for ( int j = 0; j < gmps.length; j++ ) {
    337                        tmp[k++] = gmps[j];
    338                    }
    339                }
    340            } else {
    341                // inverse orientation
    342                int cnt = 0;
    343
    344                for ( int i = getNumberOfCurveSegments() - 1; i >= 0; i-- ) {
    345                    cnt += getCurveSegmentAt( i ).getNumberOfPoints();
    346                }
    347
    348                tmp = new Position[cnt];
    349
    350                int k = 0;
    351
    352                for ( int i = getNumberOfCurveSegments() - 1; i >= 0; i-- ) {
    353                    Position[] gmps = getCurveSegmentAt( i ).getPositions();
    354
    355                    for ( int j = gmps.length - 1; j >= 0; j-- ) {
    356                        tmp[k++] = gmps[j];
    357                    }
    358                }
    359            }
    360
    361            return new LineStringImpl( tmp, this.crs );
    362        }
    363
    364        /**
    365         * returns the curve segment at the submitted index
    366         *
    367         * @param index
    368         *            index of the curve segment that should be returned
    369         * @exception GeometryException
    370         *                a exception will be thrown if <tt>index</tt> is smaller than '0' or larger than
    371         *                <tt>getNumberOfCurveSegments()-1</tt>
    372         */
    373        public CurveSegment getCurveSegmentAt( int index )
    374                                throws GeometryException {
    375            if ( ( index < 0 ) || ( index > getNumberOfCurveSegments() - 1 ) ) {
    376                throw new GeometryException( "invalid index/position to get a segment!" );
    377            }
    378
    379            return segments.get( index );
    380        }
    381
    382        /**
    383         *
    384         * @return all segments of a Curve
    385         * @throws GeometryException
    386         */
    387        public CurveSegment[] getCurveSegments()
    388                                throws GeometryException {
    389            return segments.toArray( new CurveSegment[segments.size()] );
    390        }
    391
    392        /**
    393         * @return true if no segment is within the curve
    394         */
    395        @Override
    396        public boolean isEmpty() {
    397            return ( getNumberOfCurveSegments() == 0 );
    398        }
    399
    400        /**
    401         * translate each point of the curve with the values of the submitted double array.
    402         */
    403        @Override
    404        public void translate( double[] d ) {
    405            try {
    406                for ( int i = 0; i < segments.size(); i++ ) {
    407                    Position[] pos = getCurveSegmentAt( i ).getPositions();
    408
    409                    for ( int j = 0; j < pos.length; j++ ) {
    410                        pos[j].translate( d );
    411                    }
    412                }
    413            } catch ( Exception e ) {
    414                LOG.logError( e.getLocalizedMessage(), e );
    415            }
    416            setValid( false );
    417        }
    418
    419        /**
    420         * checks if this curve is completely equal to the submitted geometry
    421         *
    422         * @param other
    423         *            object to compare to
    424         */
    425        @Override
    426        public boolean equals( Object other ) {
    427            if ( envelope == null ) {
    428                calculateEnvelope();
    429            }
    430            if ( !super.equals( other ) ) {
    431                return false;
    432            }
    433
    434            if ( !( other instanceof CurveImpl ) ) {
    435                return false;
    436            }
    437
    438            if ( !envelope.equals( ( (Geometry) other ).getEnvelope() ) ) {
    439                return false;
    440            }
    441
    442            if ( segments.size() != ( (Curve) other ).getNumberOfCurveSegments() ) {
    443                return false;
    444            }
    445
    446            try {
    447                for ( int i = 0; i < segments.size(); i++ ) {
    448                    if ( !getCurveSegmentAt( i ).equals( ( (Curve) other ).getCurveSegmentAt( i ) ) ) {
    449                        return false;
    450                    }
    451                }
    452            } catch ( Exception e ) {
    453                return false;
    454            }
    455
    456            return true;
    457        }
    458
    459        @Override
    460        public Geometry union( Geometry other ) {
    461            if ( other instanceof Curve ) {
    462                Geometry result = null;
    463                try {
    464                    Position[] p1 = getAsLineString().getPositions();
    465                    Position[] p2 = ( (Curve) other ).getAsLineString().getPositions();
    466                    List<Position> list = null;
    467                    if ( p1[0].equals( p2[0] ) ) {
    468                        list = new ArrayList<Position>( p1.length + p2.length - 1);
    469                        for ( int i = p1.length-1; i > 0; i-- ) {
    470                            list.add( p1[i] );
    471                        }
    472                        for ( Position position : p2 ) {
    473                            list.add( position );
    474                        }
    475                    } else if ( p1[0].equals( p2[p2.length - 1] ) ) {
    476                        list = new ArrayList<Position>( p1.length + p2.length - 1);
    477                        for ( Position position : p2 ) {
    478                            list.add( position );
    479                        }
    480                        for ( int i = 1; i < p1.length; i++ ) {
    481                            list.add( p1[i] );
    482                        }
    483                    } else if ( p1[p1.length - 1].equals( p2[0] ) ) {
    484                        list = new ArrayList<Position>( p1.length + p2.length - 1);
    485                        for ( Position position : p1 ) {
    486                            list.add( position );
    487                        }
    488                        for ( int i = 1; i < p2.length; i++ ) {
    489                            list.add( p2[i] );
    490                        }
    491                    } else if ( p1[p1.length - 1].equals( p2[p2.length - 1] ) ) {
    492                        list = new ArrayList<Position>( p1.length + p2.length - 1);
    493                        for ( Position position : p1 ) {
    494                            list.add( position );
    495                        }
    496                        for ( int i = p2.length-2; i >= 0; i-- ) {
    497                            list.add( p2[i] );
    498                        }
    499                    } else {
    500                        // curves not touching at start or end point
    501                        result = GeometryFactory.createMultiCurve( new Curve[] { this, (Curve) other } );
    502                    }
    503                    if ( result == null ) {
    504                        // curves touching at start or end point
    505                        result = GeometryFactory.createCurve( list.toArray( new Position[list.size()] ), crs );
    506                    }
    507                } catch ( GeometryException e ) {
    508                    throw new RuntimeException( e );
    509                }
    510                return result;
    511            } else {
    512                return super.union( other );
    513            }
    514        }
    515
    516        @Override
    517        public Object clone() {
    518            CurveImpl c = null;
    519            try {
    520                CurveSegment[] cs = new CurveSegment[getNumberOfCurveSegments()];
    521                for ( int i = 0; i < segments.size(); i++ ) {
    522                    cs[i] = (CurveSegment) ( (CurveSegmentImpl) segments.get( i ) ).clone();
    523                }
    524                c = new CurveImpl( getOrientation(), cs );
    525                c.crs = crs;
    526            } catch ( Exception ex ) {
    527                LOG.logError( "CurveImpl.clone: ", ex );
    528            }
    529            return c;
    530        }
    531
    532        @Override
    533        public String toString() {
    534            String ret = null;
    535            ret = "segments = " + segments + "\n";
    536            ret += ( "envelope = " + envelope + "\n" );
    537            return ret;
    538        }
    539    }