Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.geometry / org.gvsig.fmap.geometry.impl / src / main / java / org / gvsig / fmap / geom / primitive / impl / AbstractPrimitive.java @ 41542

History | View | Annotate | Download (28.5 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.geom.primitive.impl;
25

    
26
import java.awt.Shape;
27
import java.awt.geom.AffineTransform;
28
import java.awt.geom.PathIterator;
29
import java.io.Serializable;
30

    
31
import org.cresques.cts.ICoordTrans;
32
import org.cresques.cts.IProjection;
33
import org.gvsig.fmap.geom.Geometry;
34
import org.gvsig.fmap.geom.GeometryLocator;
35
import org.gvsig.fmap.geom.GeometryManager;
36
import org.gvsig.fmap.geom.exception.CreateGeometryException;
37
import org.gvsig.fmap.geom.handler.Handler;
38
import org.gvsig.fmap.geom.operation.GeometryOperation;
39
import org.gvsig.fmap.geom.operation.GeometryOperationContext;
40
import org.gvsig.fmap.geom.operation.GeometryOperationException;
41
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
42
import org.gvsig.fmap.geom.primitive.Envelope;
43
import org.gvsig.fmap.geom.primitive.FShape;
44
import org.gvsig.fmap.geom.primitive.GeneralPathX;
45
import org.gvsig.fmap.geom.primitive.NullGeometry;
46
import org.gvsig.fmap.geom.primitive.Point;
47
import org.gvsig.fmap.geom.primitive.Primitive;
48
import org.gvsig.fmap.geom.type.GeometryType;
49
import org.gvsig.fmap.geom.util.Converter;
50
import org.slf4j.Logger;
51
import org.slf4j.LoggerFactory;
52

    
53
import com.vividsolutions.jts.geom.Coordinate;
54
import com.vividsolutions.jts.geom.GeometryFactory;
55
import com.vividsolutions.jts.io.WKBWriter;
56
import com.vividsolutions.jts.operation.distance.DistanceOp;
57
import com.vividsolutions.jts.operation.overlay.snap.GeometrySnapper;
58
import com.vividsolutions.jts.operation.valid.IsValidOp;
59
import com.vividsolutions.jts.operation.valid.TopologyValidationError;
60
import org.gvsig.fmap.geom.impl.DefaultValidationStatus;
61
import org.gvsig.fmap.geom.primitive.OrientableCurve;
62
import org.gvsig.fmap.geom.primitive.OrientableSurface;
63

    
64

    
65
/**
66
 * @author Jorge Piera Llodr� (jorge.piera@iver.es)
67
 */
68
public abstract class AbstractPrimitive implements Primitive, FShape, Shape, Serializable {
69
        
70
        private static final Logger logger = LoggerFactory.getLogger(AbstractPrimitive.class);
71

    
72
        private static final long serialVersionUID = -4334977368955260872L;
73
        protected String id = null;
74
        protected IProjection projection = null;
75
        protected GeometryType geometryType = null;
76
        protected static final GeometryManager geomManager = GeometryLocator.getGeometryManager();
77

    
78
        /**
79
         * The constructor with the GeometryType like and argument 
80
         * is used by the {@link GeometryType}{@link #create()}
81
         * to create the geometry
82
         * @param type
83
         * The geometry type
84
         */
85
        public AbstractPrimitive(GeometryType geometryType) {
86
                this(geometryType, null, null);                
87
        }
88
        
89
        AbstractPrimitive(int type, int subtype) {
90
                try {
91
                        geometryType = geomManager.getGeometryType(type, subtype);
92
                } catch (Exception e) {
93
                        //TODO Not registered geometry
94
                        geometryType = null;
95
                }
96
        }        
97
        
98
        public AbstractPrimitive(GeometryType geometryType, String id, IProjection projection) {
99
                super();
100
                this.id = id;
101
                this.projection = projection;
102
                this.geometryType = geometryType;
103
        }
104

    
105
        public AbstractPrimitive(GeometryType geometryType, IProjection projection) {
106
                this(geometryType, null, projection);
107
        }
108

    
109
        /* (non-Javadoc)
110
         * @see org.gvsig.fmap.geom.Geometry#getGeometryType()
111
         */
112
        public GeometryType getGeometryType() {
113
                return geometryType;
114
        }
115

    
116
        /* (non-Javadoc)
117
         * @see org.gvsig.fmap.geom.Geometry#getType()
118
         */
119
        public int getType() {
120
                return geometryType.getType();
121
        }
122

    
123
        /**
124
         * (non-Javadoc)
125
         * @see com.iver.cit.gvsig.fmap.core.Geometry#getInternalShape()
126
         * @deprecated this Geometry is a Shape.
127
         */
128
        public Shape getInternalShape() {
129
                return this;
130
        }
131

    
132
        /* (non-Javadoc)
133
         * @see org.gvsig.geometries.iso.AbstractGeometry#getId()
134
         */
135
        public String getId() {
136
                return id;
137
        }
138

    
139
        /* (non-Javadoc)
140
         * @see org.gvsig.geometries.iso.AbstractGeometry#getSRS()
141
         */
142
        public IProjection getSRS() {
143
                return projection;
144
        }
145

    
146
        /* (non-Javadoc)
147
         * @see org.gvsig.geometries.iso.AbstractGeometry#transform(org.cresques.cts.IProjection)
148
         */
149
        public AbstractPrimitive transform(IProjection newProjection) {
150
                Geometry newGeom = cloneGeometry();
151
                ICoordTrans coordTrans = projection.getCT(newProjection);
152
                newGeom.reProject(coordTrans);
153
                return (AbstractPrimitive)newGeom;
154
        }
155

    
156

    
157

    
158
        /*
159
         * (non-Javadoc)
160
         * @see org.gvsig.fmap.geom.Geometry#fastIntersects(double, double, double, double)
161
         */
162
        public boolean fastIntersects(double x, double y, double w, double h) {
163

    
164
                boolean resp = true;
165
                
166
                try {
167
                        resp = intersectsRectangle(this, x, y, w, h);
168
                } catch (GeometryOperationException e) {
169
                        logger.error("While doing fastintersects: " + e.getMessage(), e);
170
                }
171
                
172
                return resp;
173
        }
174

    
175
        /*
176
         * (non-Javadoc)
177
         * @see org.gvsig.fmap.geom.Geometry#cloneGeometry()
178
         */
179
        public Geometry cloneGeometry() {
180
                return (Geometry)cloneFShape();
181
        }
182

    
183
        /*
184
         * (non-Javadoc)
185
         * @see org.gvsig.fmap.geom.Geometry#getHandlers(int)
186
         */
187
        public Handler[] getHandlers(int type) {
188
                if (type==STRETCHINGHANDLER){
189
                        return getStretchingHandlers();
190
                }else if (type==SELECTHANDLER){
191
                        return getSelectHandlers();
192
                }
193
                return null;
194
        }
195

    
196
        /*
197
         * (non-Javadoc)
198
         * @see org.gvsig.fmap.geom.Geometry#isSimple()
199
         */
200
        public boolean isSimple() {
201
            com.vividsolutions.jts.geom.Geometry jtsgeom = this.getJTS();
202
            return jtsgeom.isSimple();
203
        }
204

    
205
        public boolean isValid() {
206
            try {
207
                com.vividsolutions.jts.geom.Geometry jtsgeom = this.getJTS();
208
                return jtsgeom.isValid();
209
            } catch(Exception ex) {
210
                return false;
211
            }
212
        }
213

    
214
        public ValidationStatus getValidationStatus() {
215
            DefaultValidationStatus status = new DefaultValidationStatus(
216
                    ValidationStatus.VALID,
217
                    null
218
            );
219
            com.vividsolutions.jts.geom.Geometry jtsgeom = null;
220
            try {
221
                jtsgeom = this.getJTS();
222
                IsValidOp validOp = new IsValidOp(jtsgeom);
223
                if( validOp != null ) {
224
                    status.setValidationError(validOp.getValidationError());
225
                }
226
            } catch(Exception ex) {
227
                status.setStatusCode(ValidationStatus.CURRUPTED);
228
                status.setMesage("The geometry is corrupted.");
229
                if( this instanceof OrientableSurface ) {
230
                    int vertices = ((OrientableSurface)this).getNumVertices();
231
                    if( vertices < 3) {
232
                        status.setStatusCode(ValidationStatus.TOO_FEW_POINTS);
233
                        status.setMesage(TopologyValidationError.errMsg[TopologyValidationError.TOO_FEW_POINTS]);
234
                    }
235
                } else if( this instanceof OrientableCurve ) {
236
                    int vertices = ((OrientableCurve)this).getNumVertices();
237
                    if( vertices < 2) {
238
                        status.setStatusCode(ValidationStatus.TOO_FEW_POINTS);
239
                        status.setMesage(TopologyValidationError.errMsg[TopologyValidationError.TOO_FEW_POINTS]);
240
                    }
241
                } 
242
            }
243
            return status;
244
        }
245
        
246
        /*
247
         * (non-Javadoc)
248
         * @see org.gvsig.fmap.geom.Geometry#invokeOperation(int, org.gvsig.fmap.geom.operation.GeometryOperationContext)
249
         */
250
        public Object invokeOperation(int index, GeometryOperationContext ctx) throws GeometryOperationNotSupportedException, GeometryOperationException {
251
                return geomManager.invokeOperation(index, this, ctx);
252
        }
253

    
254
        /*
255
         * (non-Javadoc)
256
         * @see org.gvsig.fmap.geom.Geometry#invokeOperation(java.lang.String, org.gvsig.fmap.geom.operation.GeometryOperationContext)
257
         */
258
        public Object invokeOperation(String oppName, GeometryOperationContext ctx) throws GeometryOperationNotSupportedException, GeometryOperationException {
259
                return geomManager.invokeOperation(oppName, this, ctx);
260
        }
261

    
262
        /*
263
         * (non-Javadoc)
264
         * @see java.lang.Comparable#compareTo(T)
265
         */
266
        public int compareTo(Object arg0) {
267
                // TODO Auto-generated method stub
268
                return -1;
269
        }
270

    
271
        /*
272
         * (non-Javadoc)
273
         * @see java.lang.Object#toString()
274
         */
275
        public String toString() {
276
                String name=getGeometryType().getName();
277
                return name.substring(name.lastIndexOf(".")+1);
278
        }
279

    
280
        /*
281
         * (non-Javadoc)
282
         * @see java.lang.Object#equals(java.lang.Object)
283
         */
284
        public boolean equals(Object obj) {
285
                if (obj == null) {
286
                        return false;
287
                }
288
                if (this.getClass() != obj.getClass()) {
289
                        return false;
290
                }
291

    
292
                AbstractPrimitive other = (AbstractPrimitive) obj;
293
                if (this.getGeometryType().getType() != other.getGeometryType()
294
                                .getType()) {
295
                        return false;
296

    
297
                }
298
                
299
                if (this.getGeometryType().getSubType() != other.getGeometryType()
300
                                .getSubType()) {
301
                        return false;
302

    
303
                }
304
                
305
                if (this instanceof NullGeometry || obj instanceof NullGeometry) {
306
                    /*
307
                     * If any of them is null geometry, they both have to be
308
                     * null geometry, or else, they are not equal.
309
                     * This prevents null pointer exception in the rest of the
310
                     * method
311
                     */
312
                if (this instanceof NullGeometry && obj instanceof NullGeometry) {
313
                    return true;
314
                } else {
315
                    return false;
316
                }
317
                }
318
                
319
                if (this.projection != other.projection) {
320
                        if (this.projection == null) {
321
                                return false;
322
                        }
323
                        if (this.projection.getAbrev() != other.projection.getAbrev()) { //FIXME this must be false
324
                                return false;
325
                        }
326
                }
327
                if (!this.getBounds().equals(other.getBounds())) {
328
                        return false;
329
                }
330

    
331

    
332
                GeneralPathX myPath = this.getGeneralPath();
333
                GeneralPathX otherPath = other.getGeneralPath();
334
                if (myPath == null) {
335
                        if (otherPath != null) {
336
                                return false;
337
                        } else {
338
                                // TODO checkThis
339
                                return true;
340
                        }
341

    
342
                }
343
                if (myPath.getNumTypes() != otherPath.getNumTypes()) {
344
                        return false;
345
                }
346
                if (Math.abs(myPath.getNumCoords() - otherPath.getNumCoords()) > this
347
                                .getDimension()) {
348
                        return false;
349
                }
350
                PathIterator myIter = myPath.getPathIterator(null);
351
                PathIterator otherIter = otherPath.getPathIterator(null);
352
                int myType,otherType;
353
                // FIXME when 3D, 2DM and 3DM
354
                double[] myData = new double[6];
355
                double[] otherData = new double[6];
356
                double[] myFirst = new double[] { myPath.getPointAt(0).getX(),myPath.getPointAt(0).getY()};
357
                double[] otherFirst = new double[] { otherPath.getPointAt(0).getX(),otherPath.getPointAt(0).getY()};
358

    
359
                while (!myIter.isDone()) {
360
                        if (otherIter.isDone()) {
361
                                return false;
362
                        }
363
                        for (int i = 0; i < myData.length; i++) {
364
                                myData[i] = 0.0;
365
                                otherData[i] = 0.0;
366
                        }
367

    
368
                        myType = myIter.currentSegment(myData);
369
                        otherType = otherIter.currentSegment(otherData);
370

    
371
                        switch (myType) {
372
                        case PathIterator.SEG_LINETO:
373
                                if (otherType != myType) {
374
                                        if (otherType == PathIterator.SEG_CLOSE){
375
                                                if (!comparePathIteratorData(otherFirst, myData)) {
376
                                                        return false;
377
                                                }
378
                                        } else {
379
                                                return false;
380
                                        }
381
                                } else {
382
                                        if (!comparePathIteratorData(myData, otherData)) {
383
                                                return false;
384
                                        }
385
                                }
386
                                break;
387

    
388

    
389
                        case PathIterator.SEG_CLOSE:
390
                                if (otherType != myType) {
391
                                        if (otherType == PathIterator.SEG_LINETO) {
392
                                                if (!comparePathIteratorData(myFirst, otherData)) {
393
                                                        return false;
394
                                                }
395
                                        } else {
396
                                                return false;
397
                                        }
398
                                } else {
399
                                        if (!comparePathIteratorData(myData, otherData)) {
400
                                                return false;
401
                                        }
402
                                }
403
                                break;
404

    
405

    
406

    
407
                        case PathIterator.SEG_MOVETO:
408
                        case PathIterator.SEG_QUADTO:
409
                        case PathIterator.SEG_CUBICTO:
410
                                if (otherType != myType) {
411
                                        return false;
412
                                }
413
                                if (!comparePathIteratorData(myData, otherData)) {
414
                                        return false;
415
                                }
416
                                break;
417

    
418
                        } // end switch
419

    
420

    
421
                        myIter.next();
422
                        otherIter.next();
423
                }
424
                if (!otherIter.isDone()) {
425
                        return false;
426
                }
427
                return true;
428
        }
429

    
430
        private boolean comparePathIteratorData(double[] org, double[] other) {
431
                for (int i = 0; i < org.length; i++) {
432
                        if (Math.abs(org[i] - other[i]) > 0.0000001) {
433
                                return false;
434
                        }
435
                }
436
                return true;
437
        }
438

    
439
        /* (non-Javadoc)
440
         * @see org.gvsig.fmap.geom.primitive.FShape#getShapeType()
441
         */
442
        public int getShapeType() {
443
                return getType();
444
        }
445
        
446
        
447
        
448
        
449
        
450
        
451
        
452
        
453
        /**
454
         * Utility method
455
         * @param geometry
456
         * @param x
457
         * @param y
458
         * @return
459
         * @throws GeometryOperationException
460
         */
461
        protected boolean containsPoint(Geometry geom, double x, double y) throws GeometryOperationException {
462
                
463
                // exclude disjoint 
464
                Envelope env = geom.getEnvelope();
465
                if (x > env.getMaximum(0)) return false; 
466
                if (y > env.getMaximum(1)) return false; 
467
                if (x < env.getMinimum(0)) return false; 
468
                if (y < env.getMinimum(1)) return false; 
469
                
470
                // boxes overlap, need long version
471
                
472
                Geometry geompoint = null;
473
                try {
474
                        geompoint = GeometryLocator.getGeometryManager().createPoint(x, y, SUBTYPES.GEOM2D);
475
                } catch (Exception e1) {
476
                        throw new GeometryOperationException(geom.getType(), GeometryOperation.OPERATION_CONTAINS_CODE, e1);
477
                }
478
                
479
                GeometryOperationContext drgoc = new GeometryOperationContext();
480
                 drgoc.setAttribute("geom",geompoint);
481
                
482
                Object resp = null;
483
                boolean respboolean = true;
484
                try {
485
                        resp = geom.invokeOperation(GeometryOperation.OPERATION_CONTAINS_CODE, drgoc);
486
                        respboolean = ((Boolean) resp).booleanValue();
487
                } catch (Exception e) {
488
                        throw new GeometryOperationException(geom.getType(), GeometryOperation.OPERATION_CONTAINS_CODE, e);
489
                }
490

    
491
                return respboolean;
492
        }
493

    
494
        /**
495
         * 
496
         * @param geometry
497
         * @param x
498
         * @param y
499
         * @param w
500
         * @param h
501
         * @return
502
         */
503
        protected boolean containsRectangle(Geometry geom, double x, double y,
504
                        double w, double h) throws GeometryOperationException {
505
                
506
                
507
                // exclude disjoint boxes
508
                Envelope env = geom.getEnvelope();
509
                if (x > env.getMaximum(0)) return false; 
510
                if ((x+w) < env.getMinimum(0)) return false; 
511
                if (y > env.getMaximum(1)) return false; 
512
                if ((y+h) < env.getMinimum(1)) return false; 
513
                
514
                if (w == 0 && h == 0) {
515
                        return  containsPoint(geom, x, y); 
516
                }
517
                
518
                // boxes overlap, need long version
519
                Geometry rectgeom = null;
520
                GeneralPathX gpx = new GeneralPathX();
521
                gpx.moveTo(x, y);
522
                gpx.lineTo(x+w, y);
523
                gpx.lineTo(x+w, y+h);
524
                gpx.lineTo(x, y+h);
525
                gpx.lineTo(x, y);
526
                
527
                try {
528
                        rectgeom = GeometryLocator.getGeometryManager().createSurface(gpx, SUBTYPES.GEOM2D);
529
                } catch (Exception e1) {
530
                        throw new GeometryOperationException(geom.getType(), GeometryOperation.OPERATION_CONTAINS_CODE, e1);
531
                }
532
                
533
                GeometryOperationContext drgoc = new GeometryOperationContext();
534
                drgoc.setAttribute("geom",rectgeom);
535

    
536
                Object resp = null;
537
                boolean respboolean = true;
538
                try {
539
                        resp = geom.invokeOperation(GeometryOperation.OPERATION_CONTAINS_CODE, drgoc);
540
                        respboolean = ((Boolean) resp).booleanValue();
541
                } catch (Exception e) {
542
                        throw new GeometryOperationException(geom.getType(), GeometryOperation.OPERATION_CONTAINS_CODE, e);
543
                }
544

    
545
                return respboolean;
546
        }
547
        
548

    
549
        /**
550
         * 
551
         * @param geom
552
         * @param x
553
         * @param y
554
         * @param w
555
         * @param h
556
         * @return
557
         */
558
        protected boolean intersectsRectangle(Geometry geom, double x, double y,
559
                        double w, double h) throws GeometryOperationException {
560
                
561
                // exclude disjoint boxes
562
                Envelope env = geom.getEnvelope();
563
                if (x > env.getMaximum(0)) return false; 
564
                if ((x+w) < env.getMinimum(0)) return false; 
565
                if (y > env.getMaximum(1)) return false; 
566
                if ((y+h) < env.getMinimum(1)) return false; 
567
                
568
                // boxes overlap, need long version
569
                Geometry rectgeom = null;
570
                GeneralPathX gpx = new GeneralPathX();
571
                gpx.moveTo(x, y);
572
                gpx.lineTo(x+w, y);
573
                gpx.lineTo(x+w, y+h);
574
                gpx.lineTo(x, y+h);
575
                gpx.lineTo(x, y);
576
                
577
                try {
578
                        rectgeom = GeometryLocator.getGeometryManager().createSurface(gpx, SUBTYPES.GEOM2D);
579
                } catch (Exception e1) {
580
                        throw new GeometryOperationException(geom.getType(), GeometryOperation.OPERATION_INTERSECTS_CODE, e1);
581
                }
582

    
583
                GeometryOperationContext drgoc = new GeometryOperationContext();
584
                drgoc.setAttribute("geom",rectgeom);
585
                
586
                Object resp = null;
587
                boolean respboolean = true;
588
                try {
589
                        resp = geom.invokeOperation(GeometryOperation.OPERATION_INTERSECTS_CODE, drgoc);
590
                        respboolean = ((Boolean) resp).booleanValue();
591
                } catch (Exception e) {
592
                        throw new GeometryOperationException(geom.getType(), GeometryOperation.OPERATION_INTERSECTS_CODE, e);
593
                }
594

    
595
                return respboolean;
596

    
597

    
598
        }
599

    
600
        private com.vividsolutions.jts.geom.Geometry getJTS() {
601
                return Converter.geometryToJts(this);
602
        }
603
        
604
        public byte[] convertToWKB() throws GeometryOperationNotSupportedException,
605
                        GeometryOperationException {
606
                return (byte[]) this.invokeOperation(OPERATIONS.CONVERTTOWKB, null);
607
        }
608

    
609
        public byte[] convertToWKB(int srs) 
610
                throws GeometryOperationNotSupportedException, GeometryOperationException {
611
                int subType = getGeometryType().getSubType();
612
                boolean is3D = subType == 1 || subType == 3;
613
                
614
                WKBWriter write = null;
615
                if(is3D)
616
                        write = new WKBWriter(3);
617
                else
618
                        write = new WKBWriter(2);
619
                return write.write(Converter.geometryToJtsWithSRID(this, srs));
620
        }
621
        
622
        public byte[] convertToWKBForcingType(int srs, int type) 
623
                throws GeometryOperationNotSupportedException, GeometryOperationException {
624
                int subType = getGeometryType().getSubType();
625
                boolean is3D = subType == 1 || subType == 3;
626

    
627
                WKBWriter write = null;
628
                if(is3D)
629
                        write = new WKBWriter(3);
630
                else
631
                        write = new WKBWriter(2);
632
                return write.write(Converter.geometryToJtsWithSRIDForcingType(this, srs, type));
633
        }
634

    
635
        public String convertToWKT() throws GeometryOperationNotSupportedException,
636
                        GeometryOperationException {
637
                return (String) this.invokeOperation(OPERATIONS.CONVERTTOWKT, null);
638
        }
639

    
640
        public Geometry buffer(double distance)
641
                        throws GeometryOperationNotSupportedException,
642
                        GeometryOperationException {
643
                // TODO: this method can be implemented throw invokeOperation 
644
                try {
645
                        return Converter.jtsToGeometry( getJTS().buffer(distance) );
646
                } catch (CreateGeometryException e) {
647
                        throw new GeometryOperationException(e);
648
                }
649
        }
650
        
651
        public boolean contains(Geometry geometry)
652
                        throws GeometryOperationNotSupportedException,
653
                        GeometryOperationException {
654
                // TODO: this method can be implemented throw invokeOperation 
655
                return getJTS().contains(Converter.geometryToJts(geometry));
656
        }
657
        
658
        public double distance(Geometry geometry)
659
                        throws GeometryOperationNotSupportedException,
660
                        GeometryOperationException {
661
                // TODO: this method can be implemented throw invokeOperation 
662
                return getJTS().distance( Converter.geometryToJts(geometry));
663
        }
664
        
665
        public Geometry snapTo(Geometry other, double snapTolerance)
666
                        throws GeometryOperationNotSupportedException,
667
                        GeometryOperationException {
668
                Geometry result = null;
669
                GeometrySnapper snapper = new GeometrySnapper(getJTS());
670
                com.vividsolutions.jts.geom.Geometry jts_result = snapper.snapTo(Converter.geometryToJts(other), snapTolerance);
671
                try {
672
                        result = Converter.jtsToGeometry(jts_result);
673
                } catch (CreateGeometryException e) {
674
                        throw new GeometryOperationException(e);
675
                }
676
                return result;
677
        }
678
        
679
        public boolean isWithinDistance(Geometry other, double distance)
680
                        throws GeometryOperationNotSupportedException,
681
                        GeometryOperationException {
682
                return DistanceOp.isWithinDistance(this.getJTS(), Converter.geometryToJts(other), distance);
683
        }
684
        
685
        
686
        public Geometry[] closestPoints(Geometry other)
687
                        throws GeometryOperationNotSupportedException,
688
                        GeometryOperationException {
689
                Geometry[] points = null;
690

    
691
                Coordinate[] jts_points = DistanceOp.closestPoints(this.getJTS(),
692
                                Converter.geometryToJts(other));
693
                points = new Point[jts_points.length];
694
                GeometryFactory geomFactory = new GeometryFactory();
695
                for (int n = 0; n < jts_points.length; n++) {
696
                        try {
697
                                points[n] = Converter.jtsToGeometry(geomFactory.createPoint(jts_points[n]));
698
                        } catch (CreateGeometryException e) {
699
                                throw new GeometryOperationException(e);
700
                        }
701
                }
702
                return points;
703
        }
704
        
705
        public boolean overlaps(Geometry geometry)
706
                        throws GeometryOperationNotSupportedException,
707
                        GeometryOperationException {
708
                // TODO: this method can be implemented throw invokeOperation 
709
                return getJTS().overlaps(Converter.geometryToJts(geometry));
710
        }
711
        
712
        public Geometry convexHull() throws GeometryOperationNotSupportedException,
713
                        GeometryOperationException {
714
                // TODO: this method can be implemented throw invokeOperation 
715
                try {
716
                        return Converter.jtsToGeometry( getJTS().convexHull() );
717
                } catch (CreateGeometryException e) {
718
                        throw new GeometryOperationException(e);
719
                }
720
        }
721
        
722
        public boolean coveredBy(Geometry geometry)
723
                        throws GeometryOperationNotSupportedException,
724
                        GeometryOperationException {
725
                // TODO: this method can be implemented throw invokeOperation 
726
                return getJTS().coveredBy( Converter.geometryToJts(geometry));
727
        }
728
        
729
        public boolean covers(Geometry geometry)
730
                        throws GeometryOperationNotSupportedException,
731
                        GeometryOperationException {
732
                // TODO: this method can be implemented throw invokeOperation 
733
                return getJTS().covers( Converter.geometryToJts(geometry));
734
        }
735
        
736
        public boolean crosses(Geometry geometry)
737
                        throws GeometryOperationNotSupportedException,
738
                        GeometryOperationException {
739
                // TODO: this method can be implemented throw invokeOperation 
740
                return getJTS().crosses(Converter.geometryToJts(geometry));
741
        }
742
        
743
        public Geometry difference(Geometry other)
744
                        throws GeometryOperationNotSupportedException,
745
                        GeometryOperationException {
746
                // TODO: this method can be implemented throw invokeOperation 
747
                try {
748
                        return Converter.jtsToGeometry( getJTS().difference( Converter.geometryToJts(other)) );
749
                } catch (CreateGeometryException e) {
750
                        throw new GeometryOperationException(e);
751
                }
752
        }
753
        
754
        public Geometry intersection(Geometry other)
755
                        throws GeometryOperationNotSupportedException,
756
                        GeometryOperationException {
757
                // TODO: this method can be implemented throw invokeOperation 
758
                try {
759
                        Geometry geom = null;
760
                        com.vividsolutions.jts.geom.Geometry jtsgeom = getJTS().intersection(Converter.geometryToJts(other));
761
                        if( jtsgeom == null ) {
762
                                return null;
763
                        }
764
                        if( jtsgeom.isEmpty() ) {
765
                                return null;
766
                        }
767
                        geom = Converter.jtsToGeometry( jtsgeom );
768
                        return geom;
769
                } catch (CreateGeometryException e) {
770
                        throw new GeometryOperationException(e);
771
                }
772
        }
773
        
774
        public boolean intersects(Geometry geometry)
775
                        throws GeometryOperationNotSupportedException,
776
                        GeometryOperationException {
777
                // TODO: this method can be implemented throw invokeOperation 
778
            try {
779
                return getJTS().intersects(Converter.geometryToJts(geometry));
780
            } catch (Exception exc) {
781
                /*
782
                 * The JTS library sometimes throws an exception
783
                 * (Example: "TopologyException: side location conflict")
784
                 */
785
                throw new GeometryOperationException(exc);
786
            }
787
                
788
        }
789
        
790
        public boolean touches(Geometry geometry)
791
                        throws GeometryOperationNotSupportedException,
792
                        GeometryOperationException {
793
                // TODO: this method can be implemented throw invokeOperation 
794
                return getJTS().touches(Converter.geometryToJts(geometry));
795
        }
796
        
797
        public Geometry union(Geometry other)
798
                        throws GeometryOperationNotSupportedException,
799
                        GeometryOperationException {
800
                // TODO: this method can be implemented throw invokeOperation 
801
                try {
802
                        return Converter.jtsToGeometry( getJTS().union(Converter.geometryToJts(other)) );
803
                } catch (CreateGeometryException e) {
804
                        throw new GeometryOperationException(e);
805
                }
806
        }
807
        
808
        public boolean disjoint(Geometry geometry)
809
                        throws GeometryOperationNotSupportedException,
810
                        GeometryOperationException {
811
                // TODO: this method can be implemented throw invokeOperation 
812
                return getJTS().disjoint(Converter.geometryToJts(geometry));
813
        }
814
        
815
        public boolean within(Geometry geometry)
816
                        throws GeometryOperationNotSupportedException,
817
                        GeometryOperationException {
818
                // TODO: this method can be implemented throw invokeOperation 
819
                return getJTS().within(Converter.geometryToJts(geometry));
820
        }
821
        
822
        public Point centroid() throws GeometryOperationNotSupportedException, GeometryOperationException {
823
                com.vividsolutions.jts.geom.Geometry geometry = getJTS();
824
                com.vividsolutions.jts.geom.Point point = geometry.getCentroid();
825
                GeometryOperationContext geometryOperationContext = new GeometryOperationContext();
826
                geometryOperationContext.setAttribute("JTSGeometry", point);
827
                return (Point)this.invokeOperation("fromJTS", geometryOperationContext);                
828
        }
829
        
830
           
831
        public Point getInteriorPoint() throws GeometryOperationNotSupportedException, GeometryOperationException {
832
            
833
            try {
834
                com.vividsolutions.jts.geom.Geometry geometry = getJTS();
835
                com.vividsolutions.jts.geom.Point point = geometry.getInteriorPoint();
836
                GeometryOperationContext geometryOperationContext = new GeometryOperationContext();
837
                geometryOperationContext.setAttribute("JTSGeometry", point);
838
                return (Point)this.invokeOperation("fromJTS", geometryOperationContext);
839
        } catch (GeometryOperationNotSupportedException ns_ex) {
840
            throw ns_ex;
841
        } catch (GeometryOperationException op_ex) {
842
            throw op_ex;
843
            } catch (Exception ex) {
844
                /*
845
                 * This is for unexpected null pointer exceptions or other
846
                 */
847
                throw new GeometryOperationException(ex);
848
            }
849
        }   
850

    
851
        
852
        public double area() throws GeometryOperationNotSupportedException, GeometryOperationException
853
    {
854
        //Using get getJTS method instead of use the "toJTS" operation just for performance
855
        return getJTS().getArea();
856
    }
857
    
858
    public double perimeter() throws GeometryOperationNotSupportedException, GeometryOperationException
859
    {
860
      //Using get getJTS method instead of use the "toJTS" operation just for performance
861
        return getJTS().getLength();
862
    }
863

    
864
    public Shape getShape() {
865
        return this;
866
    }  
867
    
868
    public Shape getShape(AffineTransform affineTransform) {
869
        if (affineTransform == null){
870
            return this;
871
        }
872
        GeneralPathX gp = getGeneralPath();
873
        if( gp==null ) {
874
            return null;
875
        }
876
        return new GeneralPathAdapter(affineTransform, gp);
877
    }     
878
    
879
    public void rotate(double radAngle, double basex, double basey) {
880
        
881
        AffineTransform at = new AffineTransform();
882
        at.rotate(radAngle,basex,basey);
883
        this.transform(at);
884
    }
885
    
886
    public void move(double dx, double dy) {
887
        
888
        AffineTransform at = new AffineTransform();
889
        at.translate(dx, dy);
890
        this.transform(at);
891
    }
892
    
893
    public void scale(Point basePoint, double sx, double sy) {
894
        
895
        AffineTransform at = new AffineTransform();
896
        at.setToTranslation(basePoint.getX(),basePoint.getY());
897
        at.scale(sx,sy);
898
        at.translate(-basePoint.getX(),-basePoint.getY());
899
        this.transform(at);
900
    }
901

    
902
    public Geometry makeValid() {
903
        try {
904
            ValidationStatus vs = this.getValidationStatus();
905
            if (vs.isValid()) {
906
                return this;
907
            }
908
            Geometry g = null;
909
            switch (vs.getStatusCode()) {
910
                case Geometry.ValidationStatus.RING_SELF_INTERSECTION:
911
                case Geometry.ValidationStatus.SELF_INTERSECTION:
912
                    g = this.buffer(0);
913
                    if (g.isValid()) {
914
                        return g;
915
                    }
916
                    break;
917
                    
918
                case Geometry.ValidationStatus.TOO_FEW_POINTS:
919
                    if( this instanceof OrientableCurve ) {
920
                        int vertices = ((OrientableCurve)this).getNumVertices();
921
                        if( vertices<2 ) {
922
                            return new DefaultNullGeometry(this.getGeometryType());
923
                        }
924
                    }
925
                    if( this instanceof OrientableSurface ) {
926
                        int vertices = ((OrientableSurface)this).getNumVertices();
927
                        if( vertices<3 ) {
928
                            g = new DefaultNullGeometry(this.getGeometryType());
929
                            return g;
930
                        }
931
                    }
932
            }
933
        } catch (Exception ex) {
934
            return null;
935
        }
936
        return null;
937
    }
938

    
939
}
940

    
941

    
942
/*
943
Testing equality of Geometry objects
944
http://docs.geotools.org/stable/userguide/library/jts/equals.html
945

946
com.vividsolutions.jts.geom
947
Class Geometry
948
http://www.vividsolutions.com/jts/javadoc/com/vividsolutions/jts/geom/Geometry.html#normalize%28%29
949
*/