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.polyline / src / main / java / org / gvsig / vectorediting / lib / prov / polyline / PolylineEditingProvider.java @ 2616

History | View | Annotate | Download (21.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

    
25
package org.gvsig.vectorediting.lib.prov.polyline;
26

    
27
import java.util.ArrayList;
28
import java.util.LinkedHashMap;
29
import java.util.List;
30
import java.util.Map;
31
import org.gvsig.euclidean.EuclideanManager;
32
import org.gvsig.fmap.dal.exception.DataException;
33
import org.gvsig.fmap.dal.feature.FeatureStore;
34
import org.gvsig.fmap.geom.Geometry;
35
import org.gvsig.fmap.geom.GeometryLocator;
36
import org.gvsig.fmap.geom.GeometryManager;
37
import org.gvsig.fmap.geom.GeometryUtils;
38
import org.gvsig.fmap.geom.aggregate.MultiCurve;
39
import org.gvsig.fmap.geom.aggregate.MultiLine;
40
import org.gvsig.fmap.geom.exception.CreateGeometryException;
41
import org.gvsig.fmap.geom.primitive.Arc;
42
import org.gvsig.fmap.geom.primitive.Curve;
43
import org.gvsig.fmap.geom.primitive.Line;
44
import org.gvsig.fmap.geom.primitive.OrientablePrimitive;
45
import org.gvsig.fmap.geom.primitive.Point;
46
import org.gvsig.fmap.geom.primitive.Surface;
47
import org.gvsig.fmap.geom.type.GeometryType;
48
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
49
import org.gvsig.tools.ToolsLocator;
50
import org.gvsig.tools.dynobject.DynObject;
51
import org.gvsig.tools.exception.BaseException;
52
import org.gvsig.tools.i18n.I18nManager;
53
import org.gvsig.tools.service.spi.ProviderServices;
54
import org.gvsig.tools.util.ToolsUtilLocator;
55
import org.gvsig.vectorediting.lib.api.DrawingStatus;
56
import org.gvsig.vectorediting.lib.api.EditingServiceParameter;
57
import org.gvsig.vectorediting.lib.api.EditingServiceParameter.TYPE;
58
import org.gvsig.vectorediting.lib.api.exceptions.DrawServiceException;
59
import org.gvsig.vectorediting.lib.api.exceptions.FinishServiceException;
60
import org.gvsig.vectorediting.lib.api.exceptions.InvalidEntryException;
61
import org.gvsig.vectorediting.lib.api.exceptions.StartServiceException;
62
import org.gvsig.vectorediting.lib.api.exceptions.VectorEditingException;
63
import org.gvsig.vectorediting.lib.spi.AbstractEditingProvider;
64
import org.gvsig.vectorediting.lib.spi.DefaultDrawingStatus;
65
import org.gvsig.vectorediting.lib.spi.DefaultEditingServiceParameter;
66
import org.gvsig.vectorediting.lib.spi.EditingProvider;
67
import org.gvsig.vectorediting.lib.spi.EditingProviderFactory;
68
import org.gvsig.vectorediting.lib.spi.EditingProviderLocator;
69
import org.gvsig.vectorediting.lib.spi.EditingProviderManager;
70
import org.gvsig.vectorediting.lib.spi.EditingProviderServices;
71
import org.slf4j.Logger;
72
import org.slf4j.LoggerFactory;
73

    
74
public class PolylineEditingProvider extends AbstractEditingProvider implements EditingProvider {
75

    
76
    private static final Logger LOGGER = LoggerFactory.getLogger(PolylineEditingProvider.class);
77

    
78
    protected EditingProviderServices editingProviderServices = (EditingProviderServices) getProviderServices();
79

    
80
    protected EditingServiceParameter points;
81

    
82
    protected Map<String, String> options;
83

    
84
    private boolean arcMode;
85

    
86
    private boolean finishPolyline;
87

    
88
    private boolean closeGeometry;
89

    
90
    private List<MyPolyLinePoint> values;
91

    
92
    protected FeatureStore featureStore;
93
    
94
    public PolylineEditingProvider(ProviderServices providerServices, DynObject parameters) {
95
        super(providerServices);
96

    
97
        // Initialize all provider variables.
98
        this.featureStore = (FeatureStore) parameters.getDynValue(EditingProviderFactory.FEATURE_STORE_FIELD);
99

    
100
        I18nManager i18nManager = ToolsLocator.getI18nManager();
101

    
102
        options = new LinkedHashMap<>();
103
        options.put(i18nManager.getTranslation("key_arc_mode"), "arc_mode");
104
        options.put(i18nManager.getTranslation("key_line_mode"), "line_mode");
105
        options.put(i18nManager.getTranslation("key_close"), "close_polyline");
106
        options.put(i18nManager.getTranslation("key_finish"), "finish");
107
        options.put(i18nManager.getTranslation("key_remove_last_point"), "remove_last_point");
108

    
109
        String consoleMsg = editingProviderServices.makeConsoleMessage("indicate_new_point", options);
110

    
111
        points =
112
            new DefaultEditingServiceParameter("insert_point", consoleMsg, options, TYPE.LIST_POSITIONS, TYPE.OPTION);
113

    
114
        arcMode = false;
115
        finishPolyline = false;
116
        closeGeometry = false;
117
    }
118

    
119
    /**
120
     * Calculates polyline with stored values and last position received as
121
     * parameter.If last position is null calculates only with stored values.
122
     *
123
     * @param lastPosition
124
     *            of polyline.
125
     * @return A drawing status value with a list of geometries. See
126
     *         {@link DrawingStatus#getGeometries()}.
127
     * @throws org.gvsig.vectorediting.lib.api.exceptions.VectorEditingException
128
     * @throws org.gvsig.fmap.geom.exception.CreateGeometryException
129
     * @throws org.gvsig.fmap.dal.exception.DataException
130
     */
131
    protected Line calculatePolyline(Point lastPosition) throws VectorEditingException, CreateGeometryException, DataException {
132
        DefaultDrawingStatus drawingStatus = new DefaultDrawingStatus();
133
        return calculatePolyline(lastPosition, drawingStatus);
134
        
135
    }
136
    protected Line calculatePolyline(Point lastPosition, DefaultDrawingStatus drawingStatus) throws VectorEditingException, CreateGeometryException, DataException {
137
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
138
        GeometryType storeGeomType = editingProviderServices.getGeomType(featureStore);
139
        Line line = geomManager.createLine(storeGeomType.getSubType());
140
        Line previewLine = geomManager.createLine(storeGeomType.getSubType());
141
        
142
        EuclideanManager euclideanManager = ToolsUtilLocator.getEuclideanManager();
143
        EditingProviderManager editingProviderManager = EditingProviderLocator.getProviderManager();
144

    
145
        ISymbol previewSymbol = this.getPreviewSymbol();
146
//        drawingStatus.setPreviewSymbol(previewSymbol);
147
        ISymbol lineSymbolEditing = editingProviderManager.getSymbol("line-symbol-editing");
148
        ISymbol auxiliaryLineSymbolEditing = editingProviderManager.getSymbol("auxiliary-line-symbol-editing");
149
        ISymbol auxiliaryPointSymbolEditing = editingProviderManager.getSymbol("auxiliary-point-symbol-editing");
150

    
151
        Point antPoint = null;
152
        Double antm = null;
153
        Double antb = null;
154
        Double m = null;
155
        Double b = null;
156
        Point center = null;
157
        double radius = 0.0;
158
        double startAngle = 0.0;
159
        double endAngle = 0.0;
160
        double angleExt = 0.0;
161
        double sweepAngle = 0.0;
162
        boolean right = false;
163
        boolean addGeom = false;
164

    
165
        Curve lineAntPointToPoint = null;
166
        Point point = null;
167
        Point nextPoint = null;
168
        
169
        if (values.size() > 0) {
170
            for (int i = 0; i < values.size(); i++) {
171

    
172
                MyPolyLinePoint polyLinePoint = values.get(i);
173
                MyPolyLinePoint polyLineNextPoint = getNextPoint(i);
174
                point = polyLinePoint.getPoint();
175
                previewLine.addVertex(point);
176
                line.addVertex(point);
177

    
178
                if (polyLineNextPoint == null) {
179
                    nextPoint = lastPosition;
180
                    addGeom = true;
181
                } else {
182
                    nextPoint = polyLineNextPoint.getPoint();
183
                }
184

    
185
                if (nextPoint == null) {
186
                    drawingStatus.addStatus(previewLine, lineSymbolEditing, "");
187
                    drawingStatus.addStatus(previewLine, previewSymbol, "");
188
                    if(line.getNumVertices()>1){
189
                        return line;
190
                    } else {
191
                        return null;
192
                    }
193
                }
194
                
195

    
196
                try {
197
                    if (polyLinePoint.isArcMode()) {
198
                        int subtype = editingProviderServices.getSubType(featureStore);
199

    
200
                        lineAntPointToPoint = GeometryUtils.createLine(point, nextPoint, subtype);
201

    
202
                        Double[] lineParams = editingProviderServices.getLineParams(point, nextPoint);
203
                        m = lineParams[0];
204
                        b = lineParams[1];
205
                        Point[] pointPerpendicular =
206
                            editingProviderServices.getPerpendicular(antm, antb, point, subtype);
207
                        Line linePointPerpendicular = geomManager.createLine(subtype);
208
                        linePointPerpendicular.setPoints(pointPerpendicular[0], pointPerpendicular[1]);
209

    
210
                        Point midPoint = editingProviderServices.getMidPoint(point, nextPoint, subtype);
211
                        Point[] bisector = editingProviderServices.getPerpendicular(m, b, midPoint, subtype);
212
                        Line lineBisector = geomManager.createLine(subtype);
213
                        lineBisector.setPoints(bisector[0], bisector[1]);
214

    
215
                        center = editingProviderServices.getIntersection(bisector, pointPerpendicular, subtype);
216

    
217
                        double coefDirection = 1.0;
218
                        if(antPoint != null){
219
                            coefDirection = GeometryUtils.getCoefDirection(antPoint, point, nextPoint);
220
                        }
221

    
222
                        if (center != null) {
223
                            startAngle = GeometryUtils.calculateAngle(center, point);
224

    
225
                            radius = center.distance(point);
226

    
227
                            //calculate sweepAngle
228
                            sweepAngle = GeometryUtils.calculateAngle(center, point, nextPoint);
229

    
230
                            if (coefDirection < 0) {
231
                                sweepAngle = -(2 * Math.PI - sweepAngle);
232
                            }
233

    
234
                            if (Math.signum(coefDirection) != Math.signum(sweepAngle)) {
235
                                sweepAngle = -(2 * Math.PI - sweepAngle);
236
                            }
237

    
238

    
239
                        } else {
240
                            String msg
241
                                    =
242
                                String.format("Can't get intersection between bisector" + " [(%1$s,%2$s),(%3$s,%4$s)]"
243
                                    + " and perperdicular" + " [(%5$s,%6$s),(%7$s,%8$s)]", bisector[0].getX(),
244
                                    bisector[0].getY(), bisector[1].getX(), bisector[1].getY(),
245
                                    pointPerpendicular[0].getX(), pointPerpendicular[0].getY(),
246
                                    pointPerpendicular[1].getX(), pointPerpendicular[1].getY());
247

    
248
                            throw new DrawServiceException(msg, null);
249
                        }
250

    
251
                        Arc arco = GeometryUtils.createArc(
252
                                center,
253
                                radius,
254
                                startAngle,
255
                                sweepAngle,
256
                                GEOM2D);
257
                        antPoint = GeometryUtils.createPoint(center, radius, startAngle+sweepAngle-(sweepAngle/1000));
258

    
259
                        antm = -(nextPoint.getX() - center.getX()) / (nextPoint.getY() - center.getY());
260
                        if (antm == Double.POSITIVE_INFINITY) {
261
                            antb = Double.NEGATIVE_INFINITY;
262
                            if (nextPoint.getX() == 0) {
263
                                antb = 0.0;
264
                            }
265
                        } else if (antm == Double.NEGATIVE_INFINITY) {
266
                            antb = Double.POSITIVE_INFINITY;
267
                            if (nextPoint.getX() == 0) {
268
                                antb = 0.0;
269
                            }
270
                        } else {
271
                            antb = nextPoint.getY() - (antm * nextPoint.getX());
272
                        }
273

    
274
                        // Draw geometries.
275
                        if (addGeom) {
276
                            drawingStatus.addStatus(point, auxiliaryPointSymbolEditing, "");
277
                            drawingStatus.addStatus(nextPoint, auxiliaryPointSymbolEditing, "");
278
                            drawingStatus.addStatus(center, auxiliaryPointSymbolEditing, "");
279
                            drawingStatus.addStatus(lineAntPointToPoint, auxiliaryLineSymbolEditing, "");
280
                        }
281
                        
282
                        Point vertexAnt = null;
283
                        MultiLine multiline = arco.toLines();
284
                        for (int n = 0; n < multiline.getPrimitivesNumber(); n++) {
285
                            Line arcLine = (Line) multiline.getPrimitiveAt(n);
286
                            if (arcLine.getNumVertices() > 0 && vertexAnt != null && arcLine.getVertex(0) != vertexAnt) {
287
                                arcLine.flip();
288
                            }
289
                            for (int j = 0; j < arcLine.getNumVertices()-1; j++) {
290
                                if ((vertexAnt == null) || !vertexAnt.equals(arcLine.getVertex(j))) {
291
                                    line.addVertex(arcLine.getVertex(j));
292
                                    previewLine.addVertex(arcLine.getVertex(j));
293
                                    vertexAnt = arcLine.getVertex(j);
294
                                }
295
                            }
296
                            nextPoint = arcLine.getVertex(arcLine.getNumVertices()-1);
297
                        }
298
                    } else {
299
                        int subtype = editingProviderServices.getSubType(featureStore);
300

    
301
                        if (addGeom) {
302
                            drawingStatus.addStatus(point, auxiliaryPointSymbolEditing, "");
303
                            drawingStatus.addStatus(nextPoint, auxiliaryPointSymbolEditing, "");
304
                        }
305

    
306
                        antPoint = point;
307
                        //FIXME: Esto es para el c?lculo del posible arco posterior.
308
                        Double[] antLineParams = editingProviderServices.getLineParams(point, nextPoint);
309
                        antm = antLineParams[0];
310
                        antb = antLineParams[1];
311
                        right = (nextPoint.getX() >= point.getX());
312
                    }
313
                } catch (Exception e) {
314
                    throw new DrawServiceException(e);
315
                }
316
            }
317
            if(nextPoint != null) {
318
                line.addVertex(nextPoint);
319
                previewLine.addVertex(nextPoint);
320
                nextPoint = null;
321
            }
322

    
323
            drawingStatus.addStatus(previewLine, lineSymbolEditing, "");
324
            drawingStatus.addStatus(previewLine, previewSymbol, "");
325
            if(line.getNumVertices()>1){
326
                return line;
327
            } else {
328
                return null;
329
            }
330
        }
331
        return null;
332
    }
333
    
334
    
335
    protected Geometry closeGeometryIfNecessary(Geometry geometry) {
336
        if (!isClose(geometry) && (geometry != null)) {
337

    
338
            if (geometry instanceof Surface) {
339
                Surface surface = (Surface) geometry;
340
                Point firstp = surface.getVertex(0);
341
                firstp = (Point) firstp.cloneGeometry();
342
                surface.addVertex(firstp);
343
                return surface;
344
            } else if (geometry instanceof Curve) {
345
                Curve line = (Curve) geometry;
346
                Point firstp = line.getVertex(0);
347
                firstp = (Point) firstp.cloneGeometry();
348
                line.addVertex(firstp);
349
                return line;
350
            }
351
        }
352
        return geometry;
353
    }
354

    
355
    @Override
356
    public DrawingStatus getDrawingStatus(Point mousePosition) throws DrawServiceException {
357

    
358
        try {
359
            DefaultDrawingStatus drawingStatus = new DefaultDrawingStatus();
360
            Geometry geom = calculatePolyline(mousePosition, drawingStatus);
361
            return drawingStatus;
362

    
363
        } catch (Exception e) {
364
            throw new DrawServiceException(e);
365
        }
366
    }
367

    
368
    @Override
369
    public void finishAndStore() throws FinishServiceException {
370
        try {
371
            Geometry geometry = finish();
372
            if (geometry != null) {
373
                editingProviderServices.insertGeometryIntoFeatureStore(geometry, featureStore);
374
            }
375
        } catch (Exception e) {
376
            throw new FinishServiceException(e);
377
        }
378
    }
379

    
380
    @Override
381
    public Geometry finish() throws FinishServiceException {
382
        try {
383
            GeometryManager geomManager = GeometryLocator.getGeometryManager();
384
            GeometryType storeGeomType = editingProviderServices.getGeomType(featureStore);
385
            
386
            Line line = calculatePolyline(null);
387
            if(line == null){
388
                return null;
389
            }
390

    
391
            if (closeGeometry) {
392
                line = (Line) closeGeometryIfNecessary(line);
393
            }
394

    
395
            if (storeGeomType.isTypeOf(MULTICURVE)) {
396
                MultiCurve multiCurve = geomManager.createMultiCurve(storeGeomType.getSubType());
397
                multiCurve.addCurve(line);
398
                return multiCurve;
399
            } else {
400
                return line;
401
            }
402

    
403
        } catch (BaseException e) {
404
            throw new FinishServiceException(e);
405
        }
406
    }
407

    
408
    @Override
409
    public String getName() {
410
        return PolylineEditingProviderFactory.PROVIDER_NAME;
411
    }
412

    
413
    private MyPolyLinePoint getNextPoint(int i) {
414
        if (!values.isEmpty() && (i < (values.size() - 1))) {
415
            return values.get(i + 1);
416
        }
417
        return null;
418
    }
419

    
420
    private MyPolyLinePoint getPreviousPoint(int i) {
421
        if (!values.isEmpty() && (i > 0)) {
422
            return values.get(i - 1);
423
        }
424
        return null;
425
    }
426

    
427
    @Override
428
    public List<EditingServiceParameter> getParameters() {
429
        List<EditingServiceParameter> list = new ArrayList<>();
430
        list.add(points);
431
        return list;
432
    }
433

    
434
    private boolean isClose(Geometry geometry) {
435

    
436
        if (geometry != null) {
437

    
438
            if (geometry instanceof OrientablePrimitive) {
439
                OrientablePrimitive orientablePrimitive = (OrientablePrimitive) geometry;
440
                Point firstPoint = orientablePrimitive.getVertex(0);
441
                Point lastPoint = orientablePrimitive.getVertex(orientablePrimitive.getNumVertices() - 1);
442
                if (firstPoint.equals(lastPoint)) {
443
                    return true;
444
                }
445
            }
446
        }
447
        return false;
448
    }
449

    
450
    @Override
451
    public EditingServiceParameter next() {
452
        if (finishPolyline) {
453
            return null;
454
        } else {
455
            return points;
456
        }
457

    
458
    }
459

    
460
    @Override
461
    public void start() throws StartServiceException {
462
        // Stop service;
463
        stop();
464

    
465
        values = new ArrayList<>();
466
    }
467

    
468
    @Override
469
    public void stop() {
470
        if (values != null) {
471
            values.clear();
472
        }
473
        arcMode = false;
474
        finishPolyline = false;
475
        closeGeometry = false;
476
    }
477

    
478
    private void validateAndInsertValue(EditingServiceParameter param, Object value) throws InvalidEntryException {
479
        if (value instanceof String) {
480
            String option = (String) value;
481
            I18nManager i18nManager = ToolsLocator.getI18nManager();
482

    
483
            if (option.equalsIgnoreCase(i18nManager.getTranslation("key_finish"))) {
484
                finishPolyline = true;
485
                return;
486
            }
487

    
488
            if (values.size() > 0) {
489
                if (option.equalsIgnoreCase(i18nManager.getTranslation("key_remove_last_point"))) {
490
                    arcMode = values.get(values.size() - 1).isArcMode();
491
                    if (values.size() > 2) {
492
                        values.get(values.size() - 2).setArcMode(arcMode);
493
                    } else {
494
                        arcMode = false;
495
                    }
496
                    values.remove(values.size() - 1);
497
                    return;
498
                }
499
            }
500

    
501
            if (values.size() >= 2) {
502

    
503
                if (option.equalsIgnoreCase(i18nManager.getTranslation("key_arc_mode"))) {
504

    
505
                    arcMode = true;
506

    
507
                } else if (option.equalsIgnoreCase(i18nManager.getTranslation("key_line_mode"))) {
508

    
509
                    arcMode = false;
510

    
511
                } else if (option.equalsIgnoreCase(i18nManager.getTranslation("key_close"))) {
512

    
513
                    closeGeometry = true;
514
                    finishPolyline = true;
515
                }
516
            } else {
517
                throw new InvalidEntryException(null);
518
            }
519

    
520
            if (values.size() > 0) {
521
                values.get(values.size() - 1).setArcMode(arcMode);
522
                return;
523
            }
524

    
525
        } else if ((param == points) && (value instanceof Point)) {
526
             Point vertex = ((Point) value).cloneGeometry();
527
            values.add(new MyPolyLinePoint(vertex, arcMode));
528
            return;
529
        }
530
        throw new InvalidEntryException(null);
531
    }
532

    
533
    @Override
534
    public void setValue(EditingServiceParameter parameter, Object value) throws InvalidEntryException {
535
        validateAndInsertValue(parameter, value);
536
    }
537

    
538
    @Override
539
    public void setValue(Object value) throws InvalidEntryException {
540
        EditingServiceParameter param = next();
541
        validateAndInsertValue(param, value);
542
    }
543

    
544
    @Override
545
    public Object getValue(EditingServiceParameter parameter) {
546
        if(parameter == points){
547
            return values;
548
        }
549
        return null;
550
    }
551

    
552
}