Statistics
| Revision:

gvsig-vectorediting / org.gvsig.vectorediting / trunk / org.gvsig.vectorediting / org.gvsig.vectorediting.lib / org.gvsig.vectorediting.lib.prov / org.gvsig.vectorediting.lib.prov.extendline / src / main / java / org / gvsig / vectorediting / lib / prov / extendline / operation / ExtendLineOperationUtils.java @ 2204

History | View | Annotate | Download (24.4 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright ? 2007-2015 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 2
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.vectorediting.lib.prov.extendline.operation;
25

    
26
import java.util.HashMap;
27
import java.util.Map;
28
import org.gvsig.fmap.dal.exception.DataException;
29
import org.gvsig.fmap.dal.feature.Feature;
30
import org.gvsig.fmap.dal.feature.FeatureSelection;
31
import org.gvsig.fmap.geom.Geometry;
32
import org.gvsig.fmap.geom.Geometry.TYPES;
33
import org.gvsig.fmap.geom.GeometryLocator;
34
import org.gvsig.fmap.geom.GeometryManager;
35
import org.gvsig.fmap.geom.aggregate.MultiPoint;
36
import org.gvsig.fmap.geom.exception.CreateGeometryException;
37
import org.gvsig.fmap.geom.operation.GeometryOperationException;
38
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
39
import org.gvsig.fmap.geom.primitive.Arc;
40
import org.gvsig.fmap.geom.primitive.Curve;
41
import org.gvsig.fmap.geom.primitive.Point;
42
import org.gvsig.fmap.geom.primitive.Primitive;
43
import org.gvsig.tools.dispose.DisposableIterator;
44

    
45
/**
46
 * @author llmarques
47
 *
48
 */
49
public class ExtendLineOperationUtils {
50

    
51
    /**
52
     * Use it to indicate start side should be extended
53
     */
54
    public static final String START_SIDE = "start";
55

    
56
    /**
57
     * Use it to indicate end side should be extended
58
     */
59
    public static final String END_SIDE = "end";
60

    
61
    /**
62
     * Number of projections computed to know intersection points.
63
     */
64
    private final static int PROJECTION_LIMIT = 100;
65

    
66
    private static Map<Integer, ExtendLineOperation> operations
67
            = new HashMap<Integer, ExtendLineOperation>();
68

    
69
    public ExtendLineOperationUtils() {
70
    }
71

    
72
    public static void register(ExtendLineOperation operation, int geometryType) {
73
        operations.put(geometryType, operation);
74
    }
75

    
76
    public static ExtendLineOperation getOperation(Primitive geom) {
77
        Integer type = geom.getGeometryType().getType();
78

    
79
        ExtendLineOperation operation = operations.get(type);
80

    
81
        return operation;
82
    }
83

    
84
    /**
85
     * Calculates the nearest intersection among curve and boundary objects
86
     * depending on side received as parameter.
87
     *
88
     * @param line to be extended
89
     * @param sideToExtend What side will be extend. Use
90
     * {@link ExtendLineOperationUtils#START_SIDE} and
91
     * {@link ExtendLineOperationUtils#END_SIDE}
92
     * @param boundaryObjects to calculate intersection points.
93
     * @return the nearest intersection point. Return Null if arc does not
94
     * intersect with any boundary object
95
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
96
     * @throws org.gvsig.fmap.dal.exception.DataException
97
     * @throws
98
     * org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException
99
     * @throws org.gvsig.fmap.geom.operation.GeometryOperationException
100
     */
101
    public static Point curveIntersection(Curve line, String sideToExtend,
102
            FeatureSelection boundaryObjects) throws CreateGeometryException,
103
            DataException, GeometryOperationNotSupportedException,
104
            GeometryOperationException {
105

    
106
        Point initPoint = getExtremeSegmentInitPoint(line, sideToExtend);
107
        Point endPoint = getExtremeSegmentEndPoint(line, sideToExtend);
108

    
109
        return getIntersectionOfProjectedLine(initPoint, endPoint,
110
                boundaryObjects);
111
    }
112

    
113
    /**
114
     * Calculates the nearest intersection among curve and boundary objects
115
     * depending on side received as parameter.
116
     *
117
     * @param line to be extended
118
     * @param sideToExtend What side will be extend. Use
119
     * {@link ExtendLineOperationUtils#START_SIDE} and
120
     * {@link ExtendLineOperationUtils#END_SIDE}
121
     * @param boundaryObject to calculate intersection points.
122
     * @return the nearest intersection point. Return Null if arc does not
123
     * intersect with any boundary object
124
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
125
     * @throws org.gvsig.fmap.dal.exception.DataException
126
     * @throws
127
     * org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException
128
     * @throws org.gvsig.fmap.geom.operation.GeometryOperationException
129
     */
130
    public static Point curveIntersection(Curve line, String sideToExtend,
131
            Geometry boundaryObject) throws CreateGeometryException,
132
            DataException, GeometryOperationNotSupportedException,
133
            GeometryOperationException {
134

    
135
        Point initPoint = getExtremeSegmentInitPoint(line, sideToExtend);
136
        Point endPoint = getExtremeSegmentEndPoint(line, sideToExtend);
137

    
138
        return getIntersectionOfProjectedLine(initPoint, endPoint,
139
                boundaryObject);
140
    }
141

    
142
    private static Point getExtremeSegmentEndPoint(Curve line, String sideToExtend) {
143
        // Start side line is formed by second point and first point
144
        if (sideToExtend.equalsIgnoreCase(START_SIDE)) {
145
            return line.getVertex(0);
146
            // End side line is formed by penultimate point and last point
147
        } else if (sideToExtend.equalsIgnoreCase(END_SIDE)) {
148
            return line.getVertex(line.getNumVertices() - 1);
149
        }
150
        return null;
151
    }
152

    
153
    private static Point getExtremeSegmentInitPoint(Curve line, String sideToExtend) {
154
        // Start side line is formed by second point and first point
155
        if (sideToExtend.equalsIgnoreCase(START_SIDE)) {
156
            return line.getVertex(1);
157
            // End side line is formed by penultimate point and last point
158
        } else if (sideToExtend.equalsIgnoreCase(END_SIDE)) {
159
            return line.getVertex(line.getNumVertices() - 2);
160
        }
161
        return null;
162
    }
163

    
164
    /**
165
     * Calculates the nearest intersection point among arc and boundary objects
166
     * depending on side received as parameter.Strategy:
167
     *
168
     * 1- Create a full arc with the same center and radius of arc received by
169
     * parameter.2- Iterate over boundary objects.3- If some boundary object
170
     * intersects with full arc, calculates the distance to start point or end
171
     * point depending on side to be extend.4- Return the nearest intersection
172
     * point.
173
     *
174
     *
175
     * @param arcToBeExtended Arc to be extended
176
     * @param sideToExtend What side will be extend. Use
177
     * {@link ExtendLineOperationUtils#START_SIDE} and
178
     * {@link ExtendLineOperationUtils#END_SIDE}
179
     * @param boundaryObjects to calculate intersection points.
180
     * @return the nearest intersection point. Return Null if arc does not
181
     * intersect with any boundary object
182
     * @throws
183
     * org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException
184
     * @throws org.gvsig.fmap.geom.operation.GeometryOperationException
185
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
186
     * @throws org.gvsig.fmap.dal.exception.DataException
187
     */
188
    public static Point arcIntersection(Arc arcToBeExtended,
189
            String sideToExtend, FeatureSelection boundaryObjects)
190
            throws GeometryOperationNotSupportedException,
191
            GeometryOperationException, CreateGeometryException, DataException {
192

    
193
        GeometryManager geoManager = GeometryLocator.getGeometryManager();
194
        int subtype = arcToBeExtended.getGeometryType().getSubType();
195

    
196
        Point center = arcToBeExtended.getCenterPoint();
197
        double radius = center.distance(arcToBeExtended.getInitPoint());
198

    
199
        Point intersection = null;
200

    
201
        double minDistance = Double.POSITIVE_INFINITY;
202

    
203
        Arc tmpArc = (Arc) geoManager.create(TYPES.ARC, subtype);
204
        tmpArc.setPoints(center, radius, 0, Math.PI * 2);
205

    
206
        DisposableIterator it = boundaryObjects.fastIterator();
207
        while (it.hasNext()) {
208
            Feature feature = (Feature) it.next();
209
            Geometry geometry = feature.getDefaultGeometry();
210
            if (tmpArc.intersects(geometry)) {
211
                Geometry intersectionGeometry = tmpArc.intersection(geometry);
212

    
213
                if (intersectionGeometry instanceof MultiPoint) {
214
                    MultiPoint intersectionMultiPoint
215
                            = (MultiPoint) intersectionGeometry;
216

    
217
                    for (int i = 0; i < intersectionMultiPoint
218
                            .getPrimitivesNumber(); i++) {
219
                        Point point = intersectionMultiPoint.getPointAt(i);
220
                        double distance = Double.POSITIVE_INFINITY;
221

    
222
                        if (sideToExtend.equalsIgnoreCase(START_SIDE)) {
223
                            distance
224
                                    = point.distance(arcToBeExtended.getInitPoint());
225
                        } else if (sideToExtend.equalsIgnoreCase(END_SIDE)) {
226
                            distance
227
                                    = point.distance(arcToBeExtended.getEndPoint());
228
                        }
229

    
230
                        if (distance < minDistance) {
231
                            intersection = point;
232
                            minDistance = distance;
233
                        }
234
                    }
235
                } else if (intersectionGeometry instanceof Point) {
236
                    Point intersectionPoint = (Point) intersectionGeometry;
237
                    double distance = Double.POSITIVE_INFINITY;
238

    
239
                    if (sideToExtend.equalsIgnoreCase("start")) {
240
                        distance
241
                                = intersectionPoint.distance(arcToBeExtended
242
                                        .getInitPoint());
243
                    } else if (sideToExtend.equalsIgnoreCase("end")) {
244
                        distance
245
                                = intersectionPoint.distance(arcToBeExtended
246
                                        .getEndPoint());
247
                    }
248

    
249
                    if (distance < minDistance) {
250
                        intersection = intersectionPoint;
251
                        minDistance = distance;
252
                    }
253
                }
254
            }
255
        }
256
        it.dispose();
257
        return intersection;
258
    }
259

    
260
    /**
261
     * Calculates the nearest intersection point among arc and boundary objects
262
     * depending on side received as parameter.Strategy:
263
     *
264
     * 1- Create a full arc with the same center and radius of arc received by
265
     * parameter.2- Iterate over boundary objects.3- If some boundary object
266
     * intersects with full arc, calculates the distance to start point or end
267
     * point depending on side to be extend.4- Return the nearest intersection
268
     * point.
269
     *
270
     *
271
     * @param arcToBeExtended Arc to be extended
272
     * @param sideToExtend What side will be extend. Use
273
     * {@link ExtendLineOperationUtils#START_SIDE} and
274
     * {@link ExtendLineOperationUtils#END_SIDE}
275
     * @param boundaryObject to calculate intersection points.
276
     * @return the nearest intersection point. Return Null if arc does not
277
     * intersect with any boundary object
278
     * @throws
279
     * org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException
280
     * @throws org.gvsig.fmap.geom.operation.GeometryOperationException
281
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
282
     * @throws org.gvsig.fmap.dal.exception.DataException
283
     */
284
    public static Point arcIntersection(Arc arcToBeExtended,
285
            String sideToExtend, Geometry boundaryObject)
286
            throws GeometryOperationNotSupportedException,
287
            GeometryOperationException, CreateGeometryException, DataException {
288

    
289
        GeometryManager geoManager = GeometryLocator.getGeometryManager();
290
        int subtype = arcToBeExtended.getGeometryType().getSubType();
291

    
292
        Point center = arcToBeExtended.getCenterPoint();
293
        double radius = center.distance(arcToBeExtended.getInitPoint());
294

    
295
        Point intersection = null;
296

    
297
//        double minDistance = Double.POSITIVE_INFINITY;
298

    
299
        Arc tmpArc = (Arc) geoManager.create(TYPES.ARC, subtype);
300
        tmpArc.setPoints(center, radius, 0, Math.PI * 2);
301

    
302
        double distance = Double.POSITIVE_INFINITY;
303
        double minDistance = Double.POSITIVE_INFINITY;
304
        if (tmpArc.intersects(boundaryObject)) {
305
            Geometry intersectionGeometry = tmpArc.intersection(boundaryObject);
306

    
307
            if (intersectionGeometry instanceof MultiPoint) {
308
                MultiPoint intersectionMultiPoint
309
                        = (MultiPoint) intersectionGeometry;
310

    
311
                for (int i = 0; i < intersectionMultiPoint
312
                        .getPrimitivesNumber(); i++) {
313
                    Point point = intersectionMultiPoint.getPointAt(i);
314

    
315
                    if (sideToExtend.equalsIgnoreCase(START_SIDE)) {
316
                        distance
317
                                = point.distance(arcToBeExtended.getInitPoint());
318
                    } else if (sideToExtend.equalsIgnoreCase(END_SIDE)) {
319
                        distance
320
                                = point.distance(arcToBeExtended.getEndPoint());
321
                    }
322

    
323
                    if (distance < minDistance) {
324
                        intersection = point;
325
                        minDistance = distance;
326
                    }
327
                }
328
            } else if (intersectionGeometry instanceof Point) {
329
                Point intersectionPoint = (Point) intersectionGeometry;
330

    
331
                intersection = intersectionPoint;
332
            }
333
        }
334
        return intersection;
335
    }
336

    
337
    // FIXME: remove this method when geometry library has this utility method
338
    public static double getAngle(Point start, Point end)
339
            throws GeometryOperationNotSupportedException,
340
            GeometryOperationException {
341
        double angle
342
                = Math.acos((end.getX() - start.getX()) / start.distance(end));
343

    
344
        if (start.getY() > end.getY()) {
345
            angle = -angle;
346
        }
347

    
348
        if (angle < 0) {
349
            angle += (2 * Math.PI);
350
        }
351

    
352
        return angle;
353
    }
354

    
355
    /**
356
     * Gets intersection among the line formed by initPoint and endPoint and
357
     * boundary objects.If line or its projection does not intersect with any
358
     * boundary object return null.Strategy:
359
     *
360
     * 1- Get module of line to determine if an intersection point already be
361
     * vertex of line.If the distance between intersection point and start point
362
     * of line is less than module indicates that intersection point already be
363
     * curve point.2- Project line with the line parametric equation. 3- Iterate
364
     * over boundary objects. 4- Check if boundary object does not contains end
365
     * point of projected line. 5- If projected line intersects with any
366
     * boundary object, get the nearest intersection point 6- Return it.
367
     *
368
     *
369
     * @param initPoint of curve to extend
370
     * @param endPoint end point of curve to extend
371
     * @param boundaryObjects to calculate intersection points.
372
     * @return the nearest intersection point. Return Null if arc does not
373
     * intersect with any boundary object
374
     * @throws
375
     * org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException
376
     * @throws org.gvsig.fmap.geom.operation.GeometryOperationException
377
     * @throws org.gvsig.fmap.dal.exception.DataException
378
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
379
     */
380
    public static Point getIntersectionOfProjectedLine(Point initPoint,
381
            Point endPoint, FeatureSelection boundaryObjects)
382
            throws GeometryOperationNotSupportedException,
383
            GeometryOperationException, DataException, CreateGeometryException {
384

    
385
        GeometryManager geoManager = GeometryLocator.getGeometryManager();
386
        int subtype = initPoint.getGeometryType().getSubType();
387

    
388
        double module = initPoint.distance(endPoint);
389

    
390
        double minDistance = Double.POSITIVE_INFINITY;
391
        Point intersectionPoint = null;
392

    
393
        double x, y;
394
        double x1 = initPoint.getX();
395
        double y1 = initPoint.getY();
396
        double x2 = endPoint.getX();
397
        double y2 = endPoint.getY();
398

    
399
        for (int t = 1; t < PROJECTION_LIMIT; t += 10) {
400
            x = (x2 - x1) * t + x1;
401
            y = (y2 - y1) * t + y1;
402

    
403
            DisposableIterator it = boundaryObjects.fastIterator();
404
            while (it.hasNext()) {
405
                Feature feature = (Feature) it.next();
406
                Geometry geometry = feature.getDefaultGeometry();
407
                Point projectedPoint = geoManager.createPoint(x, y, subtype);
408

    
409
                if (!geometry.contains(projectedPoint)) {
410
                    Curve tmpLine = geoManager.createLine(subtype);
411
                    tmpLine.setPoints(initPoint, projectedPoint);
412

    
413
                    if (tmpLine.intersects(geometry)) {
414

    
415
                        Geometry intersecionGeometry
416
                                = geometry.intersection(tmpLine);
417

    
418
                        if (intersecionGeometry instanceof Point) {
419

    
420
                            double distance
421
                                    = ((Point) intersecionGeometry)
422
                                            .distance(initPoint);
423

    
424
                            if (distance < minDistance && distance > (module + 0.01)) {
425
                                intersectionPoint = (Point) intersecionGeometry;
426
                                minDistance = distance;
427
                            }
428

    
429
                        } else if (intersecionGeometry instanceof MultiPoint) {
430

    
431
                            MultiPoint intersectionMultiPoint
432
                                    = (MultiPoint) intersecionGeometry;
433

    
434
                            for (int i = 0; i < intersectionMultiPoint
435
                                    .getPrimitivesNumber(); i++) {
436

    
437
                                double distance
438
                                        = intersectionMultiPoint.getPointAt(i)
439
                                                .distance(initPoint);
440

    
441
                                if (distance < minDistance && distance > (module + 0.01)) {
442
                                    intersectionPoint
443
                                            = intersectionMultiPoint.getPointAt(i);
444
                                    minDistance = distance;
445
                                }
446
                            }
447
                        } else if (intersecionGeometry instanceof Curve) {
448

    
449
                            Curve intersectionCurve
450
                                    = (Curve) intersecionGeometry;
451

    
452
                            for (int i = 0; i < intersectionCurve
453
                                    .getNumVertices(); i++) {
454

    
455
                                double distance
456
                                        = intersectionCurve.getVertex(i).distance(
457
                                                endPoint);
458

    
459
                                if (distance < minDistance && distance > (module + 0.01)) {
460
                                    intersectionPoint
461
                                            = intersectionCurve.getVertex(i);
462
                                    minDistance = distance;
463
                                }
464
                            }
465
                        }
466
                    }
467
                }
468
            }
469
            it.dispose();
470
            if (intersectionPoint != null) {
471
                break;
472
            }
473
        }
474
        return intersectionPoint;
475
    }
476

    
477
    /**
478
     * Gets intersection among the line formed by initPoint and endPoint and
479
     * boundary object.If line or its projection does not intersect with
480
     * boundary object return null.Strategy:
481
     *
482
     * 1- Get module of line to determine if an intersection point already be
483
     * vertex of line.If the distance between intersection point and start point
484
     * of line is less than module indicates that intersection point already be
485
     * curve point.2- Project line with the line parametric equation. 3- Check
486
     * if boundary object does not contains end point of projected line. 5- If
487
     * projected line intersects with boundary object, get the nearest
488
     * intersection point 6- Return it.
489
     *
490
     *
491
     * @param initPoint of curve to extend
492
     * @param endPoint end point of curve to extend
493
     * @param boundaryObject to calculate intersection points.
494
     * @return the nearest intersection point. Return Null if arc does not
495
     * intersect with any boundary object
496
     * @throws
497
     * org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException
498
     * @throws org.gvsig.fmap.geom.operation.GeometryOperationException
499
     * @throws org.gvsig.fmap.dal.exception.DataException
500
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
501
     */
502
    public static Point getIntersectionOfProjectedLine(Point initPoint,
503
            Point endPoint, Geometry boundaryObject)
504
            throws GeometryOperationNotSupportedException,
505
            GeometryOperationException, DataException, CreateGeometryException {
506

    
507
        GeometryManager geoManager = GeometryLocator.getGeometryManager();
508
        int subtype = initPoint.getGeometryType().getSubType();
509

    
510
        double module = initPoint.distance(endPoint);
511

    
512
        double minDistance = Double.POSITIVE_INFINITY;
513
        Point intersectionPoint = null;
514

    
515
        double x, y;
516
        double x1 = initPoint.getX();
517
        double y1 = initPoint.getY();
518
        double x2 = endPoint.getX();
519
        double y2 = endPoint.getY();
520

    
521
        for (int t = 1; t < PROJECTION_LIMIT; t += 10) {
522
            x = (x2 - x1) * t + x1;
523
            y = (y2 - y1) * t + y1;
524

    
525
            Point projectedPoint = geoManager.createPoint(x, y, subtype);
526

    
527
            if (!boundaryObject.contains(projectedPoint)) {
528
                Curve tmpLine = geoManager.createLine(subtype);
529
                tmpLine.setPoints(initPoint, projectedPoint);
530

    
531
                if (tmpLine.intersects(boundaryObject)) {
532

    
533
                    Geometry intersecionGeometry
534
                            = boundaryObject.intersection(tmpLine);
535

    
536
                    if (intersecionGeometry instanceof Point) {
537

    
538
                        double distance
539
                                = ((Point) intersecionGeometry)
540
                                        .distance(initPoint);
541

    
542
                        if (distance < minDistance && distance > (module + 0.01)) {
543
                            intersectionPoint = (Point) intersecionGeometry;
544
                            minDistance = distance;
545
                        }
546

    
547
                    } else if (intersecionGeometry instanceof MultiPoint) {
548

    
549
                        MultiPoint intersectionMultiPoint
550
                                = (MultiPoint) intersecionGeometry;
551

    
552
                        for (int i = 0; i < intersectionMultiPoint
553
                                .getPrimitivesNumber(); i++) {
554

    
555
                            double distance
556
                                    = intersectionMultiPoint.getPointAt(i)
557
                                            .distance(initPoint);
558

    
559
                            if (distance < minDistance && distance > (module + 0.01)) {
560
                                intersectionPoint
561
                                        = intersectionMultiPoint.getPointAt(i);
562
                                minDistance = distance;
563
                            }
564
                        }
565
                    } else if (intersecionGeometry instanceof Curve) {
566

    
567
                        Curve intersectionCurve
568
                                = (Curve) intersecionGeometry;
569

    
570
                        for (int i = 0; i < intersectionCurve
571
                                .getNumVertices(); i++) {
572

    
573
                            double distance
574
                                    = intersectionCurve.getVertex(i).distance(
575
                                            endPoint);
576

    
577
                            if (distance < minDistance && distance > (module + 0.01)) {
578
                                intersectionPoint
579
                                        = intersectionCurve.getVertex(i);
580
                                minDistance = distance;
581
                            }
582
                        }
583
                    }
584
                }
585
            }
586
            if (intersectionPoint != null) {
587
                break;
588
            }
589
        }
590
        return intersectionPoint;
591
    }
592

    
593
}