Statistics
| Revision:

gvsig-lrs / org.gvsig.lrs / trunk / org.gvsig.lrs / org.gvsig.lrs.lib / org.gvsig.lrs.lib.impl / src / main / java / org / gvsig / lrs / lib / impl / LrsCreateRouteAlgorithm.java @ 51

History | View | Annotate | Download (51.4 KB)

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

    
25
import java.util.ArrayList;
26
import java.util.Collections;
27
import java.util.Iterator;
28
import java.util.List;
29
import java.util.Map.Entry;
30
import java.util.SortedMap;
31
import java.util.TreeMap;
32

    
33
import org.apache.commons.lang3.mutable.MutableInt;
34
import org.slf4j.Logger;
35
import org.slf4j.LoggerFactory;
36

    
37
import org.gvsig.fmap.dal.feature.EditableFeature;
38
import org.gvsig.fmap.dal.feature.Feature;
39
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
40
import org.gvsig.fmap.dal.feature.FeatureSet;
41
import org.gvsig.fmap.dal.feature.FeatureStore;
42
import org.gvsig.fmap.dal.feature.NewFeatureStoreParameters;
43
import org.gvsig.fmap.geom.Geometry;
44
import org.gvsig.fmap.geom.Geometry.DIMENSIONS;
45
import org.gvsig.fmap.geom.GeometryLocator;
46
import org.gvsig.fmap.geom.GeometryManager;
47
import org.gvsig.fmap.geom.aggregate.MultiLine;
48
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
49
import org.gvsig.fmap.geom.exception.CreateGeometryException;
50
import org.gvsig.fmap.geom.operation.GeometryOperationException;
51
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
52
import org.gvsig.fmap.geom.primitive.Envelope;
53
import org.gvsig.fmap.geom.primitive.Line;
54
import org.gvsig.fmap.geom.primitive.Point;
55
import org.gvsig.lrs.lib.api.LrsAlgorithm;
56
import org.gvsig.lrs.lib.api.LrsAlgorithmParams;
57
import org.gvsig.lrs.lib.api.LrsCoordinatesPriority;
58
import org.gvsig.lrs.lib.api.LrsCreateRouteAlgorithmParams;
59
import org.gvsig.lrs.lib.api.LrsSourceOfMeasures;
60
import org.gvsig.lrs.lib.api.exceptions.LrsCreateRouteException;
61
import org.gvsig.lrs.lib.api.exceptions.LrsException;
62
import org.gvsig.tools.ToolsLocator;
63
import org.gvsig.tools.dataTypes.DataType;
64
import org.gvsig.tools.exception.BaseException;
65
import org.gvsig.tools.i18n.I18nManager;
66
import org.gvsig.tools.locator.LocatorException;
67
import org.gvsig.tools.service.Manager;
68
import org.gvsig.tools.task.SimpleTaskStatus;
69
import org.gvsig.tools.visitor.VisitCanceledException;
70
import org.gvsig.tools.visitor.Visitor;
71

    
72
/**
73
 * @author fdiaz
74
 *
75
 */
76
public class LrsCreateRouteAlgorithm implements LrsAlgorithm {
77

    
78
    private static final Logger logger = LoggerFactory.getLogger(LrsCreateRouteAlgorithm.class);
79

    
80
    private LrsCreateRouteAlgorithmParams parameters;
81

    
82
    /**
83
     *
84
     */
85
    public LrsCreateRouteAlgorithm(LrsCreateRouteAlgorithmParams parameters) {
86
        this.parameters = parameters;
87

    
88
    }
89

    
90
    /*
91
     * (non-Javadoc)
92
     *
93
     * @see org.gvsig.tools.service.Service#getManager()
94
     */
95
    public Manager getManager() {
96
        return null;
97
    }
98

    
99
    /*
100
     * (non-Javadoc)
101
     *
102
     * @see org.gvsig.lrs.lib.api.LrsAlgorithm#getParams()
103
     */
104
    public LrsAlgorithmParams getParams() {
105
        return this.parameters;
106
    }
107

    
108
    /*
109
     * (non-Javadoc)
110
     *
111
     * @see org.gvsig.lrs.lib.api.LrsAlgorithm#execute(org.gvsig.tools.task.
112
     * SimpleTaskStatus)
113
     */
114
    public void execute(SimpleTaskStatus taskStatus) throws LrsException {
115
        NewFeatureStoreParameters newFeatureStoreParameters = parameters.getNewFeatureStoreParameters();
116
        FeatureStore sourceFeatureStore = parameters.getSourceFeatureStore();
117
        FeatureAttributeDescriptor idRouteField = parameters.getIdRouteField();
118
        FeatureAttributeDescriptor fromMeasureField = parameters.getFromMeasureField();
119
        FeatureAttributeDescriptor toMeasureField = parameters.getToMeasureField();
120

    
121
        logger.info(parameters.toString());
122

    
123
        taskStatus.setTitle(parameters.getName());
124
        I18nManager i18nManager = ToolsLocator.getI18nManager();
125
        taskStatus.message(i18nManager.getTranslation("grouping_features"));
126

    
127
        try {
128
            final String routeFieldName = idRouteField.getName();
129
            final String fromFieldName;
130
            final DataType fromDataType;
131
            final DataType toDataType;
132
            if (fromMeasureField != null) {
133
                fromFieldName = fromMeasureField.getName();
134
                fromDataType = fromMeasureField.getDataType();
135
            } else {
136
                fromFieldName = null;
137
                fromDataType = null;
138
            }
139
            final String toFieldName;
140
            if (toMeasureField != null) {
141
                toFieldName = toMeasureField.getName();
142
                toDataType = toMeasureField.getDataType();
143
            } else {
144
                toFieldName = null;
145
                toDataType = null;
146
            }
147

    
148
            FeatureStore newFeatureStore =
149
                LrsAlgorithmUtils.createNewDataStore(newFeatureStoreParameters, idRouteField);
150

    
151
            FeatureSet sourceFeatures;
152
            if (sourceFeatureStore.getFeatureSelection().getSize() > 0) {
153
                sourceFeatures = sourceFeatureStore.getFeatureSelection();
154
            } else {
155
                sourceFeatures = sourceFeatureStore.getFeatureSet();
156
            }
157

    
158
            final SortedMap<String, List<MSegment>> featuresMap = new TreeMap<String, List<MSegment>>();
159
            final MutableInt contId = new MutableInt(0);
160
            sourceFeatures.accept(new Visitor() {
161

    
162
                public void visit(Object obj) throws VisitCanceledException, BaseException {
163
                    Feature feature = (Feature) obj;
164
                    String routeName = (String) feature.get(routeFieldName);
165
                    Object objFrom = null;
166
                    Object objTo = null;
167
                    if (fromFieldName != null) {
168
                        objFrom = feature.get(fromFieldName);
169
                    }
170
                    if (toFieldName != null) {
171
                        objTo = feature.get(toFieldName);
172
                    }
173
                    if (!featuresMap.containsKey(routeName)) {
174
                        featuresMap.put(routeName, new ArrayList<MSegment>());
175
                    }
176
                    List<MSegment> mList = featuresMap.get(routeName);
177
                    MSegment mSegment = new MSegment();
178
                    mSegment.geometry = feature.getDefaultGeometry().cloneGeometry();
179
                    mSegment.fromValue = LrsAlgorithmUtils.getAsDouble(objFrom, fromDataType);
180
                    mSegment.toValue = LrsAlgorithmUtils.getAsDouble(objTo, toDataType);
181
                    mSegment.id = contId.getValue();
182
                    contId.increment();
183
                    mList.add(mSegment);
184
                    featuresMap.put(routeName, mList);
185
                }
186
            });
187

    
188
            taskStatus.setRangeOfValues(0, featuresMap.size());
189
            int taskCount = 0;
190

    
191
            newFeatureStore.edit(FeatureStore.MODE_FULLEDIT);
192

    
193
            for (Entry<String, List<MSegment>> entry : featuresMap.entrySet()) {
194
                String routeName = entry.getKey();
195
                List<MSegment> mList = entry.getValue();
196

    
197
                EditableFeature newFeature = newFeatureStore.createNewFeature(true);
198
                newFeature.set(routeFieldName, routeName);
199
                Geometry route = createGeometryRoute(mList);
200
                newFeature.setDefaultGeometry(route);
201

    
202
                newFeatureStore.update(newFeature);
203

    
204
                taskCount++;
205
                taskStatus.setCurValue(taskCount);
206

    
207
            }
208
            newFeatureStore.finishEditing();
209

    
210
        } catch (Exception e1) {
211
            taskStatus.abort();
212
            throw new LrsCreateRouteException("Error creating routes", e1);
213
        }
214

    
215
        taskStatus.terminate();
216

    
217
    }
218

    
219
    private Geometry createGeometryRoute(List<MSegment> mList) throws CreateGeometryException,
220
        GeometryOperationNotSupportedException, GeometryOperationException, CreateEnvelopeException {
221
        LrsSourceOfMeasures sourceOfMeasures = parameters.getSourceOfMeasures();
222
        Geometry geometryResult = null;
223
        simplifyMultilines(mList);
224
        switch (sourceOfMeasures) {
225
        case ONE_FIELD:
226
            geometryResult = calculateGeometryByOneField(mList);
227
            break;
228
        case TWO_FIELDS:
229
            geometryResult = calculateGeometryByTwoField(mList);
230
            break;
231
        case LENGTH:
232
        default:
233
            geometryResult = calculateGeometryByLength(mList);
234
            break;
235
        }
236
        geometryResult = applyOffsetAndFactor(geometryResult);
237
        return geometryResult;
238
    }
239

    
240
    private Geometry calculateGeometryByLength(List<MSegment> mList) throws CreateGeometryException,
241
        GeometryOperationNotSupportedException, GeometryOperationException, CreateEnvelopeException {
242
        boolean ignoreSpatialGaps = parameters.ignoreSpatialGaps();
243
        for (MSegment mSegment : mList) {
244
            mSegment.fromValue = LrsAlgorithmUtils.getGeometryLength(mSegment.geometry, ignoreSpatialGaps);
245
        }
246
        return calculateGeometryByOneField(mList);
247
    }
248

    
249
    private Geometry calculateGeometryByOneField(List<MSegment> mList) throws CreateGeometryException,
250
        GeometryOperationNotSupportedException, GeometryOperationException, CreateEnvelopeException {
251
        boolean ignoreSpatialGaps = parameters.ignoreSpatialGaps();
252
        GeometryManager gmanager = GeometryLocator.getGeometryManager();
253
        try {
254
            mList = sortMList(mList);
255
        } catch (Exception e) {
256
            logger.warn("Geometries couldn't be ordered");
257
        }
258

    
259
        MultiLine auxMultiLine = (MultiLine) gmanager.create(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM);
260

    
261
        Point previousPoint = null;
262
        double previousM = 0.0;
263
        for (MSegment mSegment : mList) {
264
            Geometry geom = mSegment.geometry;
265
            Double geometryLength = mSegment.getLength(ignoreSpatialGaps);
266
            if (geom instanceof Line) {
267
                Line line = (Line) geom;
268
                Line auxLine = (Line) gmanager.create(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM);
269
                double distance = 0.0;
270
                double firstM = previousM;
271
                for (int i = 0; i < line.getNumVertices(); i++) {
272
                    Point vertex = line.getVertex(i);
273
                    Point point = (Point) gmanager.create(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM);
274
                    point.setX(vertex.getX());
275
                    point.setY(vertex.getY());
276
                    if (i == 0 && previousPoint != null) {
277
                        boolean gap = false;
278
                        if (areInSame2DLocation(previousPoint, vertex)) {
279
                            // Buscamos si ha sido una bifurcaci?n
280
                            Point fork = getPossibleFork(auxMultiLine, vertex);
281
                            if(fork!=null){
282
                                previousPoint = fork;
283
                                // OJO, aqu? previousPoint pasa a ser 2DM
284
                            }
285
                        } else {
286
                            // En caso de salto, calculamos el previousPoint
287
                            // buscando el v?rtice m?s cercano
288
                            previousPoint = getClosestVertex(auxMultiLine, vertex);
289
                            // OJO, aqu? previousPoint pasa a ser 2DM
290
                            gap = true;
291
                        }
292
                        previousM = previousPoint.getCoordinateAt(previousPoint.getDimension() - 1);
293
                        if (i == 0) {
294
                            firstM = previousM;
295
                        }
296
                        if (gap && !ignoreSpatialGaps) {
297
                            Point previousVertex = getPreviousVertexToPoint(auxMultiLine, previousPoint);
298
                            if(areInSame2DLocation(previousPoint,previousVertex)){
299
                                Point nextVertex = getNextVertexToPoint(auxMultiLine, previousPoint);
300
                                double distanceToNextPoint = nextVertex.distance(previousPoint);
301
                                previousM = LrsAlgorithmUtils.straightLineThroughTwoPointsEquation(0, distanceToNextPoint,
302
                                    previousM, nextVertex.getCoordinateAt(previousVertex.getDimension() - 1),
303
                                        previousPoint.distance(point));
304
                            } else {
305
                                double distanceToPreviousPoint = previousVertex.distance(previousPoint);
306
                                previousM = LrsAlgorithmUtils.straightLineThroughTwoPointsEquation(0, distanceToPreviousPoint,
307
                                        previousVertex.getCoordinateAt(previousVertex.getDimension() - 1), previousM,
308
                                        distanceToPreviousPoint + previousPoint.distance(point));
309
                            }
310
                            firstM = previousM;
311
                        }
312
                    }
313
                    if (i != 0) {
314
                        distance += previousPoint.distance(vertex);
315
                    }
316
                    double m =
317
                        LrsAlgorithmUtils.straightLineThroughTwoPointsEquation(0, geometryLength, firstM, firstM + mSegment.fromValue,
318
                            distance);
319
                    point.setCoordinateAt(point.getDimension() - 1, m);
320
                    auxLine.addVertex(point);
321
                    previousM = m;
322
                    previousPoint = vertex;
323
                }
324
                auxMultiLine.addPrimitive(auxLine);
325
            } else if (geom instanceof MultiLine) {
326
                MultiLine multiline = (MultiLine) geom;
327
                for (int i = 0; i < multiline.getPrimitivesNumber(); i++) {
328
                    Line line = (Line) multiline.getPrimitiveAt(i);
329
                    Line auxLine = (Line) gmanager.create(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM);
330
                    double distance = 0.0;
331
                    double firstM = previousM;
332
                    for (int j = 0; j < line.getNumVertices(); j++) {
333
                        Point vertex = line.getVertex(j);
334
                        Point point = (Point) gmanager.create(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM);
335
                        point.setX(vertex.getX());
336
                        point.setY(vertex.getY());
337
                        if (j == 0 && previousPoint != null) {
338
                            boolean gap = false;
339
                            if (areInSame2DLocation(previousPoint, vertex)) {
340
                                // Buscamos si ha sido una bifurcaci?n
341
                                previousPoint = getPossibleFork(auxMultiLine, vertex);
342
                                // OJO, aqu? previousPoint pasa a ser 2DM
343
                            } else {
344
                                // En caso de salto, calculamos el previousPoint
345
                                // buscando el v?rtice m?s cercano
346
                                previousPoint = getClosestVertex(auxMultiLine, vertex);
347
                                // OJO, aqu? previousPoint pasa a ser 2DM
348
                                gap = true;
349
                            }
350
                            previousM = previousPoint.getCoordinateAt(previousPoint.getDimension() - 1);
351
                            if (j == 0) {
352
                                firstM = previousM;
353
                            }
354
                            if (gap && !ignoreSpatialGaps) {
355
                                Point previousVertex = getPreviousVertexToPoint(auxMultiLine, previousPoint);
356
                                previousVertex.getCoordinateAt(previousVertex.getDimension() - 1);
357
                                previousM =
358
                                    LrsAlgorithmUtils.straightLineThroughTwoPointsEquation(0, previousVertex.distance(previousPoint),
359
                                        previousVertex.getCoordinateAt(previousVertex.getDimension() - 1), previousM,
360
                                        previousVertex.distance(previousPoint) + previousPoint.distance(point));
361
                                firstM = previousM;
362
                            }
363
                        }
364
                        if (j != 0) {
365
                            distance += previousPoint.distance(vertex);
366
                        }
367
                        double m =
368
                            LrsAlgorithmUtils.straightLineThroughTwoPointsEquation(0, geometryLength, firstM, firstM + mSegment.fromValue,
369
                                distance);
370
                        point.setCoordinateAt(point.getDimension() - 1, m);
371
                        auxLine.addVertex(point);
372
                        previousM = m;
373
                        previousPoint = vertex;
374
                    }
375
                    multiline.addPrimitive(auxLine);
376
                }
377
            } else {
378
                // NO deber?a entrar por aqu?
379
                logger.warn("A not LINE nor MULTILINE geometry found in CreateRoute process");
380
            }
381
        }
382

    
383
        return compactMultiLine(auxMultiLine);
384
    }
385

    
386
    /**
387
     * Joins consecutive adjacent lines into the multiLine that are not involved in a fork
388
     *
389
     * @param auxMultiLine
390
     * @return
391
     * @throws CreateGeometryException
392
     * @throws GeometryOperationException
393
     * @throws GeometryOperationNotSupportedException
394
     */
395
    private MultiLine compactMultiLine(MultiLine multiLine) throws CreateGeometryException, GeometryOperationNotSupportedException, GeometryOperationException {
396
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
397
        MultiLine result =  (MultiLine) geomManager.create(multiLine.getGeometryType());
398

    
399
        int primitivesNumber = multiLine.getPrimitivesNumber();
400
        List<Line> lines = new ArrayList<Line>(primitivesNumber);
401
        for(int i = 0; i < primitivesNumber; i++){
402
            lines.add((Line)multiLine.getPrimitiveAt(i).cloneGeometry());
403
        }
404
        if (lines.size() > 0) {
405
            Line line = lines.get(0);
406
            while (lines.size() > 1) {
407
                Point lastVertex = line.getVertex(line.getNumVertices() - 1);
408
                lines.remove(0);
409
                // Borramos la primera linea de la lista ==> lines.get(0) es la siguiente
410
                Line line2 = lines.get(0);
411
                // Si el ultimo punto de la primera
412
                if (lastVertex.equals(line2.getVertex(0)) && !bifurcation(lastVertex, lines)) {
413
                    for(int i = 1; i<line2.getNumVertices(); i++){
414
                        line.addVertex(line2.getVertex(i));
415
                    }
416
                } else {
417
                    result.addPrimitive(line);
418
                    line = line2;
419
                }
420
            }
421
            result.addPrimitive(line);
422
        }
423
        return result;
424
    }
425

    
426
    /**
427
     * Checks if a bifurcation occurs at one point.
428
     *
429
     * @param point
430
     * @param lines
431
     * @return
432
     */
433
    private boolean bifurcation(Point point, List<org.gvsig.fmap.geom.primitive.Line> lines) {
434
        // Saltamos la primera linea
435
        for(int i = 1; i<lines.size(); i++){
436
            if(point.equals(lines.get(i).getVertex(0))){
437
                return true;
438
            }
439
        }
440
        return false;
441
    }
442

    
443
    /**
444
     * Returns the previous vertex to a point.
445
     *
446
     * @param auxMultiLine
447
     * @param previousPoint
448
     * @return
449
     * @throws GeometryOperationException
450
     * @throws GeometryOperationNotSupportedException
451
     * @throws CreateGeometryException
452
     */
453
    private Point getPreviousVertexToPoint(MultiLine multiLine, Point point) throws CreateGeometryException,
454
        GeometryOperationNotSupportedException, GeometryOperationException {
455
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
456
        for (int i = 0; i < multiLine.getPrimitivesNumber(); i++) {
457
            Line line = (Line) multiLine.getPrimitiveAt(i);
458
            if (line.intersects(point)) {
459
                for (int j = 0; j < line.getNumVertices() - 1; j++) {
460
                    if (point.equals(line.getVertex(j + 1))) {
461
                        return line.getVertex(j);
462
                    }
463
                    Line auxLine = (Line) geomManager.create(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM);
464
                    auxLine.addVertex(line.getVertex(j));
465
                    auxLine.addVertex(line.getVertex(j + 1));
466
                    if (auxLine.intersects(point)) {
467
                        return line.getVertex(j);
468
                    }
469
                }
470
            }
471
        }
472
        return null;
473
    }
474

    
475
    /**
476
     * Returns the next vertex to a point.
477
     *
478
     * @param auxMultiLine
479
     * @param previousPoint
480
     * @return
481
     * @throws GeometryOperationException
482
     * @throws GeometryOperationNotSupportedException
483
     * @throws CreateGeometryException
484
     */
485
    private Point getNextVertexToPoint(MultiLine multiLine, Point point) throws CreateGeometryException,
486
        GeometryOperationNotSupportedException, GeometryOperationException {
487
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
488
        for (int i = 0; i < multiLine.getPrimitivesNumber(); i++) {
489
            Line line = (Line) multiLine.getPrimitiveAt(i);
490
            if (line.intersects(point)) {
491
                for (int j = 0; j < line.getNumVertices() - 1; j++) {
492
                    if (point.equals(line.getVertex(j))) {
493
                        return line.getVertex(j+1);
494
                    }
495
                    Line auxLine = (Line) geomManager.create(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM);
496
                    auxLine.addVertex(line.getVertex(j));
497
                    auxLine.addVertex(line.getVertex(j + 1));
498
                    if (auxLine.intersects(point)) {
499
                        return line.getVertex(j+1);
500
                    }
501
                }
502
            }
503
        }
504
        return null;
505
    }
506

    
507
    /**
508
     * Checks if a bifurcation occurs at one point and return the vertex with maximum M
509
     *
510
     * @param multiLine
511
     * @param vertex
512
     * @return
513
     */
514
    private Point getPossibleFork(MultiLine multiLine, Point point) {
515

    
516
        List<Point> vertices = new ArrayList<Point>();
517
        for (int i = 0; i < multiLine.getPrimitivesNumber(); i++) {
518
            Line line = (Line) multiLine.getPrimitiveAt(i);
519
            for (int j = 0; j < line.getNumVertices(); j++) {
520
                Point vertex = line.getVertex(j);
521
                if (areInSame2DLocation(vertex, point)) {
522
                    vertices.add(vertex);
523
                }
524
            }
525
        }
526
        if (vertices.size() > 0) {
527
            Double maxM = Double.NEGATIVE_INFINITY;
528
            Point forked = null;
529
            for (Iterator<Point> iterator = vertices.iterator(); iterator.hasNext();) {
530
                Point vertex = (Point) iterator.next();
531
                double m = vertex.getCoordinateAt(vertex.getDimension() - 1);
532
                if (m > maxM) {
533
                    maxM = m;
534
                    forked = vertex;
535
                }
536
            }
537
            return forked;
538
        }
539
        return null;
540
    }
541

    
542
    /**
543
     * Compares x & y coordinates of a point.
544
     *
545
     * @param p1
546
     * @param p2
547
     * @return
548
     */
549
    private boolean areInSame2DLocation(Point p1, Point p2) {
550
        return ((p1.getX() == p2.getX()) && (p1.getY() == p2.getY()));
551
    }
552

    
553
    /**
554
     * Returns the vertex of the multiline closest to a point
555
     *
556
     * @param mGeometry
557
     * @param vertex
558
     * @return
559
     * @throws GeometryOperationException
560
     * @throws GeometryOperationNotSupportedException
561
     * @throws CreateEnvelopeException
562
     */
563
    private Point getClosestVertex(MultiLine multiLine, Point point) throws CreateEnvelopeException,
564
        GeometryOperationNotSupportedException, GeometryOperationException {
565
        Point result = null;
566
        double minDistance = Double.POSITIVE_INFINITY;
567

    
568
        for (int i = 0; i < multiLine.getPrimitivesNumber(); i++) {
569
            Line line = (Line) multiLine.getPrimitiveAt(i);
570
            for (int j = 0; j < line.getNumVertices(); j++) {
571
                Point vertex = line.getVertex(j);
572
                double distance = point.distance(vertex);
573
                if (distance <= minDistance) {
574
                    minDistance = distance;
575
                    result = vertex;
576
                }
577
            }
578
        }
579

    
580
        return result;
581
    }
582

    
583
    /**
584
     * Returns a multiline calculate by two field method
585
     *
586
     * @param mList
587
     * @return
588
     * @throws CreateGeometryException
589
     * @throws GeometryOperationNotSupportedException
590
     * @throws GeometryOperationException
591
     */
592
    private MultiLine calculateGeometryByTwoField(List<MSegment> mList) throws CreateGeometryException,
593
        GeometryOperationNotSupportedException, GeometryOperationException {
594
        GeometryManager geomanager = GeometryLocator.getGeometryManager();
595
        MultiLine mGeometry = (MultiLine) geomanager.create(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM);
596

    
597
        for (MSegment mSegment : mList) {
598
            Geometry geometry = mSegment.geometry;
599
            List<Line> geometryLines = extractLines(geometry);
600
            Double geometryLength = LrsAlgorithmUtils.getGeometryLength(geometry);
601

    
602
            Double geometryMFirstPoint = mSegment.fromValue;
603
            Double geometryMLastPoint = mSegment.toValue;
604

    
605
            Double distance = Double.valueOf(0);
606
            for (Line line : geometryLines) {
607
                Double lineLength = getLineLength(line);
608
                Double mFirstPoint = LrsAlgorithmUtils.calculateM(geometryLength, geometryMFirstPoint, geometryMLastPoint, distance);
609
                distance += lineLength;
610
                Double mLastPoint = LrsAlgorithmUtils.calculateM(geometryLength, geometryMFirstPoint, geometryMLastPoint, distance);
611
                Line mLine = lineToMLine(line, mFirstPoint, mLastPoint);
612
                mGeometry.addPrimitive(mLine);
613
            }
614
        }
615

    
616
        return mGeometry;
617
    }
618

    
619
    /**
620
     * Converts a Line2D in a Line2DM filled it with proportional calculated M's
621
     *
622
     * @param line
623
     * @param minMValue
624
     * @param maxMValue
625
     * @return
626
     * @throws CreateGeometryException
627
     * @throws GeometryOperationNotSupportedException
628
     * @throws GeometryOperationException
629
     */
630
    private Line lineToMLine(Line line, Double minMValue, Double maxMValue) throws CreateGeometryException,
631
        GeometryOperationNotSupportedException, GeometryOperationException {
632
        GeometryManager geomanager = GeometryLocator.getGeometryManager();
633
        Double lineLength = getLineLength(line);
634
        Line lineM = (Line) geomanager.create(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM);
635
        Double inLineDistance = Double.valueOf(0);
636
        for (int i = 0; i < line.getNumVertices(); i++) {
637
            Point vertex = line.getVertex(i);
638
            Point mVertex = (Point) geomanager.create(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM);
639
            mVertex.setX(vertex.getX());
640
            mVertex.setY(vertex.getY());
641

    
642
            Double mValue;
643
            if (i == 0)
644
                mValue = minMValue;
645
            else if (i == line.getNumVertices() - 1)
646
                mValue = maxMValue;
647
            else {
648
                Point previousVertex = line.getVertex(i - 1);
649
                inLineDistance += vertex.distance(previousVertex);
650
                mValue = LrsAlgorithmUtils.calculateM(lineLength, minMValue, maxMValue, inLineDistance);
651
            }
652

    
653
            mVertex.setCoordinateAt(mVertex.getDimension() - 1, mValue);
654
            lineM.addVertex(mVertex);
655
        }
656
        return lineM;
657
    }
658

    
659

    
660
    /**
661
     * Simplify the multilines in mList calling simplifyMultiline method
662
     *
663
     * @param mList
664
     * @throws CreateGeometryException
665
     * @throws LocatorException
666
     */
667
    private void simplifyMultilines(List<MSegment> mList) throws CreateGeometryException, LocatorException {
668
        for (MSegment mSegment : mList) {
669
            mSegment.geometry = simplifyMultiline(mSegment.geometry);
670
        }
671
    }
672

    
673
    /**
674
     * Simplify a Multiline ordering and joining her lines if can.
675
     *
676
     * @param geometry
677
     * @return
678
     * @throws CreateGeometryException
679
     * @throws LocatorException
680
     */
681
    private Geometry simplifyMultiline(Geometry geometry) throws CreateGeometryException, LocatorException {
682
        if (geometry instanceof MultiLine) {
683
            MultiLine multiline = (MultiLine) geometry;
684

    
685
            if (multiline.getPrimitivesNumber() == 1) {
686
                return multiline.getPrimitiveAt(0);
687
            } else {
688
                List<Line> simplifiedLines = new ArrayList<Line>();
689
                List<Line> complexLines = new ArrayList<Line>();
690
                for (int i = 0; i < multiline.getPrimitivesNumber(); i++) {
691
                    complexLines.add((Line) multiline.getPrimitiveAt(i));
692
                }
693

    
694
                Line line = null;
695
                while (complexLines.size() > 0) {
696
                    line = complexLines.remove(0);
697
                    int i = 0;
698
                    while (i < complexLines.size()) {
699
                        Line auxLine = complexLines.get(i);
700
                        Line unitedLine = unionAdjacentLines(line, auxLine);
701
                        if (unitedLine != null) {
702
                            line = unitedLine;
703
                            complexLines.remove(i);
704
                            i = 0;
705
                        } else {
706
                            i++;
707
                        }
708
                    }
709
                    simplifiedLines.add(line);
710
                }
711

    
712
                if (simplifiedLines.size() == 1) {
713
                    geometry = simplifiedLines.get(0);
714
                } else {
715
                    MultiLine simplifiedMultiLine =
716
                        (MultiLine) GeometryLocator.getGeometryManager().create(multiline.getGeometryType());
717
                    for (Line simpleLine : simplifiedLines) {
718
                        simplifiedMultiLine.addPrimitive(simpleLine);
719
                    }
720
                    return simplifiedMultiLine;
721
                }
722
            }
723
        }
724
        return geometry;
725
    }
726

    
727
    /**
728
     * Join two adjacent lines flipping it if necessary
729
     *
730
     * @param line1
731
     * @param line2
732
     * @return
733
     */
734
    private Line unionAdjacentLines(Line line1, Line line2) {
735
        if (line1 == null || line2 == null) {
736
            return null;
737
        }
738
        Line resultLine;
739
        try {
740
            resultLine = (Line) GeometryLocator.getGeometryManager().create(line1.getGeometryType());
741
        } catch (Exception e) {
742
            return null;
743
        }
744

    
745
        Point firstPointL1 = line1.getVertex(0);
746
        Point lastPointL1 = line1.getVertex(line1.getNumVertices() - 1);
747
        Point firstPointL2 = line2.getVertex(0);
748
        Point lastPointL2 = line2.getVertex(line2.getNumVertices() - 1);
749
        if (lastPointL1.equals(firstPointL2)) {
750
            resultLine = (Line) line1.cloneGeometry();
751
            for (int i = 1; i < line2.getNumVertices(); i++) {
752
                resultLine.addVertex((Point) line2.getVertex(i).cloneGeometry());
753
            }
754
            return resultLine;
755
        }
756
        if (lastPointL2.equals(firstPointL1)) {
757
            resultLine = (Line) line2.cloneGeometry();
758
            for (int i = 1; i < line1.getNumVertices(); i++) {
759
                resultLine.addVertex((Point) line1.getVertex(i).cloneGeometry());
760
            }
761
            return resultLine;
762
        }
763
        if (firstPointL1.equals(firstPointL2)) {
764
            for (int i = line1.getNumVertices() - 1; i >= 0; i--) {
765
                resultLine.addVertex((Point) line1.getVertex(i).cloneGeometry());
766
            }
767
            for (int i = 1; i < line2.getNumVertices(); i++) {
768
                resultLine.addVertex((Point) line2.getVertex(i).cloneGeometry());
769
            }
770
            return resultLine;
771
        }
772
        if (lastPointL1.equals(lastPointL2)) {
773
            resultLine = (Line) line1.cloneGeometry();
774
            for (int i = line2.getNumVertices() - 2; i >= 0; i--) {
775
                resultLine.addVertex((Point) line2.getVertex(i).cloneGeometry());
776
            }
777
            return resultLine;
778
        }
779
        return null;
780
    }
781

    
782
    /**
783
     * Sorts mList
784
     *
785
     * @param mList
786
     * @return
787
     * @throws CreateEnvelopeException
788
     * @throws GeometryOperationNotSupportedException
789
     * @throws GeometryOperationException
790
     */
791
    private List<MSegment> sortMList(List<MSegment> mList) throws CreateEnvelopeException,
792
        GeometryOperationNotSupportedException, GeometryOperationException {
793
        LrsCoordinatesPriority coordinatePriority = parameters.getCoordinatePriority();
794
        GeometryManager geomanager = GeometryLocator.getGeometryManager();
795
        Envelope envelope = geomanager.createEnvelope(Geometry.SUBTYPES.GEOM2D);
796
        for (MSegment mSegment : mList) {
797
            envelope.add(mSegment.geometry.getEnvelope());
798
        }
799
        Point origin = envelope.getLowerCorner();
800
        switch (coordinatePriority) {
801
        case DOWN_LEFT:
802
            break;
803
        case DOWN_RIGHT:
804
            Double maxX = envelope.getMaximum(DIMENSIONS.X);
805
            origin.setX(maxX);
806
            break;
807
        case UP_LEFT:
808
            Double maxY = envelope.getMaximum(DIMENSIONS.Y);
809
            origin.setY(maxY);
810
            break;
811
        case UP_RIGHT:
812
            origin = envelope.getUpperCorner();
813
            break;
814
        default:
815
            break;
816
        }
817

    
818
        List<Stretch> stretches = createStretches(mList, origin);
819
        stretches = sortStretches(stretches, origin);
820
        return extractSegmentsFromStretches(stretches);
821
    }
822

    
823
    /**
824
     * Extracts segment from stretches and returns a list of segment.
825
     *
826
     * @param stretches
827
     * @return
828
     */
829
    private List<MSegment> extractSegmentsFromStretches(List<Stretch> stretches) {
830
        List<MSegment> result = new ArrayList<MSegment>();
831
        for (Stretch stretch : stretches) {
832
            for (int i = 0; i < stretch.getSegmentNumber(); i++) {
833
                result.add(stretch.getSegment(i));
834
            }
835
        }
836
        return result;
837
    }
838

    
839
    /**
840
     * Sort the stretches
841
     *
842
     * @param stretches
843
     * @param origin
844
     * @return
845
     * @throws GeometryOperationNotSupportedException
846
     * @throws GeometryOperationException
847
     */
848
    private List<Stretch> sortStretches(List<Stretch> stretches, Point origin)
849
        throws GeometryOperationNotSupportedException, GeometryOperationException {
850
        List<Stretch> result = new ArrayList<Stretch>();
851

    
852
        Point originPoint = origin;
853
        while (result.size() < stretches.size()) {
854
            // Buscamos tramos que sean adyacentes al origin
855
            if (result.size() == 0) {
856
                addUnvisitedAdjacentStretches(stretches, result, originPoint);
857
            }
858
            if (result.size() == 0) {
859
                result.add(getNearestUnvisitedStretch(stretches, originPoint, result));
860
            }
861

    
862
            boolean addedAdjacentStretches = true;
863
            while (addedAdjacentStretches) {
864
                addedAdjacentStretches = false;
865
                int visitedNumber = result.size();
866
                for (int i = 0; i < visitedNumber; i++) {
867
                    Stretch visited = result.get(i);
868
                    addUnvisitedAdjacentStretches(stretches, result, visited.getFinalPoint());
869
                }
870
                addedAdjacentStretches = (visitedNumber < result.size());
871
            }
872

    
873
            int visitedNumber = result.size();
874
            Stretch nearest = null;
875
            for (int i = visitedNumber - 1; i >= 0; i--) {
876
                if(nearest!=null){
877
                    break;
878
                }
879
                Stretch visited = result.get(i);
880
                for (int j=0; j<visited.getSegmentNumber(); j++) {
881
                    if(nearest!=null){
882
                        break;
883
                    }
884
                    MSegment segment = visited.getSegment(j);
885
                    Geometry geom = segment.geometry;
886
                    if(geom instanceof Line){
887
                        Line line = (Line)geom;
888
                        for (int k=0; k<line.getNumVertices(); k++){
889
                            nearest = getNearestUnvisitedStretch(stretches, line.getVertex(k), result);
890
                            if (nearest != null) {
891
                                result.add(nearest);
892
                                break;
893
                            }
894
                        }
895
                    } else { //geom is multiline
896
                        MultiLine multiline = (MultiLine)geom;
897
                        for (int l=0; l<multiline.getPrimitivesNumber(); l++){
898
                            if(nearest!=null){
899
                                break;
900
                            }
901
                            Line line = (Line)multiline.getPrimitiveAt(l);
902
                            for (int k=0; k<line.getNumVertices(); k++){
903
                                nearest = getNearestUnvisitedStretch(stretches, line.getVertex(k), result);
904
                                if (nearest != null) {
905
                                    result.add(nearest);
906
                                    break;
907
                                }
908
                            }
909

    
910
                        }
911
                    }
912
                }
913
            }
914
        }
915
        return result;
916
    }
917

    
918
    /**
919
     * Adds unvisited adjacent stretches to the visited list
920
     *
921
     * @param stretches
922
     * @param visited
923
     * @param originPoint
924
     * @throws GeometryOperationNotSupportedException
925
     * @throws GeometryOperationException
926
     */
927
    private void addUnvisitedAdjacentStretches(List<Stretch> stretches, List<Stretch> visited, Point originPoint)
928
        throws GeometryOperationNotSupportedException, GeometryOperationException {
929
        for (Stretch stretch : stretches) {
930
            if (!visited.contains(stretch)) {
931
                if (areInSame2DLocation(stretch.getInitialPoint(), originPoint)) {
932
                    visited.add(stretch);
933
                } else if (areInSame2DLocation(stretch.getFinalPoint(), originPoint)) {
934
                    visited.add(stretch.flip());
935
                }
936
            }
937
        }
938
    }
939

    
940
    /**
941
     * Returns the unvisited stretch nearest to a point
942
     *
943
     * @param stretches
944
     * @param origin
945
     * @param visited
946
     * @return
947
     * @throws GeometryOperationNotSupportedException
948
     * @throws GeometryOperationException
949
     */
950
    private Stretch getNearestUnvisitedStretch(List<Stretch> stretches, Point origin, List<Stretch> visited)
951
        throws GeometryOperationNotSupportedException, GeometryOperationException {
952

    
953
        double minDistance = Double.POSITIVE_INFINITY;
954
        Stretch nearest = null;
955
        boolean needFlip = false;
956
        for (Stretch stretch : stretches) {
957
            if (!visited.contains(stretch)) {
958
                Double initialDistance = origin.distance(stretch.getInitialPoint());
959
                if (initialDistance < minDistance) {
960
                    minDistance = initialDistance;
961
                    nearest = stretch;
962
                    needFlip = false;
963
                }
964
                Double finalDistance = origin.distance(stretch.getFinalPoint());
965
                if (finalDistance < minDistance) {
966
                    minDistance = finalDistance;
967
                    nearest = stretch;
968
                    needFlip = true;
969
                }
970
            }
971
        }
972
        if (needFlip && nearest != null) {
973
            nearest.flip();
974
        }
975
        return nearest;
976
    }
977

    
978
    /**
979
     * Creates stretches from mList and returns a list of stretches
980
     *
981
     * @param mList
982
     * @param origin
983
     * @return
984
     * @throws GeometryOperationNotSupportedException
985
     * @throws GeometryOperationException
986
     */
987
    private List<Stretch> createStretches(List<MSegment> mList, Point origin)
988
        throws GeometryOperationNotSupportedException, GeometryOperationException {
989

    
990
        List<MSegment> addedMSegment = new ArrayList<LrsCreateRouteAlgorithm.MSegment>();
991
        List<Stretch> stretches = new ArrayList<Stretch>();
992
        while (addedMSegment.size() < mList.size()) {
993
            for (MSegment mSegment : mList) {
994
                if (!addedMSegment.contains(mSegment)) {
995
                    Stretch stretch = new Stretch();
996
                    stretches.add(stretch);
997
                    stretch.addSegment(mSegment);
998
                    addedMSegment.add(mSegment);
999

    
1000
                    List<MSegment> initialNextSegments =
1001
                        mSegment.searchNextSegments(stretch.getInitialPoint(), mList);
1002
                    do {
1003
                        if (initialNextSegments.size() == 1) {
1004
                            MSegment previousSegment = initialNextSegments.get(0);
1005
                            if (!addedMSegment.contains(previousSegment)) {
1006
                                if (!previousSegment.getFinalPoint().equals(stretch.getInitialPoint())) {
1007
                                    previousSegment.flip();
1008
                                }
1009
                                stretch.addSegment(0, previousSegment);
1010
                                addedMSegment.add(previousSegment);
1011
                                initialNextSegments =
1012
                                    previousSegment.searchNextSegments(stretch.getInitialPoint(), mList);
1013
                            } else {
1014
                                break;
1015
                            }
1016
                        } else {
1017
                            break;
1018
                        }
1019
                    } while (initialNextSegments.size() == 1);
1020

    
1021
                    List<MSegment> finalNextSegments =
1022
                        mSegment.searchNextSegments(stretch.getFinalPoint(), mList);
1023
                    do {
1024
                        if (finalNextSegments.size() == 1) {
1025
                            MSegment nextSegment = finalNextSegments.get(0);
1026
                            if (!addedMSegment.contains(nextSegment)) {
1027
                                if (!nextSegment.getInitialPoint().equals(stretch.getFinalPoint())) {
1028
                                    nextSegment.flip();
1029
                                }
1030
                                stretch.addSegment(nextSegment);
1031
                                addedMSegment.add(nextSegment);
1032
                                finalNextSegments =
1033
                                    nextSegment.searchNextSegments(stretch.getFinalPoint(), mList);
1034
                            } else {
1035
                                break;
1036
                            }
1037
                        } else {
1038
                            break;
1039
                        }
1040
                    } while ((finalNextSegments.size() == 1));
1041
                }
1042
            }
1043
        }
1044
        return stretches;
1045
    }
1046

    
1047
    /**
1048
     * Extracts lines of a geometry.
1049
     *
1050
     * @param geometry
1051
     * @return
1052
     */
1053
    private List<Line> extractLines(Geometry geometry) {
1054
        List<Line> lines = new ArrayList<Line>();
1055
        if (geometry instanceof Line) {
1056
            lines.add((Line) geometry);
1057
        }
1058
        if (geometry instanceof MultiLine) {
1059
            MultiLine multiline = (MultiLine) geometry;
1060
            for (int i = 0; i < multiline.getPrimitivesNumber(); i++) {
1061
                lines.add((Line) multiline.getPrimitiveAt(i));
1062
            }
1063
        }
1064
        return lines;
1065
    }
1066

    
1067
    /**
1068
     * Applies offsetAndFactor to a route
1069
     *
1070
     * @param geometry
1071
     * @return
1072
     */
1073
    private Geometry applyOffsetAndFactor(Geometry geometry) {
1074
        double measureFactor = parameters.getMeasureFactor();
1075
        double measureOffset = parameters.getMeasureOffset();
1076
        if (geometry instanceof Line) {
1077
            Line line = (Line) geometry;
1078
            for (int i = 0; i < line.getNumVertices(); i++) {
1079
                Point mVertex = line.getVertex(i);
1080
                Double mValue = mVertex.getCoordinateAt(mVertex.getDimension() - 1);
1081
                Double newMValue = (mValue * measureFactor) + measureOffset;
1082
                mVertex.setCoordinateAt(mVertex.getDimension() - 1, newMValue);
1083
                line.setVertex(i, mVertex);
1084
            }
1085
        }
1086
        if (geometry instanceof MultiLine) {
1087
            MultiLine multiLine = (MultiLine) geometry;
1088
            for (int i = 0; i < multiLine.getPrimitivesNumber(); i++) {
1089
                Line line = (Line) multiLine.getPrimitiveAt(i);
1090
                for (int j = 0; j < line.getNumVertices(); j++) {
1091
                    Point mVertex = line.getVertex(j);
1092
                    Double mValue = mVertex.getCoordinateAt(mVertex.getDimension() - 1);
1093
                    Double newMValue = (mValue * measureFactor) + measureOffset;
1094
                    mVertex.setCoordinateAt(mVertex.getDimension() - 1, newMValue);
1095
                    line.setVertex(j, mVertex);
1096
                }
1097
            }
1098
        }
1099
        return geometry;
1100
    }
1101

    
1102
    /**
1103
     * Returns the geometric length of a line
1104
     *
1105
     * @param line
1106
     * @return lenght
1107
     * @throws GeometryOperationException
1108
     * @throws GeometryOperationNotSupportedException
1109
     */
1110
    private double getLineLength(Line line) throws GeometryOperationNotSupportedException, GeometryOperationException {
1111
        double lenght = 0;
1112
        Point previousVertex = null;
1113
        for (int i = 0; i < line.getNumVertices(); i++) {
1114
            Point vertex = line.getVertex(i);
1115
            if (previousVertex != null) {
1116
                lenght += previousVertex.distance(vertex);
1117
            }
1118
            previousVertex = vertex;
1119
        }
1120
        return lenght;
1121
    }
1122

    
1123
    /*
1124
     * (non-Javadoc)
1125
     *
1126
     * @see org.gvsig.lrs.lib.api.LrsAlgorithm#setParams(org.gvsig.lrs.lib.api.
1127
     * LrsAlgorithmParams)
1128
     */
1129
    public void setParams(LrsAlgorithmParams params) throws IllegalArgumentException {
1130
        if (!(params instanceof LrsCreateRouteAlgorithmParams)) {
1131
            throw new IllegalArgumentException("params should be LrsCreateRouteAlgorithmParams type.");
1132
        }
1133
        this.parameters = (LrsCreateRouteAlgorithmParams) params;
1134
    }
1135

    
1136
    private class MSegment {
1137

    
1138
        Geometry geometry;
1139
        Double fromValue;
1140
        Double toValue;
1141
        int id;
1142

    
1143
        protected MSegment clone() {
1144
            MSegment cloned = new MSegment();
1145
            cloned.geometry = geometry.cloneGeometry();
1146

    
1147
            cloned.fromValue = null;
1148
            if (fromValue != null) {
1149
                cloned.fromValue = new Double(fromValue);
1150
            }
1151

    
1152
            cloned.toValue = null;
1153
            if (toValue != null) {
1154
                cloned.toValue = new Double(toValue);
1155
            }
1156

    
1157
            cloned.id = id;
1158

    
1159
            return cloned;
1160
        }
1161

    
1162
        protected Point getInitialPoint() {
1163
            if (geometry instanceof Line) {
1164
                Line line = ((Line) geometry);
1165
                return line.getVertex(0);
1166
            } else if (geometry instanceof MultiLine) {
1167
                MultiLine multiLine = (MultiLine) geometry;
1168
                Line firstLine = ((Line) multiLine.getPrimitiveAt(0));
1169
                return firstLine.getVertex(0);
1170
            }
1171
            return null;
1172
        }
1173

    
1174
        protected Point getFinalPoint() {
1175
            if (geometry instanceof Line) {
1176
                Line line = ((Line) geometry);
1177
                return line.getVertex(line.getNumVertices() - 1);
1178
            } else if (geometry instanceof MultiLine) {
1179
                MultiLine multiLine = (MultiLine) geometry;
1180
                Line lastLine = ((Line) multiLine.getPrimitiveAt(multiLine.getPrimitivesNumber() - 1));
1181
                return lastLine.getVertex(lastLine.getNumVertices() - 1);
1182
            }
1183
            return null;
1184
        }
1185

    
1186
        protected void flip() throws GeometryOperationNotSupportedException, GeometryOperationException {
1187
            geometry.flip();
1188
        }
1189

    
1190
        /**
1191
         * @param point
1192
         * @param mList
1193
         * @return
1194
         */
1195
        protected List<MSegment> searchNextSegments(Point point, List<MSegment> mList) {
1196
            List<MSegment> result = new ArrayList<LrsCreateRouteAlgorithm.MSegment>();
1197
            for (Iterator<MSegment> iterator = mList.iterator(); iterator.hasNext();) {
1198
                MSegment mSegment = (MSegment) iterator.next();
1199
                if (mSegment != this) { // !addedSegments.contains(mSegment)) {
1200
                    Geometry geom = mSegment.geometry;
1201
                    if (geom instanceof Line) {
1202
                        Line line = ((Line) geom);
1203
                        if (line.getVertex(0).equals(point) || line.getVertex(line.getNumVertices() - 1).equals(point)) {
1204
                            result.add(mSegment);
1205
                        }
1206
                        ;
1207
                    } else if (geom instanceof MultiLine) {
1208
                        MultiLine multiLine = (MultiLine) geom;
1209
                        Line firstLine = ((Line) multiLine.getPrimitiveAt(0));
1210
                        Line lastLine = ((Line) multiLine.getPrimitiveAt(multiLine.getPrimitivesNumber() - 1));
1211
                        if (firstLine.getVertex(0).equals(point)
1212
                            || lastLine.getVertex(lastLine.getNumVertices() - 1).equals(point)) {
1213
                            result.add(mSegment);
1214
                        }
1215
                    }
1216
                }
1217
            }
1218
            return result;
1219
        }
1220

    
1221
        public double getLength(boolean ignoreSpatialGaps) throws GeometryOperationNotSupportedException,
1222
            GeometryOperationException {
1223
            return LrsAlgorithmUtils.getGeometryLength(geometry, ignoreSpatialGaps);
1224
        }
1225
    }
1226

    
1227
    private class Stretch {
1228

    
1229
        private List<MSegment> segments;
1230
        private Point initialPoint;
1231
        private Point finalPoint;
1232

    
1233
        public Stretch() {
1234
            segments = new ArrayList<MSegment>();
1235
        }
1236

    
1237
        public MSegment getSegment(int index) {
1238
            return segments.get(index);
1239
        }
1240

    
1241
        public int getSegmentNumber() {
1242
            return segments.size();
1243
        }
1244

    
1245
        public void addSegment(MSegment segment) {
1246
            if (segments.isEmpty()) {
1247
                initialPoint = segment.getInitialPoint();
1248
            }
1249
            finalPoint = segment.getFinalPoint();
1250
            segments.add(segment);
1251
        }
1252

    
1253
        public void addSegment(int index, MSegment segment) {
1254
            if (index == 0) {
1255
                initialPoint = segment.getInitialPoint();
1256
            }
1257
            if (index >= segments.size()) {
1258
                finalPoint = segment.getFinalPoint();
1259
            }
1260
            segments.add(index, segment);
1261
        }
1262

    
1263
        public double getLength(boolean ignoreSpatialGaps) throws GeometryOperationNotSupportedException,
1264
            GeometryOperationException {
1265
            double result = 0.0;
1266
            for (MSegment segment : segments) {
1267
                result += segment.getLength(ignoreSpatialGaps);
1268
            }
1269
            return result;
1270
        }
1271

    
1272
        public Stretch flip() throws GeometryOperationNotSupportedException, GeometryOperationException {
1273
            Collections.reverse(segments);
1274
            for (Iterator<MSegment> iterator = segments.iterator(); iterator.hasNext();) {
1275
                MSegment segment = (MSegment) iterator.next();
1276
                segment.flip();
1277
            }
1278
            Point aux = initialPoint;
1279
            initialPoint = finalPoint;
1280
            finalPoint = aux;
1281
            return this;
1282
        }
1283

    
1284
        public Point getInitialPoint() {
1285
            return initialPoint;
1286
        }
1287

    
1288
        public Point getFinalPoint() {
1289
            return finalPoint;
1290
        }
1291

    
1292
    }
1293

    
1294
}