Statistics
| Revision:

gvsig-vectorediting / org.gvsig.vectorediting / trunk / org.gvsig.vectorediting / org.gvsig.vectorediting.lib / org.gvsig.vectorediting.lib.prov / org.gvsig.vectorediting.lib.prov.chamfer / src / main / java / org / gvsig / vectorediting / lib / prov / chamfer / ChamferByLengthAndAngleEditingProvider.java @ 4284

History | View | Annotate | Download (66.8 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.lib.prov.chamfer;
25

    
26
import java.awt.Color;
27
import java.awt.geom.Point2D;
28
import java.util.ArrayList;
29
import java.util.Arrays;
30
import java.util.HashMap;
31
import java.util.List;
32
import java.util.Map;
33
import java.util.Objects;
34
import org.apache.commons.lang3.tuple.ImmutablePair;
35
import org.apache.commons.lang3.tuple.Pair;
36
import org.gvsig.euclidean.EuclideanLine2D;
37
import org.gvsig.euclidean.EuclideanManager;
38
import org.gvsig.fmap.dal.feature.EditableFeature;
39
import org.gvsig.fmap.dal.feature.Feature;
40
import org.gvsig.fmap.dal.feature.FeatureStore;
41
import org.gvsig.fmap.geom.Geometry;
42
import org.gvsig.fmap.geom.GeometryException;
43
import org.gvsig.fmap.geom.GeometryLocator;
44
import org.gvsig.fmap.geom.GeometryManager;
45
import org.gvsig.fmap.geom.GeometryUtils;
46
import org.gvsig.fmap.geom.aggregate.MultiLine;
47
import org.gvsig.fmap.geom.aggregate.MultiPrimitive;
48
import org.gvsig.fmap.geom.exception.CreateGeometryException;
49
import org.gvsig.fmap.geom.operation.GeometryOperationException;
50
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
51
import org.gvsig.fmap.geom.primitive.Arc;
52
import org.gvsig.fmap.geom.primitive.Curve;
53
import org.gvsig.fmap.geom.primitive.Line;
54
import org.gvsig.fmap.geom.primitive.Point;
55
import org.gvsig.fmap.geom.primitive.Polygon;
56
import org.gvsig.fmap.geom.primitive.Primitive;
57
import org.gvsig.fmap.geom.primitive.Surface;
58
import org.gvsig.fmap.mapcontext.MapContext;
59
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
60
import org.gvsig.symbology.SymbologyLocator;
61
import org.gvsig.symbology.SymbologyManager;
62
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.text.ISimpleTextSymbol;
63
import org.gvsig.tools.ToolsLocator;
64
import org.gvsig.tools.dataTypes.DataTypes;
65
import org.gvsig.tools.dynobject.DynObject;
66
import org.gvsig.tools.i18n.I18nManager;
67
import org.gvsig.tools.service.spi.ProviderServices;
68
import org.gvsig.tools.util.ToolsUtilLocator;
69
import org.gvsig.vectorediting.lib.api.DrawingStatus;
70
import org.gvsig.vectorediting.lib.api.EditingServiceParameter;
71
import org.gvsig.vectorediting.lib.api.EditingServiceParameter.TYPE;
72
import org.gvsig.vectorediting.lib.api.exceptions.DrawServiceException;
73
import org.gvsig.vectorediting.lib.api.exceptions.FinishServiceException;
74
import org.gvsig.vectorediting.lib.api.exceptions.InvalidEntryException;
75
import org.gvsig.vectorediting.lib.api.exceptions.StartServiceException;
76
import org.gvsig.vectorediting.lib.api.exceptions.StopServiceException;
77
import static org.gvsig.vectorediting.lib.prov.chamfer.SegmentData.SEGMENT_POSITION_FIRST;
78
import static org.gvsig.vectorediting.lib.prov.chamfer.SegmentData.SEGMENT_POSITION_LAST;
79
import static org.gvsig.vectorediting.lib.prov.chamfer.SegmentData.SEGMENT_POSITION_MIDDLE;
80
import org.gvsig.vectorediting.lib.spi.AbstractEditingProvider;
81
import org.gvsig.vectorediting.lib.spi.DefaultDrawingStatus;
82
import org.gvsig.vectorediting.lib.spi.DefaultEditingServiceParameter;
83
import org.gvsig.vectorediting.lib.spi.DefaultEditingServiceParameterOptions;
84
import org.gvsig.vectorediting.lib.spi.EditingProvider;
85
import org.gvsig.vectorediting.lib.spi.EditingProviderFactory;
86
import org.gvsig.vectorediting.lib.spi.EditingProviderLocator;
87
import org.gvsig.vectorediting.lib.spi.EditingProviderManager;
88
import org.gvsig.vectorediting.lib.spi.EditingProviderServices;
89
import org.slf4j.Logger;
90
import org.slf4j.LoggerFactory;
91

    
92
/**
93
 * @author fdiaz
94
 *
95
 */
96
public class ChamferByLengthAndAngleEditingProvider extends AbstractEditingProvider {
97

    
98
    private static final Logger LOGGER = LoggerFactory.getLogger(ChamferByLengthAndAngleEditingProvider.class);
99
    
100
    private static final int ERR_OK = 0;
101
    private static final int ERR_CHAMFER_TOO_LARGE = 1;
102
    private static final int ERR_SEGMENT_DATA_NOT_FILLED = 2;
103
    private static final int ERR_FIRST_SEGMENT_DATA_NULL = 3;
104
    private static final int ERR_SAME_SEGMENT = 4;
105
    private static final int ERR_CANT_CALCULATE_CHAMFER_POINT = 5;
106
    private static final int ERR_NON_ADJACENT_SEGMENTS = 6;
107
    private static final int ERR_DIFFERENT_GEOMETRY_TYPES = 7;
108
    private static final int ERR_CANT_CONNECT_SEGMENTS = 8;
109
    private static final int ERR_ONE_OF_THE_TWO_SEGMENTS_ISNT_EXTREME = 9;
110
    private static final int ERR_INVALID_VALUE = 10;
111
    private static final int ERR_INVALID_GEOMETRY_TYPE = 11;
112
    private static final int ERR_CANT_FIND_NEAREST_GEOMETRY = 12;
113
    private static final int ERR_CANT_CALCULATE_CHAMFER = 13;
114
    
115
    private static String[] stateMessages= {
116
        "_Valid",
117
        "_Chamfer_too_large",
118
        "_Cant_fill_segment_data",
119
        "_First_segment_data_is_null",
120
        "_Same_segment",
121
        "_Cant_calculate_chamfer_point",
122
        "_Non-adjacent_segments",
123
        "_Different_geometry_types",
124
        "_Cant_connect_segments",
125
        "_One_of_the_two_segments_isnt_extreme",
126
        "_Invalid_value",
127
        "_Invalid_geometry_type",
128
        "_Cant_find_nearest_geometry",
129
        "_Cant_calculate_chamfer"
130
        
131
    };
132

    
133

    
134
    private static final int INSIDE_THE_SEGMENT = 0;
135
    private static final int BEYOND_THE_SEGMENT = 1;
136
    private static final int INVALID_ZONE = -1;
137

    
138
    private static final String CHAMFER_LENGTH = "_Length";
139
//    private static final String CHAMFER_ANGLE = "_Angle";
140
//
141
//    private static final String SHORT_CHAMFER_LENGTH = "_Short_length";
142
//    private static final String SHORT_CHAMFER_ANGLE = "_Short_angle";
143

    
144
//    private static final String CHAMFER_METHOD = "_Method";
145

    
146
    private static final String DELETE_SECOND_SELECTED_GEOMETRY_QUESTION = "_Delete_second_selected_geometry_question";
147

    
148
    private static final String DELETE_SECOND_SELECTED_GEOMETRY = "_Delete_second_selected_geometry";
149

    
150
    private static final String YES = "_yes";
151
    private static final String NO = "_no";
152

    
153
    private static final String SHORT_YES = "_short_yes";
154
    private static final String SHORT_NO = "_short_no";
155
    //Variable est?tica para guardarnos el deleteSecondFeatureDefaultValue
156
    private static Boolean deleteSecondFeatureDefaultValue;
157

    
158
    private final EditingServiceParameter lengthParameter;
159
    
160
    private final EditingServiceParameter firstSegmentParameter;
161

    
162
    private final EditingServiceParameter secondSegmentParameter;
163

    
164
    private final EditingServiceParameter angleParameter;
165

    
166
    private final EditingServiceParameter deleteSecondSelectedGeometryParameter;
167

    
168
    private final Map<EditingServiceParameter, Object> values;
169

    
170
    private final FeatureStore featureStore;
171

    
172
    private final MapContext mapContext;
173

    
174
    private SegmentData firstSegmentData;
175
    private SegmentData secondSegmentData;
176

    
177
    private Point pointToChamfer;
178

    
179
    //Variable est?tica para guardarnos la distancia por defecto
180
    private static Double savedDistance;
181
    
182
    private ISymbol previewSymbol;
183

    
184
    /**
185
     * Default constructor.
186
     *
187
     * @param providerServices available services for this provider
188
     * @param parameters of this provider
189
     */
190
    public ChamferByLengthAndAngleEditingProvider(ProviderServices providerServices,
191
            DynObject parameters) {
192
        super(providerServices);
193
        I18nManager i18nManager = ToolsLocator.getI18nManager();
194

    
195
        this.featureStore
196
                = (FeatureStore) parameters
197
                        .getDynValue(EditingProviderFactory.FEATURE_STORE_FIELD);
198

    
199
        this.mapContext
200
                = (MapContext) parameters
201
                        .getDynValue(EditingProviderFactory.MAPCONTEXT_FIELD);
202

    
203
        this.firstSegmentParameter
204
                = new DefaultEditingServiceParameter("_First_segment", "_First_segment", TYPE.POSITION);
205

    
206
        this.secondSegmentParameter
207
                = new DefaultEditingServiceParameter("_Second_segment", "_Second_segment", TYPE.POSITION);
208

    
209
//        DefaultEditingServiceParameterOptions methodOptions = new DefaultEditingServiceParameterOptions()
210
//                .add(i18nManager.getTranslation(CHAMFER_LENGTH), CHAMFER_LENGTH, i18nManager.getTranslation(SHORT_CHAMFER_LENGTH))
211
//                .add(i18nManager.getTranslation(CHAMFER_ANGLE), CHAMFER_ANGLE, i18nManager.getTranslation(SHORT_CHAMFER_ANGLE));
212

    
213
//        String methodConsoleMsg
214
//                = ((EditingProviderServices) providerServices).makeConsoleMessage(
215
//                        i18nManager.getTranslation(CHAMFER_METHOD), methodOptions);
216

    
217
        this.lengthParameter = new DefaultEditingServiceParameter(
218
                "_Length",
219
                "_Length",
220
                TYPE.VALUE,
221
//                TYPE.POSITION,
222
                TYPE.DISTANCE
223
        );
224

    
225
        this.angleParameter
226
                = new DefaultEditingServiceParameter("_Angle", "_Angle",
227
                        TYPE.POSITION,
228
                        TYPE.VALUE);
229

    
230
        DefaultEditingServiceParameterOptions deleteSecondSelectedGeometryParameterOptions = new DefaultEditingServiceParameterOptions()
231
                .add(YES, true, i18nManager.getTranslation(SHORT_YES))
232
                .add(NO, false, i18nManager.getTranslation(SHORT_NO));
233

    
234
        String consoleMsg
235
                = ((EditingProviderServices) providerServices).makeConsoleMessage(
236
                        DELETE_SECOND_SELECTED_GEOMETRY_QUESTION, deleteSecondSelectedGeometryParameterOptions);
237

    
238
        this.deleteSecondSelectedGeometryParameter
239
                = new DefaultEditingServiceParameter(
240
                        DELETE_SECOND_SELECTED_GEOMETRY,
241
                        consoleMsg,
242
                        deleteSecondSelectedGeometryParameterOptions,
243
                        null, //deleteSecondFeatureDefaultValue,
244
                        false,
245
                        TYPE.OPTION).setDataType(DataTypes.BOOLEAN);
246

    
247
        this.values = new HashMap<>();
248
        this.firstSegmentData = null;
249
        this.secondSegmentData = null;
250
    }
251

    
252
    @Override
253
    public String getName() {
254
        return ChamferByLengthAndAngleEditingProviderFactory.PROVIDER_NAME;
255
    }
256

    
257
    @Override
258
    public EditingServiceParameter next() {
259
        if (values.get(lengthParameter) == null) {
260
            return this.lengthParameter;
261
        } else if (values.get(firstSegmentParameter) == null) {
262
            return this.firstSegmentParameter;
263
        } else if (values.get(secondSegmentParameter) == null) {
264
            return this.secondSegmentParameter;
265
        } else if (values.get(angleParameter) == null) {
266
            return this.angleParameter;
267
        } else if (values.get(deleteSecondSelectedGeometryParameter) == null && 
268
                !Objects.equals(firstSegmentData.getFeature().getReference(), secondSegmentData.getFeature().getReference())) {
269
            return this.deleteSecondSelectedGeometryParameter;
270
        }
271
        return null;
272
    }
273

    
274
    @Override
275
    public DrawingStatus getDrawingStatus(Point mousePosition)
276
            throws DrawServiceException {
277
        DefaultDrawingStatus geometries = new DefaultDrawingStatus();
278

    
279
        GeometryManager geometryManager = GeometryLocator.getGeometryManager();
280
        EditingProviderManager editingProviderManager
281
                = EditingProviderLocator.getProviderManager();
282
        ISymbol lineSymbolEditing = editingProviderManager.getSymbol("line-symbol-editing");
283
        ISymbol auxiliaryLineSymbolEditing = editingProviderManager.getSymbol("auxiliary-line-symbol-editing");
284
        ISymbol auxiliaryPointSymbolEditing = editingProviderManager.getSymbol("auxiliary-point-symbol-editing");
285
        ISymbol polygonSymbolEditing = editingProviderManager.getSymbol("polygon-symbol-editing");
286
        ISymbol ruleAxisSymbol = editingProviderManager.getSymbol("rule-axis-symbol");
287
        
288
        auxiliaryPointSymbolEditing.setColor(Color.RED);
289
        ISimpleTextSymbol textSymbol = getTextSymbol();
290

    
291
        EditingProviderServices editingProviderServices
292
                = (EditingProviderServices) getProviderServices();
293

    
294
        ISymbol previewSymbol = null;
295
        try {
296
            int subtype = editingProviderServices.getSubType(featureStore);
297
            Double distance;
298
            if (values != null) {
299
                if (values.get(this.lengthParameter) == null) {
300
                    return geometries;
301
                } else if (this.firstSegmentData == null) {
302
                    Feature firstFeature = getFeatureNearestPoint(mousePosition);
303
                    if (firstFeature == null) {
304
                        return geometries;
305
                    }
306
                    Geometry firstGeometry = firstFeature.getDefaultGeometry();
307
                    if (firstGeometry == null || !validateGeometryType(firstGeometry)) {
308
                        return geometries;
309
                    }
310
                    
311
                    SegmentData segmentData = new SegmentData(firstFeature, mousePosition);
312
                    geometries.addStatus(segmentData.getProjectedPoint(), auxiliaryPointSymbolEditing, "");
313
                    geometries.addStatus(GeometryUtils.createLine(mousePosition, segmentData.getProjectedPoint(), subtype), auxiliaryLineSymbolEditing, "");
314
                    geometries.addStatus(segmentData.getLine(), auxiliaryLineSymbolEditing, "");
315
                    return geometries;
316

    
317
                } else if (this.secondSegmentData == null) {
318
                    geometries.addStatus(firstSegmentData.getLine(), auxiliaryLineSymbolEditing, "");
319
                    geometries.addStatus(firstSegmentData.getProjectedPoint(), auxiliaryPointSymbolEditing, "");
320

    
321
                    Feature secondFeature = getFeatureNearestPoint(mousePosition);
322
                    if (secondFeature == null) {
323
                        return geometries;
324
                    }
325
                    Geometry secondGeometry = secondFeature.getDefaultGeometry();
326
                    if (secondGeometry == null || !validateGeometryType(secondGeometry)) {
327
                        return geometries;
328
                    }
329
                    SegmentData segmentData = new SegmentData(secondFeature, mousePosition);
330
                    Pair<Point, Point> oppositePoints = calculateOpositeToChamferVertices(firstSegmentData, segmentData);
331
                    if (validateAsSecondSegmentData(segmentData, oppositePoints.getRight()) == ERR_OK) {
332
                        geometries.addStatus(segmentData.getProjectedPoint(), auxiliaryPointSymbolEditing, "");
333
                        geometries.addStatus(GeometryUtils.createLine(mousePosition, segmentData.getProjectedPoint(), subtype), auxiliaryLineSymbolEditing, "");
334
                        geometries.addStatus(segmentData.getLine(), auxiliaryLineSymbolEditing, "");
335

    
336
                        Point tmpPointToChamfer = calculatePointToChamfer(firstSegmentData, segmentData);
337
                        geometries.addStatus(tmpPointToChamfer, auxiliaryPointSymbolEditing, "");
338

    
339
                    } else {
340
                        return geometries;
341
                    }
342
                } else if (values.get(angleParameter) == null) {
343
                    Point tmpPointToFillet = calculatePointToChamfer(firstSegmentData, secondSegmentData);
344
                    Pair<Point, Point> oppositePoints = calculateOpositeToChamferVertices(firstSegmentData, secondSegmentData);
345
                    geometries.addStatus(
346
                            GeometryUtils.createLine(oppositePoints.getLeft(), tmpPointToFillet, subtype), 
347
                            auxiliaryLineSymbolEditing, 
348
                            ""
349
                    );
350
                    geometries.addStatus(
351
                            GeometryUtils.createLine(oppositePoints.getRight(), tmpPointToFillet, subtype), 
352
                            auxiliaryLineSymbolEditing, 
353
                            ""
354
                    );
355

    
356
                    distance = (Double) getValue(lengthParameter);
357
                    double angle = GeometryUtils.calculateAngle(
358
                            pointToChamfer,
359
                            mousePosition);
360
                    
361
                    geometries.addStatus(tmpPointToFillet, auxiliaryPointSymbolEditing, "");
362

    
363
                    //Draw scaffolding
364
                    ScaffoldingToChamfer scaffolding = calculateScaffolding(firstSegmentData, secondSegmentData, tmpPointToFillet, distance, angle, subtype);
365
                    if(scaffolding == null){
366
                        return geometries;
367
                    }
368
                    
369
                    geometries.addStatus(
370
                            GeometryUtils.createLine(
371
                                    tmpPointToFillet, 
372
                                    scaffolding.getP1(),
373
                                    subtype), 
374
                            auxiliaryLineSymbolEditing,
375
                            ""
376
                    );
377
                    if(scaffolding.isReversed()){
378
                        geometries.addStatus(
379
                                GeometryUtils.createLine(
380
                                        scaffolding.getP1(), 
381
                                        GeometryUtils.createPoint(scaffolding.getChamferRight().getX(), scaffolding.getChamferRight().getY()),
382
                                        subtype), 
383
                                auxiliaryLineSymbolEditing, 
384
                                ""
385
                        );
386
                    } else {
387
                        geometries.addStatus(
388
                                GeometryUtils.createLine(
389
                                        scaffolding.getP1(), 
390
                                        GeometryUtils.createPoint(scaffolding.getChamferRight().getX(), scaffolding.getChamferRight().getY()),
391
                                        subtype), 
392
                                auxiliaryLineSymbolEditing, 
393
                                ""
394
                        );
395
                    }
396
                    
397
                    geometries.addStatus(
398
                            GeometryUtils.createLine(
399
                                    GeometryUtils.createPoint(scaffolding.getChamferRight().getX(), scaffolding.getChamferRight().getY()),
400
                                    GeometryUtils.createPoint(scaffolding.getChamferLeft().getX(), scaffolding.getChamferLeft().getY()),
401
                                    subtype), 
402
                            auxiliaryLineSymbolEditing, 
403
                            ""
404
                    );
405

    
406
                    //Draw angle
407
                    Line ruleAxisBaseLine;
408
                    ruleAxisBaseLine = geometryManager.createLine(subtype);
409
                    ruleAxisBaseLine.addVertex(tmpPointToFillet);
410
                    Point p2 = geometryManager.createPoint(
411
                            tmpPointToFillet.getX() + tmpPointToFillet.distance(mousePosition),
412
                            tmpPointToFillet.getY(), subtype);
413
                    ruleAxisBaseLine.addVertex(p2);
414
                    geometries.addStatus(ruleAxisBaseLine, ruleAxisSymbol, "");
415

    
416
                    Line angleLine = geometryManager.createLine(subtype);
417
                    angleLine.addVertex(tmpPointToFillet);
418
                    angleLine.addVertex(mousePosition);
419
                    geometries.addStatus(angleLine, ruleAxisSymbol, "");
420

    
421
                    Double ext = (2 * Math.PI) - angle;
422
                    Arc arc = GeometryUtils.createArc(
423
                            tmpPointToFillet,
424
                            tmpPointToFillet.distance(mousePosition) / 2,
425
                            0,
426
                            angle,
427
                            Geometry.SUBTYPES.GEOM2D);
428
                    geometries.addStatus(arc, auxiliaryLineSymbolEditing, "");
429
                    double textDistance = 3 * tmpPointToFillet.distance(mousePosition) / 4;
430
                    Point pointText = geometryManager.createPoint(tmpPointToFillet.getX() + textDistance * Math.cos(angle / 2), tmpPointToFillet.getY() + textDistance * Math.sin(angle / 2), subtype);
431
                    geometries.addStatus(pointText, textSymbol, GeometryUtils.formatAngle("%5.3D\u00B0", Math.toDegrees(angle)));
432
                    
433
                    
434
                    //Draw result
435
                    drawResult(geometries, firstSegmentData, secondSegmentData, distance, angle, subtype);
436
                    return geometries;
437
                } else {
438
                    drawResult(
439
                            geometries, 
440
                            firstSegmentData, 
441
                            secondSegmentData,
442
                            (Double) getValue(lengthParameter), 
443
                            Math.toRadians((Double) getValue(angleParameter)), 
444
                            subtype
445
                    );
446
                    return geometries;
447
                }
448
            }
449
        } catch (Exception e) {
450
            throw new DrawServiceException(e);
451
        }
452
        return geometries;
453
    }
454

    
455
    private void drawResult(DefaultDrawingStatus geometries, SegmentData firstSegmentData, SegmentData secondSegmentData, Double length, Double angle, int subtype) throws CreateGeometryException, GeometryOperationNotSupportedException, IllegalStateException, GeometryException, GeometryOperationException {
456
        if(previewSymbol == null){
457
            return;
458
        }
459
        //Draw result
460
        Line chamfer = calculateChamfer(firstSegmentData, secondSegmentData, length, angle, subtype);
461
        if (chamfer == null) {
462
            return;
463
        }
464
        if (Objects.equals(firstSegmentData.getPrimitive(), secondSegmentData.getPrimitive())) {
465
            geometries.addStatus(chamferPrimitive(firstSegmentData.getPrimitive(), chamfer), previewSymbol, null);
466
        } else {
467
            geometries.addStatus(chamferPrimitives(firstSegmentData.getPrimitive(), secondSegmentData.getPrimitive(), chamfer), previewSymbol, null);
468
        }
469
    }
470

    
471
    private ISimpleTextSymbol getTextSymbol() {
472
        SymbologyManager symbologyManager = SymbologyLocator.getSymbologyManager();
473
        ISimpleTextSymbol textSymbol = symbologyManager.createSimpleTextSymbol();
474
        textSymbol.setFontSize(10);
475
        return textSymbol;
476
    }
477

    
478
    @Override
479
    public List<EditingServiceParameter> getParameters() {
480
        List<EditingServiceParameter> parameters
481
                = new ArrayList<>();
482
        parameters.add(lengthParameter);
483
        parameters.add(firstSegmentParameter);
484
        parameters.add(secondSegmentParameter);
485
        parameters.add(angleParameter);
486
        parameters.add(deleteSecondSelectedGeometryParameter);
487
        return parameters;
488
    }
489

    
490
    @Override
491
    public boolean isEnabled(EditingServiceParameter parameter) {
492
        return true;
493
    }
494

    
495
    @Override
496
    public void setValue(EditingServiceParameter parameter, Object value) throws InvalidEntryException {
497
        validateAndInsertValue(parameter, value);
498
    }
499

    
500
    @Override
501
    public void setValue(Object value) throws InvalidEntryException {
502
        EditingServiceParameter param = next();
503
        validateAndInsertValue(param, value);
504
    }
505

    
506
    private void validateAndInsertValue(EditingServiceParameter param,
507
            Object value) throws InvalidEntryException {
508

    
509
        try {
510
            EditingProviderServices editingProviderServices
511
                    = (EditingProviderServices) getProviderServices();
512
            int subtype = editingProviderServices.getSubType(featureStore);
513
            
514
            I18nManager i18n = ToolsLocator.getI18nManager();
515

    
516
            
517
            if (param == lengthParameter) {
518
                Double distance = null;
519
                if (value instanceof Double) {
520
                    distance = (Double) value;
521
                } else if (value == null) {
522
                    distance = (Double) lengthParameter.getDefaultValue();
523
                    if(distance == null){
524
                        throw new InvalidEntryException(getName(), ERR_INVALID_VALUE, i18n.getTranslation(stateMessages[ERR_INVALID_VALUE]));
525
                    }
526
                }
527
                values.put(param, distance);
528
                savedDistance = distance;
529
            } else if (param == firstSegmentParameter) {
530
                if (value instanceof Point) {
531
                    Point point = (Point) value;
532

    
533
                    Feature firstFeature = getFeatureNearestPoint(point);
534
                    if (firstFeature == null) {
535
                        throw new InvalidEntryException(new IllegalArgumentException("Can't find nearest feature."));
536
                    }
537
                    Geometry firstGeometry = firstFeature.getDefaultGeometry();
538
                    if (!validateGeometryType(firstGeometry)) {
539
                        throw new InvalidEntryException(getName(), ERR_INVALID_GEOMETRY_TYPE, i18n.getTranslation(stateMessages[ERR_INVALID_GEOMETRY_TYPE]));
540
                    }
541
                    this.firstSegmentData = new SegmentData(firstFeature, point);
542
                    if (!this.firstSegmentData.isFilled()) {
543
                        this.firstSegmentData = null;
544
                        throw new InvalidEntryException(getName(), ERR_CANT_FIND_NEAREST_GEOMETRY, i18n.getTranslation(stateMessages[ERR_CANT_FIND_NEAREST_GEOMETRY]));
545
                    }
546
                    if (firstSegmentData == null) {
547
                        throw new InvalidEntryException(getName(), ERR_CANT_FIND_NEAREST_GEOMETRY, i18n.getTranslation(stateMessages[ERR_CANT_FIND_NEAREST_GEOMETRY]));
548
                    }
549
                    values.put(param, value);
550
                    previewSymbol = getPreviewSymbol(this.firstSegmentData.getFeature());
551
                }
552
            } else if (param == secondSegmentParameter) {
553
                if (value instanceof Point) {
554
                    Point point = (Point) value;
555
                    Feature secondFeature = getFeatureNearestPoint(point);
556
                    if (secondFeature == null) {
557
                        throw new InvalidEntryException(getName(), ERR_CANT_FIND_NEAREST_GEOMETRY, i18n.getTranslation(stateMessages[ERR_CANT_FIND_NEAREST_GEOMETRY]));
558
                    }
559
                    SegmentData segmentData = new SegmentData(secondFeature, point);
560
                    Pair<Point, Point> oppositeVertices = calculateOpositeToChamferVertices(this.firstSegmentData, segmentData);
561
                    int errno = validateAsSecondSegmentData(segmentData, oppositeVertices.getRight());
562
                    if (errno != ERR_OK) {
563
                        this.secondSegmentData = null;
564
                        this.pointToChamfer = null;
565
                        throw new InvalidEntryException(getName(), errno, i18n.getTranslation(stateMessages[errno]));
566
                    } else {
567
                        try {
568
                            this.secondSegmentData = segmentData;
569
                            this.pointToChamfer = calculatePointToChamfer(this.firstSegmentData, this.secondSegmentData);
570
                            angleParameter.setDefaultValue(calculateDefaultAngle(this.pointToChamfer, oppositeVertices));
571
                            values.put(param, value);
572
                        } catch (GeometryOperationNotSupportedException | GeometryOperationException ex) {
573
                            throw new InvalidEntryException(getName(), ERR_CANT_CALCULATE_CHAMFER_POINT, i18n.getTranslation(stateMessages[ERR_CANT_FIND_NEAREST_GEOMETRY]));
574
                        }
575
                    }
576
                }
577
                            
578
            } else if (param == angleParameter) {
579

    
580
                Double angle = null;
581
                if (value instanceof Double) {
582
                    angle = Math.toRadians((Double)value);
583
                } else if (value instanceof Point) {
584
                    Point point = (Point) value;
585
                    angle = GeometryUtils.calculateAngle(
586
                            pointToChamfer,
587
                            point);
588
                } else if (value == null) {
589
                    angle = Math.toRadians((Double) param.getDefaultValue());
590
                } else {
591
                    throw new InvalidEntryException(getName(), ERR_INVALID_VALUE, i18n.getTranslation(stateMessages[ERR_INVALID_VALUE]));
592
                }
593
                Double distance = (Double) getValue(lengthParameter);
594
                Line chamfer = calculateChamfer(firstSegmentData, secondSegmentData, distance, angle, subtype);
595
                if(chamfer == null){
596
                    throw new InvalidEntryException(getName(), ERR_CANT_CALCULATE_CHAMFER, i18n.getTranslation(stateMessages[ERR_CANT_FIND_NEAREST_GEOMETRY]));
597
                } else {
598
                    values.put(param, Math.toDegrees(angle));
599
                }
600
            } else if (param == deleteSecondSelectedGeometryParameter) {
601
                Boolean v = (Boolean) param.getOptions2().getValue(value, param.getDefaultValue());
602
                values.put(param, v);
603
                deleteSecondFeatureDefaultValue = v;
604
            }
605
        } catch (InvalidEntryException ex) {
606
            throw ex;
607
        } catch (Exception ex) {
608
            throw new InvalidEntryException(ex);
609
        }
610

    
611
    }
612

    
613
    private boolean validateGeometryType(Geometry geometry) throws IllegalArgumentException {
614
        List<Integer> validGeometryTypes = new ArrayList(Arrays.asList(
615
                Geometry.TYPES.LINE,
616
                Geometry.TYPES.POLYGON,
617
                Geometry.TYPES.MULTILINE,
618
                Geometry.TYPES.MULTIPOLYGON
619
        ));
620

    
621
        return validGeometryTypes.contains(geometry.getType());
622
    }
623

    
624
    @Override
625
    public Geometry finish() throws FinishServiceException {
626
        return null;
627
    }
628

    
629
    @Override
630
    public void finishAndStore() throws FinishServiceException {
631
        Line chamfer; // = null;
632
        Double distance = (Double) getValue(lengthParameter);
633
        Double angle = (Double) getValue(angleParameter);
634
        try {
635

    
636
            EditingProviderServices editingProviderServices = (EditingProviderServices) getProviderServices();
637
            int subType = editingProviderServices.getSubType(featureStore);
638

    
639
            chamfer = calculateChamfer(
640
                    this.firstSegmentData, 
641
                    this.secondSegmentData,
642
                    (Double) getValue(lengthParameter),
643
                    Math.toRadians((Double) getValue(angleParameter)), 
644
                    subType
645
            );
646
            if(chamfer == null){
647
                throw new FinishServiceException("Can't calculate chamfer.", null);
648
            }
649

    
650
            Feature firstFeature = firstSegmentData.getFeature();
651
            Feature secondFeature = secondSegmentData.getFeature();
652

    
653
            Boolean doDeleteSecondSelectedGeometry = false;
654
            if (!Objects.equals(firstFeature.getReference(), secondFeature.getReference())) {
655
                doDeleteSecondSelectedGeometry = (Boolean) values.get(this.deleteSecondSelectedGeometryParameter);
656
            }
657

    
658
            EditableFeature editableFeature = firstFeature.getEditable();
659
            Geometry modifiedGeometry; //= null; //editableFeature.getDefaultGeometry().cloneGeometry();
660
            GeometryManager geomManager = GeometryLocator.getGeometryManager();
661
            Geometry firstGeometry = firstSegmentData.getGeometry();
662
            Primitive firstPrimitive = firstSegmentData.getPrimitive();
663
            Primitive secondPrimitive = secondSegmentData.getPrimitive();
664
            if (Objects.equals(firstFeature.getReference(), secondFeature.getReference())) {
665
                if (firstGeometry instanceof MultiPrimitive) {
666
                    modifiedGeometry = geomManager.create(firstGeometry.getGeometryType());
667
                    MultiPrimitive firstMultiPrimitive = (MultiPrimitive) firstGeometry;
668
                    if (Objects.equals(firstPrimitive, secondPrimitive)) {
669
                        for (Geometry geometry : firstMultiPrimitive) {
670
                            Primitive primitive = (Primitive) geometry;
671
                            if (Objects.equals(firstPrimitive, primitive)) {
672
                                Primitive modifiedPrimitive = chamferPrimitive(primitive, chamfer);
673
                                ((MultiPrimitive) modifiedGeometry).addPrimitive(modifiedPrimitive);
674
                            } else if (Objects.equals(secondPrimitive, primitive)) {
675
                                //Don't add second primitive
676
                            } else {
677
                                ((MultiPrimitive) modifiedGeometry).addPrimitive(primitive);
678
                            }
679
                        }
680
                    } else {
681
                        Primitive modifiedPrimitive = chamferPrimitives(firstPrimitive, secondPrimitive, chamfer);
682
                        for (Geometry geometry : firstMultiPrimitive) {
683
                            Primitive primitive = (Primitive) geometry;
684
                            if (Objects.equals(firstPrimitive, primitive)) {
685
                                ((MultiPrimitive) modifiedGeometry).addPrimitive(modifiedPrimitive);
686
                            } else if (Objects.equals(secondPrimitive, primitive)) {
687
                                //Don't add second primitive
688
                            } else {
689
                                ((MultiPrimitive) modifiedGeometry).addPrimitive(primitive);
690
                            }
691
                        }
692
                    }
693
                } else {
694
                    modifiedGeometry = chamferPrimitive((Primitive) editableFeature.getDefaultGeometry(), chamfer);
695
                }
696

    
697
            } else { // Different features
698

    
699
                doDeleteSecondSelectedGeometry = (Boolean) values.get(this.deleteSecondSelectedGeometryParameter);
700
                Primitive modifiedPrimitive = chamferPrimitives(firstPrimitive, secondPrimitive, chamfer);
701

    
702
                modifiedGeometry = geomManager.create(firstGeometry.getGeometryType());
703
                if (firstGeometry instanceof MultiPrimitive) {
704
                    MultiPrimitive firstMultiPrimitive = (MultiPrimitive) firstGeometry;
705
                    for (Geometry geometry : firstMultiPrimitive) {
706
                        Primitive primitive = (Primitive) geometry;
707
                        if (Objects.equals(firstPrimitive, primitive)) {
708
                            ((MultiPrimitive) modifiedGeometry).addPrimitive(modifiedPrimitive);
709
                        } else {
710
                            ((MultiPrimitive) modifiedGeometry).addPrimitive(primitive);
711
                        }
712
                    }
713
                } else {
714
                    modifiedGeometry = modifiedPrimitive;
715
                }
716
                if (doDeleteSecondSelectedGeometry) {
717
                    secondFeature.getStore().delete(secondFeature);
718
                }
719
            }
720
            editableFeature.setDefaultGeometry(modifiedGeometry);
721
            ((EditingProviderServices) getProviderServices())
722
                    .updateFeatureInFeatureStore(
723
                            editableFeature, featureStore);
724

    
725

    
726
        } catch (Exception e) {
727
            throw new FinishServiceException(e);
728
        }
729
    }
730

    
731
    private Primitive chamferPrimitive(Primitive primitive, Line chamfer) throws IllegalStateException, GeometryException, GeometryOperationException, GeometryOperationNotSupportedException {
732
        Primitive modifiedPrimitive = (Primitive) (primitive.cloneGeometry());
733
        if (primitive instanceof Line || primitive instanceof Polygon) {
734
            modifiedPrimitive = (Primitive) (primitive.cloneGeometry());
735
        } else if (primitive instanceof Curve) {
736
            modifiedPrimitive = (Line) primitive.toLines().getPrimitiveAt(0);
737
        } else if (primitive instanceof Surface) {
738
            modifiedPrimitive = (Line) primitive.toPolygons().getPrimitiveAt(0);
739
        }
740
        if (Objects.equals(firstSegmentData.getIdxVertex(), secondSegmentData.getIdxVertex() - 1)) {
741
            if (modifiedPrimitive instanceof Line) {
742
                ((Line) modifiedPrimitive).removeVertex(firstSegmentData.getIdxVertex() + 1);
743
                int i = 1;
744
                for (Point point : chamfer) {
745
                    ((Line) modifiedPrimitive).insertVertex(firstSegmentData.getIdxVertex() + i++, point);
746
                }
747
            } else if (modifiedPrimitive instanceof Polygon) {
748
                ((Polygon) modifiedPrimitive).removeVertex(firstSegmentData.getIdxVertex() + 1);
749
                int i = 1;
750
                for (Point point : chamfer) {
751
                    ((Polygon) modifiedPrimitive).insertVertex(firstSegmentData.getIdxVertex() + i++, point);
752
                }
753
            }
754
        } else if (Objects.equals(firstSegmentData.getIdxVertex(), secondSegmentData.getIdxVertex() + 1)) {
755
            if (modifiedPrimitive instanceof Line) {
756
                ((Line) modifiedPrimitive).removeVertex(secondSegmentData.getIdxVertex() + 1);
757
                Line flipedChamfer = (Line)chamfer.cloneGeometry();
758
                flipedChamfer.flip();
759
                int i = 1;
760
                for (Point point : flipedChamfer) {
761
                    ((Line) modifiedPrimitive).insertVertex(secondSegmentData.getIdxVertex() + i++, point);
762
                }
763
            } else if (modifiedPrimitive instanceof Polygon) {
764
                ((Polygon) modifiedPrimitive).removeVertex(secondSegmentData.getIdxVertex() + 1);
765
                Line flipedChamfer = (Line)chamfer.cloneGeometry();
766
                flipedChamfer.flip();
767
                int i = 1;
768
                for (Point point : flipedChamfer) {
769
                    ((Polygon) modifiedPrimitive).insertVertex(secondSegmentData.getIdxVertex() + i++, point);
770
                }
771
            }
772
        } else if (Objects.equals(this.firstSegmentData.getPosition(), SEGMENT_POSITION_LAST) && Objects.equals(this.secondSegmentData.getPosition(), SEGMENT_POSITION_FIRST)) {
773
            if (modifiedPrimitive instanceof Line) {
774
                ((Line) modifiedPrimitive).removeVertex(0);
775
                ((Line) modifiedPrimitive).removeVertex(((Line) modifiedPrimitive).getNumVertices() - 1);
776
                for (Point point : chamfer) {
777
                    ((Line) modifiedPrimitive).addVertex(point); //.insertVertex(secondSegmentData.getIdxVertex() + i++, point);
778
                }
779

    
780
            } else if (modifiedPrimitive instanceof Polygon) {
781
                ((Polygon) modifiedPrimitive).removeVertex(0);
782
                ((Polygon) modifiedPrimitive).removeVertex(((Polygon) modifiedPrimitive).getNumVertices() - 1);
783

    
784
                ((Polygon) modifiedPrimitive).insertVertex(0, chamfer.getVertex(chamfer.getNumVertices()-1));
785
                for (Point point : chamfer) {
786
                    ((Polygon) modifiedPrimitive).addVertex(point); //.insertVertex(secondSegmentData.getIdxVertex() + i++, point);
787
                }
788

    
789
            }
790
        } else if (Objects.equals(this.firstSegmentData.getPosition(), SEGMENT_POSITION_FIRST) && Objects.equals(this.secondSegmentData.getPosition(), SEGMENT_POSITION_LAST)) {
791
            Line flipedChamfer = (Line)chamfer.cloneGeometry();
792
            flipedChamfer.flip();
793
            if (modifiedPrimitive instanceof Line) {
794
                ((Line) modifiedPrimitive).removeVertex(0);
795
                ((Line) modifiedPrimitive).removeVertex(((Line) modifiedPrimitive).getNumVertices() - 1);
796

    
797
                int i = 1;
798
                for (Point point : flipedChamfer) {
799
                    ((Line) modifiedPrimitive).addVertex(point); //.insertVertex(firstSegmentData.getIdxVertex() + i++, point);
800
                }
801
            } else if (modifiedPrimitive instanceof Polygon) {
802
                ((Polygon) modifiedPrimitive).removeVertex(0);
803
                ((Polygon) modifiedPrimitive).removeVertex(((Polygon) modifiedPrimitive).getNumVertices() - 1);
804

    
805
                ((Polygon) modifiedPrimitive).insertVertex(0, flipedChamfer.getVertex(flipedChamfer.getNumVertices()-1));
806
                for (Point point : flipedChamfer) {
807
                    ((Polygon) modifiedPrimitive).addVertex(point);//.insertVertex(firstSegmentData.getIdxVertex() + i++, point);
808
                }
809
            }
810
        } else {
811
            throw new IllegalStateException("Invalid segments");
812
        }
813
        return modifiedPrimitive;
814
    }
815

    
816
    private Primitive chamferPrimitives(Primitive firstPrimitive, Primitive secondPrimitive, Line chamfer) throws IllegalStateException, GeometryException, GeometryOperationNotSupportedException, GeometryOperationException {
817
        //Cannot be polygons
818
        if(firstPrimitive == null){
819
            throw new IllegalArgumentException("firstPrimitive is null");
820
        }
821
        Line firstLine;
822
        if (firstPrimitive instanceof Line) {
823
            firstLine = (Line) firstPrimitive.cloneGeometry();
824
        } else {
825
            MultiLine lines = firstPrimitive.toLines();
826
            if(lines==null){
827
                throw new IllegalArgumentException("Can't find first primitive.");
828
            }
829
            firstLine = (Line) lines.getPrimitiveAt(0);
830
        }
831
        if(secondPrimitive == null){
832
            throw new IllegalArgumentException("secondPrimitive is null");
833
        }
834
        Line secondLine;
835
        if (secondPrimitive instanceof Line) {
836
            secondLine = (Line) secondPrimitive;
837
        } else {
838
            MultiLine lines = secondPrimitive.toLines();
839
            if(lines==null){
840
                throw new IllegalArgumentException("Can't find second primitive.");
841
            }
842
            secondLine = (Line) lines.getPrimitiveAt(0);
843
        }
844

    
845
        Line modifiedPrimitive = firstLine;
846
        if (Objects.equals(this.firstSegmentData.getPosition(), SEGMENT_POSITION_LAST)) {
847
            modifiedPrimitive.removeVertex(modifiedPrimitive.getNumVertices() - 1);
848
            for (Point point : chamfer) {
849
                modifiedPrimitive.addVertex(point);
850
            }
851
            
852
            if (Objects.equals(this.secondSegmentData.getPosition(), SEGMENT_POSITION_FIRST)) {
853
                for (int i = 0; i < secondLine.getNumVertices(); i++) {
854
                    if (i != 0) {
855
                        ((Line) modifiedPrimitive).addVertex(secondLine.getVertex(i));
856
                    }
857
                }
858
            } else { //LAST
859
                for (int i = secondLine.getNumVertices() - 1; i >= 0; i--) {
860
                    if (i != secondLine.getNumVertices() - 1) {
861
                        ((Line) modifiedPrimitive).addVertex(secondLine.getVertex(i));
862
                    }
863
                }
864
            }
865
        } else {
866
            modifiedPrimitive.removeVertex(0);
867
            for (Point point : chamfer) {
868
                modifiedPrimitive.insertVertex(0, point);
869
            }
870
            
871
            if (Objects.equals(this.secondSegmentData.getPosition(), SEGMENT_POSITION_FIRST)) {
872
                for (int i = 0; i < secondLine.getNumVertices(); i++) {
873
                    if (i != 0) {
874
                        ((Line) modifiedPrimitive).insertVertex(0, secondLine.getVertex(i));
875
                    }
876
                }
877
            } else { //LAST
878
                for (int i = secondLine.getNumVertices() - 1; i >= 0; i--) {
879
                    if (i != secondLine.getNumVertices() - 1) {
880
                        ((Line) modifiedPrimitive).insertVertex(0, secondLine.getVertex(i));
881
                    }
882
                }
883
            }
884
        }
885
        return modifiedPrimitive;
886
    }
887

    
888
    private Pair<Point, Point> calculateOpositeToChamferVertices(SegmentData firstSegmentData, SegmentData secondSegmentData) throws GeometryOperationNotSupportedException, GeometryOperationException {
889
        Point firstVertex;
890
        Point secondVertex;
891
        if (Objects.equals(firstSegmentData.getPrimitive(), secondSegmentData.getPrimitive())) {
892
            if (Objects.equals(firstSegmentData.getIdxVertex(), secondSegmentData.getIdxVertex() - 1)) {
893
                firstVertex = firstSegmentData.getLine().getVertex(0);
894
                secondVertex = secondSegmentData.getLine().getVertex(1);
895
            } else if (Objects.equals(firstSegmentData.getIdxVertex(), secondSegmentData.getIdxVertex() + 1)) {
896
                firstVertex = firstSegmentData.getLine().getVertex(1);
897
                secondVertex = secondSegmentData.getLine().getVertex(0);
898
            } else {
899
                if (Objects.equals(firstSegmentData.getPosition(), SEGMENT_POSITION_FIRST)) {
900
                    firstVertex = firstSegmentData.getLine().getVertex(1);
901
                } else { //SEGMENT_POSITION_LAST
902
                    firstVertex = firstSegmentData.getLine().getVertex(0);
903
                }
904

    
905
                if (Objects.equals(secondSegmentData.getPosition(), SEGMENT_POSITION_FIRST)) {
906
                    secondVertex = secondSegmentData.getLine().getVertex(1);
907
                } else { //SEGMENT_POSITION_LAST
908
                    secondVertex = secondSegmentData.getLine().getVertex(0);
909
                }
910
            }
911
        } else {
912
            if (Objects.equals(firstSegmentData.getPosition(), SEGMENT_POSITION_FIRST)) {
913
                firstVertex = firstSegmentData.getLine().getVertex(1);
914
            } else {
915
                firstVertex = firstSegmentData.getLine().getVertex(0);
916
            }
917

    
918
            if (Objects.equals(secondSegmentData.getPosition(), SEGMENT_POSITION_FIRST)) {
919
                secondVertex = secondSegmentData.getLine().getVertex(1);
920
            } else {
921
                secondVertex = secondSegmentData.getLine().getVertex(0);
922
            }
923
        }
924
        return new ImmutablePair<>(firstVertex, secondVertex);
925
    }
926

    
927
    @Override
928
    public void start() throws StartServiceException {
929
        this.values.clear();
930
        this.firstSegmentData = null;
931
        this.secondSegmentData = null;
932
        this.pointToChamfer = null;
933

    
934
        if (savedDistance != null) {
935
            this.lengthParameter.setDefaultValue(savedDistance);
936
        }
937
    }
938

    
939
    @Override
940
    public void restart() throws StartServiceException, InvalidEntryException, StopServiceException {
941
        this.values.clear();
942
        this.firstSegmentData = null;
943
        this.secondSegmentData = null;
944
        this.pointToChamfer = null;
945

    
946
        if (savedDistance != null) {
947
            this.lengthParameter.setDefaultValue(savedDistance);
948
        }
949

    
950
    }
951

    
952
    @Override
953
    public void initDefaultValues() {
954
        super.initDefaultValues();
955
        if (deleteSecondFeatureDefaultValue != null) {
956
            this.deleteSecondSelectedGeometryParameter.setDefaultValue(deleteSecondFeatureDefaultValue);
957
        }
958
    }
959
    
960
    
961

    
962
    @Override
963
    public void stop() throws StopServiceException {
964
        this.values.clear();
965
        this.firstSegmentData = null;
966
        this.secondSegmentData = null;
967
        this.pointToChamfer = null;
968
    }
969

    
970
    @Override
971
    public Object getValue(EditingServiceParameter parameter) {
972
        return values != null ? values.get(parameter) : null;
973
    }
974

    
975
    private Feature getFeatureNearestPoint(Point point) {
976
        EditingProviderServices editingProviderServices = (EditingProviderServices) getProviderServices();
977
        Feature feature = editingProviderServices.getFeature(point, featureStore, mapContext);
978
        return feature;
979
    }
980

    
981
    private int validateAsSecondSegmentData(SegmentData segmentData, Point oppositeVertex) throws GeometryOperationNotSupportedException, GeometryOperationException {
982

    
983
        if (!segmentData.isFilled()) {
984
            return ERR_SEGMENT_DATA_NOT_FILLED;
985
        }
986
        if (this.firstSegmentData == null) {
987
            return ERR_FIRST_SEGMENT_DATA_NULL;
988
        }
989
        Primitive firstPrimitive = this.firstSegmentData.getPrimitive();
990
        Primitive secondPrimitive = segmentData.getPrimitive();
991
        if (Objects.equals(firstPrimitive, secondPrimitive)) {
992
            if (Objects.equals(this.firstSegmentData.getIdxVertex(), segmentData.getIdxVertex())) {
993
                return ERR_SAME_SEGMENT;
994
            }
995
            if (Math.abs(this.firstSegmentData.getIdxVertex() - segmentData.getIdxVertex()) <= 1) {
996
                return validateSegmentsAndLength(firstSegmentData, segmentData, calculatePointToChamfer(firstSegmentData, segmentData));
997
            }
998
            switch (firstPrimitive.getType()) {
999
                case Geometry.TYPES.LINE:
1000
                    if (((Line) firstPrimitive).isClosed()) {
1001
                        if ((this.firstSegmentData.getPosition().equals(SEGMENT_POSITION_FIRST) && segmentData.getPosition().equals(SEGMENT_POSITION_LAST)
1002
                                || this.firstSegmentData.getPosition().equals(SEGMENT_POSITION_LAST) && segmentData.getPosition().equals(SEGMENT_POSITION_FIRST))) {
1003
                            return validateSegmentsAndLength(firstSegmentData, segmentData, calculatePointToChamfer(firstSegmentData, segmentData));
1004
                        }
1005

    
1006
                    } else {
1007
                        if ((this.firstSegmentData.getPosition().equals(SEGMENT_POSITION_FIRST) || this.firstSegmentData.getPosition().equals(SEGMENT_POSITION_LAST))
1008
                                && (segmentData.getPosition().equals(SEGMENT_POSITION_FIRST) || segmentData.getPosition().equals(SEGMENT_POSITION_LAST))) {
1009
                            Point tmpPointToChamfer = calculatePointToChamfer(firstSegmentData, segmentData);
1010
                            if (tmpPointToChamfer == null
1011
                                    || calculateZoneInSegment(tmpPointToChamfer, segmentData) == INVALID_ZONE
1012
                                    || calculateZoneInSegment(tmpPointToChamfer, firstSegmentData) == INVALID_ZONE) {
1013
                                return ERR_CANT_CALCULATE_CHAMFER_POINT;
1014
                            }
1015
                            if (!isPointBetweenTwoPoints(segmentData.getProjectedPoint(), oppositeVertex, tmpPointToChamfer)) {
1016
                                return ERR_CANT_CALCULATE_CHAMFER_POINT;
1017
                            }
1018
                            return validateSegmentsAndLength(firstSegmentData, segmentData, calculatePointToChamfer(firstSegmentData, segmentData));
1019
                        }
1020
                    }
1021
                    return ERR_NON_ADJACENT_SEGMENTS;
1022

    
1023
                case Geometry.TYPES.POLYGON:
1024
                    if (this.firstSegmentData.getPosition().equals(SEGMENT_POSITION_FIRST) && segmentData.getPosition().equals(SEGMENT_POSITION_LAST)
1025
                            || this.firstSegmentData.getPosition().equals(SEGMENT_POSITION_LAST) && segmentData.getPosition().equals(SEGMENT_POSITION_FIRST)) {
1026
                        return validateSegmentsAndLength(firstSegmentData, segmentData, calculatePointToChamfer(firstSegmentData, segmentData));
1027
                    }
1028
                    return ERR_NON_ADJACENT_SEGMENTS;
1029
                default:
1030
                    return ERR_NON_ADJACENT_SEGMENTS;
1031
            }
1032
        } else {
1033
            if (firstPrimitive.getType() != Geometry.TYPES.LINE
1034
                    || secondPrimitive.getType() != Geometry.TYPES.LINE) {
1035
                return ERR_DIFFERENT_GEOMETRY_TYPES;
1036
            }
1037
            if (this.firstSegmentData.getPosition().equals(SEGMENT_POSITION_MIDDLE)
1038
                    || segmentData.getPosition().equals(SEGMENT_POSITION_MIDDLE)) {
1039
                return ERR_ONE_OF_THE_TWO_SEGMENTS_ISNT_EXTREME;
1040
            }
1041
            Point tmpPointToChamfer = calculatePointToChamfer(firstSegmentData, segmentData);
1042
            if (tmpPointToChamfer == null || !isPointBetweenTwoPoints(segmentData.getProjectedPoint(), oppositeVertex, tmpPointToChamfer)) {
1043
                return ERR_CANT_CALCULATE_CHAMFER_POINT;
1044
            }
1045
            return validateSegmentsAndLength(firstSegmentData, segmentData, tmpPointToChamfer);
1046
        }
1047
    }
1048
    
1049
    private int validateSegmentsAndLength(SegmentData firstSegmentData, SegmentData secondSegmentData, Point pointToChamfer) throws GeometryOperationNotSupportedException, GeometryOperationException {
1050
        Pair<Point, Point> oppositeVertices = calculateOpositeToChamferVertices(firstSegmentData, secondSegmentData);
1051
        Double length = (Double) getValue(lengthParameter);
1052
        double maxLength = Math.max(
1053
                oppositeVertices.getLeft().distance(pointToChamfer),
1054
                Math.max(
1055
                        oppositeVertices.getRight().distance(pointToChamfer),
1056
                        oppositeVertices.getRight().distance(oppositeVertices.getLeft())
1057
                )
1058
        );
1059
        if (length > maxLength) {
1060
            return ERR_CHAMFER_TOO_LARGE;
1061
        }
1062
        return ERR_OK;
1063
    }
1064

    
1065
    private Point calculatePointToChamfer(SegmentData firstSegmentData, SegmentData secondSegmentData) throws GeometryOperationNotSupportedException, GeometryOperationException {
1066
        Primitive firstPrimitive = firstSegmentData.getPrimitive();
1067
        Primitive secondPrimitive = secondSegmentData.getPrimitive();
1068
        if (Objects.equals(firstPrimitive, secondPrimitive)) {
1069
            if (Objects.equals(firstSegmentData.getIdxVertex(), secondSegmentData.getIdxVertex())) {
1070
                return null;
1071
            }
1072
            switch (firstPrimitive.getType()) {
1073
                case Geometry.TYPES.LINE:
1074
                    if (((Line) firstPrimitive).isClosed()) {
1075
                        if (Objects.equals(firstSegmentData.getIdxVertex(), secondSegmentData.getIdxVertex() - 1)) {
1076
                            return firstSegmentData.getLine().getVertex(1);
1077
                        } else if (Objects.equals(firstSegmentData.getIdxVertex(), secondSegmentData.getIdxVertex() + 1)) {
1078
                            return firstSegmentData.getLine().getVertex(0);
1079
                        } else if (firstSegmentData.getPosition().equals(SEGMENT_POSITION_FIRST) && secondSegmentData.getPosition().equals(SEGMENT_POSITION_LAST)) {
1080
                            return firstSegmentData.getLine().getVertex(0);
1081
                        } else if (firstSegmentData.getPosition().equals(SEGMENT_POSITION_LAST) && secondSegmentData.getPosition().equals(SEGMENT_POSITION_FIRST)) {
1082
                            return firstSegmentData.getLine().getVertex(1);
1083
                        } else {
1084
                            return null;
1085
                        }
1086
                    } else {
1087
                        if (Objects.equals(firstSegmentData.getIdxVertex(), secondSegmentData.getIdxVertex() - 1)) {
1088
                            return firstSegmentData.getLine().getVertex(1);
1089
                        } else if (Objects.equals(firstSegmentData.getIdxVertex(), secondSegmentData.getIdxVertex() + 1)) {
1090
                            return firstSegmentData.getLine().getVertex(0);
1091
                        } else if (firstSegmentData.getPosition().equals(SEGMENT_POSITION_FIRST) && secondSegmentData.getPosition().equals(SEGMENT_POSITION_LAST)
1092
                                || firstSegmentData.getPosition().equals(SEGMENT_POSITION_LAST) && secondSegmentData.getPosition().equals(SEGMENT_POSITION_FIRST)) {
1093
                            return calculatePointToChamferSeparateSegments(firstSegmentData, secondSegmentData);
1094
                        } else {
1095
                            return null;
1096
                        }
1097
                    }
1098
                case Geometry.TYPES.POLYGON:
1099
                    if (Objects.equals(firstSegmentData.getIdxVertex(), secondSegmentData.getIdxVertex() - 1)) {
1100
                        return firstSegmentData.getLine().getVertex(1);
1101
                    } else if (Objects.equals(firstSegmentData.getIdxVertex(), secondSegmentData.getIdxVertex() + 1)) {
1102
                        return firstSegmentData.getLine().getVertex(0);
1103
                    } else if (firstSegmentData.getPosition().equals(SEGMENT_POSITION_FIRST) && secondSegmentData.getPosition().equals(SEGMENT_POSITION_LAST)) {
1104
                        return firstSegmentData.getLine().getVertex(0);
1105
                    } else if (firstSegmentData.getPosition().equals(SEGMENT_POSITION_LAST) && secondSegmentData.getPosition().equals(SEGMENT_POSITION_FIRST)) {
1106
                        return firstSegmentData.getLine().getVertex(1);
1107
                    } else {
1108
                        return null;
1109
                    }
1110
                default:
1111
                    return null;
1112
            }
1113
        } else {
1114
            if (firstPrimitive.getType() != Geometry.TYPES.LINE) {
1115
                return null;
1116
            }
1117
            if (secondPrimitive.getType() != Geometry.TYPES.LINE) {
1118
                return null;
1119
            }
1120

    
1121
            if ((firstSegmentData.getPosition().equals(SEGMENT_POSITION_FIRST) || firstSegmentData.getPosition().equals(SEGMENT_POSITION_LAST))
1122
                    && (secondSegmentData.getPosition().equals(SEGMENT_POSITION_FIRST) || secondSegmentData.getPosition().equals(SEGMENT_POSITION_LAST))) {
1123
                return calculatePointToChamferSeparateSegments(firstSegmentData, secondSegmentData);
1124
            } else {
1125
                return null;
1126
            }
1127
        }
1128
    }
1129

    
1130
    private Point calculatePointToChamferSeparateSegments(SegmentData firstSegmentData, SegmentData secondSegmentData) throws GeometryOperationNotSupportedException, GeometryOperationException {
1131
        EuclideanManager euclideanManager = ToolsUtilLocator.getEuclideanManager();
1132
        EuclideanLine2D firstLine = euclideanManager.createLine2D(
1133
                firstSegmentData.getLine().getVertex(0).getX(),
1134
                firstSegmentData.getLine().getVertex(0).getY(),
1135
                firstSegmentData.getLine().getVertex(1).getX(),
1136
                firstSegmentData.getLine().getVertex(1).getY());
1137
        EuclideanLine2D secondLine = euclideanManager.createLine2D(
1138
                secondSegmentData.getLine().getVertex(0).getX(),
1139
                secondSegmentData.getLine().getVertex(0).getY(),
1140
                secondSegmentData.getLine().getVertex(1).getX(),
1141
                secondSegmentData.getLine().getVertex(1).getY());
1142
        Point2D intersection = firstLine.getIntersection(secondLine);
1143
        Point intersectionPoint = GeometryUtils.createPoint(intersection.getX(), intersection.getY());
1144
        if (intersectionPoint == null) {
1145
            return null; //throw new IllegalArgumentException("Not valid segments.");
1146
        }
1147
        if (firstSegmentData.getPosition().equals(SEGMENT_POSITION_LAST)
1148
                && calculateZoneInSegment(intersectionPoint, firstSegmentData) == INVALID_ZONE) {
1149
            return null;
1150
        }
1151
        if (firstSegmentData.getPosition().equals(SEGMENT_POSITION_FIRST)
1152
                && calculateZoneInSegment(intersectionPoint, firstSegmentData) == INVALID_ZONE) {
1153
            return null;
1154
        }
1155
        if (secondSegmentData.getPosition().equals(SEGMENT_POSITION_LAST)
1156
                && calculateZoneInSegment(intersectionPoint, firstSegmentData) == INVALID_ZONE) {
1157
            return null;
1158
        }
1159
        if (secondSegmentData.getPosition().equals(SEGMENT_POSITION_FIRST)
1160
                && calculateZoneInSegment(intersectionPoint, firstSegmentData) == INVALID_ZONE) {
1161
            return null;
1162
        }
1163
        return intersectionPoint;
1164
    }
1165

    
1166
    private int calculateZoneInSegment(Point point, SegmentData segmentData) throws GeometryOperationNotSupportedException, GeometryOperationException {
1167
        //We assume that the point is on the line to which the segment belongs.
1168
        Line line = segmentData.getLine();
1169
        if (line.getNumVertices() > 2) {
1170
            throw new IllegalArgumentException("Segment has more than two vertex.");
1171
        }
1172

    
1173
        Point firstVertex;
1174
        Point secondVertex;
1175

    
1176
        if (Objects.equals(segmentData.getPosition(), SEGMENT_POSITION_LAST)) {
1177
            firstVertex = line.getVertex(0);
1178
            secondVertex = line.getVertex(1);
1179
        } else { // SEGMENT_POSITION_FIRST,  SEGMENT_POSITION_MIDDLE doesn't matter
1180
            firstVertex = line.getVertex(1);
1181
            secondVertex = line.getVertex(0);
1182
        }
1183

    
1184
        double segmentLenght = firstVertex.distance(secondVertex);
1185
        if (segmentLenght >= firstVertex.distance(point) && segmentLenght >= secondVertex.distance(point)) {
1186
            return INSIDE_THE_SEGMENT; //0
1187
        } else if (firstVertex.distance(point) > secondVertex.distance(point)) {
1188
            return BEYOND_THE_SEGMENT; //1
1189
        } else {
1190
            return INVALID_ZONE; //-1
1191
        }
1192
    }
1193

    
1194
    private boolean isPointBetweenTwoPoints(Point point, Point vertex1, Point vertex2) {
1195
        //The three points must be aligned
1196
        if (point.getX() < vertex1.getX() && point.getX() < vertex2.getX()) {
1197
            return false;
1198
        }
1199
        if (point.getX() > vertex1.getX() && point.getX() > vertex2.getX()) {
1200
            return false;
1201
        }
1202
        if (point.getY() < vertex1.getY() && point.getY() < vertex2.getY()) {
1203
            return false;
1204
        }
1205
        if (point.getY() > vertex1.getY() && point.getY() > vertex2.getY()) {
1206
            return false;
1207
        }
1208
        return true;
1209
    }
1210

    
1211
    private double calculateDefaultAngle(Point pointToChamfer, Pair<Point, Point> oppositeVertices) throws GeometryOperationNotSupportedException, GeometryOperationException, CreateGeometryException {
1212
        
1213
        EuclideanManager euclideanManager = ToolsUtilLocator.getEuclideanManager();
1214
        Point2D p = euclideanManager.getPointAtDistance(
1215
                pointToChamfer.getX(),
1216
                pointToChamfer.getY(),
1217
                pointToChamfer.distance(oppositeVertices.getLeft()),
1218
                GeometryUtils.calculateAngle(pointToChamfer, oppositeVertices.getRight()), 
1219
                null
1220
        );
1221
        
1222
        Point midPoint = GeometryUtils.getMidPoint(
1223
                oppositeVertices.getLeft(),
1224
                GeometryUtils.createPoint(p.getX(), p.getY()), 
1225
                pointToChamfer.getGeometryType().getSubType()
1226
        );
1227
        double angle = GeometryUtils.calculateAngle(
1228
                pointToChamfer,
1229
                midPoint
1230
        );
1231
        angle = angle + Math.PI/2;
1232
        if(angle > 2*Math.PI){
1233
            angle = angle - 2*Math.PI;
1234
        }
1235
        return Math.toDegrees(angle);
1236
    }
1237

    
1238
    private Line calculateChamfer(SegmentData firstSegmentData, SegmentData secondSegmentData, Double length, Double angle, int subType) throws GeometryOperationNotSupportedException, GeometryOperationException, CreateGeometryException {
1239

    
1240
        ScaffoldingToChamfer scaffolding = calculateScaffolding(firstSegmentData, secondSegmentData, pointToChamfer, length, angle, subType);
1241
        if(scaffolding == null){
1242
            return null;
1243
        }
1244
        Line chamfer;
1245
        if(scaffolding.isReversed()) {
1246
            chamfer = GeometryUtils.createLine(
1247
                    scaffolding.chamferRight.getX(),
1248
                    scaffolding.chamferRight.getY(),
1249
                    scaffolding.chamferLeft.getX(),
1250
                    scaffolding.chamferLeft.getY(),
1251
                    subType
1252
            );
1253
        } else {
1254
            chamfer = GeometryUtils.createLine(
1255
                    scaffolding.chamferLeft.getX(),
1256
                    scaffolding.chamferLeft.getY(),
1257
                    scaffolding.chamferRight.getX(),
1258
                    scaffolding.chamferRight.getY(), 
1259
                    subType
1260
            );
1261
        }
1262
        
1263
        return chamfer;
1264
    }
1265
    
1266
    /**
1267
     * 
1268
     * @param firstSegmentData
1269
     * @param secondSegmentData
1270
     * @param pointToChamfer
1271
     * @param distance
1272
     * @param angle must be in radians
1273
     * @param subType
1274
     * @return 
1275
     */
1276
    private ScaffoldingToChamfer calculateScaffolding(SegmentData firstSegmentData, SegmentData secondSegmentData, Point pointToChamfer, Double length, Double angle, int subType) throws GeometryOperationNotSupportedException, GeometryOperationException, CreateGeometryException {
1277

    
1278
        Pair<Point, Point> oppositeVertices = calculateOpositeToChamferVertices(firstSegmentData, secondSegmentData);
1279
        Point p1 = GeometryUtils.createPoint(pointToChamfer, length, angle);
1280
        EuclideanManager euclideanManager = ToolsUtilLocator.getEuclideanManager();
1281
        
1282
        boolean reverse = false;
1283

    
1284
        EuclideanLine2D base = euclideanManager.createLine2D(
1285
                pointToChamfer.getX(),
1286
                pointToChamfer.getY(),
1287
                p1.getX(),
1288
                p1.getY()
1289
        );
1290

    
1291
        Point o1 = oppositeVertices.getLeft();
1292
        Point o2 = oppositeVertices.getRight();
1293

    
1294
        EuclideanLine2D left = euclideanManager.createLine2D(
1295
                pointToChamfer.getX(),
1296
                pointToChamfer.getY(),
1297
                o1.getX(),
1298
                o1.getY()
1299
        );
1300
        EuclideanLine2D leftParallel = left.getParallel(p1.getX(), p1.getY());
1301

    
1302
        EuclideanLine2D right = euclideanManager.createLine2D(
1303
                pointToChamfer.getX(),
1304
                pointToChamfer.getY(),
1305
                o2.getX(),
1306
                o2.getY()
1307
        );
1308

    
1309
        Point2D chamferRight = leftParallel.getIntersection(right);
1310

    
1311
        if (!isPointBetweenTwoPoints(
1312
                GeometryUtils.createPoint(chamferRight.getX(), chamferRight.getY()),
1313
                o2,
1314
                pointToChamfer)) { //Le damos la vuelta a los vertices opuestos y volvemos probar
1315
            reverse = true;
1316
            o1 = oppositeVertices.getRight();
1317
            o2 = oppositeVertices.getLeft();
1318

    
1319
            left = euclideanManager.createLine2D(
1320
                    pointToChamfer.getX(),
1321
                    pointToChamfer.getY(),
1322
                    o1.getX(),
1323
                    o1.getY()
1324
            );
1325
            leftParallel = left.getParallel(p1.getX(), p1.getY());
1326

    
1327
            right = euclideanManager.createLine2D(
1328
                    pointToChamfer.getX(),
1329
                    pointToChamfer.getY(),
1330
                    o2.getX(),
1331
                    o2.getY()
1332
            );
1333

    
1334
            chamferRight = leftParallel.getIntersection(right);
1335

    
1336
            if (!isPointBetweenTwoPoints(
1337
                    GeometryUtils.createPoint(chamferRight.getX(), chamferRight.getY()),
1338
                    o2,
1339
                    pointToChamfer)) {
1340
                return null;
1341
            }
1342
        }
1343

    
1344
        
1345
        EuclideanLine2D baseParallel = base.getParallel(chamferRight);
1346
        
1347
        Point2D chamferLeft = baseParallel.getIntersection(left);
1348

    
1349
        if (!isPointBetweenTwoPoints(
1350
                GeometryUtils.createPoint(chamferLeft.getX(), chamferLeft.getY()), 
1351
                o1, 
1352
                pointToChamfer)
1353
        ) {
1354
            return null;
1355
        }
1356
        
1357
        ScaffoldingToChamfer scaffolding;
1358
        scaffolding = new ScaffoldingToChamfer(chamferLeft, chamferRight, p1, reverse);
1359
        
1360
        return scaffolding;
1361
    }
1362

    
1363
    private class ScaffoldingToChamfer {
1364

    
1365
        private final Point2D chamferLeft;
1366
        private final Point2D chamferRight;
1367
        private final Point p1;
1368
        private final boolean reverse;
1369

    
1370
        public ScaffoldingToChamfer(Point2D chamferLeft, Point2D chamferRight, Point p1, boolean reverse) {
1371
            this.chamferLeft = chamferLeft;
1372
            this.chamferRight = chamferRight;
1373
            this.p1 = p1;
1374
            this.reverse = reverse;
1375
        }
1376

    
1377

    
1378
        public Point2D getChamferRight() {
1379
            return chamferRight;
1380
        }
1381

    
1382
        public Point2D getChamferLeft() {
1383
            return chamferLeft;
1384
        }
1385

    
1386
        public Point getP1() {
1387
            return p1;
1388
        }
1389
        
1390
        public boolean isReversed() {
1391
            return reverse;
1392
        }
1393
        
1394
        
1395
    }
1396
}