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

History | View | Annotate | Download (33.8 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(), new ArrayList<Point>());
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
                            if (routeAndPoints.points instanceof List){
176
                                List<Point> points=routeAndPoints.points;
177
                                if (feature.getDefaultGeometry() instanceof Point){
178
                                    Geometry geometry=routeAndPoints.route;
179
                                    if (isValidPoint(point,geometry, convertedSearchRadius)){
180
                                        try {
181
                                            Point mPoint= pointToMPoint(geometry,point, measure);
182
                                            points.add(mPoint);
183
                                        } catch (Exception e) {
184
                                            logger.debug("Error adding point",e);
185
                                        }
186
                                    }
187
                                }
188
                            }
189
                        }
190
                    }
191
                }
192
            });
193

    
194
            taskStatus.setRangeOfValues(0, featuresMap.size());
195
            int taskCount = 0;
196

    
197
            newFeatureStore.edit(FeatureStore.MODE_FULLEDIT);
198

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

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

    
232
        taskStatus.terminate();
233
    }
234

    
235

    
236
    private Point pointToMPoint(Geometry geometry,Point point, Double measure) throws CreateGeometryException, GeometryOperationNotSupportedException, GeometryOperationException{
237
        GeometryManager geomanager = GeometryLocator.getGeometryManager();
238

    
239
        Point[] pointsInLine=(Point[])geometry.closestPoints(point);
240
        Point pointInLine=pointsInLine[0];
241

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

    
249
        return mPoint;
250
    }
251

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

    
257
        try {
258
            IProjection projection = sourceFeatureStore.getDefaultFeatureType().getDefaultSRS();
259

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

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

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

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

    
290

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

    
296

    
297

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

    
307
        private final Double PRECISION=new Double(1.0e-5);
308

    
309
        public Geometry getRoute(){
310
            return route;
311
        }
312

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

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

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

    
371
                    previousVertex = vertex;
372
                }
373
            }
374
        }
375

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

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

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

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

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

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

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

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

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

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

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

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

    
543
                Double calibrationRatio=distanceBetweenOldFixedPoints/distanceBetweenFixedPoints;
544

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

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

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

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

    
570
            Double newMValueBeforePoint=vertices.get(prevFixedPointPos).getCoordinateAt(MDIMENSION);
571
            Double newMValueAfterPoint=vertices.get(nextFixedPointPos).getCoordinateAt(MDIMENSION);
572

    
573
            Double oldMValueBeforePoint;
574
            Double oldMValueAfterPoint;
575
            if (calculationMethod.equals(LrsMeasureCalculationMethods.DISTANCE)){
576
                oldMValueBeforePoint=distances.get(prevFixedPointPos);
577
                oldMValueAfterPoint=distances.get(nextFixedPointPos);
578
            }else{
579
                oldMValueBeforePoint=oldMValues.get(prevFixedPointPos);
580
                oldMValueAfterPoint=oldMValues.get(nextFixedPointPos);
581
            }
582

    
583
            Double distanceBetweenFixedPoints=newMValueAfterPoint-newMValueBeforePoint;
584
            Double distanceBetweenOldFixedPoints=oldMValueAfterPoint-oldMValueBeforePoint;
585

    
586
            Double calibrationRatio=distanceBetweenOldFixedPoints/distanceBetweenFixedPoints;
587

    
588
            Double valueToRecalculate=vertices.get(pos).getCoordinateAt(MDIMENSION);
589
            Double distanceBetween=valueToRecalculate-oldMValueBeforePoint;
590
            Double mValue=newMValueBeforePoint+(distanceBetween/calibrationRatio);
591
            refreshMValueGeometryVertex(pos,mValue, true);
592
        }
593

    
594

    
595
        private Integer getNextPosFixedPoint(int pos){
596
            Integer nextFixedPointPos= findNextFixedPointInLine(pos);
597
            if (nextFixedPointPos!=null){
598
                return nextFixedPointPos;
599
            }else{
600
                int lastPositionInLine=getLastPositionInLine(pos);
601
                        nextFixedPointPos=findNextFixedPointInNextLines(lastPositionInLine,new ArrayList<Integer>());
602
                        if (nextFixedPointPos!=null){
603
                            return nextFixedPointPos;
604
                        }
605
                        try{
606
                    Integer nearestVertex=findNearestNextPoint(lastPositionInLine);
607
                    return getNextPosFixedPoint(nearestVertex);
608
                        }catch (Exception e){
609
                            return null;
610
                        }
611
                    }
612
                }
613

    
614
        private Integer getLastPositionInLine (int pos){
615
            Integer lineVisited=lineIndexes.get(pos);
616
            for (int i=pos+1;i<vertices.size();i++){
617
                if (!lineVisited.equals(lineIndexes.get(i))){
618
                    return i-1;
619
            }
620
        }
621
            return vertices.size()-1;
622
        }
623

    
624
        private Integer findNextFixedPointInNextLines(int pos,List<Integer> visitedLines){
625
            Integer nextFixedPointPos= findNextFixedPointInLine(pos);
626
            if (nextFixedPointPos!=null){
627
                return nextFixedPointPos;
628
            }else{
629
                Integer lineIndex=lineIndexes.get(pos);
630
                visitedLines.add(lineIndex);
631
                int lastPositionInLine=getLastPositionInLine(pos);
632
                Point lastVertexInLine=vertices.get(lastPositionInLine);
633
                for (int i=pos+1;i<vertices.size();i++){
634
                    if (LrsAlgorithmUtils.equalPoints(lastVertexInLine, vertices.get(i))){
635
                        if (!visitedLines.contains(lineIndexes.get(i))){
636
                            findNextFixedPointInNextLines(i,visitedLines);
637
                        }
638
                    }
639
                }
640
            }
641
            return null;
642
        }
643

    
644
        private Integer findNextFixedPointInLine(int vertexPos){
645
            int lineIndex=lineIndexes.get(vertexPos);
646
            for (int i=vertexPos;i<vertices.size();i++){
647
                if(!lineIndexes.get(i).equals(lineIndex)){
648
                    return null;
649
                }
650
                if (isFixedPoint.get(i)){
651
                    return i;
652
                }
653
            }
654
            return null;
655
        }
656

    
657

    
658
        private Integer findNearestNextPoint(int vertexPos) throws GeometryOperationNotSupportedException, GeometryOperationException{
659
            Point vertex=vertices.get(vertexPos);
660
            double nearestDistance = Double.POSITIVE_INFINITY;
661
            Integer nearestPointPos=null;
662
            for (int i=vertexPos+1;i<vertices.size();i++){
663
                    Double distance=vertex.distance(vertices.get(i));
664
                if(nearestDistance>distance && distance>Double.valueOf(0)){
665
                        nearestDistance=distance;
666
                        nearestPointPos=i;
667
                    }
668
                }
669
            return nearestPointPos;
670
        }
671

    
672

    
673
        private Integer getPreviousPosFixedPoint(int pos){
674
            Integer prevFixedPointPos= findPrevFixedPointInLine(pos);
675
            if (prevFixedPointPos!=null){
676
                return prevFixedPointPos;
677
            }else{
678
                Integer lineVisited=lineIndexes.get(pos);
679
                for (int i=pos-1;i>=0;i--){
680
                    if (!lineVisited.equals(lineIndexes.get(i))){//Line has changed
681
                        int lastPositionInLine=i+1;
682
                        for (int j=lastPositionInLine;j>=0;j--){
683
                            if (LrsAlgorithmUtils.equalPoints(vertices.get(lastPositionInLine), vertices.get(j))){
684
                                if (isFixedPoint.get(j)){
685
                                    return j;
686
                                }
687
                            }
688
                        }
689
                        try{
690
                            return findNearestPrevFixedPoint(lastPositionInLine);
691
                        }catch (Exception e){
692
                            return null;
693
                        }
694
                    }
695
                }
696
            }
697
            return null;
698
        }
699
        private Integer findPrevFixedPointInLine(int vertexPos){
700
            int lineIndex=lineIndexes.get(vertexPos);
701
            for (int i=vertexPos;i>=0;i--){
702
                if(!lineIndexes.get(i).equals(lineIndex)){
703
                    return null;
704
                }
705
                if (isFixedPoint.get(i)){
706
                    return i;
707
                }
708
            }
709
            return null;
710
        }
711
        private Integer findNearestPrevFixedPoint(int vertexPos) throws GeometryOperationNotSupportedException, GeometryOperationException{
712
            Point vertex=vertices.get(vertexPos);
713
            double nearestDistance = Double.POSITIVE_INFINITY;
714
            Integer nearestPointPos=null;
715
            for (int i=vertexPos-1;i>=0;i--){
716
                if (isFixedPoint.get(i)){
717
                    Double distance=vertex.distance(vertices.get(i));
718
                    if(nearestDistance>distance){
719
                        nearestDistance=distance;
720
                        nearestPointPos=i;
721
                    }
722
                }
723
            }
724
            return nearestPointPos;
725
        }
726

    
727

    
728
        private void refreshMValueGeometryVertex(int i, Double mValue, boolean fixed){
729
            List<Point> points=LrsAlgorithmUtils.extractPoints(route);
730
            vertices.get(i).setCoordinateAt(MDIMENSION, mValue);
731
            points.get(i).setCoordinateAt(MDIMENSION,mValue);
732
            isFixedPoint.set(i, fixed);
733
        }
734

    
735
    }
736

    
737
    private class RouteAndPoints {
738
        private Geometry route;
739
        private List<Point> points;
740

    
741

    
742
        /**
743
         *
744
         */
745
        public RouteAndPoints(Geometry route, List<Point> points) {
746
            this.setRoute(route);
747
            this.setPoints(points);
748
        }
749

    
750

    
751
        /**
752
         * @return the route
753
         */
754
        public Geometry getRoute() {
755
            return route;
756
        }
757

    
758

    
759
        /**
760
         * @param route the route to set
761
         */
762
        public void setRoute(Geometry route) {
763
            this.route = route;
764
        }
765

    
766

    
767
        /**
768
         * @return the points
769
         */
770
        public List<Point> getPoints() {
771
            return points;
772
        }
773

    
774

    
775
        /**
776
         * @param points the points to set
777
         */
778
        public void setPoints(List<Point> points) {
779
            this.points = points;
780
        }
781

    
782
    }
783
}
784

    
785

    
786

    
787