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 / LrsCalibrateRouteAlgorithm.java @ 68

History | View | Annotate | Download (34.6 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.HashMap;
27
import java.util.List;
28
import java.util.Map;
29
import java.util.Map.Entry;
30

    
31
import org.cresques.cts.IProjection;
32
import org.slf4j.Logger;
33
import org.slf4j.LoggerFactory;
34

    
35
import org.gvsig.fmap.dal.feature.EditableFeature;
36
import org.gvsig.fmap.dal.feature.Feature;
37
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
38
import org.gvsig.fmap.dal.feature.FeatureSet;
39
import org.gvsig.fmap.dal.feature.FeatureStore;
40
import org.gvsig.fmap.dal.feature.NewFeatureStoreParameters;
41
import org.gvsig.fmap.geom.Geometry;
42
import org.gvsig.fmap.geom.GeometryLocator;
43
import org.gvsig.fmap.geom.GeometryManager;
44
import org.gvsig.fmap.geom.exception.CreateGeometryException;
45
import org.gvsig.fmap.geom.operation.GeometryOperationException;
46
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
47
import org.gvsig.fmap.geom.primitive.Line;
48
import org.gvsig.fmap.geom.primitive.Point;
49
import org.gvsig.lrs.lib.api.DistanceUnits;
50
import org.gvsig.lrs.lib.api.LrsAlgorithm;
51
import org.gvsig.lrs.lib.api.LrsAlgorithmParams;
52
import org.gvsig.lrs.lib.api.LrsCalibrateRouteAlgorithmParams;
53
import org.gvsig.lrs.lib.api.LrsCreateRouteAlgorithmParams;
54
import org.gvsig.lrs.lib.api.LrsMeasureCalculationMethods;
55
import org.gvsig.lrs.lib.api.exceptions.LrsCalibrateRouteException;
56
import org.gvsig.lrs.lib.api.exceptions.LrsException;
57
import org.gvsig.tools.ToolsLocator;
58
import org.gvsig.tools.exception.BaseException;
59
import org.gvsig.tools.i18n.I18nManager;
60
import org.gvsig.tools.service.Manager;
61
import org.gvsig.tools.task.SimpleTaskStatus;
62
import org.gvsig.tools.visitor.VisitCanceledException;
63
import org.gvsig.tools.visitor.Visitor;
64

    
65
/**
66
 * @author dmartinez
67
 *
68
 */
69
public class LrsCalibrateRouteAlgorithm implements LrsAlgorithm {
70

    
71
    private static final Logger logger = LoggerFactory.getLogger(LrsCalibrateRouteAlgorithm.class);
72

    
73
    private LrsCalibrateRouteAlgorithmParams parameters;
74

    
75
    /**
76
     *
77
     */
78
    public LrsCalibrateRouteAlgorithm(LrsCalibrateRouteAlgorithmParams parameters) {
79
        this.parameters = parameters;
80

    
81
    }
82

    
83
    /*
84
     * (non-Javadoc)
85
     *
86
     * @see org.gvsig.tools.service.Service#getManager()
87
     */
88
    public Manager getManager() {
89
        return null;
90
    }
91

    
92
    /*
93
     * (non-Javadoc)
94
     *
95
     * @see org.gvsig.lrs.lib.api.LrsAlgorithm#getParams()
96
     */
97
    public  LrsAlgorithmParams getParams() {
98
        return this.parameters;
99
    }
100

    
101
    /* (non-Javadoc)
102
     * @see org.gvsig.lrs.lib.api.LrsAlgorithm#setParams(org.gvsig.lrs.lib.api.LrsAlgorithmParams)
103
     */
104
    public void setParams(LrsAlgorithmParams params) throws IllegalArgumentException {
105
        if(!(params instanceof LrsCreateRouteAlgorithmParams)){
106
            throw new IllegalArgumentException("params should be LrsCalibrateRouteAlgorithmParams type.");
107
        }
108
        this.parameters = (LrsCalibrateRouteAlgorithmParams) params;
109
    }
110

    
111
    /*
112
     * (non-Javadoc)
113
     * @see org.gvsig.lrs.lib.api.LrsAlgorithm#execute(org.gvsig.tools.task.SimpleTaskStatus)
114
     */
115
    public void execute(final SimpleTaskStatus taskStatus) throws LrsException {
116
        NewFeatureStoreParameters newFeatureStoreParameters =
117
            parameters.getNewFeatureStoreParameters();
118
        FeatureStore sourceFeatureStore = parameters.getSourceFeatureStore();
119
        FeatureAttributeDescriptor idRouteField = parameters.getIdRouteField();
120
        FeatureStore calibratePointFeatureStore= parameters.getCalibratePointFeatureStore();
121
        FeatureAttributeDescriptor idRouteCalibratePointField =parameters.getCalibratePointIdRouteField();
122
        FeatureAttributeDescriptor fromMeasureField = parameters.getFromMeasureField();
123
        final boolean includeAll=parameters.includeAll();
124

    
125
        logger.info(parameters.toString());
126

    
127
        taskStatus.setTitle(parameters.getName());
128
        I18nManager i18nManager = ToolsLocator.getI18nManager();
129
        taskStatus.message(i18nManager.getTranslation("grouping_features"));
130

    
131
        try {
132
            final String routeFieldName = idRouteField.getName();
133
            final String routeCalibratePointFieldName=idRouteCalibratePointField.getName();
134
            final String measureFieldName=fromMeasureField.getName();
135
            final Double convertedSearchRadius=calculateConvertedSearchRadius();
136

    
137
            FeatureStore newFeatureStore = LrsAlgorithmUtils
138
                .createNewDataStore(newFeatureStoreParameters, idRouteField);
139

    
140
            FeatureSet sourceFeatures;
141
            if (sourceFeatureStore.getFeatureSelection().getSize() > 0) {
142
                sourceFeatures = sourceFeatureStore.getFeatureSelection();
143
            } else {
144
                sourceFeatures = sourceFeatureStore.getFeatureSet();
145
            }
146

    
147
            final Map<String, RouteAndPoints> featuresMap =
148
                new HashMap<String, RouteAndPoints>();
149
            sourceFeatures.accept(new Visitor() {
150

    
151
                public void visit(Object obj)
152
                    throws VisitCanceledException, BaseException {
153
                    Feature feature = (Feature) obj;
154
                    String routeName = (String) feature.get(routeFieldName);
155
                    RouteAndPoints routeAndPoints = new RouteAndPoints(feature.getDefaultGeometry());
156

    
157
                    featuresMap.put(routeName, routeAndPoints);
158
                }
159
            });
160

    
161
            FeatureSet pointFeatures=calibratePointFeatureStore.getFeatureSet();
162
            pointFeatures.accept(new Visitor() {
163

    
164
                public void visit(Object obj) throws VisitCanceledException, BaseException {
165
                    Feature feature = (Feature) obj;
166
                    String routeName = (String) feature.get(routeCalibratePointFieldName);
167
                    Double measure= (Double) feature.get(measureFieldName);
168
                    Geometry geomPoint=(Point)feature.getDefaultGeometry();
169

    
170
                    if (geomPoint instanceof Point){
171
                        Point point=(Point) geomPoint;
172
                        Object valueObject=featuresMap.get(routeName);
173
                        if (valueObject != null && valueObject instanceof RouteAndPoints) {
174
                            RouteAndPoints routeAndPoints = (RouteAndPoints) valueObject;
175
                            List<Point> points = routeAndPoints.getPoints();
176
                            if (feature.getDefaultGeometry() instanceof Point) {
177
                                Geometry route = routeAndPoints.getRoute();
178
                                if (isValidPoint(point, route, convertedSearchRadius)) {
179
                                    try {
180
                                        Point mPoint = getInRouteMPoint(route, point, measure);
181
                                        points.add(mPoint);
182
                                    } catch (Exception e) {
183
                                        logger.debug("Error adding point", e);
184
                                    }
185
                                }
186
                            }
187
                        }
188
                    }
189
                }
190
            });
191

    
192
            taskStatus.setRangeOfValues(0, featuresMap.size());
193
            int taskCount = 0;
194

    
195
            newFeatureStore.edit(FeatureStore.MODE_FULLEDIT);
196

    
197
            for (Entry<String, RouteAndPoints> entry : featuresMap.entrySet()) {
198
                String routeName = entry.getKey();
199
                Object valueObject = entry.getValue();
200
                List<Point> points=null;
201
                Geometry geometry=null;
202

    
203
                if (valueObject!=null && valueObject instanceof RouteAndPoints){
204
                    RouteAndPoints routeAndPoints=(RouteAndPoints)valueObject;
205
                        geometry=routeAndPoints.getRoute();
206
                        points=routeAndPoints.getPoints();
207
                }
208
                if (!points.isEmpty()){
209
                    EditableFeature newFeature =
210
                        newFeatureStore.createNewFeature(true);
211
                    newFeature.set(routeFieldName, routeName);
212
                    Geometry calibratedRoute = calibrateRoute(geometry,points);
213
                    newFeature.setDefaultGeometry(calibratedRoute);
214
                    newFeatureStore.update(newFeature);
215
                } else if (includeAll) {
216
                    EditableFeature newFeature = newFeatureStore.createNewFeature(true);
217
                    newFeature.set(routeFieldName, routeName);
218
                    newFeature.setDefaultGeometry(geometry);
219
                    newFeatureStore.update(newFeature);
220
                }
221
                taskCount++;
222
                taskStatus.setCurValue(taskCount);
223
            }
224
            newFeatureStore.finishEditing();
225
        } catch (Exception e1) {
226
            taskStatus.abort();
227
            throw new LrsCalibrateRouteException("Error calibrating routes", e1);
228
        }
229

    
230
        taskStatus.terminate();
231
    }
232

    
233

    
234
    private Point getInRouteMPoint(Geometry geometry,Point point, Double measure) throws CreateGeometryException, GeometryOperationNotSupportedException, GeometryOperationException{
235
        GeometryManager geomanager = GeometryLocator.getGeometryManager();
236

    
237
        Point[] pointsInLine=(Point[])geometry.closestPoints(point);
238
        Point pointInLine=pointsInLine[0];
239

    
240
        Point mPoint = (Point) geomanager
241
            .create(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM);
242
        mPoint.setX(pointInLine.getX());
243
        mPoint.setY(pointInLine.getY());
244
        int mDimension=mPoint.getDimension()-1;
245
        mPoint.setCoordinateAt(mDimension, measure);
246

    
247
        return mPoint;
248
    }
249

    
250
    private Double calculateConvertedSearchRadius(){
251
        Double searchRadius=parameters.getSearchRadius();
252
        DistanceUnits measureUnits = parameters.getMeasureUnits();
253
        FeatureStore sourceFeatureStore = parameters.getSourceFeatureStore();
254

    
255
        try {
256
            IProjection projection = sourceFeatureStore.getDefaultFeatureType().getDefaultSRS();
257

    
258
            Double searchRadiusInMeters=searchRadius*measureUnits.getTransToMeter();
259
            //TODO
260
            //DistanceUnits projectionDistanceUnits=getProjectionDistanceUnits(projection);
261
            //return searchRadiusInMeters/projectionDistanceUnits.getTransToMeter();
262
            return searchRadiusInMeters;
263
        } catch (Exception e) {
264
            return new Double(0);
265
        }
266
    }
267

    
268
    private boolean isValidPoint(Point point,Geometry geometry, Double convertedSearchRadius){
269
        try {
270
            return geometry.isWithinDistance(point, convertedSearchRadius);
271
        } catch (Exception e) {
272
            return false;
273
        }
274
    }
275

    
276
    private Geometry calibrateRoute(Geometry geometry, List<Point> points) {
277
        LrsMeasureCalculationMethods calculationMethod= parameters.getMeasureCalculationMethods();
278
        boolean ignoreSpatialGaps = parameters.ignoreSpatialGaps();
279
        boolean interpolateBetweenCalibrationPoints=parameters.interpolateBetweenCalibrationPoints();
280
        boolean extrapolateBeforeCalibrationPoints=parameters.extrapolateBeforeCalibrationPoints();
281
        boolean extrapolateAfterCalibrationPoints=parameters.extrapolateAfterCalibrationPoints();
282

    
283
        if (points.isEmpty()){
284
            return geometry;
285
        }
286
        ExpandedRoute expandedRoute=new ExpandedRoute(geometry, ignoreSpatialGaps);
287

    
288

    
289
        expandedRoute.addFixedPoints(points);
290
        expandedRoute.calculateCalibrationPoints(calculationMethod,extrapolateBeforeCalibrationPoints,interpolateBetweenCalibrationPoints,extrapolateAfterCalibrationPoints);
291
        return expandedRoute.getRoute();
292
    }
293

    
294

    
295

    
296
    class ExpandedRoute{
297
        private Geometry route;
298
        private List<Boolean> isFixedPoint;
299
        private List<Double> distances;
300
        private List<Double>oldMValues;
301
        private List<Point> vertices;
302
        private List<Integer> lineIndexes;
303
        private int MDIMENSION;
304

    
305
        private final Double PRECISION=new Double(1.0e-5);
306

    
307
        public Geometry getRoute(){
308
            return route;
309
        }
310

    
311
        public ExpandedRoute(Geometry geometry, boolean ignoreSpatialGaps){
312
            isFixedPoint=new ArrayList<Boolean>();
313
            distances=new ArrayList<Double>();
314
            oldMValues=new ArrayList<Double>();
315
            vertices=new ArrayList<Point>();
316
            lineIndexes=new ArrayList<Integer>();
317
            route=geometry.cloneGeometry();
318

    
319
            double distance = 0;
320
            List<Line> lines=LrsAlgorithmUtils.extractLines(geometry);
321
            Point previousVertex=null;
322
            for (int i=0; i<lines.size();i++){
323
                Line line=lines.get(i);
324
                for (int j=0; j<line.getNumVertices();j++){
325
                    Point vertex=line.getVertex(j);
326
                    if(j==0){
327
                       if (previousVertex==null){
328
                           //First point in geometry
329
                           MDIMENSION=vertex.getDimension()-1;
330
                           distance=0;
331
                       }
332
                       Integer visitedIndex = getIndexVisitedVertex(vertex);
333
                       if (visitedIndex!=null){
334
                           previousVertex=vertices.get(visitedIndex);
335
                           distance=distances.get(visitedIndex);
336
                       }else{
337
                           if (previousVertex!=null){
338
                               try {
339
                                   if(!LrsAlgorithmUtils.equalPoints(vertex, previousVertex)){
340
                                       Integer nearestVertexPos=getIndexNearestVisitedVertex(vertex);
341
                                       if (ignoreSpatialGaps){
342
                                           distance=distances.get(nearestVertexPos);
343
                                       }else{
344
                                           Point nearestVertex=vertices.get(nearestVertexPos);
345
                                           distance=distances.get(nearestVertexPos);
346
                                           distance+=vertex.distance(nearestVertex);
347
                                       }
348
                                   }
349
                               } catch (Exception e) {
350
                                   distance=Double.NaN;
351
                               }
352
                           }
353
                       }
354
                    }else{
355
                        try {
356
                            distance+=vertex.distance(previousVertex);
357
                        } catch (Exception e) {
358
                            distance=Double.NaN;
359
                        }
360
                    }
361
                    Double mValue=vertex.getCoordinateAt(MDIMENSION);
362

    
363
                    isFixedPoint.add(false);
364
                    vertices.add(vertex);
365
                    distances.add(distance);
366
                    oldMValues.add(mValue);
367
                    lineIndexes.add(i);
368

    
369
                    previousVertex = vertex;
370
                }
371
            }
372
        }
373

    
374
        private Integer getIndexNearestVisitedVertex(Point vertex) throws GeometryOperationNotSupportedException, GeometryOperationException{
375
            double nearestDistance = Double.POSITIVE_INFINITY;
376
            Integer nearestPointPos=null;
377
            for (int i=0;i<vertices.size();i++){
378
                Double distance=vertex.distance(vertices.get(i));
379
                if(nearestDistance>distance && distance>Double.valueOf(0)){
380
                    nearestDistance=distance;
381
                    nearestPointPos=i;
382
                }
383
            }
384
            return nearestPointPos;
385
        }
386

    
387
        private Integer getIndexVisitedVertex(Point point){
388
            double distance = Double.NEGATIVE_INFINITY;
389
            Integer index = null;
390
            for(int i =0; i<vertices.size(); i++){
391
                if (LrsAlgorithmUtils.equalPoints(point, vertices.get(i))){
392
                    if(this.distances.get(i)>distance){
393
                        distance = this.distances.get(i);
394
                        index = i;
395
                    }
396
                }
397
            }
398
            return index;
399
        }
400

    
401
        private void addFixedPoints(List<Point> fixedPoints){
402
            for (Point fixedPoint:fixedPoints){
403
                Double length=Double.valueOf(0);
404
                int index = 0;
405
                List<Line> lines=LrsAlgorithmUtils.extractLines(route);
406
                List<Integer>insertAtList=new ArrayList<Integer>();
407
                List<Double>lengths=new ArrayList<Double>();
408
                List<Double>oldValues=new ArrayList<Double>();
409
                List<Integer>lineReference=new ArrayList<Integer>();
410
                for (int i=0; i<lines.size();i++){
411
                    Line line=lines.get(i);
412
                    try{
413
                        if (line.isWithinDistance(fixedPoint, PRECISION)){
414
                            length=distances.get(index);
415
                            for (int j=0;j<line.getNumVertices();j++){
416
                                Point vertex=line.getVertex(j);
417
                                Point nextVertex;
418
                                if (j+1<line.getNumVertices()){
419
                                    nextVertex=line.getVertex(j+1);
420
                                }else{
421
                                    nextVertex=null;
422
                                }
423
                                if(LrsAlgorithmUtils.equalPoints(vertex, fixedPoint)||vertex.distance(fixedPoint)<=PRECISION){
424
                                    oldMValues.set(index, vertex.getCoordinateAt(MDIMENSION));
425
                                    Double mValue=fixedPoint.getCoordinateAt(MDIMENSION);
426
                                    vertex.setCoordinateAt(MDIMENSION, mValue);
427
                                    isFixedPoint.set(index, true);
428
                                    vertices.set(index, vertex);
429
                                }else{
430
                                    if (nextVertex!=null
431
                                        && !LrsAlgorithmUtils.equalPoints(nextVertex, fixedPoint)
432
                                        && vertex.distance(fixedPoint)>PRECISION
433
                                        && nextVertex.distance(fixedPoint)>PRECISION){
434

    
435
                                        GeometryManager geomanager = GeometryLocator.getGeometryManager();
436
                                        Line segment= (Line) geomanager
437
                                            .create(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM);
438
                                        segment.addVertex(vertex);
439
                                        segment.addVertex(nextVertex);
440
                                        //FIXME
441
                                        //if (line.intersects(fixedPoint)){
442
                                        if (segment.isWithinDistance(fixedPoint, PRECISION)){
443
                                            double distanceFirstVertex=distances.get(index);
444
                                            double distanceToFixedPoint=vertex.distance(fixedPoint);
445
                                            length=distanceFirstVertex+distanceToFixedPoint;
446
                                            Double oldMValue=LrsAlgorithmUtils.straightLineThroughTwoPointsEquation(
447
                                                distances.get(index),
448
                                                distances.get(index+1),
449
                                                vertex.getCoordinateAt(MDIMENSION),
450
                                                nextVertex.getCoordinateAt(MDIMENSION),
451
                                                length);
452
                                            insertAtList.add(index+1);
453
                                            lengths.add(length);
454
                                            oldValues.add(oldMValue);
455
                                            lineReference.add(i);
456
                                        }
457
                                    }
458
                                }
459
                                index++;
460
                            }
461
                        }else{
462
                            index+=line.getNumVertices();
463
                        }
464
                    }catch(Exception e){
465
                        logger.warn("Error inserting point "+fixedPoint.toString(),e);
466
                    }
467
                }
468
                int pos=0;
469
                for (Integer insertAt:insertAtList){
470
                    Double distance=lengths.get(pos);
471
                    Double oldMValue=oldValues.get(pos);
472
                    Integer linePos=lineReference.get(pos);
473
                    int correctedPosition=insertAt+pos;
474
                    route=LrsAlgorithmUtils.insertVertex(route, fixedPoint, correctedPosition);
475
                    isFixedPoint.add(correctedPosition, true);
476
                    distances.add(correctedPosition, distance);
477
                    oldMValues.add(correctedPosition, oldMValue);
478
                    lineIndexes.add(correctedPosition, linePos);
479
                    vertices.add(correctedPosition, fixedPoint);
480
                    pos++;
481
                }
482
            }
483
        }
484

    
485
        public void resetMeasuresToDistances(){
486
             List<Point> points=LrsAlgorithmUtils.extractPoints(route);
487
             for (int i=0;i<points.size();i++){
488
                 if (!isFixedPoint.get(i)){
489
                     points.get(i).setCoordinateAt(MDIMENSION, distances.get(i));
490
                     vertices.get(i).setCoordinateAt(MDIMENSION, distances.get(i));
491
                     oldMValues.set(i, distances.get(i));
492
                 }
493
             }
494
        }
495

    
496
        public void calculateCalibrationPoints(LrsMeasureCalculationMethods calculationMethod,boolean before, boolean between, boolean after){
497
            for (int i=0; i<vertices.size();i++){
498
                if(!isFixedPoint.get(i)){
499
                    Integer prevFixedPointPos=getPreviousPosFixedPoint(i);
500
                    Integer nextFixedPointPos=getNextPosFixedPoint(i,false);
501

    
502
                    if (prevFixedPointPos==null && nextFixedPointPos!=null  && before){
503
                        extrapolateBeforeCalibrationPoints(calculationMethod,nextFixedPointPos,i);
504
                    }
505
                    if (prevFixedPointPos!=null && nextFixedPointPos!=null && between){
506
                        calculateMValue(calculationMethod,prevFixedPointPos,nextFixedPointPos,i);
507
                    }
508
                    if (prevFixedPointPos!=null && nextFixedPointPos==null && after){
509
                        extrapolateAfterCalibrationPoints(calculationMethod,prevFixedPointPos,i);
510
                    }
511
                }
512
            }
513
        }
514

    
515
        private void extrapolateBeforeCalibrationPoints(LrsMeasureCalculationMethods calculationMethod,int firstFixedPointPos,int pos){
516
            Integer secondFixedPointPos=getNextPosFixedPoint(firstFixedPointPos,false);
517
            if (secondFixedPointPos!=null){
518

    
519
                if (calculationMethod.equals(LrsMeasureCalculationMethods.DISTANCE)){
520
                    if (!isFixedPoint.get(pos)){
521
                        List<Point> points=LrsAlgorithmUtils.extractPoints(route);
522
                        points.get(pos).setCoordinateAt(MDIMENSION, distances.get(pos));
523
                        vertices.get(pos).setCoordinateAt(MDIMENSION, distances.get(pos));
524
                        oldMValues.set(pos, distances.get(pos));
525
                    }
526
                }
527

    
528
                Double newMValueFirstPoint=vertices.get(firstFixedPointPos).getCoordinateAt(MDIMENSION);
529
                Double newMValueSecondPoint=vertices.get(secondFixedPointPos).getCoordinateAt(MDIMENSION);
530

    
531
                Double oldMValueFirstPoint;
532
                Double oldMValueSecondPoint;
533
                if (calculationMethod.equals(LrsMeasureCalculationMethods.DISTANCE)){
534
                    oldMValueFirstPoint=distances.get(firstFixedPointPos);
535
                    oldMValueSecondPoint=distances.get(secondFixedPointPos);
536
                }else{
537
                    oldMValueFirstPoint=oldMValues.get(firstFixedPointPos);
538
                    oldMValueSecondPoint=oldMValues.get(secondFixedPointPos);
539
                }
540

    
541
                Double distanceBetweenFixedPoints=newMValueSecondPoint-newMValueFirstPoint;
542
                Double distanceBetweenOldFixedPoints=oldMValueSecondPoint-oldMValueFirstPoint;
543

    
544
                Double calibrationRatio=distanceBetweenOldFixedPoints/distanceBetweenFixedPoints;
545

    
546
                Double valueToRecalculate=vertices.get(pos).getCoordinateAt(MDIMENSION);
547
                Double distanceBetween=oldMValueFirstPoint-valueToRecalculate;
548
                Double mValue=newMValueFirstPoint-(distanceBetween/calibrationRatio);
549
                refreshMValueGeometryVertex(pos,mValue,false);
550
            }
551
        }
552

    
553
        private void extrapolateAfterCalibrationPoints(LrsMeasureCalculationMethods calculationMethod,int lastFixedPointPos,int pos){
554
            Integer prevFixedPointPos=getPreviousPosFixedPoint(lastFixedPointPos);
555
            if (prevFixedPointPos!=null){
556
                calculateMValue(calculationMethod,prevFixedPointPos,lastFixedPointPos,pos);
557
            }
558
        }
559

    
560
        private void calculateMValue(LrsMeasureCalculationMethods calculationMethod,Integer prevFixedPointPos,int nextFixedPointPos,int pos){
561

    
562
            if (calculationMethod.equals(LrsMeasureCalculationMethods.DISTANCE)){
563
                if (!isFixedPoint.get(pos)){
564
                    List<Point> points=LrsAlgorithmUtils.extractPoints(route);
565
                    points.get(pos).setCoordinateAt(MDIMENSION, distances.get(pos));
566
                    vertices.get(pos).setCoordinateAt(MDIMENSION, distances.get(pos));
567
                    oldMValues.set(pos, distances.get(pos));
568
                }
569
            }
570

    
571
            Double newMValueBeforePoint=vertices.get(prevFixedPointPos).getCoordinateAt(MDIMENSION);
572
            Double newMValueAfterPoint=vertices.get(nextFixedPointPos).getCoordinateAt(MDIMENSION);
573
            while (newMValueBeforePoint.equals(newMValueAfterPoint)){
574
                prevFixedPointPos=getPreviousPosFixedPoint(prevFixedPointPos);
575
                if (prevFixedPointPos!=null){
576
                    newMValueBeforePoint=vertices.get(prevFixedPointPos).getCoordinateAt(MDIMENSION);
577
                }else{
578
                    refreshMValueGeometryVertex(pos,Double.NaN, false);
579
                    return;
580
                }
581
            }
582

    
583
            Double oldMValueBeforePoint;
584
            Double oldMValueAfterPoint;
585
            if (calculationMethod.equals(LrsMeasureCalculationMethods.DISTANCE)){
586
                oldMValueBeforePoint=distances.get(prevFixedPointPos);
587
                oldMValueAfterPoint=distances.get(nextFixedPointPos);
588
            }else{
589
                oldMValueBeforePoint=oldMValues.get(prevFixedPointPos);
590
                oldMValueAfterPoint=oldMValues.get(nextFixedPointPos);
591
            }
592

    
593
            Double distanceBetweenFixedPoints=newMValueAfterPoint-newMValueBeforePoint;
594
            Double distanceBetweenOldFixedPoints=oldMValueAfterPoint-oldMValueBeforePoint;
595

    
596
            Double calibrationRatio=distanceBetweenOldFixedPoints/distanceBetweenFixedPoints;
597

    
598
            Double valueToRecalculate=vertices.get(pos).getCoordinateAt(MDIMENSION);
599
            Double distanceBetween=valueToRecalculate-oldMValueBeforePoint;
600
            Double mValue=newMValueBeforePoint+(distanceBetween/calibrationRatio);
601
            refreshMValueGeometryVertex(pos,mValue, true);
602
        }
603

    
604

    
605
        private Integer getNextPosFixedPoint(int pos, boolean selfInclude){
606
            Integer nextFixedPointPos= findNextFixedPointInLine(pos, selfInclude);
607
            if (nextFixedPointPos!=null){
608
                return nextFixedPointPos;
609
            }else{
610
                int lastPositionInLine=getLastPositionInLine(pos);
611
                        nextFixedPointPos=findNextFixedPointInNextLines(lastPositionInLine,new ArrayList<Integer>());
612
                        if (nextFixedPointPos!=null){
613
                            return nextFixedPointPos;
614
                        }
615
                        try{
616
                    Integer nearestVertex=findNearestNextPoint(lastPositionInLine);
617
                    return getNextPosFixedPoint(nearestVertex, true);
618
                        }catch (Exception e){
619
                            return null;
620
                        }
621
                    }
622
                }
623

    
624
        private Integer getLastPositionInLine (int pos){
625
            Integer lineVisited=lineIndexes.get(pos);
626
            for (int i=pos+1;i<vertices.size();i++){
627
                if (!lineVisited.equals(lineIndexes.get(i))){
628
                    return i-1;
629
            }
630
        }
631
            return vertices.size()-1;
632
        }
633

    
634
        private Integer findNextFixedPointInNextLines(int pos,List<Integer> visitedLines){
635
            Integer nextFixedPointPos= findNextFixedPointInLine(pos, true);
636
            if (nextFixedPointPos!=null){
637
                return nextFixedPointPos;
638
            }else{
639
                Integer lineIndex=lineIndexes.get(pos);
640
                visitedLines.add(lineIndex);
641
                int lastPositionInLine=getLastPositionInLine(pos);
642
                Point lastVertexInLine=vertices.get(lastPositionInLine);
643
                for (int i=lastPositionInLine;i<vertices.size();i++){
644
                    if (LrsAlgorithmUtils.equalPoints(lastVertexInLine, vertices.get(i))){
645
                        if (!visitedLines.contains(lineIndexes.get(i))){
646
                            findNextFixedPointInNextLines(i,visitedLines);
647
                        }
648
                    }
649
                }
650
            }
651
            return null;
652
        }
653

    
654
        private Integer findNextFixedPointInLine(int vertexPos, boolean selfInclude){
655
            int lineIndex=lineIndexes.get(vertexPos);
656
            if (!selfInclude){
657
                vertexPos+=1;
658
            }
659
            for (int i=vertexPos;i<vertices.size();i++){
660
                if(!lineIndexes.get(i).equals(lineIndex)){
661
                    return null;
662
                }
663
                if (isFixedPoint.get(i)){
664
                    return i;
665
                }
666
            }
667
            return null;
668
        }
669

    
670

    
671
        private Integer findNearestNextPoint(int vertexPos) throws GeometryOperationNotSupportedException, GeometryOperationException{
672
            Point vertex=vertices.get(vertexPos);
673
            double nearestDistance = Double.POSITIVE_INFINITY;
674
            Integer nearestPointPos=null;
675
            for (int i=vertexPos+1;i<vertices.size();i++){
676
                    Double distance=vertex.distance(vertices.get(i));
677
                if(nearestDistance>distance && distance>Double.valueOf(0)){
678
                        nearestDistance=distance;
679
                        nearestPointPos=i;
680
                    }
681
                }
682
            return nearestPointPos;
683
        }
684

    
685

    
686
        private Integer getPreviousPosFixedPoint(int pos){
687
            Integer prevFixedPointPos= findPrevFixedPointInLine(pos);
688
            if (prevFixedPointPos!=null){
689
                return prevFixedPointPos;
690
            }else{
691
                Integer lineVisited=lineIndexes.get(pos);
692
                for (int i=pos-1;i>=0;i--){
693
                    if (!lineVisited.equals(lineIndexes.get(i))){//Line has changed
694
                        int lastPositionInLine=i+1;
695
                        for (int j=lastPositionInLine;j>=0;j--){
696
                            if (LrsAlgorithmUtils.equalPoints(vertices.get(lastPositionInLine), vertices.get(j))){
697
                                if (isFixedPoint.get(j) && j<pos){
698
                                    return j;
699
                                }
700
                            }
701
                        }
702
                        try{
703
                            return findNearestPrevFixedPoint(lastPositionInLine);
704
                        }catch (Exception e){
705
                            return null;
706
                        }
707
                    }
708
                }
709
            }
710
            return null;
711
        }
712
        private Integer findPrevFixedPointInLine(int vertexPos){
713
            int lineIndex=lineIndexes.get(vertexPos);
714
            for (int i=vertexPos-1;i>=0;i--){
715
                if(!lineIndexes.get(i).equals(lineIndex)){
716
                    return null;
717
                }
718
                if (isFixedPoint.get(i)){
719
                    return i;
720
                }
721
            }
722
            return null;
723
        }
724
        private Integer findNearestPrevFixedPoint(int vertexPos) throws GeometryOperationNotSupportedException, GeometryOperationException{
725
            Point vertex=vertices.get(vertexPos);
726
            double nearestDistance = Double.POSITIVE_INFINITY;
727
            Integer nearestPointPos=null;
728
            for (int i=vertexPos-1;i>=0;i--){
729
                if (isFixedPoint.get(i)){
730
                    Double distance=vertex.distance(vertices.get(i));
731
                    if(nearestDistance>distance){
732
                        nearestDistance=distance;
733
                        nearestPointPos=i;
734
                    }
735
                }
736
            }
737
            return nearestPointPos;
738
        }
739

    
740

    
741
        private void refreshMValueGeometryVertex(int i, Double mValue, boolean fixed){
742
            List<Point> points=LrsAlgorithmUtils.extractPoints(route);
743
            vertices.get(i).setCoordinateAt(MDIMENSION, mValue);
744
            points.get(i).setCoordinateAt(MDIMENSION,mValue);
745
            isFixedPoint.set(i, fixed);
746
        }
747

    
748
    }
749

    
750
    private class RouteAndPoints {
751
        private Geometry route;
752
        private List<Point> points;
753

    
754

    
755
        /**
756
         *
757
         */
758
        public RouteAndPoints(Geometry route) {
759
            this.setRoute(route);
760
            this.setPoints(new ArrayList<Point>());
761
        }
762

    
763

    
764
        /**
765
         * @return the route
766
         */
767
        public Geometry getRoute() {
768
            return route;
769
        }
770

    
771

    
772
        /**
773
         * @param route the route to set
774
         */
775
        public void setRoute(Geometry route) {
776
            this.route = route;
777
        }
778

    
779

    
780
        /**
781
         * @return the points
782
         */
783
        public List<Point> getPoints() {
784
            return points;
785
        }
786

    
787

    
788
        /**
789
         * @param points the points to set
790
         */
791
        public void setPoints(List<Point> points) {
792
            this.points = points;
793
        }
794

    
795
    }
796
}
797

    
798

    
799

    
800