Statistics
| Revision:

gvsig-vectorediting / org.gvsig.vectorediting.offset / trunk / org.gvsig.vectorediting.offset / org.gvsig.vectorediting.offset.lib / org.gvsig.vectorediting.offset.lib.prov / org.gvsig.vectorediting.offset.lib.prov.offset / src / main / java / org / gvsig / vectorediting / offset / lib / prov / offset / OffsetEditingProvider.java @ 2173

History | View | Annotate | Download (26 KB)

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

    
26
import java.util.ArrayList;
27
import java.util.HashMap;
28
import java.util.LinkedHashMap;
29
import java.util.List;
30
import java.util.Map;
31
import org.apache.commons.lang3.StringUtils;
32
import org.gvsig.fmap.dal.exception.DataException;
33
import org.gvsig.fmap.dal.feature.EditableFeature;
34
import org.gvsig.fmap.dal.feature.Feature;
35
import org.gvsig.fmap.dal.feature.FeatureSelection;
36
import org.gvsig.fmap.dal.feature.FeatureStore;
37
import org.gvsig.fmap.geom.Geometry;
38
import org.gvsig.fmap.geom.GeometryException;
39
import org.gvsig.fmap.geom.GeometryLocator;
40
import org.gvsig.fmap.geom.GeometryManager;
41
import org.gvsig.fmap.geom.aggregate.Aggregate;
42
import org.gvsig.fmap.geom.aggregate.MultiCurve;
43
import org.gvsig.fmap.geom.aggregate.MultiPoint;
44
import org.gvsig.fmap.geom.aggregate.MultiSurface;
45
import org.gvsig.fmap.geom.operation.GeometryOperationException;
46
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
47
import org.gvsig.fmap.geom.primitive.Arc;
48
import org.gvsig.fmap.geom.primitive.Circle;
49
import org.gvsig.fmap.geom.primitive.Circumference;
50
import org.gvsig.fmap.geom.primitive.Curve;
51
import org.gvsig.fmap.geom.primitive.Ellipse;
52
import org.gvsig.fmap.geom.primitive.FilledSpline;
53
import org.gvsig.fmap.geom.primitive.Line;
54
import org.gvsig.fmap.geom.primitive.PeriEllipse;
55
import org.gvsig.fmap.geom.primitive.Point;
56
import org.gvsig.fmap.geom.primitive.Polygon;
57
import org.gvsig.fmap.geom.primitive.Spline;
58
import org.gvsig.fmap.geom.primitive.Surface;
59
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
60
import org.gvsig.tools.ToolsLocator;
61
import org.gvsig.tools.dispose.DisposableIterator;
62
import org.gvsig.tools.dynobject.DynObject;
63
import org.gvsig.tools.i18n.I18nManager;
64
import org.gvsig.tools.service.spi.ProviderServices;
65
import org.gvsig.vectorediting.lib.api.DrawingStatus;
66
import org.gvsig.vectorediting.lib.api.EditingServiceParameter;
67
import org.gvsig.vectorediting.lib.api.EditingServiceParameter.TYPE;
68
import org.gvsig.vectorediting.lib.api.exceptions.DrawServiceException;
69
import org.gvsig.vectorediting.lib.api.exceptions.FinishServiceException;
70
import org.gvsig.vectorediting.lib.api.exceptions.InvalidEntryException;
71
import org.gvsig.vectorediting.lib.api.exceptions.StartServiceException;
72
import org.gvsig.vectorediting.lib.spi.AbstractEditingProvider;
73
import org.gvsig.vectorediting.lib.spi.DefaultDrawingStatus;
74
import org.gvsig.vectorediting.lib.spi.DefaultEditingServiceParameter;
75
import org.gvsig.vectorediting.lib.spi.EditingProvider;
76
import org.gvsig.vectorediting.lib.spi.EditingProviderFactory;
77
import org.gvsig.vectorediting.lib.spi.EditingProviderLocator;
78
import org.gvsig.vectorediting.lib.spi.EditingProviderManager;
79
import org.gvsig.vectorediting.lib.spi.EditingProviderServices;
80

    
81
public class OffsetEditingProvider extends AbstractEditingProvider implements
82
        EditingProvider {
83

    
84
    private static final Double PRECISION = 1.0e-5;
85

    
86
    private static final String LEFT = "_left";
87

    
88
    private static final String RIGHT = "_right";
89

    
90
    private final EditingServiceParameter selectionParameter;
91

    
92
    private final EditingServiceParameter offsetParameter;
93

    
94
    private final EditingServiceParameter sideParameter;
95

    
96
    private final EditingServiceParameter deleteOriginalGeometriesParameter;
97

    
98
    private boolean deleteOriginalGeometries = false;
99

    
100
    private Map<EditingServiceParameter, Object> values;
101

    
102
    private final Map<String, String> options;
103

    
104
    private final FeatureStore featureStore;
105

    
106
    public OffsetEditingProvider(ProviderServices providerServices, DynObject parameters) {
107
        super(providerServices);
108
        this.featureStore = (FeatureStore) parameters.getDynValue(EditingProviderFactory.FEATURE_STORE_FIELD);
109
        I18nManager i18nManager = ToolsLocator.getI18nManager();
110

    
111
        this.selectionParameter
112
                = new DefaultEditingServiceParameter("selection",
113
                        i18nManager.getTranslation("selection"), TYPE.SELECTION);
114

    
115
        this.offsetParameter
116
                = new DefaultEditingServiceParameter("offset_distance",
117
                        i18nManager.getTranslation("offset_distance"),
118
                        TYPE.POSITION, TYPE.VALUE, TYPE.DISTANCE);
119

    
120
        Map<String, String> sideOptions = new HashMap<>();
121
        sideOptions.put(LEFT, i18nManager.getTranslation(LEFT));
122
        sideOptions.put(RIGHT, i18nManager.getTranslation(RIGHT));
123

    
124
        this.sideParameter
125
                = new DefaultEditingServiceParameter("side",
126
                        i18nManager.getTranslation("_side"),
127
                        sideOptions,
128
                        TYPE.OPTION, TYPE.POSITION);
129

    
130
        this.options = new LinkedHashMap<>();
131
        options.put(i18nManager.getTranslation("short_yes"),
132
                "delete_original_geometries");
133
        options.put(i18nManager.getTranslation("short_no"),
134
                "keep_original_geometries");
135

    
136
//        EditingProviderServices editingProviderServices
137
//                = (EditingProviderServices) getProviderServices();
138

    
139
        String consoleMsg
140
                = ((EditingProviderServices)providerServices).makeConsoleMessage(
141
                        "delete_original_geometries_question", options);
142

    
143
        this.deleteOriginalGeometriesParameter
144
                = new DefaultEditingServiceParameter("Delete original geometries",
145
                        consoleMsg, options, TYPE.OPTION);
146

    
147
    }
148

    
149
    @Override
150
    public EditingServiceParameter next() {
151

    
152
        if (values.get(selectionParameter) == null) {
153
            return selectionParameter;
154
        } else if (values.get(offsetParameter) == null) {
155
            return offsetParameter;
156
        } else if (values.get(sideParameter) == null) {
157
            Object offsetValue = values.get(offsetParameter);
158
            if (!(offsetValue instanceof Point)) {
159
                Double distance = (Double) offsetValue;
160
                if (distance >= 0) {
161
                    return sideParameter;
162
                }
163
            }
164
        }
165

    
166
        if (values.get(deleteOriginalGeometriesParameter) == null) {
167
            return this.deleteOriginalGeometriesParameter;
168
        }
169

    
170
        return null;
171
    }
172

    
173
    @Override
174
    public DrawingStatus getDrawingStatus(Point mousePosition) throws DrawServiceException {
175
        DefaultDrawingStatus drawingStatus = new DefaultDrawingStatus();
176
        EditingProviderManager editingProviderManager
177
                = EditingProviderLocator.getProviderManager();
178
//        ISymbol auxiliaryLineSymbolEditing = editingProviderManager.getSymbol("auxiliary-line-symbol-editing");
179
        ISymbol auxiliaryPointSymbolEditing = editingProviderManager.getSymbol("auxiliary-point-symbol-editing");
180
        ISymbol auxiliaryLineSymbolEditingDirection = editingProviderManager.getSymbol("auxiliary-line-symbol-editing-direction");
181
        ISymbol lineSymbolEditing = editingProviderManager.getSymbol("line-symbol-editing");
182
        ISymbol polygonSymbolEditing = editingProviderManager.getSymbol("polygon-symbol-editing");
183

    
184
        FeatureSelection selected
185
                = (FeatureSelection) values.get(selectionParameter);
186
        try {
187
            if ((selected != null) && !selected.isEmpty()) {
188
                Point point; // = null;
189
                double distance = 0.0;
190
                double side = 1.0;
191
                Object offsetValue = values.get(offsetParameter);
192

    
193
                if (offsetValue != null) {
194
                    if (offsetValue instanceof Point) {
195
                        distance = Math.abs(getMinDistance(selected, (Point) offsetValue));
196
                    } else {
197
                        distance = (Double) offsetValue;
198
                    }
199

    
200
                    Object sideValue = values.get(sideParameter);
201
                    if (sideValue == null) {
202
                        point = mousePosition;
203
                        side = Math.signum(getMinDistance(selected, point));
204
                    } else {
205
                        Double signum = getSideSignum((String) sideValue);
206
                        if (signum != null) {
207
                            side = signum;
208
                        }
209
                    }
210
                } else {
211
                    point = mousePosition;
212
                    distance = getMinDistance(selected, point);
213
                }
214

    
215
                DisposableIterator it;
216
                it = selected.fastIterator();
217

    
218
                while (it.hasNext()) {
219
                    Feature feat = (Feature) it.next();
220
                    Geometry transformedGeometry = feat.getDefaultGeometry().offset(distance * side);
221

    
222
                    ISymbol symbol = null;
223
                    if (transformedGeometry instanceof Curve || transformedGeometry instanceof MultiCurve) {
224
                        symbol = lineSymbolEditing;
225
                        drawingStatus.addStatus(feat.getDefaultGeometry(), auxiliaryLineSymbolEditingDirection, "Direction");
226
                    } else if (transformedGeometry instanceof Surface || transformedGeometry instanceof MultiSurface) {
227
                        symbol = polygonSymbolEditing;
228
                    } else if (transformedGeometry instanceof Point || transformedGeometry instanceof MultiPoint) {
229
                        symbol = auxiliaryPointSymbolEditing;
230
                    }
231
                    if (transformedGeometry instanceof Aggregate) {
232
                        int primitivesNumber = ((Aggregate) transformedGeometry).getPrimitivesNumber();
233
                        for (int i = 0; i < primitivesNumber; i++) {
234
                            drawingStatus.addStatus(((Aggregate) transformedGeometry).getPrimitiveAt(i), symbol, "");
235
                        }
236
                    } else {
237
                        drawingStatus.addStatus(transformedGeometry, symbol, "");
238
                    }
239
                }
240
                it.dispose();
241
            }
242
            return drawingStatus;
243
        } catch (Exception e) {
244
            throw new DrawServiceException(e);
245
        }
246
    }
247

    
248
    /**
249
     * @param selected
250
     * @param point
251
     * @return
252
     * @throws DataException
253
     * @throws GeometryOperationException
254
     * @throws GeometryOperationNotSupportedException
255
     * @throws GeometryException
256
     */
257
    private double getMinDistance(FeatureSelection selected, Point point) throws DataException, GeometryOperationNotSupportedException, GeometryOperationException, GeometryException {
258
        double minorDistance = Double.POSITIVE_INFINITY;
259
        DisposableIterator it;
260
        it = selected.fastIterator();
261
        while (it.hasNext()) {
262
            Feature feat = (Feature) it.next();
263
            Geometry geometry = feat.getDefaultGeometry();
264
            double distance = getDistance(geometry, point);
265
            if (distance < minorDistance) {
266
                minorDistance = distance;
267
            }
268
        }
269
        it.dispose();
270
        return minorDistance;
271

    
272
    }
273

    
274
    /**
275
     * @param geometry
276
     * @param point
277
     * @return
278
     * @throws GeometryOperationException
279
     * @throws GeometryOperationNotSupportedException
280
     * @throws GeometryException
281
     */
282
    private double getDistance(Geometry geometry, Point point) throws GeometryOperationNotSupportedException, GeometryOperationException, GeometryException {
283
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
284
        if (geometry instanceof Arc) {
285
            Arc arc = (Arc) geometry;
286
            Point center = arc.getCenterPoint();
287
            double radius = center.distance(arc.getInitPoint());
288
            double distance = center.distance(point) - radius;
289
            return distance;
290
        }
291

    
292
        if (geometry instanceof Circle) {
293
            Circle circle = (Circle) geometry;
294
            return circle.getCenter().distance(point) - circle.getRadious();
295
        }
296
        if (geometry instanceof Circumference) {
297
            Circumference circumference = (Circumference) geometry;
298
            return circumference.getCenter().distance(point) - circumference.getRadious();
299
        }
300
        if (geometry instanceof PeriEllipse) {
301
            double minDistance = Double.POSITIVE_INFINITY;
302
            PeriEllipse ellipse = (PeriEllipse) geometry;
303
            Geometry[] closestPoints = point.closestPoints(ellipse);
304
            if (closestPoints != null) {
305
                for (int i = 0; i < closestPoints.length; i++) {
306
                    Geometry closestPoint = closestPoints[i];
307
                    if (!point.equals(closestPoint)) {
308
                        double distance = closestPoint.distance(point);
309
                        if (distance < minDistance) {
310
                            minDistance = distance;
311
                        }
312
                    }
313
                }
314
            }
315
            Ellipse auxEllipse = (Ellipse) geomManager.create(Geometry.TYPES.ELLIPSE, geometry.getGeometryType().getSubType());
316
            auxEllipse.setPoints(ellipse.getAxis1Start(), ellipse.getAxis1End(), ellipse.getAxis2Dist());
317
            if (auxEllipse.contains(point)) {
318
                return -minDistance;
319
            }
320
            return minDistance;
321
        }
322
        if (geometry instanceof Ellipse) {
323
            Ellipse ellipse = (Ellipse) geometry;
324
            PeriEllipse auxPeriEllipse = (PeriEllipse) geomManager.create(Geometry.TYPES.PERIELLIPSE, geometry.getGeometryType().getSubType());
325
            auxPeriEllipse.setPoints(ellipse.getAxis1Start(), ellipse.getAxis1End(), ellipse.getAxis2Dist());
326
            double distance = getDistance(auxPeriEllipse, point);
327

    
328
            return distance;
329
        }
330

    
331
        if (geometry instanceof Spline || geometry instanceof FilledSpline) {
332
            return getDistance(geometry.toLines().getPrimitiveAt(0), point);
333
        }
334

    
335
        if (geometry instanceof Line) {
336
            Line line = (Line) geometry;
337
            double minDistance = Double.POSITIVE_INFINITY;
338
            Geometry[] closestPoints = point.closestPoints(line);
339
            Point closestPoint = null;
340
            if (closestPoints != null) {
341
                for (Geometry closestPoint1 : closestPoints) {
342
                    Point p = (Point) closestPoint1;
343
                    if (!point.equals(p)) {
344
                        double distance = p.distance(point);
345
                        if (distance < minDistance) {
346
                            minDistance = distance;
347
                            closestPoint = p;
348
                        }
349
                    }
350
                }
351
            }
352
            if (closestPoint != null) {
353
                for (int i = 0; i < line.getNumVertices() - 1; i++) {
354
                    Line segment = (Line) geomManager.create(Geometry.TYPES.LINE, geometry.getGeometryType().getSubType());
355
                    segment.addVertex(line.getVertex(i));
356
                    segment.addVertex(line.getVertex(i + 1));
357
                    if (segment.isWithinDistance(closestPoint, PRECISION)) {
358
                        if (line.getVertex(0).equals(line.getVertex(line.getNumVertices() - 1))) { //isClosed
359
                            if (line.toPolygons().contains(point)) {
360
                                return -minDistance;
361
                            }
362
                            return minDistance;
363
                        } else {
364
                            return getDirectedDistance(closestPoint, point, segment);
365
                        }
366
                    }
367
                }
368
            }
369
        }
370

    
371
        if (geometry instanceof Polygon) {
372
            Polygon polygon = (Polygon) geometry;
373
            if (!polygon.contains(point)) {
374
                double minDistance = Double.POSITIVE_INFINITY;
375
                Geometry[] closestPoints = point.closestPoints(polygon);
376
                Point closestPoint = null;
377
                if (closestPoints != null) {
378
                    for (Geometry closestPoint1 : closestPoints) {
379
                        Point p = (Point) closestPoint1;
380
                        if (!point.equals(p)) {
381
                            double distance = p.distance(point);
382
                            if (distance < minDistance) {
383
                                minDistance = distance;
384
                                closestPoint = p;
385
                            }
386
                        }
387
                    }
388
                }
389
                if (closestPoint != null) {
390
                    return closestPoint.distance(point);
391
                }
392
            } else {
393
                Line auxLine = (Line) polygon.toLines().getPrimitiveAt(0);
394
                if (auxLine != null) {
395
                    return getDistance(auxLine, point);
396
                }
397
            }
398
        }
399

    
400
        if (geometry instanceof Aggregate) {
401
            double minDistance = Double.POSITIVE_INFINITY;
402
            Aggregate aggregate2 = (Aggregate) geometry;
403
            for (int i = 0; i < aggregate2.getPrimitivesNumber(); i++) {
404
                double distance = getDistance(aggregate2.getPrimitiveAt(i), point);
405
                if (distance < minDistance) {
406
                    minDistance = distance;
407
                }
408
            }
409
            return minDistance;
410
        }
411
        return 0.0;
412
    }
413

    
414
    @Override
415
    public void stop() {
416
        values.clear();
417
    }
418

    
419
    private void validateAndInsertValue(EditingServiceParameter param,
420
            Object value) throws InvalidEntryException {
421
        I18nManager i18nManager = ToolsLocator.getI18nManager();
422

    
423
        if (param == selectionParameter) {
424
            if (value instanceof FeatureSelection) {
425
                values.put(param, value);
426
            }
427
        } else if (param == offsetParameter) {
428
            if (value instanceof Point) {
429
                try {
430
                    Double distance = getMinDistance((FeatureSelection) values.get(selectionParameter), (Point) value);
431
                    values.put(param, Math.abs(distance));
432
                    values.put(sideParameter, coerceSide(distance));
433
                } catch (Exception e) {
434
                    throw new InvalidEntryException(e);
435
                }
436
                return;
437
            }
438
            if (value instanceof Double) {
439
                Double distance = (Double) value;
440
                if (distance >= 0) {
441
                    values.put(param, value);
442
                } else {
443
                    values.put(param, Math.abs(distance));
444
                    values.put(sideParameter, coerceSide(distance));
445
                }
446
            }
447
        } else if (param == sideParameter) {
448
            if (value instanceof Point) {
449
                try {
450
                    values.put(param, coerceSide(getMinDistance((FeatureSelection) values.get(selectionParameter), (Point) value)));
451
                } catch (Exception e) {
452
                    throw new InvalidEntryException(e);
453
                }
454
                return;
455
            }
456
            if (value instanceof String) {
457
                values.put(param, coerceSide(value));
458
            }
459
        } else if (param == deleteOriginalGeometriesParameter) {
460
            if (value instanceof String) {
461
                if (((String) value).trim().equalsIgnoreCase(
462
                        i18nManager.getTranslation("short_yes"))) {
463
                    deleteOriginalGeometries = true;
464
                } else if (((String) value).trim().equalsIgnoreCase(
465
                        i18nManager.getTranslation("short_no"))) {
466
                    deleteOriginalGeometries = false;
467
                } else {
468
                    throw new InvalidEntryException(null);
469
                }
470
                values.put(param, value);
471
            }
472
        }
473

    
474
    }
475

    
476
    private String coerceSide(Object value) throws InvalidEntryException {
477

    
478
        if (value instanceof Double) {
479
            return (Double) value >= 0 ? LEFT : RIGHT;
480
        }
481
        if (value instanceof String) {
482
            Double signum = getSideSignum((String) value);
483
            if (signum != null) {
484
                return signum >= 0 ? LEFT : RIGHT;
485
            }
486
        }
487
        throw new InvalidEntryException(null);
488
    }
489

    
490
    private Double getSideSignum(String side) {
491
        I18nManager i18nManager = ToolsLocator.getI18nManager();
492
        String sideTrim = side.trim();
493
        if (StringUtils.equalsIgnoreCase(sideTrim, LEFT)
494
                || StringUtils.startsWithIgnoreCase(i18nManager.getTranslation(LEFT), sideTrim)) {
495
            return 1.0;
496
        } else if (StringUtils.equalsIgnoreCase(sideTrim, RIGHT)
497
                || StringUtils.startsWithIgnoreCase(i18nManager.getTranslation(RIGHT), sideTrim)) {
498
            return -1.0;
499
        }
500
        return null;
501
    }
502

    
503
    @Override
504
    public List<EditingServiceParameter> getParameters() {
505
        List<EditingServiceParameter> list
506
                = new ArrayList<>();
507
        list.add(selectionParameter);
508
        list.add(offsetParameter);
509
        list.add(sideParameter);
510
        return list;
511
    }
512

    
513
    @Override
514
    public void setValue(Object value) throws InvalidEntryException {
515
        EditingServiceParameter param = next();
516
        validateAndInsertValue(param, value);
517
    }
518

    
519
    @Override
520
    public void finishAndStore() throws FinishServiceException {
521

    
522
        FeatureSelection selected
523
                = (FeatureSelection) values.get(selectionParameter);
524
        try {
525
            if (!selected.isEmpty()) {
526
                double side = 1.0;
527
                Object sideValue = values.get(sideParameter);
528
                if (sideValue != null) {
529
                    if (sideValue instanceof String) {
530
                        Double signum = getSideSignum((String) sideValue);
531
                        side = signum != null ? signum : null;
532
                    }
533
                }
534
                double distance = ((Double) values.get(offsetParameter)) * side;
535
                DisposableIterator it;
536
                it = selected.fastIterator();
537

    
538
                while (it.hasNext()) {
539
                    Feature feature = (Feature) it.next();
540
                    Geometry geom;
541
                    try {
542
                        geom = feature.getDefaultGeometry().offset(distance);
543
                    } catch (GeometryOperationNotSupportedException | GeometryOperationException e) {
544
                        throw new FinishServiceException(e);
545
                    }
546

    
547
                    if (this.deleteOriginalGeometries) {
548
                        // Se sustituye la geometr?a original por la
549
                        // calculada
550
                        EditableFeature editableFeature
551
                                = feature.getEditable();
552
                        editableFeature.setDefaultGeometry(geom);
553
                        ((EditingProviderServices) getProviderServices())
554
                                .updateFeatureInFeatureStore(editableFeature,
555
                                        featureStore);
556
                    } else {
557
                        // Se crea una feature nueva copiando los valores de
558
                        // la feature original excepto aquellos que sean PK
559
                        EditingProviderServices editingProviderServices
560
                                = (EditingProviderServices) getProviderServices();
561
                        EditableFeature editableFeature
562
                                = editingProviderServices
563
                                        .getFeatureCopyWithoutPK(featureStore,
564
                                                feature);
565
                        editableFeature.setDefaultGeometry(geom);
566
                        editingProviderServices
567
                                .insertFeatureIntoFeatureStore(editableFeature,
568
                                        featureStore);
569
                    }
570

    
571
                }
572
                it.dispose();
573
                featureStore.getFeatureSelection().deselectAll();
574
            }
575
        } catch (DataException e) {
576
            throw new FinishServiceException(e);
577
        }
578
    }
579

    
580
    private Double getDirectedDistance(Point pointInLine, Point distancePoint, Line line)
581
            throws GeometryOperationNotSupportedException, GeometryOperationException {
582
        Double distance = distancePoint.distance(pointInLine);
583
        EditingProviderServices editingProviderServices
584
                = (EditingProviderServices) getProviderServices();
585
        Double angle = editingProviderServices.getAngle(pointInLine, distancePoint);
586
        double angleLine = editingProviderServices.getAngle(line.getVertex(0), line.getVertex(1));
587

    
588
        Double angleDifference = angle - angleLine;
589
        if (angleDifference < 0) {
590
            angleDifference += 2 * Math.PI;
591
        }
592
        if (angleDifference > Math.PI) {
593
            distance = -distance;
594
        }
595
        return distance;
596
    }
597

    
598
    @Override
599
    public Geometry finish() throws FinishServiceException {
600
        return null;
601
    }
602

    
603
    @Override
604
    public void start() throws StartServiceException {
605
        this.values = new HashMap<>();
606
        FeatureSelection selected = null;
607
        if (featureStore != null) {
608
            try {
609
                selected
610
                        = (FeatureSelection) featureStore.getFeatureSelection()
611
                                .clone();
612
            } catch (DataException e) {
613
                throw new StartServiceException(e);
614
            } catch (CloneNotSupportedException e) {
615
                // Do nothing
616
            }
617
            if ((selected != null) && (selected.getSelectedCount() > 0)) {
618
                values.put(selectionParameter, selected);
619
            }
620
        }
621
    }
622

    
623
    @Override
624
    public String getName() {
625
        return OffsetEditingProviderFactory.PROVIDER_NAME;
626
    }
627
}