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

History | View | Annotate | Download (38 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.text.DecimalFormat;
27
import java.util.ArrayList;
28
import java.util.HashMap;
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 static org.gvsig.fmap.geom.Geometry.JOIN_STYLE_ROUND;
39
import org.gvsig.fmap.geom.GeometryException;
40
import org.gvsig.fmap.geom.GeometryLocator;
41
import org.gvsig.fmap.geom.GeometryManager;
42
import org.gvsig.fmap.geom.GeometryUtils;
43
import org.gvsig.fmap.geom.aggregate.Aggregate;
44
import org.gvsig.fmap.geom.aggregate.MultiCurve;
45
import org.gvsig.fmap.geom.aggregate.MultiPoint;
46
import org.gvsig.fmap.geom.aggregate.MultiSurface;
47
import org.gvsig.fmap.geom.operation.GeometryOperationException;
48
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
49
import org.gvsig.fmap.geom.primitive.Arc;
50
import org.gvsig.fmap.geom.primitive.Circle;
51
import org.gvsig.fmap.geom.primitive.Circumference;
52
import org.gvsig.fmap.geom.primitive.Curve;
53
import org.gvsig.fmap.geom.primitive.Ellipse;
54
import org.gvsig.fmap.geom.primitive.FilledSpline;
55
import org.gvsig.fmap.geom.primitive.Line;
56
import org.gvsig.fmap.geom.primitive.PeriEllipse;
57
import org.gvsig.fmap.geom.primitive.Point;
58
import org.gvsig.fmap.geom.primitive.Polygon;
59
import org.gvsig.fmap.geom.primitive.Primitive;
60
import org.gvsig.fmap.geom.primitive.Spline;
61
import org.gvsig.fmap.geom.primitive.Surface;
62
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
63
import org.gvsig.symbology.SymbologyLocator;
64
import org.gvsig.symbology.SymbologyManager;
65
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.text.ISimpleTextSymbol;
66
import org.gvsig.tools.ToolsLocator;
67
import org.gvsig.tools.dataTypes.DataTypes;
68
import org.gvsig.tools.dispose.DisposableIterator;
69
import org.gvsig.tools.dispose.DisposeUtils;
70
import org.gvsig.tools.dynobject.DynObject;
71
import org.gvsig.tools.i18n.I18nManager;
72
import org.gvsig.tools.service.spi.ProviderServices;
73
import org.gvsig.vectorediting.lib.api.DrawingStatus;
74
import org.gvsig.vectorediting.lib.api.EditingServiceParameter;
75
import org.gvsig.vectorediting.lib.api.EditingServiceParameter.TYPE;
76
import org.gvsig.vectorediting.lib.api.exceptions.DrawServiceException;
77
import org.gvsig.vectorediting.lib.api.exceptions.FinishServiceException;
78
import org.gvsig.vectorediting.lib.api.exceptions.InvalidEntryException;
79
import org.gvsig.vectorediting.lib.api.exceptions.StartServiceException;
80
import org.gvsig.vectorediting.lib.api.exceptions.StopServiceException;
81
import org.gvsig.vectorediting.lib.spi.AbstractEditingProvider;
82
import org.gvsig.vectorediting.lib.spi.DefaultDrawingStatus;
83
import org.gvsig.vectorediting.lib.spi.DefaultEditingServiceParameter;
84
import org.gvsig.vectorediting.lib.spi.DefaultEditingServiceParameterOptions;
85
import org.gvsig.vectorediting.lib.spi.EditingProvider;
86
import org.gvsig.vectorediting.lib.spi.EditingProviderFactory;
87
import org.gvsig.vectorediting.lib.spi.EditingProviderLocator;
88
import org.gvsig.vectorediting.lib.spi.EditingProviderManager;
89
import org.gvsig.vectorediting.lib.spi.EditingProviderServices;
90

    
91
public class OffsetEditingProvider extends AbstractEditingProvider implements
92
        EditingProvider {
93

    
94
    private static final Double PRECISION = 1.0e-5;
95

    
96
    private static final String SIDE = "_side";
97

    
98
    private static final String LEFT = "_left";
99

    
100
    private static final String RIGHT = "_right";
101

    
102
    private static final String SHORT_LEFT = "_short_left";
103

    
104
    private static final String SHORT_RIGHT = "_short_right";
105

    
106
    private static final String JOIN_STYLE = "_join_style";
107

    
108
    private static final String ROUND = "_round";
109

    
110
    private static final String MITRE = "_mitre";
111
    
112
    private static final String BEVEL = "_bevel";
113

    
114
    private static final String SHORT_ROUND = "_short_round";
115

    
116
    private static final String SHORT_MITRE = "_short_mitre";
117
    
118
    private static final String SHORT_BEVEL = "_short_bevel";
119

    
120
    private final EditingServiceParameter selectionParameter;
121

    
122
    private final EditingServiceParameter offsetParameter;
123

    
124
    private final EditingServiceParameter sideParameter;
125

    
126
    private final DefaultEditingServiceParameter joinStyleParameter;
127
    
128
    private final EditingServiceParameter equidistantOffsets;
129
    
130
    private final EditingServiceParameter deleteOriginalGeometriesParameter;
131

    
132
//    private boolean deleteOriginalGeometries = false;
133

    
134
    private Map<EditingServiceParameter, Object> values;
135

    
136
//    private final Map<String, String> options;
137

    
138
    private final FeatureStore featureStore;
139
    
140
    public OffsetEditingProvider(ProviderServices providerServices, DynObject parameters) {
141
        super(providerServices);
142
        this.featureStore = (FeatureStore) parameters.getDynValue(EditingProviderFactory.FEATURE_STORE_FIELD);
143
        I18nManager i18nManager = ToolsLocator.getI18nManager();
144

    
145
        EditingProviderServices editingProviderServices
146
                = (EditingProviderServices) getProviderServices();
147
        
148
        this.selectionParameter
149
                = new DefaultEditingServiceParameter("selection",
150
                        i18nManager.getTranslation("selection"), TYPE.SELECTION);
151

    
152
        this.offsetParameter
153
                = new DefaultEditingServiceParameter("offset_distance",
154
                        i18nManager.getTranslation("offset_distance"),
155
                        TYPE.POSITION, TYPE.VALUE, TYPE.DISTANCE);
156

    
157
        Map<String, String> sideOptions = new HashMap<>();
158
        sideOptions.put(i18nManager.getTranslation(SHORT_LEFT), i18nManager.getTranslation(LEFT));
159
        sideOptions.put(i18nManager.getTranslation(SHORT_RIGHT), i18nManager.getTranslation(RIGHT));
160
        
161
        String sideConsoleMsg
162
        = ((EditingProviderServices)providerServices).makeConsoleMessage(
163
                i18nManager.getTranslation(SIDE), sideOptions);
164

    
165

    
166
        this.sideParameter
167
                = new DefaultEditingServiceParameter("side",
168
                        sideConsoleMsg,
169
                        sideOptions,
170
                        TYPE.OPTION, TYPE.POSITION).setDataType(DataTypes.STRING);
171

    
172
        DefaultEditingServiceParameterOptions joinStyleOptions = new DefaultEditingServiceParameterOptions()
173
                .add(i18nManager.getTranslation(ROUND), ROUND, i18nManager.getTranslation(SHORT_ROUND))
174
                .add(i18nManager.getTranslation(MITRE), MITRE, i18nManager.getTranslation(SHORT_MITRE))
175
                .add(i18nManager.getTranslation(BEVEL), BEVEL, i18nManager.getTranslation(SHORT_BEVEL));
176

    
177

    
178
        String joinStyleConsoleMsg = ((EditingProviderServices)providerServices).makeConsoleMessage(
179
                i18nManager.getTranslation(JOIN_STYLE), joinStyleOptions);
180

    
181
        this.joinStyleParameter
182
                = new DefaultEditingServiceParameter(
183
                        "joinStyle",
184
                        joinStyleConsoleMsg,
185
                        joinStyleOptions,
186
                        i18nManager.getTranslation(SHORT_ROUND),
187
                        true, 
188
                        TYPE.OPTION); //.setDataType(DataTypes.STRING);
189
        this.joinStyleParameter.setDefaultValue(ROUND);
190

    
191

    
192
        this.equidistantOffsets = new DefaultEditingServiceParameter("equidistant_offsets", "equidistant_offsets", true, TYPE.VALUE);
193
        this.equidistantOffsets.setDefaultValue(1);
194
        
195
        DefaultEditingServiceParameterOptions deleteOriginalGeometriesOptions2 = new DefaultEditingServiceParameterOptions()
196
                .add("delete_original_geometries", true, i18nManager.getTranslation("_yes"))
197
                .add("keep_original_geometries", false, i18nManager.getTranslation("_no"));
198

    
199
        String consoleMsg
200
                = editingProviderServices.makeConsoleMessage(
201
                        "delete_original_geometries_question", deleteOriginalGeometriesOptions2);
202

    
203
        this.deleteOriginalGeometriesParameter
204
                = new DefaultEditingServiceParameter(
205
                        i18nManager.getTranslation("delete_original_geometries"),
206
                        consoleMsg,
207
                        deleteOriginalGeometriesOptions2,
208
                        false,
209
                        TYPE.OPTION).setDataType(DataTypes.BOOLEAN);
210

    
211
    }
212

    
213
    @Override
214
    public EditingServiceParameter next() {
215

    
216
        if (values.get(selectionParameter) == null) {
217
            return selectionParameter;
218
        }
219
        if (values.get(offsetParameter) == null) {
220
            return offsetParameter;
221
        }
222
        if (values.get(sideParameter) == null) {
223
            Object offsetValue = values.get(offsetParameter);
224
            if (!(offsetValue instanceof Point)) {
225
                Double distance = (Double) offsetValue;
226
                if (distance >= 0) {
227
                    return sideParameter;
228
                }
229
            }
230
        }
231

    
232
        if (values.get(deleteOriginalGeometriesParameter) == null) {
233
            return this.deleteOriginalGeometriesParameter;
234
        }
235

    
236
        return null;
237
    }
238

    
239
    @Override
240
    public DrawingStatus getDrawingStatus(Point mousePosition) throws DrawServiceException {
241
        DefaultDrawingStatus drawingStatus = new DefaultDrawingStatus();
242
        EditingProviderManager editingProviderManager
243
                = EditingProviderLocator.getProviderManager();
244
        EditingProviderServices editingProviderServices =
245
            (EditingProviderServices) getProviderServices();
246
        int subtype;
247
        try {
248
            subtype = editingProviderServices.getSubType(featureStore);
249
        } catch (DataException e2) {
250
            throw new DrawServiceException(e2);
251
        }
252
        ISymbol auxiliaryLineSymbolEditing = editingProviderManager.getSymbol("auxiliary-line-symbol-editing");
253
        ISymbol auxiliaryPointSymbolEditing = editingProviderManager.getSymbol("auxiliary-point-symbol-editing");
254
        ISymbol auxiliaryLineSymbolEditingDirection = editingProviderManager.getSymbol("auxiliary-line-symbol-editing-direction");
255
        ISymbol lineSymbolEditing = editingProviderManager.getSymbol("line-symbol-editing");
256
        ISymbol polygonSymbolEditing = editingProviderManager.getSymbol("polygon-symbol-editing");
257

    
258
        if (values != null) {
259
            Number equidistantOffsetsNumberValue = ((Number) values.get(this.equidistantOffsets));
260
            int equidistantOffsetsValue = equidistantOffsetsNumberValue != null ? equidistantOffsetsNumberValue.intValue() : ((Number) this.equidistantOffsets.getDefaultValue()).intValue();
261

    
262
            FeatureSelection selected
263
                    = (FeatureSelection) values.get(selectionParameter);
264
            try {
265
                if ((selected != null) && !selected.isEmpty()) {
266
                    Point point; // = null;
267
                    double distance = 0.0;
268
                    double side = 1.0;
269
                    Object offsetValue = values.get(offsetParameter);
270

    
271
                    if (offsetValue != null) {
272
                        if (offsetValue instanceof Point) {
273
                            distance = Math.abs(getMinDistance(selected, (Point) offsetValue));
274
                        } else {
275
                            distance = (Double) offsetValue;
276
                        }
277

    
278
                        Object sideValue = values.get(sideParameter);
279
                        if (sideValue == null) {
280
                            point = mousePosition;
281
                            side = Math.signum(getMinDistance(selected, point));
282
                        } else {
283
                            Double signum = getSideSignum((String) sideValue);
284
                            if (signum != null) {
285
                                side = signum;
286
                            }
287
                        }
288
                    } else {
289
                        point = mousePosition;
290
                        Geometry closestGeometry = getClosestGeometry(selected, point);
291
                        Point closestPoint = getClosestPoint(closestGeometry, point);
292
                        distance = getMinDistance(selected, point); //closestPoint.distance(point); //getMinDistance(selected, point);
293
                        ISymbol symbol = lineSymbolEditing;
294
                        Line auxLine = GeometryUtils.createLine(closestPoint, point, subtype);
295
                        drawingStatus.addStatus(
296
                                auxLine,
297
                                auxiliaryLineSymbolEditing,
298
                                ""
299
                        );
300

    
301
                        Point pointText = GeometryUtils.createPoint(
302
                                0.5 * (closestPoint.getX() + point.getX()),
303
                                0.5 * (closestPoint.getY() + point.getY())
304
                        );
305

    
306
                        ISimpleTextSymbol textSymbol = getTextSymbol();
307
                        drawingStatus.addStatus(
308
                                pointText,
309
                                textSymbol,
310
                                new DecimalFormat("#.0#").format(distance)
311
                        );
312

    
313
                    }
314

    
315
                    int joinStyleValue = coerceJoinStyle(values.get(joinStyleParameter));
316

    
317
                    DisposableIterator it;
318
                    it = selected.fastIterator();
319

    
320
                    while (it.hasNext()) {
321
                        Feature feat = (Feature) it.next();
322

    
323
                        ISymbol previewSymbol = this.getPreviewSymbol(feat);
324

    
325
                        for (int c = 1; c <= equidistantOffsetsValue; c++) {
326

    
327
                            Geometry transformedGeometry = feat.getDefaultGeometry().offset(joinStyleValue, c * distance * side);
328

    
329
                            ISymbol symbol = null;
330
                            if (transformedGeometry instanceof Curve || transformedGeometry instanceof MultiCurve) {
331
                                symbol = lineSymbolEditing;
332
                                drawingStatus.addStatus(feat.getDefaultGeometry(), auxiliaryLineSymbolEditingDirection, "Direction");
333
                            } else if (transformedGeometry instanceof Surface || transformedGeometry instanceof MultiSurface) {
334
                                symbol = polygonSymbolEditing;
335
                            } else if (transformedGeometry instanceof Point || transformedGeometry instanceof MultiPoint) {
336
                                symbol = auxiliaryPointSymbolEditing;
337
                            }
338
                            if (transformedGeometry instanceof Aggregate) {
339
                                int primitivesNumber = ((Aggregate) transformedGeometry).getPrimitivesNumber();
340
                                for (int i = 0; i < primitivesNumber; i++) {
341
                                    final Primitive primitive = ((Aggregate) transformedGeometry).getPrimitiveAt(i);
342
                                    drawingStatus.addStatus(primitive, symbol, "");
343
                                    drawingStatus.addStatus(primitive, previewSymbol, "");
344
                                }
345
                            } else {
346
                                drawingStatus.addStatus(transformedGeometry, symbol, "");
347
                                drawingStatus.addStatus(transformedGeometry, previewSymbol, "");
348
                            }
349
                        }
350
                    }
351
                    DisposeUtils.disposeQuietly(it);
352
                }
353
            } catch (Exception e) {
354
                throw new DrawServiceException(e);
355
            }
356
        }
357
        return drawingStatus;
358
    }
359

    
360
    /**
361
     * @param selected
362
     * @param point
363
     * @return
364
     * @throws DataException
365
     * @throws GeometryOperationException
366
     * @throws GeometryOperationNotSupportedException
367
     * @throws GeometryException
368
     */
369
    private double getMinDistance(FeatureSelection selected, Point point) throws DataException, GeometryOperationNotSupportedException, GeometryOperationException, GeometryException {
370
//        Geometry closestGeometry = getClosestGeometry(selected, point);
371
//        if(closestGeometry != null){
372
//            return closestGeometry.distance(point);
373
//        }
374
//        //No deber?a pasar por aqu?
375
        double minorDistance = Double.POSITIVE_INFINITY;
376
        DisposableIterator it;
377
        it = selected.fastIterator();
378
        while (it.hasNext()) {
379
            Feature feat = (Feature) it.next();
380
            Geometry geometry = feat.getDefaultGeometry();
381
            double distance = getDistance(geometry, point);
382
            if (distance < minorDistance) {
383
                minorDistance = distance;
384
            }
385
        }
386
        it.dispose();
387
        return minorDistance;
388

    
389
    }
390
    
391
    private Geometry getClosestGeometry(FeatureSelection selected, Point point) throws DataException, GeometryOperationNotSupportedException, GeometryOperationException, GeometryException {
392
        double minorDistance = Double.POSITIVE_INFINITY;
393
        DisposableIterator it;
394
        it = selected.fastIterator();
395
        Geometry closestGeometry = null;
396
        while (it.hasNext()) {
397
            Feature feat = (Feature) it.next();
398
            Geometry geometry = feat.getDefaultGeometry();
399
            double distance = getDistance(geometry, point);
400
            if (distance < minorDistance) {
401
                closestGeometry = geometry;
402
                minorDistance = distance;
403
            }
404
        }
405
        it.dispose();
406
        return closestGeometry;
407

    
408
    }
409

    
410
    /**
411
     * @param geometry
412
     * @param point
413
     * @return
414
     * @throws GeometryOperationException
415
     * @throws GeometryOperationNotSupportedException
416
     * @throws GeometryException
417
     */
418
    private double getDistance(Geometry geometry, Point point) throws GeometryOperationNotSupportedException, GeometryOperationException, GeometryException {
419
//        Point closest = getClosestPoint(geometry, point);
420
//        if(closest != null) {
421
//            return closest.distance(point);
422
//        }
423
        //No deber?a pasar por aqu?
424
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
425
        if (geometry instanceof Arc) {
426
            Arc arc = (Arc) geometry;
427
            Point center = arc.getCenterPoint();
428
            double radius = center.distance(arc.getInitPoint());
429
            double distance = center.distance(point) - radius;
430
            return distance;
431
        }
432

    
433
        if (geometry instanceof Circle) {
434
            Circle circle = (Circle) geometry;
435
            return circle.getCenter().distance(point) - circle.getRadious();
436
        }
437
        if (geometry instanceof Circumference) {
438
            Circumference circumference = (Circumference) geometry;
439
            return circumference.getCenter().distance(point) - circumference.getRadious();
440
        }
441
        if (geometry instanceof PeriEllipse) {
442
            double minDistance = Double.POSITIVE_INFINITY;
443
            PeriEllipse ellipse = (PeriEllipse) geometry;
444
            Geometry[] closestPoints = point.closestPoints(ellipse);
445
            if (closestPoints != null) {
446
                for (Geometry closestPoint : closestPoints) {
447
                    if (!point.equals(closestPoint)) {
448
                        double distance = closestPoint.distance(point);
449
                        if (distance < minDistance) {
450
                            minDistance = distance;
451
                        }
452
                    }
453
                }
454
            }
455
            Ellipse auxEllipse = (Ellipse) geomManager.create(Geometry.TYPES.ELLIPSE, geometry.getGeometryType().getSubType());
456
            auxEllipse.setPoints(ellipse.getAxis1Start(), ellipse.getAxis1End(), ellipse.getAxis2Dist());
457
            if (auxEllipse.contains(point)) {
458
                return -minDistance;
459
            }
460
            return minDistance;
461
        }
462
        if (geometry instanceof Ellipse) {
463
            Ellipse ellipse = (Ellipse) geometry;
464
            PeriEllipse auxPeriEllipse = (PeriEllipse) geomManager.create(Geometry.TYPES.PERIELLIPSE, geometry.getGeometryType().getSubType());
465
            auxPeriEllipse.setPoints(ellipse.getAxis1Start(), ellipse.getAxis1End(), ellipse.getAxis2Dist());
466
            double distance = getDistance(auxPeriEllipse, point);
467

    
468
            return distance;
469
        }
470

    
471
        if (geometry instanceof Spline || geometry instanceof FilledSpline) {
472
            return getDistance(geometry.toLines().getPrimitiveAt(0), point);
473
        }
474

    
475
        if (geometry instanceof Line) {
476
            Line line = (Line) geometry;
477
            double minDistance = Double.POSITIVE_INFINITY;
478
            Geometry[] closestPoints = point.closestPoints(line);
479
            Point closestPoint = null;
480
            if (closestPoints != null) {
481
                for (Geometry closestPoint1 : closestPoints) {
482
                    Point p = (Point) closestPoint1;
483
                    if (!point.equals(p)) {
484
                        double distance = p.distance(point);
485
                        if (distance < minDistance) {
486
                            minDistance = distance;
487
                            closestPoint = p;
488
                        }
489
                    }
490
                }
491
            }
492
            if (closestPoint != null) {
493
                for (int i = 0; i < line.getNumVertices() - 1; i++) {
494
                    Line segment = (Line) geomManager.create(Geometry.TYPES.LINE, geometry.getGeometryType().getSubType());
495
                    segment.addVertex(line.getVertex(i));
496
                    segment.addVertex(line.getVertex(i + 1));
497
                    if (segment.isWithinDistance(closestPoint, PRECISION)) {
498
                        if (line.getVertex(0).equals(line.getVertex(line.getNumVertices() - 1))) { //isClosed
499
                            if (line.toPolygons().contains(point)) {
500
                                return -minDistance;
501
                            }
502
                            return minDistance;
503
                        } else {
504
                            return getDirectedDistance(closestPoint, point, segment);
505
                        }
506
                    }
507
                }
508
            }
509
        }
510

    
511
        if (geometry instanceof Polygon) {
512
            Polygon polygon = (Polygon) geometry;
513
            if (!polygon.contains(point)) {
514
                double minDistance = Double.POSITIVE_INFINITY;
515
                Geometry[] closestPoints = point.closestPoints(polygon);
516
                Point closestPoint = null;
517
                if (closestPoints != null) {
518
                    for (Geometry closestPoint1 : closestPoints) {
519
                        Point p = (Point) closestPoint1;
520
                        if (!point.equals(p)) {
521
                            double distance = p.distance(point);
522
                            if (distance < minDistance) {
523
                                minDistance = distance;
524
                                closestPoint = p;
525
                            }
526
                        }
527
                    }
528
                }
529
                if (closestPoint != null) {
530
                    return closestPoint.distance(point);
531
                }
532
            } else {
533
                Line auxLine = (Line) polygon.toLines().getPrimitiveAt(0);
534
                if (auxLine != null) {
535
                    return getDistance(auxLine, point);
536
                }
537
            }
538
        }
539

    
540
        if (geometry instanceof Aggregate) {
541
            double minDistance = Double.POSITIVE_INFINITY;
542
            Aggregate aggregate2 = (Aggregate) geometry;
543
            for (int i = 0; i < aggregate2.getPrimitivesNumber(); i++) {
544
                double distance = getDistance(aggregate2.getPrimitiveAt(i), point);
545
                if (distance < minDistance) {
546
                    minDistance = distance;
547
                }
548
            }
549
            return minDistance;
550
        }
551
        return 0.0;
552
    }
553

    
554
    
555
    private Point getClosestPoint(Geometry geometry, Point point) throws GeometryOperationNotSupportedException, GeometryOperationException, GeometryException {
556
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
557
        if (geometry instanceof Line) {
558
            Line line = (Line) geometry;
559
            return (Point)line.closestPoints(point)[0];
560
        } else {
561
            return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
562
        }
563
//        if (geometry instanceof Arc) {
564
//            return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
565
//        }
566
//
567
//        if (geometry instanceof Circle) {
568
//            return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
569
//        }
570
//        if (geometry instanceof Circumference) {
571
//            return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
572
//        }
573
//        if (geometry instanceof PeriEllipse) {
574
//            return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
575
//        }
576
//        if (geometry instanceof Ellipse) {
577
//            return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
578
//        }
579
//
580
//        if (geometry instanceof Spline || geometry instanceof FilledSpline) {
581
//            return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
582
//        }
583
//
584
//
585
//        if (geometry instanceof Polygon) {
586
//            return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
587
//        }
588
//
589
//        if (geometry instanceof Aggregate) {
590
//            return (Point)geometry.toLines().getPrimitiveAt(0).closestPoints(point)[0];
591
//        }
592
//        return null;
593
    }
594

    
595
//    
596
    @Override
597
    public void stop() {
598
        values.clear();
599
    }
600

    
601
    @Override
602
    public void restart() throws StartServiceException, InvalidEntryException, StopServiceException {
603
//        values.put(selectionParameter, null);
604
        values.put(offsetParameter, null);
605
        values.put(sideParameter, null);
606
        values.put(deleteOriginalGeometriesParameter, null);
607
    }
608

    
609
    
610
    private void validateAndInsertValue(EditingServiceParameter param,
611
            Object value) throws InvalidEntryException {
612
        I18nManager i18nManager = ToolsLocator.getI18nManager();
613

    
614
        try {
615
            if (param == selectionParameter) {
616
                if (value instanceof FeatureSelection) {
617
                    values.put(param, value);
618
                }
619
            } else if (param == joinStyleParameter) {
620
                if (value instanceof String) {
621
                    values.put(param, fixJoinStyle(value));
622
                }
623
            } else if (param == offsetParameter) {
624
                if (value instanceof Point) {
625
                    Double distance = getMinDistance((FeatureSelection) values.get(selectionParameter), (Point) value);
626
                    if (distance == 0.0) {
627
                        throw new IllegalArgumentException("distance can't be 0");
628
                    }
629
                    values.put(param, Math.abs(distance));
630
                    values.put(sideParameter, coerceSide(distance));
631
                    return;
632
                }
633
                if (value instanceof Double) {
634
                    Double distance = (Double) value;
635
                    if (distance > 0) {
636
                        values.put(param, value);
637
                    } else if (distance == 0.0) {
638
                        throw new IllegalArgumentException("distance can't be 0");
639
                    } else {
640
                        values.put(param, Math.abs(distance));
641
                        values.put(sideParameter, coerceSide(distance));
642
                    }
643
                }
644
            } else if (param == sideParameter) {
645
                if (value instanceof Point) {
646
                    values.put(param, coerceSide(getMinDistance((FeatureSelection) values.get(selectionParameter), (Point) value)));
647
                    return;
648
                }
649
                if (value instanceof String) {
650
                    values.put(param, coerceSide(value));
651
                }
652
            } else if (param == equidistantOffsets) {
653
                if (value instanceof Number) {
654
                    int intValue = ((Number) value).intValue();
655
                    if(intValue >= 1) {
656
                        values.put(param, ((Number) value).intValue());
657
                    }
658
                }
659
            } else if (param == deleteOriginalGeometriesParameter) {
660
                values.put(param, param.getOptions2().getValue(value, param.getDefaultValue()));
661
            }
662
        } catch (Exception e) {
663
            throw new InvalidEntryException(e);
664
        }
665

    
666
    }
667

    
668
    private String coerceSide(Object value) throws InvalidEntryException {
669

    
670
        if (value instanceof Double) {
671
            return (Double) value >= 0 ? LEFT : RIGHT;
672
        }
673
        if (value instanceof String) {
674
            Double signum = getSideSignum((String) value);
675
            if (signum != null) {
676
                return signum >= 0 ? LEFT : RIGHT;
677
            }
678
        }
679
        throw new InvalidEntryException(null);
680
    }
681

    
682
    private String fixJoinStyle(Object value) throws InvalidEntryException {
683

    
684
        if (value instanceof String) {
685
            I18nManager i18nManager = ToolsLocator.getI18nManager();
686
            String joinStyleTrim = ((String)value).trim();
687
            if (StringUtils.equalsIgnoreCase(joinStyleTrim, ROUND)
688
                    || StringUtils.startsWithIgnoreCase(i18nManager.getTranslation(ROUND), joinStyleTrim)) {
689
                return ROUND;
690
            } else if (StringUtils.equalsIgnoreCase(joinStyleTrim, BEVEL)
691
                    || StringUtils.startsWithIgnoreCase(i18nManager.getTranslation(BEVEL), joinStyleTrim)) {
692
                return BEVEL;
693
            } else if (StringUtils.equalsIgnoreCase(joinStyleTrim, MITRE)
694
                    || StringUtils.startsWithIgnoreCase(i18nManager.getTranslation(MITRE), joinStyleTrim)) {
695
                return MITRE;
696
            }
697
        }
698
        throw new InvalidEntryException(null);
699
    }
700

    
701
    private Double getSideSignum(String side) {
702
        I18nManager i18nManager = ToolsLocator.getI18nManager();
703
        String sideTrim = side.trim();
704
        if (StringUtils.equalsIgnoreCase(sideTrim, LEFT)
705
                || StringUtils.startsWithIgnoreCase(i18nManager.getTranslation(LEFT), sideTrim)) {
706
            return 1.0;
707
        } else if (StringUtils.equalsIgnoreCase(sideTrim, RIGHT)
708
                || StringUtils.startsWithIgnoreCase(i18nManager.getTranslation(RIGHT), sideTrim)) {
709
            return -1.0;
710
        }
711
        return null;
712
    }
713

    
714
    @Override
715
    public List<EditingServiceParameter> getParameters() {
716
        List<EditingServiceParameter> list
717
                = new ArrayList<>();
718
        list.add(selectionParameter);
719
        list.add(joinStyleParameter);
720
        list.add(offsetParameter);
721
        list.add(sideParameter);
722
        list.add(equidistantOffsets);
723
        list.add(deleteOriginalGeometriesParameter);
724
        return list;
725
    }
726

    
727
    @Override
728
    public void setValue(EditingServiceParameter parameter, Object value) throws InvalidEntryException {
729
        validateAndInsertValue(parameter, value);
730
    }
731

    
732
    @Override
733
    public void setValue(Object value) throws InvalidEntryException {
734
        EditingServiceParameter param = next();
735
        validateAndInsertValue(param, value);
736
    }
737

    
738
    @Override
739
    public void finishAndStore() throws FinishServiceException {
740

    
741
        FeatureSelection selected
742
                = (FeatureSelection) values.get(selectionParameter);
743
        try {
744
            if (!selected.isEmpty()) {
745
                double side = 1.0;
746
                Object sideValue = values.get(sideParameter);
747
                if (sideValue != null) {
748
                    if (sideValue instanceof String) {
749
                        Double signum = getSideSignum((String) sideValue);
750
                        side = signum != null ? signum : null;
751
                    }
752
                }
753
                double distance = ((Double) values.get(offsetParameter)) * side;
754
                DisposableIterator it;
755
                it = selected.fastIterator();
756
                int joinStyleValue = coerceJoinStyle(values.get(joinStyleParameter));
757
                Number equidistantOffsetsNumberValue = ((Number) values.get(this.equidistantOffsets));
758
                int equidistantOffsetsValue = equidistantOffsetsNumberValue != null ? equidistantOffsetsNumberValue.intValue() : ((Number)this.equidistantOffsets.getDefaultValue()).intValue();
759

    
760
                while (it.hasNext()) {
761
                    Feature feature = (Feature) it.next();
762
                    for (int c = 1; c <= equidistantOffsetsValue; c++) {
763

    
764
                        Geometry geom;
765
                        try {
766
                            geom = feature.getDefaultGeometry().offset(joinStyleValue, c * distance);
767
                        } catch (GeometryOperationNotSupportedException | GeometryOperationException e) {
768
                            throw new FinishServiceException(e);
769
                        }
770

    
771
                        if ((boolean) values.get(deleteOriginalGeometriesParameter) && c == 1) {
772
                            // Se sustituye la geometr?a original por la primera calculada
773
                            EditableFeature editableFeature
774
                                    = feature.getEditable();
775
                            editableFeature.setDefaultGeometry(geom);
776
                            ((EditingProviderServices) getProviderServices())
777
                                    .updateFeatureInFeatureStore(editableFeature,
778
                                            featureStore);
779
                        } else {
780
                            // Se crea una feature nueva copiando los valores de
781
                            // la feature original excepto aquellos que sean PK
782
                            EditingProviderServices editingProviderServices
783
                                    = (EditingProviderServices) getProviderServices();
784
                            EditableFeature editableFeature
785
                                    = editingProviderServices
786
                                            .getFeatureCopyWithoutUniqueIndex(featureStore,
787
                                                    feature);
788
                            editableFeature.setDefaultGeometry(geom);
789
                            editingProviderServices
790
                                    .insertFeatureIntoFeatureStore(editableFeature,
791
                                            featureStore);
792
                        }
793
                    }
794

    
795
                }
796
                it.dispose();
797
//                featureStore.getFeatureSelection().deselectAll();
798
            }
799
        } catch (DataException e) {
800
            throw new FinishServiceException(e);
801
        }
802
    }
803

    
804
    private Double getDirectedDistance(Point pointInLine, Point distancePoint, Line line)
805
            throws GeometryOperationNotSupportedException, GeometryOperationException {
806
        Double distance = distancePoint.distance(pointInLine);
807
        EditingProviderServices editingProviderServices
808
                = (EditingProviderServices) getProviderServices();
809
        Double angle = editingProviderServices.getAngle(pointInLine, distancePoint);
810
        double angleLine = editingProviderServices.getAngle(line.getVertex(0), line.getVertex(1));
811

    
812
        Double angleDifference = angle - angleLine;
813
        if (angleDifference < 0) {
814
            angleDifference += 2 * Math.PI;
815
        }
816
        if (angleDifference > Math.PI) {
817
            distance = -distance;
818
        }
819
        return distance;
820
    }
821

    
822
    @Override
823
    public Geometry finish() throws FinishServiceException {
824
        return null;
825
    }
826

    
827
    @Override
828
    public void start() throws StartServiceException {
829
        this.values = new HashMap<>();
830
        FeatureSelection selected = null;
831
        if (featureStore != null) {
832
            try {
833
                selected
834
                        = (FeatureSelection) featureStore.getFeatureSelection()
835
                                .clone();
836
            } catch (DataException e) {
837
                throw new StartServiceException(e);
838
            } catch (CloneNotSupportedException e) {
839
                // Do nothing
840
            }
841
            if ((selected != null) && (selected.getSelectedCount() > 0)) {
842
                values.put(selectionParameter, selected);
843
            }
844
        }
845
    }
846
    
847
    @Override
848
    public String getName() {
849
        return OffsetEditingProviderFactory.PROVIDER_NAME;
850
    }
851

    
852
    private int coerceJoinStyle(Object joinStyle) {
853
        if(joinStyle instanceof String) {
854
            switch ((String)joinStyle) {
855
                default:
856
                case ROUND:
857
                    return JOIN_STYLE_ROUND;
858
                case MITRE:
859
                    return Geometry.JOIN_STYLE_MITRE;
860
                case BEVEL:
861
                    return Geometry.JOIN_STYLE_BEVEL;
862
            }
863
        }
864
        return JOIN_STYLE_ROUND;
865
    }
866

    
867
    @Override
868
    public boolean isEnabled(EditingServiceParameter parameter) {
869
        if (parameter == joinStyleParameter) {
870
            return true;
871
        }
872
        if (parameter == equidistantOffsets) {
873
            return true;
874
        }
875
        return true;
876
    }
877
    
878
    private ISimpleTextSymbol getTextSymbol(){
879
        SymbologyManager symbologyManager = SymbologyLocator.getSymbologyManager();
880
        ISimpleTextSymbol textSymbol = symbologyManager.createSimpleTextSymbol();
881
        textSymbol.setFontSize(10);
882
        return textSymbol;
883
    }
884
    
885
    @Override
886
    public Object getValue(EditingServiceParameter parameter) {
887
        return values!=null?values.get(parameter):null;
888
    }
889

    
890
    
891
}