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 @ 325

History | View | Annotate | Download (13.8 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

    
25
package org.gvsig.vectorediting.lib.prov.extendline.operation;
26

    
27
import java.util.HashMap;
28
import java.util.Map;
29

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

    
47
/**
48
 * @author llmarques
49
 *
50
 */
51
public class ExtendLineOperationUtils {
52

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

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

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

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

    
71
    public ExtendLineOperationUtils() {
72
    }
73

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

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

    
81
        ExtendLineOperation operation = operations.get(type);
82

    
83
        return operation;
84
    }
85

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

    
107
        Point initPoint = null;
108
        Point endPoint = null;
109

    
110
        // Start side line is formed by second point and first point
111
        if (sideToExtend.equalsIgnoreCase(START_SIDE)) {
112

    
113
            initPoint = line.getVertex(1);
114
            endPoint = line.getVertex(0);
115

    
116
            // End side line is formed by penultimate point and last point
117
        } else if (sideToExtend.equalsIgnoreCase(END_SIDE)) {
118

    
119
            initPoint = line.getVertex(line.getNumVertices() - 2);
120
            endPoint = line.getVertex(line.getNumVertices() - 1);
121

    
122
        }
123

    
124
        return getIntersectionOfProjectedLine(initPoint, endPoint,
125
            boundaryObjects);
126
    }
127

    
128
    /**
129
     * Calculates the nearest intersection point among arc and boundary objects
130
     * depending on side received as parameter.
131
     * 
132
     * Strategy:
133
     * 
134
     * 1- Create a full arc with the same center and radius of arc received by
135
     * parameter.
136
     * 2- Iterate over boundary objects.
137
     * 3- If some boundary object intersects with full arc, calculates the
138
     * distance to start point or end point depending on side to be extend.
139
     * 4- Return the nearest intersection point.
140
     * 
141
     * @param arcToBeExtended
142
     *            Arc to be extended
143
     * @param sideToExtend
144
     *            What side will be extend. Use
145
     *            {@link ExtendLineOperationUtils#START_SIDE} and
146
     *            {@link ExtendLineOperationUtils#END_SIDE}
147
     * @param boundaryObjects
148
     *            to calculate intersection points.
149
     * @return the nearest intersection point. Return Null if arc does not
150
     *         intersect with any boundary object
151
     */
152
    public static Point arcIntersection(Arc arcToBeExtended,
153
        String sideToExtend, FeatureSelection boundaryObjects)
154
        throws GeometryOperationNotSupportedException,
155
        GeometryOperationException, CreateGeometryException, DataException {
156

    
157
        GeometryManager geoManager = GeometryLocator.getGeometryManager();
158
        int subtype = arcToBeExtended.getGeometryType().getSubType();
159

    
160
        Point center = arcToBeExtended.getCenterPoint();
161
        double radius = center.distance(arcToBeExtended.getInitPoint());
162

    
163
        Point intersection = null;
164

    
165
        double minDistance = Double.POSITIVE_INFINITY;
166

    
167
        Arc tmpArc = (Arc) geoManager.create(TYPES.ARC, subtype);
168
        tmpArc.setPoints(center, radius, 0, Math.PI * 2);
169

    
170
        DisposableIterator it = boundaryObjects.fastIterator();
171
        while (it.hasNext()) {
172
            Feature feature = (Feature) it.next();
173
            Geometry geometry = feature.getDefaultGeometry();
174
            if (tmpArc.intersects(geometry)) {
175
                Geometry intersectionGeometry = tmpArc.intersection(geometry);
176

    
177
                if (intersectionGeometry instanceof MultiPoint) {
178
                    MultiPoint intersectionMultiPoint =
179
                        (MultiPoint) intersectionGeometry;
180

    
181
                    for (int i = 0; i < intersectionMultiPoint
182
                        .getPrimitivesNumber(); i++) {
183
                        Point point = intersectionMultiPoint.getPointAt(i);
184
                        double distance = Double.POSITIVE_INFINITY;
185

    
186
                        if (sideToExtend.equalsIgnoreCase(START_SIDE)) {
187
                            distance =
188
                                point.distance(arcToBeExtended.getInitPoint());
189
                        } else if (sideToExtend.equalsIgnoreCase(END_SIDE)) {
190
                            distance =
191
                                point.distance(arcToBeExtended.getEndPoint());
192
                        }
193

    
194
                        if (distance < minDistance) {
195
                            intersection = point;
196
                            minDistance = distance;
197
                        }
198
                    }
199
                } else if (intersectionGeometry instanceof Point) {
200
                    Point intersectionPoint = (Point) intersectionGeometry;
201
                    double distance = Double.POSITIVE_INFINITY;
202

    
203
                    if (sideToExtend.equalsIgnoreCase("start")) {
204
                        distance =
205
                            intersectionPoint.distance(arcToBeExtended
206
                                .getInitPoint());
207
                    } else if (sideToExtend.equalsIgnoreCase("end")) {
208
                        distance =
209
                            intersectionPoint.distance(arcToBeExtended
210
                                .getEndPoint());
211
                    }
212

    
213
                    if (distance < minDistance) {
214
                        intersection = intersectionPoint;
215
                        minDistance = distance;
216
                    }
217
                }
218
            }
219
        }
220
        it.dispose();
221
        return intersection;
222
    }
223

    
224
    // FIXME: remove this method when geometry library has this utility method
225
    public static double getAngle(Point start, Point end)
226
        throws GeometryOperationNotSupportedException,
227
        GeometryOperationException {
228
        double angle =
229
            Math.acos((end.getX() - start.getX()) / start.distance(end));
230

    
231
        if (start.getY() > end.getY()) {
232
            angle = -angle;
233
        }
234

    
235
        if (angle < 0) {
236
            angle += (2 * Math.PI);
237
        }
238

    
239
        return angle;
240
    }
241

    
242
    /**
243
     * Gets intersection among the line formed by initPoint and endPoint and
244
     * boundary objects. If line or its projection does not intersect with any
245
     * boundary object return null.
246
     * 
247
     * Strategy:
248
     * 
249
     * 1- Get module of line to determine if an intersection point already be
250
     * vertex of line. If the distance between intersection point and start
251
     * point of line is less than module indicates that intersection point
252
     * already be curve point.
253
     * 2- Project line with the line parametric equation.
254
     * 3- Iterate over boundary objects.
255
     * 4- Check if boundary object does not contains end point of projected
256
     * line.
257
     * 5- If projected line intersects with any boundary object, get the nearest
258
     * intersection point
259
     * 6- Return it.
260
     * 
261
     * 
262
     * @param initPoint
263
     *            of curve to extend
264
     * @param endPoint
265
     *            end point of curve to extend
266
     * @param boundaryObjects
267
     *            to calculate intersection points.
268
     * @return the nearest intersection point. Return Null if arc does not
269
     *         intersect with any boundary object
270
     */
271
    public static Point getIntersectionOfProjectedLine(Point initPoint,
272
        Point endPoint, FeatureSelection boundaryObjects)
273
        throws GeometryOperationNotSupportedException,
274
        GeometryOperationException, DataException, CreateGeometryException {
275

    
276
        GeometryManager geoManager = GeometryLocator.getGeometryManager();
277
        int subtype = initPoint.getGeometryType().getSubType();
278

    
279
        double module = initPoint.distance(endPoint);
280

    
281
        double minDistance = Double.POSITIVE_INFINITY;
282
        Point intersectionPoint = null;
283

    
284
        double x, y;
285
        double x1 = initPoint.getX();
286
        double y1 = initPoint.getY();
287
        double x2 = endPoint.getX();
288
        double y2 = endPoint.getY();
289

    
290
        for (int t = 1; t < PROJECTION_LIMIT; t += 10) {
291
            x = (x2 - x1) * t + x1;
292
            y = (y2 - y1) * t + y1;
293

    
294
            DisposableIterator it = boundaryObjects.fastIterator();
295
            while (it.hasNext()) {
296
                Feature feature = (Feature) it.next();
297
                Geometry geometry = feature.getDefaultGeometry();
298
                Point projectedPoint = geoManager.createPoint(x, y, subtype);
299

    
300
                if (!geometry.contains(projectedPoint)) {
301
                    Curve tmpLine = geoManager.createLine(subtype);
302
                    tmpLine.setPoints(initPoint, projectedPoint);
303

    
304
                    if (tmpLine.intersects(geometry)) {
305

    
306
                        Geometry intersecionGeometry =
307
                            geometry.intersection(tmpLine);
308

    
309
                        if (intersecionGeometry instanceof Point) {
310

    
311
                            double distance =
312
                                ((Point) intersecionGeometry)
313
                                    .distance(initPoint);
314

    
315
                            if (distance < minDistance && distance > module) {
316
                                intersectionPoint = (Point) intersecionGeometry;
317
                                minDistance = distance;
318
                            }
319

    
320
                        } else if (intersecionGeometry instanceof MultiPoint) {
321

    
322
                            MultiPoint intersectionMultiPoint =
323
                                (MultiPoint) intersecionGeometry;
324

    
325
                            for (int i = 0; i < intersectionMultiPoint
326
                                .getPrimitivesNumber(); i++) {
327

    
328
                                double distance =
329
                                    intersectionMultiPoint.getPointAt(i)
330
                                        .distance(initPoint);
331

    
332
                                if (distance < minDistance && distance > module) {
333
                                    intersectionPoint =
334
                                        intersectionMultiPoint.getPointAt(i);
335
                                    minDistance = distance;
336
                                }
337
                            }
338
                        } else if (intersecionGeometry instanceof Curve) {
339

    
340
                            Curve intersectionCurve =
341
                                (Curve) intersecionGeometry;
342

    
343
                            for (int i = 0; i < intersectionCurve
344
                                .getNumVertices(); i++) {
345

    
346
                                double distance =
347
                                    intersectionCurve.getVertex(i).distance(
348
                                        initPoint);
349

    
350
                                if (distance < minDistance && distance > module) {
351
                                    intersectionPoint =
352
                                        intersectionCurve.getVertex(i);
353
                                    minDistance = distance;
354
                                }
355
                            }
356
                        }
357
                    }
358
                }
359
            }
360
            it.dispose();
361
            if (intersectionPoint != null) {
362
                break;
363
            }
364
        }
365
        return intersectionPoint;
366
    }
367
}