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

History | View | Annotate | Download (58 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
                            previousPoint = getPossibleFork(auxMultiLine, vertex);
281
                            // OJO, aqu? previousPoint pasa a ser 2DM
282
                        } else {
283
                            // En caso de salto, calculamos el previousPoint
284
                            // // y si no, buscamos el v?rtice m?s cercano
285
                            previousPoint = getClosestVertex(auxMultiLine, vertex);
286
                            // OJO, aqu? previousPoint pasa a ser 2DM
287
                            gap = true;
288
                        }
289
                        previousM = previousPoint.getCoordinateAt(previousPoint.getDimension() - 1);
290
                        if (i == 0) {
291
                            firstM = previousM;
292
                        }
293
                        if (gap && !ignoreSpatialGaps) {
294
                            Point previousVertex = getPreviousVertexToPoint(auxMultiLine, previousPoint);
295
                            previousVertex.getCoordinateAt(previousVertex.getDimension() - 1);
296
                            previousM =
297
                                strightLineThroughTwoPointsEquation(0, previousVertex.distance(previousPoint),
298
                                    previousVertex.getCoordinateAt(previousVertex.getDimension() - 1), previousM,
299
                                    previousVertex.distance(previousPoint) + previousPoint.distance(point));
300
                            firstM = previousM;
301
                        }
302
                    }
303
                    if (i != 0) {
304
                        distance += previousPoint.distance(vertex);
305
                    }
306
                    double m =
307
                        strightLineThroughTwoPointsEquation(0, geometryLength, firstM, firstM + mSegment.fromValue,
308
                            distance);
309
                    point.setCoordinateAt(point.getDimension() - 1, m);
310
                    auxLine.addVertex(point);
311
                    previousM = m;
312
                    previousPoint = vertex;
313
                }
314
                auxMultiLine.addPrimitive(auxLine);
315
            } else if (geom instanceof MultiLine) {
316
                MultiLine multiline = (MultiLine) geom;
317
                for (int i = 0; i < multiline.getPrimitivesNumber(); i++) {
318
                    Line line = (Line) multiline.getPrimitiveAt(i);
319
                    Line auxLine = (Line) gmanager.create(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM);
320
                    double distance = 0.0;
321
                    double firstM = previousM;
322
                    for (int j = 0; j < line.getNumVertices(); j++) {
323
                        Point vertex = line.getVertex(j);
324
                        Point point = (Point) gmanager.create(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM);
325
                        point.setX(vertex.getX());
326
                        point.setY(vertex.getY());
327
                        if (j == 0 && previousPoint != null) {
328
                            boolean gap = false;
329
                            if (areInSame2DLocation(previousPoint, vertex)) {
330
                                // Buscamos si ha sido una bifurcaci?n
331
                                previousPoint = getPossibleFork(auxMultiLine, vertex);
332
                                // OJO, aqu? previousPoint pasa a ser 2DM
333
                            } else {
334
                                // En caso de salto, calculamos el previousPoint
335
                                previousPoint = getClosestVertex(auxMultiLine, vertex);
336
                                // OJO, aqu? previousPoint pasa a ser 2DM
337
                                gap = true;
338
                            }
339
                            previousM = previousPoint.getCoordinateAt(previousPoint.getDimension() - 1);
340
                            if (j == 0) {
341
                                firstM = previousM;
342
                            }
343
                            if (gap && !ignoreSpatialGaps) {
344
                                Point previousVertex = getPreviousVertexToPoint(auxMultiLine, previousPoint);
345
                                previousVertex.getCoordinateAt(previousVertex.getDimension() - 1);
346
                                previousM =
347
                                    strightLineThroughTwoPointsEquation(0, previousVertex.distance(previousPoint),
348
                                        previousVertex.getCoordinateAt(previousVertex.getDimension() - 1), previousM,
349
                                        previousVertex.distance(previousPoint) + previousPoint.distance(point));
350
                                firstM = previousM;
351
                            }
352
                        }
353
                        if (j != 0) {
354
                            distance += previousPoint.distance(vertex);
355
                        }
356
                        double m =
357
                            strightLineThroughTwoPointsEquation(0, geometryLength, firstM, firstM + mSegment.fromValue,
358
                                distance);
359
                        point.setCoordinateAt(point.getDimension() - 1, m);
360
                        auxLine.addVertex(point);
361
                        previousM = m;
362
                        previousPoint = vertex;
363
                    }
364
                    multiline.addPrimitive(auxLine);
365
                }
366
            } else {
367
                // NO deber?a entrar por aqu?
368
                logger.warn("A not LINE nor MULTILINE geometry found in CreateRoute process");
369
            }
370
        }
371

    
372
        return compactMultiLine(auxMultiLine);
373
    }
374

    
375
    /**
376
     * Joins consecutive adjacent lines into the multiLine that are not involved in a fork
377
     *
378
     * @param auxMultiLine
379
     * @return
380
     * @throws CreateGeometryException
381
     * @throws GeometryOperationException
382
     * @throws GeometryOperationNotSupportedException
383
     */
384
    private MultiLine compactMultiLine(MultiLine multiLine) throws CreateGeometryException, GeometryOperationNotSupportedException, GeometryOperationException {
385
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
386
        MultiLine result =  (MultiLine) geomManager.create(multiLine.getGeometryType());
387

    
388
        int primitivesNumber = multiLine.getPrimitivesNumber();
389
        List<Line> lines = new ArrayList<Line>(primitivesNumber);
390
        for(int i = 0; i < primitivesNumber; i++){
391
            lines.add((Line)multiLine.getPrimitiveAt(i).cloneGeometry());
392
        }
393
        if (lines.size() > 0) {
394
            Line line = lines.get(0);
395
            while (lines.size() > 1) {
396
                Point lastVertex = line.getVertex(line.getNumVertices() - 1);
397
                lines.remove(0);
398
                // Borramos la primera linea de la lista ==> lines.get(0) es la siguiente
399
                Line line2 = lines.get(0);
400
                // Si el ultimo punto de la primera
401
                if (lastVertex.equals(line2.getVertex(0)) && !bifurcation(lastVertex, lines)) {
402
                    for(int i = 1; i<line2.getNumVertices(); i++){
403
                        line.addVertex(line2.getVertex(i));
404
                    }
405
                } else {
406
                    result.addPrimitive(line);
407
                    line = line2;
408
                }
409
            }
410
            result.addPrimitive(line);
411
        }
412
        return result;
413
    }
414

    
415
    /**
416
     * Checks if a bifurcation occurs at one point.
417
     *
418
     * @param point
419
     * @param lines
420
     * @return
421
     */
422
    private boolean bifurcation(Point point, List<org.gvsig.fmap.geom.primitive.Line> lines) {
423
        // Saltamos la primera linea
424
        for(int i = 1; i<lines.size(); i++){
425
            if(point.equals(lines.get(i).getVertex(0))){
426
                return true;
427
            }
428
        }
429
        return false;
430
    }
431

    
432
    /**
433
     * Returns the previous vertex to a point.
434
     *
435
     * @param auxMultiLine
436
     * @param previousPoint
437
     * @return
438
     * @throws GeometryOperationException
439
     * @throws GeometryOperationNotSupportedException
440
     * @throws CreateGeometryException
441
     */
442
    private Point getPreviousVertexToPoint(MultiLine multiLine, Point point) throws CreateGeometryException,
443
        GeometryOperationNotSupportedException, GeometryOperationException {
444
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
445
        for (int i = 0; i < multiLine.getPrimitivesNumber(); i++) {
446
            Line line = (Line) multiLine.getPrimitiveAt(i);
447
            if (line.intersects(point)) {
448
                for (int j = 0; j < line.getNumVertices() - 1; j++) {
449
                    if (point.equals(line.getVertex(j + 1))) {
450
                        return line.getVertex(j);
451
                    }
452
                    Line auxLine = (Line) geomManager.create(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM);
453
                    auxLine.addVertex(line.getVertex(j));
454
                    auxLine.addVertex(line.getVertex(j + 1));
455
                    if (auxLine.intersects(point)) {
456
                        return line.getVertex(j);
457
                    }
458
                }
459
            }
460
        }
461
        return null;
462
    }
463

    
464
//    /**
465
//     * Returns the measure corresponding to the point into the geometry
466
//     *
467
//     * @param mGeometry
468
//     * @param point
469
//     * @return
470
//     * @throws GeometryOperationException
471
//     * @throws GeometryOperationNotSupportedException
472
//     * @throws CreateGeometryException
473
//     */
474
//    private double getM(MultiLine multiLine, Point point) throws GeometryOperationNotSupportedException,
475
//        GeometryOperationException, CreateGeometryException {
476
//        GeometryManager geomManager = GeometryLocator.getGeometryManager();
477
//        if (!(multiLine.getGeometryType().isSubTypeOf(Geometry.SUBTYPES.GEOM2DM))
478
//            || (multiLine.getGeometryType().isSubTypeOf(Geometry.SUBTYPES.GEOM3DM))) {
479
//            return Double.NaN;
480
//        }
481
//        if (!(point.getGeometryType().isSubTypeOf(Geometry.SUBTYPES.GEOM2DM))
482
//            || (point.getGeometryType().isSubTypeOf(Geometry.SUBTYPES.GEOM3DM))) {
483
//            return Double.NaN;
484
//        }
485
//        for (int i = 0; i < multiLine.getPrimitivesNumber(); i++) {
486
//            Line line = (Line) multiLine.getPrimitiveAt(i);
487
//            if (line.intersects(point)) {
488
//                for (int j = 0; j < line.getNumVertices() - 1; j++) {
489
//                    Point vertex1 = line.getVertex(j);
490
//                    double m1 = vertex1.getCoordinateAt(vertex1.getDimension() - 1);
491
//                    double x1 = vertex1.getX();
492
//                    double y1 = vertex1.getY();
493
//                    if (point.equals(vertex1)) {
494
//                        return m1;
495
//                    }
496
//                    Point vertex2 = line.getVertex(j + 1);
497
//                    double m2 = vertex2.getCoordinateAt(vertex2.getDimension() - 1);
498
//                    double x2 = vertex2.getX();
499
//                    double y2 = vertex2.getY();
500
//                    if (point.equals(vertex2)) {
501
//                        return m2;
502
//                    }
503
//                    Line auxLine = (Line) geomManager.create(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM);
504
//                    auxLine.addVertex(line.getVertex(j));
505
//                    auxLine.addVertex(line.getVertex(j + 1));
506
//                    if (auxLine.intersects(point)) {
507
//                        if (x1 != x2) {
508
//                            return strightLineThroughTwoPointsEquation(x1, x2, m1, m2, point.getX());
509
//                        } else {
510
//                            return strightLineThroughTwoPointsEquation(y1, y2, m1, m2, point.getY());
511
//                        }
512
//                    }
513
//                }
514
//            }
515
//        }
516
//        return Double.NaN;
517
//    }
518

    
519
    /**
520
     * Checks if a bifurcation occurs at one point and return the vertex with maximum M
521
     *
522
     * @param multiLine
523
     * @param vertex
524
     * @return
525
     */
526
    private Point getPossibleFork(MultiLine multiLine, Point point) {
527

    
528
        List<Point> vertices = new ArrayList<Point>();
529
        for (int i = 0; i < multiLine.getPrimitivesNumber(); i++) {
530
            Line line = (Line) multiLine.getPrimitiveAt(i);
531
            for (int j = 0; j < line.getNumVertices(); j++) {
532
                Point vertex = line.getVertex(j);
533
                if (areInSame2DLocation(vertex, point)) {
534
                    vertices.add(vertex);
535
                }
536
            }
537
        }
538
        if (vertices.size() > 0) {
539
            Double maxM = Double.NEGATIVE_INFINITY;
540
            Point forked = null;
541
            for (Iterator<Point> iterator = vertices.iterator(); iterator.hasNext();) {
542
                Point vertex = (Point) iterator.next();
543
                double m = vertex.getCoordinateAt(vertex.getDimension() - 1);
544
                if (m > maxM) {
545
                    maxM = m;
546
                    forked = vertex;
547
                }
548
            }
549
            return forked;
550
        }
551
        return null;
552
    }
553

    
554
    /**
555
     * Compares x & y coordinates of a point.
556
     *
557
     * @param p1
558
     * @param p2
559
     * @return
560
     */
561
    private boolean areInSame2DLocation(Point p1, Point p2) {
562
        return ((p1.getX() == p2.getX()) && (p1.getY() == p2.getY()));
563
    }
564

    
565
    /**
566
     * Returns the vertex of the multiline closest to a point
567
     *
568
     * @param mGeometry
569
     * @param vertex
570
     * @return
571
     * @throws GeometryOperationException
572
     * @throws GeometryOperationNotSupportedException
573
     * @throws CreateEnvelopeException
574
     */
575
    private Point getClosestVertex(MultiLine multiLine, Point point) throws CreateEnvelopeException,
576
        GeometryOperationNotSupportedException, GeometryOperationException {
577
        Point result = null;
578
        double minDistance = Double.POSITIVE_INFINITY;
579

    
580
        for (int i = 0; i < multiLine.getPrimitivesNumber(); i++) {
581
            Line line = (Line) multiLine.getPrimitiveAt(i);
582
            for (int j = 0; j < line.getNumVertices(); j++) {
583
                Point vertex = line.getVertex(j);
584
                double distance = point.distance(vertex);
585
                if (distance <= minDistance) {
586
                    minDistance = distance;
587
                    result = vertex;
588
                }
589
            }
590
        }
591

    
592
        return result;
593
    }
594

    
595
//    /**
596
//     * @param closestPoints
597
//     * @return
598
//     * @throws CreateEnvelopeException
599
//     * @throws GeometryOperationException
600
//     * @throws GeometryOperationNotSupportedException
601
//     */
602
//    private Point getClosestPointByCoordinatePriority(Geometry[] closestPoints) throws CreateEnvelopeException,
603
//        GeometryOperationNotSupportedException, GeometryOperationException {
604
//        LrsCoordinatesPriority coordinatePriority = parameters.getCoordinatePriority();
605
//        GeometryManager geomanager = GeometryLocator.getGeometryManager();
606
//        Envelope envelope = geomanager.createEnvelope(Geometry.SUBTYPES.GEOM2D);
607
//        for (int i = 0; i < closestPoints.length; i++) {
608
//            envelope.add(closestPoints[i]);
609
//        }
610
//        Point origin = envelope.getLowerCorner();
611
//        switch (coordinatePriority) {
612
//        case DOWN_LEFT:
613
//            break;
614
//        case DOWN_RIGHT:
615
//            Double maxX = envelope.getMaximum(DIMENSIONS.X);
616
//            origin.setX(maxX);
617
//            break;
618
//        case UP_LEFT:
619
//            Double maxY = envelope.getMaximum(DIMENSIONS.Y);
620
//            origin.setY(maxY);
621
//            break;
622
//        case UP_RIGHT:
623
//            origin = envelope.getUpperCorner();
624
//            break;
625
//        default:
626
//            break;
627
//        }
628
//        Point closestPoint = null;
629
//        double minDistance = Double.POSITIVE_INFINITY;
630
//        for (int i = 0; i < closestPoints.length; i++) {
631
//            Point point = (Point) closestPoints[i];
632
//            double distance = origin.distance(point);
633
//            if (minDistance > distance) {
634
//                minDistance = distance;
635
//                closestPoint = point;
636
//            }
637
//        }
638
//        return closestPoint;
639
//    }
640

    
641
//    private Double getCalculatedMValueForFirstPoint(Geometry mGeometry, Geometry geometry) {
642
//        List<Point> mPoints = extractPoints(mGeometry);
643
//        Point point = extractFirstPoint(geometry);
644
//        for (Point mPoint : mPoints) {
645
//            if (mPoint.getX() == point.getX() && mPoint.getY() == point.getY()) {
646
//                int dimensionM = mPoint.getDimension() - 1;
647
//                return mPoint.getCoordinateAt(dimensionM);
648
//            }
649
//        }
650
//        return null;
651
//    }
652

    
653
    /**
654
     * Returns a multiline calculate by two field method
655
     *
656
     * @param mList
657
     * @return
658
     * @throws CreateGeometryException
659
     * @throws GeometryOperationNotSupportedException
660
     * @throws GeometryOperationException
661
     */
662
    private MultiLine calculateGeometryByTwoField(List<MSegment> mList) throws CreateGeometryException,
663
        GeometryOperationNotSupportedException, GeometryOperationException {
664
        GeometryManager geomanager = GeometryLocator.getGeometryManager();
665
        MultiLine mGeometry = (MultiLine) geomanager.create(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM);
666

    
667
        for (MSegment mSegment : mList) {
668
            Geometry geometry = mSegment.geometry;
669
            List<Line> geometryLines = extractLines(geometry);
670
            Double geometryLength = LrsAlgorithmUtils.getGeometryLength(geometry);
671

    
672
            Double geometryMFirstPoint = mSegment.fromValue;
673
            Double geometryMLastPoint = mSegment.toValue;
674

    
675
            Double distance = Double.valueOf(0);
676
            for (Line line : geometryLines) {
677
                Double lineLength = getLineLength(line);
678
                Double mFirstPoint = calculateM(geometryMLastPoint, geometryMFirstPoint, distance, geometryLength);
679
                distance += lineLength;
680
                Double mLastPoint = calculateM(geometryMLastPoint, geometryMFirstPoint, distance, geometryLength);
681
                Line mLine = lineToMLine(line, mFirstPoint, mLastPoint);
682
                mGeometry.addPrimitive(mLine);
683
            }
684
        }
685

    
686
        return mGeometry;
687
    }
688

    
689
    /**
690
     * Converts a Line2D in a Line2DM filled it with proportional calculated M's
691
     *
692
     * @param line
693
     * @param minMValue
694
     * @param maxMValue
695
     * @return
696
     * @throws CreateGeometryException
697
     * @throws GeometryOperationNotSupportedException
698
     * @throws GeometryOperationException
699
     */
700
    private Line lineToMLine(Line line, Double minMValue, Double maxMValue) throws CreateGeometryException,
701
        GeometryOperationNotSupportedException, GeometryOperationException {
702
        GeometryManager geomanager = GeometryLocator.getGeometryManager();
703
        Double lineLength = getLineLength(line);
704
        Line lineM = (Line) geomanager.create(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM);
705
        Double inLineDistance = Double.valueOf(0);
706
        for (int i = 0; i < line.getNumVertices(); i++) {
707
            Point vertex = line.getVertex(i);
708
            Point mVertex = (Point) geomanager.create(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM);
709
            mVertex.setX(vertex.getX());
710
            mVertex.setY(vertex.getY());
711

    
712
            Double mValue;
713
            if (i == 0)
714
                mValue = minMValue;
715
            else if (i == line.getNumVertices() - 1)
716
                mValue = maxMValue;
717
            else {
718
                Point previousVertex = line.getVertex(i - 1);
719
                inLineDistance += vertex.distance(previousVertex);
720
                mValue = calculateM(maxMValue, minMValue, inLineDistance, lineLength);
721
            }
722

    
723
            mVertex.setCoordinateAt(mVertex.getDimension() - 1, mValue);
724
            lineM.addVertex(mVertex);
725
        }
726
        return lineM;
727
    }
728

    
729
    /**
730
     * Reduced versi?n of stright line through two points equation to calculate M's
731
     *
732
     * @param maxValue
733
     * @param minValue
734
     * @param relativeDistance
735
     * @param totalLength
736
     * @return
737
     */
738
    private Double calculateM(Double maxValue, Double minValue, Double relativeDistance, Double totalLength) {
739
        if (totalLength.equals(Double.valueOf(0)))
740
            return Double.POSITIVE_INFINITY;
741
        return ((maxValue - minValue) * (relativeDistance) / (totalLength)) + minValue;
742
    }
743

    
744
    /**
745
     * Stright line through two points equation.
746
     *
747
     * @param x1
748
     * @param x2
749
     * @param y1
750
     * @param y2
751
     * @param x
752
     * @return
753
     */
754
    private double strightLineThroughTwoPointsEquation(double x1, double x2, double y1, double y2, double x) {
755
        if (x2 - x1 == 0.0) {
756
            return Double.POSITIVE_INFINITY;
757
        }
758
        return ((y2 - y1) * (x - x1) / (x2 - x1)) + y1;
759
    }
760

    
761
    /**
762
     * Simplify the multilines in mList calling simplifyMultiline method
763
     *
764
     * @param mList
765
     * @throws CreateGeometryException
766
     * @throws LocatorException
767
     */
768
    private void simplifyMultilines(List<MSegment> mList) throws CreateGeometryException, LocatorException {
769
        for (MSegment mSegment : mList) {
770
            mSegment.geometry = simplifyMultiline(mSegment.geometry);
771
        }
772
    }
773

    
774
    /**
775
     * Simplify a Multiline ordering and joining her lines if can.
776
     *
777
     * @param geometry
778
     * @return
779
     * @throws CreateGeometryException
780
     * @throws LocatorException
781
     */
782
    private Geometry simplifyMultiline(Geometry geometry) throws CreateGeometryException, LocatorException {
783
        if (geometry instanceof MultiLine) {
784
            MultiLine multiline = (MultiLine) geometry;
785

    
786
            if (multiline.getPrimitivesNumber() == 1) {
787
                return multiline.getPrimitiveAt(0);
788
            } else {
789
                List<Line> simplifiedLines = new ArrayList<Line>();
790
                List<Line> complexLines = new ArrayList<Line>();
791
                for (int i = 0; i < multiline.getPrimitivesNumber(); i++) {
792
                    complexLines.add((Line) multiline.getPrimitiveAt(i));
793
                }
794

    
795
                Line line = null;
796
                while (complexLines.size() > 0) {
797
                    line = complexLines.remove(0);
798
                    int i = 0;
799
                    while (i < complexLines.size()) {
800
                        Line auxLine = complexLines.get(i);
801
                        Line unitedLine = unionAdjacentLines(line, auxLine);
802
                        if (unitedLine != null) {
803
                            line = unitedLine;
804
                            complexLines.remove(i);
805
                            i = 0;
806
                        } else {
807
                            i++;
808
                        }
809
                    }
810
                    simplifiedLines.add(line);
811
                }
812

    
813
                if (simplifiedLines.size() == 1) {
814
                    geometry = simplifiedLines.get(0);
815
                } else {
816
                    MultiLine simplifiedMultiLine =
817
                        (MultiLine) GeometryLocator.getGeometryManager().create(multiline.getGeometryType());
818
                    for (Line simpleLine : simplifiedLines) {
819
                        simplifiedMultiLine.addPrimitive(simpleLine);
820
                    }
821
                    return simplifiedMultiLine;
822
                }
823
            }
824
        }
825
        return geometry;
826
    }
827

    
828
    /**
829
     * Join two adjacent lines flipping it if necessary
830
     *
831
     * @param line1
832
     * @param line2
833
     * @return
834
     */
835
    private Line unionAdjacentLines(Line line1, Line line2) {
836
        if (line1 == null || line2 == null) {
837
            return null;
838
        }
839
        Line resultLine;
840
        try {
841
            resultLine = (Line) GeometryLocator.getGeometryManager().create(line1.getGeometryType());
842
        } catch (Exception e) {
843
            return null;
844
        }
845

    
846
        Point firstPointL1 = line1.getVertex(0);
847
        Point lastPointL1 = line1.getVertex(line1.getNumVertices() - 1);
848
        Point firstPointL2 = line2.getVertex(0);
849
        Point lastPointL2 = line2.getVertex(line2.getNumVertices() - 1);
850
        if (lastPointL1.equals(firstPointL2)) {
851
            resultLine = (Line) line1.cloneGeometry();
852
            for (int i = 1; i < line2.getNumVertices(); i++) {
853
                resultLine.addVertex((Point) line2.getVertex(i).cloneGeometry());
854
            }
855
            return resultLine;
856
        }
857
        if (lastPointL2.equals(firstPointL1)) {
858
            resultLine = (Line) line2.cloneGeometry();
859
            for (int i = 1; i < line1.getNumVertices(); i++) {
860
                resultLine.addVertex((Point) line1.getVertex(i).cloneGeometry());
861
            }
862
            return resultLine;
863
        }
864
        if (firstPointL1.equals(firstPointL2)) {
865
            for (int i = line1.getNumVertices() - 1; i >= 0; i--) {
866
                resultLine.addVertex((Point) line1.getVertex(i).cloneGeometry());
867
            }
868
            for (int i = 1; i < line2.getNumVertices(); i++) {
869
                resultLine.addVertex((Point) line2.getVertex(i).cloneGeometry());
870
            }
871
            return resultLine;
872
        }
873
        if (lastPointL1.equals(lastPointL2)) {
874
            resultLine = (Line) line1.cloneGeometry();
875
            for (int i = line2.getNumVertices() - 2; i >= 0; i--) {
876
                resultLine.addVertex((Point) line2.getVertex(i).cloneGeometry());
877
            }
878
            return resultLine;
879
        }
880
        return null;
881
    }
882

    
883
//    /**
884
//     * Calculate distance between a point and the firstPoint of the geometry
885
//     *
886
//     * @param point
887
//     * @param geometry
888
//     * @return
889
//     * @throws GeometryOperationNotSupportedException
890
//     * @throws GeometryOperationException
891
//     */
892
//    private Double calculateGap(Point point, Geometry geometry) throws GeometryOperationNotSupportedException,
893
//        GeometryOperationException {
894
//        Double gap = new Double(0);
895
//        if (geometry instanceof Line) {
896
//            Line line = (Line) geometry;
897
//            if (point != null) {
898
//                Point firstPoint = line.getVertex(0);
899
//                gap = firstPoint.distance(point);
900
//            }
901
//        }
902
//        if (geometry instanceof MultiLine) {
903
//            MultiLine multiLine = (MultiLine) geometry;
904
//            if (point != null) {
905
//                Line line = (Line) multiLine.getPrimitiveAt(0);
906
//                Point firstPoint = line.getVertex(0);
907
//                gap = firstPoint.distance(point);
908
//            }
909
//        }
910
//        return gap;
911
//    }
912

    
913
    /**
914
     * Sorts mList
915
     *
916
     * @param mList
917
     * @return
918
     * @throws CreateEnvelopeException
919
     * @throws GeometryOperationNotSupportedException
920
     * @throws GeometryOperationException
921
     */
922
    private List<MSegment> sortMList(List<MSegment> mList) throws CreateEnvelopeException,
923
        GeometryOperationNotSupportedException, GeometryOperationException {
924
        LrsCoordinatesPriority coordinatePriority = parameters.getCoordinatePriority();
925
        GeometryManager geomanager = GeometryLocator.getGeometryManager();
926
        Envelope envelope = geomanager.createEnvelope(Geometry.SUBTYPES.GEOM2D);
927
        for (MSegment mSegment : mList) {
928
            envelope.add(mSegment.geometry.getEnvelope());
929
        }
930
        Point origin = envelope.getLowerCorner();
931
        switch (coordinatePriority) {
932
        case DOWN_LEFT:
933
            break;
934
        case DOWN_RIGHT:
935
            Double maxX = envelope.getMaximum(DIMENSIONS.X);
936
            origin.setX(maxX);
937
            break;
938
        case UP_LEFT:
939
            Double maxY = envelope.getMaximum(DIMENSIONS.Y);
940
            origin.setY(maxY);
941
            break;
942
        case UP_RIGHT:
943
            origin = envelope.getUpperCorner();
944
            break;
945
        default:
946
            break;
947
        }
948

    
949
        List<Stretch> stretches = createStretches(mList, origin);
950
        stretches = sortStretches(stretches, origin);
951
        return extractSegmentsFromStretches(stretches);
952
    }
953

    
954
    /**
955
     * Extracts segment from stretches and returns a list of segment.
956
     *
957
     * @param stretches
958
     * @return
959
     */
960
    private List<MSegment> extractSegmentsFromStretches(List<Stretch> stretches) {
961
        List<MSegment> result = new ArrayList<MSegment>();
962
        for (Stretch stretch : stretches) {
963
            for (int i = 0; i < stretch.getSegmentNumber(); i++) {
964
                result.add(stretch.getSegment(i));
965
            }
966
        }
967
        return result;
968
    }
969

    
970
    /**
971
     * Sort the stretches
972
     *
973
     * @param stretches
974
     * @param origin
975
     * @return
976
     * @throws GeometryOperationNotSupportedException
977
     * @throws GeometryOperationException
978
     */
979
    private List<Stretch> sortStretches(List<Stretch> stretches, Point origin)
980
        throws GeometryOperationNotSupportedException, GeometryOperationException {
981
        List<Stretch> result = new ArrayList<Stretch>();
982

    
983
        Point originPoint = origin;
984
        while (result.size() < stretches.size()) {
985
            // Buscamos tramos que sean adyacentes al origin
986
            if (result.size() == 0) {
987
                addUnvisitedAdjacentStretches(stretches, result, originPoint);
988
            }
989
            if (result.size() == 0) {
990
                result.add(getNearestUnvisitedStretch(stretches, originPoint, result));
991
            }
992

    
993
            boolean addedAdjacentStretches = true;
994
            while (addedAdjacentStretches) {
995
                addedAdjacentStretches = false;
996
                int visitedNumber = result.size();
997
                for (int i = 0; i < visitedNumber; i++) {
998
                    Stretch visited = result.get(i);
999
                    addUnvisitedAdjacentStretches(stretches, result, visited.getFinalPoint());
1000
                }
1001
                addedAdjacentStretches = (visitedNumber < result.size());
1002
            }
1003

    
1004
            int visitedNumber = result.size();
1005
            for (int i = visitedNumber - 1; i >= 0; i--) {
1006
                Stretch visited = result.get(i);
1007
                Stretch nearest = getNearestUnvisitedStretch(stretches, visited.getFinalPoint(), result);
1008
                if (nearest != null) {
1009
                    result.add(nearest);
1010
                    break;
1011
                }
1012
            }
1013
        }
1014
        return result;
1015
    }
1016

    
1017
    /**
1018
     * Adds unvisited adjacent stretches to the visited list
1019
     *
1020
     * @param stretches
1021
     * @param visited
1022
     * @param originPoint
1023
     * @throws GeometryOperationNotSupportedException
1024
     * @throws GeometryOperationException
1025
     */
1026
    private void addUnvisitedAdjacentStretches(List<Stretch> stretches, List<Stretch> visited, Point originPoint)
1027
        throws GeometryOperationNotSupportedException, GeometryOperationException {
1028
        for (Stretch stretch : stretches) {
1029
            if (!visited.contains(stretch)) {
1030
                if (areInSame2DLocation(stretch.getInitialPoint(), originPoint)) {
1031
                    visited.add(stretch);
1032
                } else if (areInSame2DLocation(stretch.getFinalPoint(), originPoint)) {
1033
                    visited.add(stretch.flip());
1034
                }
1035
            }
1036
        }
1037
    }
1038

    
1039
    /**
1040
     * Returns the unvisited stretch nearest to a point
1041
     *
1042
     * @param stretches
1043
     * @param origin
1044
     * @param visited
1045
     * @return
1046
     * @throws GeometryOperationNotSupportedException
1047
     * @throws GeometryOperationException
1048
     */
1049
    private Stretch getNearestUnvisitedStretch(List<Stretch> stretches, Point origin, List<Stretch> visited)
1050
        throws GeometryOperationNotSupportedException, GeometryOperationException {
1051

    
1052
        double minDistance = Double.POSITIVE_INFINITY;
1053
        Stretch nearest = null;
1054
        boolean needFlip = false;
1055
        for (Stretch stretch : stretches) {
1056
            if (!visited.contains(stretch)) {
1057
                Double initialDistance = origin.distance(stretch.getInitialPoint());
1058
                if (initialDistance < minDistance) {
1059
                    minDistance = initialDistance;
1060
                    nearest = stretch;
1061
                    needFlip = false;
1062
                }
1063
                Double finalDistance = origin.distance(stretch.getFinalPoint());
1064
                if (finalDistance < minDistance) {
1065
                    minDistance = finalDistance;
1066
                    nearest = stretch;
1067
                    needFlip = true;
1068
                }
1069
            }
1070
        }
1071
        if (needFlip && nearest != null) {
1072
            nearest.flip();
1073
        }
1074
        return nearest;
1075
    }
1076

    
1077
    /**
1078
     * Creates stretches from mList and returns a list of stretches
1079
     *
1080
     * @param mList
1081
     * @param origin
1082
     * @return
1083
     * @throws GeometryOperationNotSupportedException
1084
     * @throws GeometryOperationException
1085
     */
1086
    private List<Stretch> createStretches(List<MSegment> mList, Point origin)
1087
        throws GeometryOperationNotSupportedException, GeometryOperationException {
1088

    
1089
        List<MSegment> addedMSegment = new ArrayList<LrsCreateRouteAlgorithm.MSegment>();
1090
        List<Stretch> stretches = new ArrayList<Stretch>();
1091
        while (addedMSegment.size() < mList.size()) {
1092
            for (MSegment mSegment : mList) {
1093
                if (!addedMSegment.contains(mSegment)) {
1094
                    Stretch stretch = new Stretch();
1095
                    stretches.add(stretch);
1096
                    stretch.addSegment(mSegment);
1097
                    addedMSegment.add(mSegment);
1098

    
1099
                    List<MSegment> initialNextSegments =
1100
                        mSegment.searchNextSegments(stretch.getInitialPoint(), mList);
1101
                    do {
1102
                        if (initialNextSegments.size() == 1) {
1103
                            MSegment previousSegment = initialNextSegments.get(0);
1104
                            if (!addedMSegment.contains(previousSegment)) {
1105
                                if (!previousSegment.getFinalPoint().equals(stretch.getInitialPoint())) {
1106
                                    previousSegment.flip();
1107
                                }
1108
                                stretch.addSegment(0, previousSegment);
1109
                                addedMSegment.add(previousSegment);
1110
                                initialNextSegments =
1111
                                    previousSegment.searchNextSegments(stretch.getInitialPoint(), mList);
1112
                            } else {
1113
                                break;
1114
                            }
1115
                        } else {
1116
                            break;
1117
                        }
1118
                    } while (initialNextSegments.size() == 1);
1119

    
1120
                    List<MSegment> finalNextSegments =
1121
                        mSegment.searchNextSegments(stretch.getFinalPoint(), mList);
1122
                    do {
1123
                        if (finalNextSegments.size() == 1) {
1124
                            MSegment nextSegment = finalNextSegments.get(0);
1125
                            if (!addedMSegment.contains(nextSegment)) {
1126
                                if (!nextSegment.getInitialPoint().equals(stretch.getFinalPoint())) {
1127
                                    nextSegment.flip();
1128
                                }
1129
                                stretch.addSegment(nextSegment);
1130
                                addedMSegment.add(nextSegment);
1131
                                finalNextSegments =
1132
                                    nextSegment.searchNextSegments(stretch.getFinalPoint(), mList);
1133
                            } else {
1134
                                break;
1135
                            }
1136
                        } else {
1137
                            break;
1138
                        }
1139
                    } while ((finalNextSegments.size() == 1));
1140
                }
1141
            }
1142
        }
1143
        return stretches;
1144
    }
1145

    
1146

    
1147
//    private Point extractFirstPoint(Geometry geometry) {
1148
//        Point firstPoint = null;
1149
//        List<Line> lines = extractLines(geometry);
1150
//        if (lines != null && !lines.isEmpty()) {
1151
//            firstPoint = lines.get(0).getVertex(0);
1152
//        }
1153
//        return firstPoint;
1154
//    }
1155

    
1156
//    private List<Point> extractPoints(Geometry geometry) {
1157
//        List<Point> points = new ArrayList<Point>();
1158
//        List<Line> lines = extractLines(geometry);
1159
//        for (Line line : lines) {
1160
//            for (int i = 0; i < line.getNumVertices(); i++) {
1161
//                points.add(line.getVertex(i));
1162
//            }
1163
//        }
1164
//        return points;
1165
//    }
1166

    
1167
    /**
1168
     * Extracts lines of a geometry.
1169
     *
1170
     * @param geometry
1171
     * @return
1172
     */
1173
    private List<Line> extractLines(Geometry geometry) {
1174
        List<Line> lines = new ArrayList<Line>();
1175
        if (geometry instanceof Line) {
1176
            lines.add((Line) geometry);
1177
        }
1178
        if (geometry instanceof MultiLine) {
1179
            MultiLine multiline = (MultiLine) geometry;
1180
            for (int i = 0; i < multiline.getPrimitivesNumber(); i++) {
1181
                lines.add((Line) multiline.getPrimitiveAt(i));
1182
            }
1183
        }
1184
        return lines;
1185
    }
1186

    
1187
    /**
1188
     * Applies offsetAndFactor to a route
1189
     *
1190
     * @param geometry
1191
     * @return
1192
     */
1193
    private Geometry applyOffsetAndFactor(Geometry geometry) {
1194
        double measureFactor = parameters.getMeasureFactor();
1195
        double measureOffset = parameters.getMeasureOffset();
1196
        if (geometry instanceof Line) {
1197
            Line line = (Line) geometry;
1198
            for (int i = 0; i < line.getNumVertices(); i++) {
1199
                Point mVertex = line.getVertex(i);
1200
                Double mValue = mVertex.getCoordinateAt(mVertex.getDimension() - 1);
1201
                Double newMValue = (mValue * measureFactor) + measureOffset;
1202
                mVertex.setCoordinateAt(mVertex.getDimension() - 1, newMValue);
1203
                line.setVertex(i, mVertex);
1204
            }
1205
        }
1206
        if (geometry instanceof MultiLine) {
1207
            MultiLine multiLine = (MultiLine) geometry;
1208
            for (int i = 0; i < multiLine.getPrimitivesNumber(); i++) {
1209
                Line line = (Line) multiLine.getPrimitiveAt(i);
1210
                for (int j = 0; j < line.getNumVertices(); j++) {
1211
                    Point mVertex = line.getVertex(j);
1212
                    Double mValue = mVertex.getCoordinateAt(mVertex.getDimension() - 1);
1213
                    Double newMValue = (mValue * measureFactor) + measureOffset;
1214
                    mVertex.setCoordinateAt(mVertex.getDimension() - 1, newMValue);
1215
                    line.setVertex(j, mVertex);
1216
                }
1217
            }
1218
        }
1219
        return geometry;
1220
    }
1221

    
1222
//    private Map<Object, List<FeatureReference>> getGroupedReferences(FeatureSelection selection,
1223
//        final FeatureAttributeDescriptor idRouteField) throws BaseException {
1224
//        final Map<Object, List<FeatureReference>> refs = new HashMap<Object, List<FeatureReference>>();
1225
//        selection.accept(new Visitor() {
1226
//
1227
//            public void visit(Object obj) throws VisitCanceledException, BaseException {
1228
//                Feature feature = (Feature) obj;
1229
//                Object id = feature.getFeature(idRouteField.getName());
1230
//                FeatureReference reference = feature.getReference();
1231
//                List<FeatureReference> references = refs.get(id);
1232
//                if (references == null) {
1233
//                    references = new ArrayList<FeatureReference>();
1234
//                }
1235
//                references.add(reference);
1236
//                refs.put(id, references);
1237
//            }
1238
//        });
1239
//        return refs;
1240
//    }
1241

    
1242
    /**
1243
     * Returns the geometric length of a line
1244
     *
1245
     * @param line
1246
     * @return lenght
1247
     * @throws GeometryOperationException
1248
     * @throws GeometryOperationNotSupportedException
1249
     */
1250
    private double getLineLength(Line line) throws GeometryOperationNotSupportedException, GeometryOperationException {
1251
        double lenght = 0;
1252
        Point previousVertex = null;
1253
        for (int i = 0; i < line.getNumVertices(); i++) {
1254
            Point vertex = line.getVertex(i);
1255
            if (previousVertex != null) {
1256
                lenght += previousVertex.distance(vertex);
1257
            }
1258
            previousVertex = vertex;
1259
        }
1260
        return lenght;
1261
    }
1262

    
1263
//    /**
1264
//     * @param multiLine
1265
//     * @return lenght
1266
//     * @throws GeometryOperationException
1267
//     * @throws GeometryOperationNotSupportedException
1268
//     */
1269
//    private double getMultiLineLength(MultiLine multiLine, boolean ignoreSpatialGaps)
1270
//        throws GeometryOperationNotSupportedException, GeometryOperationException {
1271
//        // We assume that the primitives are consecutive.
1272
//        double lenght = 0;
1273
//        Point previousVertex = null;
1274
//        for (int j = 0; j < multiLine.getPrimitivesNumber(); j++) {
1275
//            Line line = (Line) multiLine.getPrimitiveAt(j);
1276
//            if (ignoreSpatialGaps) {
1277
//                previousVertex = null;
1278
//            }
1279
//            for (int i = 0; i < line.getNumVertices(); i++) {
1280
//                Point vertex = line.getVertex(i);
1281
//                if (previousVertex != null) {
1282
//                    lenght += previousVertex.distance(vertex);
1283
//                }
1284
//                previousVertex = vertex;
1285
//            }
1286
//        }
1287
//        return lenght;
1288
//    }
1289

    
1290
    /*
1291
     * (non-Javadoc)
1292
     *
1293
     * @see org.gvsig.lrs.lib.api.LrsAlgorithm#setParams(org.gvsig.lrs.lib.api.
1294
     * LrsAlgorithmParams)
1295
     */
1296
    public void setParams(LrsAlgorithmParams params) throws IllegalArgumentException {
1297
        if (!(params instanceof LrsCreateRouteAlgorithmParams)) {
1298
            throw new IllegalArgumentException("params should be LrsCreateRouteAlgorithmParams type.");
1299
        }
1300
    }
1301

    
1302
    private class MSegment {
1303

    
1304
        Geometry geometry;
1305
        Double fromValue;
1306
        Double toValue;
1307
        int id;
1308

    
1309
        protected MSegment clone() {
1310
            MSegment cloned = new MSegment();
1311
            cloned.geometry = geometry.cloneGeometry();
1312

    
1313
            cloned.fromValue = null;
1314
            if (fromValue != null) {
1315
                cloned.fromValue = new Double(fromValue);
1316
            }
1317

    
1318
            cloned.toValue = null;
1319
            if (toValue != null) {
1320
                cloned.toValue = new Double(toValue);
1321
            }
1322

    
1323
            cloned.id = id;
1324

    
1325
            return cloned;
1326
        }
1327

    
1328
        protected Point getInitialPoint() {
1329
            if (geometry instanceof Line) {
1330
                Line line = ((Line) geometry);
1331
                return line.getVertex(0);
1332
            } else if (geometry instanceof MultiLine) {
1333
                MultiLine multiLine = (MultiLine) geometry;
1334
                Line firstLine = ((Line) multiLine.getPrimitiveAt(0));
1335
                return firstLine.getVertex(0);
1336
            }
1337
            return null;
1338
        }
1339

    
1340
        protected Point getFinalPoint() {
1341
            if (geometry instanceof Line) {
1342
                Line line = ((Line) geometry);
1343
                return line.getVertex(line.getNumVertices() - 1);
1344
            } else if (geometry instanceof MultiLine) {
1345
                MultiLine multiLine = (MultiLine) geometry;
1346
                Line lastLine = ((Line) multiLine.getPrimitiveAt(multiLine.getPrimitivesNumber() - 1));
1347
                return lastLine.getVertex(lastLine.getNumVertices() - 1);
1348
            }
1349
            return null;
1350
        }
1351

    
1352
        protected void flip() throws GeometryOperationNotSupportedException, GeometryOperationException {
1353
            geometry.flip();
1354
        }
1355

    
1356
        /**
1357
         * @param point
1358
         * @param mList
1359
         * @return
1360
         */
1361
        protected List<MSegment> searchNextSegments(Point point, List<MSegment> mList) {
1362
            List<MSegment> result = new ArrayList<LrsCreateRouteAlgorithm.MSegment>();
1363
            for (Iterator<MSegment> iterator = mList.iterator(); iterator.hasNext();) {
1364
                MSegment mSegment = (MSegment) iterator.next();
1365
                if (mSegment != this) { // !addedSegments.contains(mSegment)) {
1366
                    Geometry geom = mSegment.geometry;
1367
                    if (geom instanceof Line) {
1368
                        Line line = ((Line) geom);
1369
                        if (line.getVertex(0).equals(point) || line.getVertex(line.getNumVertices() - 1).equals(point)) {
1370
                            result.add(mSegment);
1371
                        }
1372
                        ;
1373
                    } else if (geom instanceof MultiLine) {
1374
                        MultiLine multiLine = (MultiLine) geom;
1375
                        Line firstLine = ((Line) multiLine.getPrimitiveAt(0));
1376
                        Line lastLine = ((Line) multiLine.getPrimitiveAt(multiLine.getPrimitivesNumber() - 1));
1377
                        if (firstLine.getVertex(0).equals(point)
1378
                            || lastLine.getVertex(lastLine.getNumVertices() - 1).equals(point)) {
1379
                            result.add(mSegment);
1380
                        }
1381
                    }
1382
                }
1383
            }
1384
            return result;
1385
        }
1386

    
1387
        public double getLength(boolean ignoreSpatialGaps) throws GeometryOperationNotSupportedException,
1388
            GeometryOperationException {
1389
            return LrsAlgorithmUtils.getGeometryLength(geometry, ignoreSpatialGaps);
1390
        }
1391
    }
1392

    
1393
    private class Stretch {
1394

    
1395
        private List<MSegment> segments;
1396
        private Point initialPoint;
1397
        private Point finalPoint;
1398

    
1399
        public Stretch() {
1400
            segments = new ArrayList<MSegment>();
1401
        }
1402

    
1403
        public MSegment getSegment(int index) {
1404
            return segments.get(index);
1405
        }
1406

    
1407
        public int getSegmentNumber() {
1408
            return segments.size();
1409
        }
1410

    
1411
        public void addSegment(MSegment segment) {
1412
            if (segments.isEmpty()) {
1413
                initialPoint = segment.getInitialPoint();
1414
            }
1415
            finalPoint = segment.getFinalPoint();
1416
            segments.add(segment);
1417
        }
1418

    
1419
        public void addSegment(int index, MSegment segment) {
1420
            if (index == 0) {
1421
                initialPoint = segment.getInitialPoint();
1422
            }
1423
            if (index >= segments.size()) {
1424
                finalPoint = segment.getFinalPoint();
1425
            }
1426
            segments.add(index, segment);
1427
        }
1428

    
1429
        public double getLength(boolean ignoreSpatialGaps) throws GeometryOperationNotSupportedException,
1430
            GeometryOperationException {
1431
            double result = 0.0;
1432
            for (MSegment segment : segments) {
1433
                result += segment.getLength(ignoreSpatialGaps);
1434
            }
1435
            return result;
1436
        }
1437

    
1438
        public Stretch flip() throws GeometryOperationNotSupportedException, GeometryOperationException {
1439
            Collections.reverse(segments);
1440
            for (Iterator<MSegment> iterator = segments.iterator(); iterator.hasNext();) {
1441
                MSegment segment = (MSegment) iterator.next();
1442
                segment.flip();
1443
            }
1444
            Point aux = initialPoint;
1445
            initialPoint = finalPoint;
1446
            finalPoint = aux;
1447
            return this;
1448
        }
1449

    
1450
        public Point getInitialPoint() {
1451
            return initialPoint;
1452
        }
1453

    
1454
        public Point getFinalPoint() {
1455
            return finalPoint;
1456
        }
1457

    
1458
    }
1459

    
1460
//    private class PointToReferencePointComparator implements Comparator<Point> {
1461
//
1462
//        private Point referencePoint;
1463
//
1464
//        public PointToReferencePointComparator(Point referencePoint) {
1465
//            this.referencePoint = referencePoint;
1466
//        }
1467
//
1468
//        public int compare(Point point1, Point point2) {
1469
//            Double distance1;
1470
//            try {
1471
//                distance1 = point1.distance(referencePoint);
1472
//            } catch (Exception e) {
1473
//                distance1 = Double.MAX_VALUE;
1474
//            }
1475
//            Double distance2;
1476
//            try {
1477
//                distance2 = point2.distance(referencePoint);
1478
//            } catch (Exception e) {
1479
//                distance2 = Double.MAX_VALUE;
1480
//            }
1481
//            return distance1.compareTo(distance2);
1482
//        }
1483
//    }
1484

    
1485
}