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 / DefaultMeasuresCalculator.java @ 74

History | View | Annotate | Download (22 KB)

1
package org.gvsig.lrs.lib.impl;
2

    
3
import org.gvsig.lrs.lib.api.MeasuresCalculator;
4
import java.util.ArrayList;
5
import java.util.List;
6
import org.gvsig.fmap.geom.Geometry;
7
import org.gvsig.fmap.geom.GeometryLocator;
8
import org.gvsig.fmap.geom.GeometryManager;
9
import org.gvsig.fmap.geom.operation.GeometryOperationException;
10
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
11
import org.gvsig.fmap.geom.primitive.Line;
12
import org.gvsig.fmap.geom.primitive.Point;
13
import org.gvsig.lrs.lib.api.LrsMeasureCalculationMethods;
14
import org.slf4j.Logger;
15
import org.slf4j.LoggerFactory;
16

    
17
class DefaultMeasuresCalculator implements MeasuresCalculator {
18

    
19
    private static final Logger logger = LoggerFactory.getLogger(DefaultMeasuresCalculator.class);
20

    
21
    private Geometry route;
22
    private List<Boolean> isFixedPoint;
23
    private List<Double> distances;
24
    private List<Double> oldMValues;
25
    private List<Point> vertices;
26
    private List<Integer> lineIndexes;
27
    private int MDIMENSION;
28

    
29
    private final Double PRECISION = new Double(1.0e-5);
30

    
31
    @Override
32
    public Geometry getResult() {
33
        return route;
34
    }
35

    
36
    public DefaultMeasuresCalculator(Geometry geometry, boolean ignoreSpatialGaps) {
37
        isFixedPoint = new ArrayList<Boolean>();
38
        distances = new ArrayList<Double>();
39
        oldMValues = new ArrayList<Double>();
40
        vertices = new ArrayList<Point>();
41
        lineIndexes = new ArrayList<Integer>();
42
        route = geometry.cloneGeometry();
43

    
44
        double distance = 0;
45
        List<Line> lines = LrsAlgorithmUtils.extractLines(geometry);
46
        Point previousVertex = null;
47
        for (int i = 0; i < lines.size(); i++) {
48
            Line line = lines.get(i);
49
            for (int j = 0; j < line.getNumVertices(); j++) {
50
                Point vertex = line.getVertex(j);
51
                if (j == 0) {
52
                    if (previousVertex == null) {
53
                        //First point in geometry
54
                        MDIMENSION = vertex.getDimension() - 1;
55
                        distance = 0;
56
                    }
57
                    Integer visitedIndex = getIndexVisitedVertex(vertex);
58
                    if (visitedIndex != null) {
59
                        previousVertex = vertices.get(visitedIndex);
60
                        distance = distances.get(visitedIndex);
61
                    } else {
62
                        if (previousVertex != null) {
63
                            try {
64
                                if (!LrsAlgorithmUtils.equalPoints(vertex, previousVertex)) {
65
                                    Integer nearestVertexPos = getIndexNearestVisitedVertex(vertex);
66
                                    if (ignoreSpatialGaps) {
67
                                        distance = distances.get(nearestVertexPos);
68
                                    } else {
69
                                        Point nearestVertex = vertices.get(nearestVertexPos);
70
                                        distance = distances.get(nearestVertexPos);
71
                                        distance += vertex.distance(nearestVertex);
72
                                    }
73
                                }
74
                            } catch (Exception e) {
75
                                distance = Double.NaN;
76
                            }
77
                        }
78
                    }
79
                } else {
80
                    try {
81
                        distance += vertex.distance(previousVertex);
82
                    } catch (Exception e) {
83
                        distance = Double.NaN;
84
                    }
85
                }
86
                Double mValue = vertex.getCoordinateAt(MDIMENSION);
87

    
88
                isFixedPoint.add(false);
89
                vertices.add(vertex);
90
                distances.add(distance);
91
                oldMValues.add(mValue);
92
                lineIndexes.add(i);
93

    
94
                previousVertex = vertex;
95
            }
96
        }
97
    }
98

    
99
    private Integer getIndexNearestVisitedVertex(Point vertex) throws GeometryOperationNotSupportedException, GeometryOperationException {
100
        double nearestDistance = Double.POSITIVE_INFINITY;
101
        Integer nearestPointPos = null;
102
        for (int i = 0; i < vertices.size(); i++) {
103
            Double distance = vertex.distance(vertices.get(i));
104
            if (nearestDistance > distance && distance > Double.valueOf(0)) {
105
                nearestDistance = distance;
106
                nearestPointPos = i;
107
            }
108
        }
109
        return nearestPointPos;
110
    }
111

    
112
    private Integer getIndexVisitedVertex(Point point) {
113
        double distance = Double.NEGATIVE_INFINITY;
114
        Integer index = null;
115
        for (int i = 0; i < vertices.size(); i++) {
116
            if (LrsAlgorithmUtils.equalPoints(point, vertices.get(i))) {
117
                if (this.distances.get(i) > distance) {
118
                    distance = this.distances.get(i);
119
                    index = i;
120
                }
121
            }
122
        }
123
        return index;
124
    }
125

    
126
    @Override
127
    public void addControlPoints(List<Point> fixedPoints) {
128
        for (Point fixedPoint : fixedPoints) {
129
            Double length = Double.valueOf(0);
130
            int index = 0;
131
            List<Line> lines = LrsAlgorithmUtils.extractLines(route);
132
            List<Integer> insertAtList = new ArrayList<Integer>();
133
            List<Double> lengths = new ArrayList<Double>();
134
            List<Double> oldValues = new ArrayList<Double>();
135
            List<Integer> lineReference = new ArrayList<Integer>();
136
            for (int i = 0; i < lines.size(); i++) {
137
                Line line = lines.get(i);
138
                try {
139
                    if (line.isWithinDistance(fixedPoint, PRECISION)) {
140
                        length = distances.get(index);
141
                        for (int j = 0; j < line.getNumVertices(); j++) {
142
                            Point vertex = line.getVertex(j);
143
                            Point nextVertex;
144
                            if (j + 1 < line.getNumVertices()) {
145
                                nextVertex = line.getVertex(j + 1);
146
                            } else {
147
                                nextVertex = null;
148
                            }
149
                            if (LrsAlgorithmUtils.equalPoints(vertex, fixedPoint) || vertex.distance(fixedPoint) <= PRECISION) {
150
                                oldMValues.set(index, vertex.getCoordinateAt(MDIMENSION));
151
                                Double mValue = fixedPoint.getCoordinateAt(MDIMENSION);
152
                                vertex.setCoordinateAt(MDIMENSION, mValue);
153
                                isFixedPoint.set(index, true);
154
                                vertices.set(index, vertex);
155
                            } else {
156
                                if (nextVertex != null
157
                                        && !LrsAlgorithmUtils.equalPoints(nextVertex, fixedPoint)
158
                                        && vertex.distance(fixedPoint) > PRECISION
159
                                        && nextVertex.distance(fixedPoint) > PRECISION) {
160

    
161
                                    GeometryManager geomanager = GeometryLocator.getGeometryManager();
162
                                    Line segment = (Line) geomanager
163
                                            .create(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM);
164
                                    segment.addVertex(vertex);
165
                                    segment.addVertex(nextVertex);
166
                                    //FIXME
167
                                    //if (line.intersects(fixedPoint)){
168
                                    if (segment.isWithinDistance(fixedPoint, PRECISION)) {
169
                                        double distanceFirstVertex = distances.get(index);
170
                                        double distanceToFixedPoint = vertex.distance(fixedPoint);
171
                                        length = distanceFirstVertex + distanceToFixedPoint;
172
                                        Double oldMValue = LrsAlgorithmUtils.straightLineThroughTwoPointsEquation(
173
                                                distances.get(index),
174
                                                distances.get(index + 1),
175
                                                vertex.getCoordinateAt(MDIMENSION),
176
                                                nextVertex.getCoordinateAt(MDIMENSION),
177
                                                length);
178
                                        insertAtList.add(index + 1);
179
                                        lengths.add(length);
180
                                        oldValues.add(oldMValue);
181
                                        lineReference.add(i);
182
                                    }
183
                                }
184
                            }
185
                            index++;
186
                        }
187
                    } else {
188
                        index += line.getNumVertices();
189
                    }
190
                } catch (Exception e) {
191
                    logger.warn("Error inserting point " + fixedPoint.toString(), e);
192
                }
193
            }
194
            int pos = 0;
195
            for (Integer insertAt : insertAtList) {
196
                Double distance = lengths.get(pos);
197
                Double oldMValue = oldValues.get(pos);
198
                Integer linePos = lineReference.get(pos);
199
                int correctedPosition = insertAt + pos;
200
                route = LrsAlgorithmUtils.insertVertex(route, fixedPoint, correctedPosition);
201
                isFixedPoint.add(correctedPosition, true);
202
                distances.add(correctedPosition, distance);
203
                oldMValues.add(correctedPosition, oldMValue);
204
                lineIndexes.add(correctedPosition, linePos);
205
                vertices.add(correctedPosition, fixedPoint);
206
                pos++;
207
            }
208
        }
209
    }
210

    
211
    @Override
212
    public void setFirstMeasure(double mvalue) {
213
        Point mPoint = (Point) this.vertices.get(0).cloneGeometry();
214
        int mDimension = mPoint.getDimension() - 1;
215
        mPoint.setCoordinateAt(mDimension, mvalue);
216
        List<Point> points = new ArrayList<>();
217
        this.addControlPoints(points);
218
    }
219

    
220
    @Override
221
    public void setLastMeasure(double mvalue) {
222
        Point mPoint = (Point) this.vertices.get(this.vertices.size()-1).cloneGeometry();
223
        int mDimension = mPoint.getDimension() - 1;
224
        mPoint.setCoordinateAt(mDimension, mvalue);
225
        List<Point> points = new ArrayList<>();
226
        this.addControlPoints(points);
227
    }
228

    
229
    @Override
230
    public void setMeasuresToDistances() {
231
        List<Point> points = LrsAlgorithmUtils.extractPoints(route);
232
        for (int i = 0; i < points.size(); i++) {
233
            if (!isFixedPoint.get(i)) {
234
                points.get(i).setCoordinateAt(MDIMENSION, distances.get(i));
235
                vertices.get(i).setCoordinateAt(MDIMENSION, distances.get(i));
236
                oldMValues.set(i, distances.get(i));
237
            }
238
        }
239
    }
240

    
241
    public void calculate() {
242
        this.calculate(
243
                LrsMeasureCalculationMethods.DISTANCE,
244
                false,
245
                true,
246
                false
247
        );
248
    }
249
    
250
    @Override
251
    public void calculate(LrsMeasureCalculationMethods calculationMethod, boolean before, boolean between, boolean after) {
252
        for (int i = 0; i < vertices.size(); i++) {
253
            if (!isFixedPoint.get(i)) {
254
                Integer prevFixedPointPos = getPreviousPosFixedPoint(i);
255
                Integer nextFixedPointPos = getNextPosFixedPoint(i, false);
256

    
257
                if (prevFixedPointPos == null && nextFixedPointPos != null && before) {
258
                    extrapolateBeforeCalibrationPoints(calculationMethod, nextFixedPointPos, i);
259
                }
260
                if (prevFixedPointPos != null && nextFixedPointPos != null && between) {
261
                    calculateMValue(calculationMethod, prevFixedPointPos, nextFixedPointPos, i);
262
                }
263
                if (prevFixedPointPos != null && nextFixedPointPos == null && after) {
264
                    extrapolateAfterCalibrationPoints(calculationMethod, prevFixedPointPos, i);
265
                }
266
            }
267
        }
268
    }
269

    
270
    private void extrapolateBeforeCalibrationPoints(LrsMeasureCalculationMethods calculationMethod, int firstFixedPointPos, int pos) {
271
        Integer secondFixedPointPos = getNextPosFixedPoint(firstFixedPointPos, false);
272
        if (secondFixedPointPos != null) {
273

    
274
            if (calculationMethod.equals(LrsMeasureCalculationMethods.DISTANCE)) {
275
                if (!isFixedPoint.get(pos)) {
276
                    List<Point> points = LrsAlgorithmUtils.extractPoints(route);
277
                    points.get(pos).setCoordinateAt(MDIMENSION, distances.get(pos));
278
                    vertices.get(pos).setCoordinateAt(MDIMENSION, distances.get(pos));
279
                    oldMValues.set(pos, distances.get(pos));
280
                }
281
            }
282

    
283
            Double newMValueFirstPoint = vertices.get(firstFixedPointPos).getCoordinateAt(MDIMENSION);
284
            Double newMValueSecondPoint = vertices.get(secondFixedPointPos).getCoordinateAt(MDIMENSION);
285

    
286
            Double oldMValueFirstPoint;
287
            Double oldMValueSecondPoint;
288
            if (calculationMethod.equals(LrsMeasureCalculationMethods.DISTANCE)) {
289
                oldMValueFirstPoint = distances.get(firstFixedPointPos);
290
                oldMValueSecondPoint = distances.get(secondFixedPointPos);
291
            } else {
292
                oldMValueFirstPoint = oldMValues.get(firstFixedPointPos);
293
                oldMValueSecondPoint = oldMValues.get(secondFixedPointPos);
294
            }
295

    
296
            Double distanceBetweenFixedPoints = newMValueSecondPoint - newMValueFirstPoint;
297
            Double distanceBetweenOldFixedPoints = oldMValueSecondPoint - oldMValueFirstPoint;
298

    
299
            Double calibrationRatio = distanceBetweenOldFixedPoints / distanceBetweenFixedPoints;
300

    
301
            Double valueToRecalculate = vertices.get(pos).getCoordinateAt(MDIMENSION);
302
            Double distanceBetween = oldMValueFirstPoint - valueToRecalculate;
303
            Double mValue = newMValueFirstPoint - (distanceBetween / calibrationRatio);
304
            refreshMValueGeometryVertex(pos, mValue, false);
305
        }
306
    }
307

    
308
    private void extrapolateAfterCalibrationPoints(LrsMeasureCalculationMethods calculationMethod, int lastFixedPointPos, int pos) {
309
        Integer prevFixedPointPos = getPreviousPosFixedPoint(lastFixedPointPos);
310
        if (prevFixedPointPos != null) {
311
            calculateMValue(calculationMethod, prevFixedPointPos, lastFixedPointPos, pos);
312
        }
313
    }
314

    
315
    private void calculateMValue(LrsMeasureCalculationMethods calculationMethod, Integer prevFixedPointPos, int nextFixedPointPos, int pos) {
316

    
317
        if (calculationMethod.equals(LrsMeasureCalculationMethods.DISTANCE)) {
318
            if (!isFixedPoint.get(pos)) {
319
                List<Point> points = LrsAlgorithmUtils.extractPoints(route);
320
                points.get(pos).setCoordinateAt(MDIMENSION, distances.get(pos));
321
                vertices.get(pos).setCoordinateAt(MDIMENSION, distances.get(pos));
322
                oldMValues.set(pos, distances.get(pos));
323
            }
324
        }
325

    
326
        Double newMValueBeforePoint = vertices.get(prevFixedPointPos).getCoordinateAt(MDIMENSION);
327
        Double newMValueAfterPoint = vertices.get(nextFixedPointPos).getCoordinateAt(MDIMENSION);
328
        while (newMValueBeforePoint.equals(newMValueAfterPoint)) {
329
            prevFixedPointPos = getPreviousPosFixedPoint(prevFixedPointPos);
330
            if (prevFixedPointPos != null) {
331
                newMValueBeforePoint = vertices.get(prevFixedPointPos).getCoordinateAt(MDIMENSION);
332
            } else {
333
                refreshMValueGeometryVertex(pos, Double.NaN, false);
334
                return;
335
            }
336
        }
337

    
338
        Double oldMValueBeforePoint;
339
        Double oldMValueAfterPoint;
340
        if (calculationMethod.equals(LrsMeasureCalculationMethods.DISTANCE)) {
341
            oldMValueBeforePoint = distances.get(prevFixedPointPos);
342
            oldMValueAfterPoint = distances.get(nextFixedPointPos);
343
        } else {
344
            oldMValueBeforePoint = oldMValues.get(prevFixedPointPos);
345
            oldMValueAfterPoint = oldMValues.get(nextFixedPointPos);
346
        }
347

    
348
        Double distanceBetweenFixedPoints = newMValueAfterPoint - newMValueBeforePoint;
349
        Double distanceBetweenOldFixedPoints = oldMValueAfterPoint - oldMValueBeforePoint;
350

    
351
        Double calibrationRatio = distanceBetweenOldFixedPoints / distanceBetweenFixedPoints;
352

    
353
        Double valueToRecalculate = vertices.get(pos).getCoordinateAt(MDIMENSION);
354
        Double distanceBetween = valueToRecalculate - oldMValueBeforePoint;
355
        Double mValue = newMValueBeforePoint + (distanceBetween / calibrationRatio);
356
        refreshMValueGeometryVertex(pos, mValue, true);
357
    }
358

    
359
    private Integer getNextPosFixedPoint(int pos, boolean selfInclude) {
360
        Integer nextFixedPointPos = findNextFixedPointInLine(pos, selfInclude);
361
        if (nextFixedPointPos != null) {
362
            return nextFixedPointPos;
363
        } else {
364
            int lastPositionInLine = getLastPositionInLine(pos);
365
            nextFixedPointPos = findNextFixedPointInNextLines(lastPositionInLine, new ArrayList<Integer>());
366
            if (nextFixedPointPos != null) {
367
                return nextFixedPointPos;
368
            }
369
            try {
370
                Integer nearestVertex = findNearestNextPoint(lastPositionInLine);
371
                return getNextPosFixedPoint(nearestVertex, true);
372
            } catch (Exception e) {
373
                return null;
374
            }
375
        }
376
    }
377

    
378
    private Integer getLastPositionInLine(int pos) {
379
        Integer lineVisited = lineIndexes.get(pos);
380
        for (int i = pos + 1; i < vertices.size(); i++) {
381
            if (!lineVisited.equals(lineIndexes.get(i))) {
382
                return i - 1;
383
            }
384
        }
385
        return vertices.size() - 1;
386
    }
387

    
388
    private Integer findNextFixedPointInNextLines(int pos, List<Integer> visitedLines) {
389
        Integer nextFixedPointPos = findNextFixedPointInLine(pos, true);
390
        if (nextFixedPointPos != null) {
391
            return nextFixedPointPos;
392
        } else {
393
            Integer lineIndex = lineIndexes.get(pos);
394
            visitedLines.add(lineIndex);
395
            int lastPositionInLine = getLastPositionInLine(pos);
396
            Point lastVertexInLine = vertices.get(lastPositionInLine);
397
            for (int i = lastPositionInLine; i < vertices.size(); i++) {
398
                if (LrsAlgorithmUtils.equalPoints(lastVertexInLine, vertices.get(i))) {
399
                    if (!visitedLines.contains(lineIndexes.get(i))) {
400
                        findNextFixedPointInNextLines(i, visitedLines);
401
                    }
402
                }
403
            }
404
        }
405
        return null;
406
    }
407

    
408
    private Integer findNextFixedPointInLine(int vertexPos, boolean selfInclude) {
409
        int lineIndex = lineIndexes.get(vertexPos);
410
        if (!selfInclude) {
411
            vertexPos += 1;
412
        }
413
        for (int i = vertexPos; i < vertices.size(); i++) {
414
            if (!lineIndexes.get(i).equals(lineIndex)) {
415
                return null;
416
            }
417
            if (isFixedPoint.get(i)) {
418
                return i;
419
            }
420
        }
421
        return null;
422
    }
423

    
424
    private Integer findNearestNextPoint(int vertexPos) throws GeometryOperationNotSupportedException, GeometryOperationException {
425
        Point vertex = vertices.get(vertexPos);
426
        double nearestDistance = Double.POSITIVE_INFINITY;
427
        Integer nearestPointPos = null;
428
        for (int i = vertexPos + 1; i < vertices.size(); i++) {
429
            Double distance = vertex.distance(vertices.get(i));
430
            if (nearestDistance > distance && distance > Double.valueOf(0)) {
431
                nearestDistance = distance;
432
                nearestPointPos = i;
433
            }
434
        }
435
        return nearestPointPos;
436
    }
437

    
438
    private Integer getPreviousPosFixedPoint(int pos) {
439
        Integer prevFixedPointPos = findPrevFixedPointInLine(pos);
440
        if (prevFixedPointPos != null) {
441
            return prevFixedPointPos;
442
        } else {
443
            Integer lineVisited = lineIndexes.get(pos);
444
            for (int i = pos - 1; i >= 0; i--) {
445
                if (!lineVisited.equals(lineIndexes.get(i))) {//Line has changed
446
                    int lastPositionInLine = i + 1;
447
                    for (int j = lastPositionInLine; j >= 0; j--) {
448
                        if (LrsAlgorithmUtils.equalPoints(vertices.get(lastPositionInLine), vertices.get(j))) {
449
                            if (isFixedPoint.get(j) && j < pos) {
450
                                return j;
451
                            }
452
                        }
453
                    }
454
                    try {
455
                        return findNearestPrevFixedPoint(lastPositionInLine);
456
                    } catch (Exception e) {
457
                        return null;
458
                    }
459
                }
460
            }
461
        }
462
        return null;
463
    }
464

    
465
    private Integer findPrevFixedPointInLine(int vertexPos) {
466
        int lineIndex = lineIndexes.get(vertexPos);
467
        for (int i = vertexPos - 1; i >= 0; i--) {
468
            if (!lineIndexes.get(i).equals(lineIndex)) {
469
                return null;
470
            }
471
            if (isFixedPoint.get(i)) {
472
                return i;
473
            }
474
        }
475
        return null;
476
    }
477

    
478
    private Integer findNearestPrevFixedPoint(int vertexPos) throws GeometryOperationNotSupportedException, GeometryOperationException {
479
        Point vertex = vertices.get(vertexPos);
480
        double nearestDistance = Double.POSITIVE_INFINITY;
481
        Integer nearestPointPos = null;
482
        for (int i = vertexPos - 1; i >= 0; i--) {
483
            if (isFixedPoint.get(i)) {
484
                Double distance = vertex.distance(vertices.get(i));
485
                if (nearestDistance > distance) {
486
                    nearestDistance = distance;
487
                    nearestPointPos = i;
488
                }
489
            }
490
        }
491
        return nearestPointPos;
492
    }
493

    
494
    private void refreshMValueGeometryVertex(int i, Double mValue, boolean fixed) {
495
        List<Point> points = LrsAlgorithmUtils.extractPoints(route);
496
        vertices.get(i).setCoordinateAt(MDIMENSION, mValue);
497
        points.get(i).setCoordinateAt(MDIMENSION, mValue);
498
        isFixedPoint.set(i, fixed);
499
    }
500

    
501
}