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

History | View | Annotate | Download (22.7 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.Iterator;
29
import java.util.LinkedHashMap;
30
import java.util.List;
31
import java.util.Map;
32

    
33
import org.gvsig.fmap.dal.exception.DataException;
34
import org.gvsig.fmap.dal.feature.FeatureStore;
35
import org.gvsig.fmap.geom.Geometry;
36
import org.gvsig.fmap.geom.Geometry.TYPES;
37
import org.gvsig.fmap.geom.GeometryLocator;
38
import org.gvsig.fmap.geom.GeometryManager;
39
import org.gvsig.fmap.geom.aggregate.MultiCurve;
40
import org.gvsig.fmap.geom.exception.CreateGeometryException;
41
import org.gvsig.fmap.geom.primitive.Curve;
42
import org.gvsig.fmap.geom.primitive.Line;
43
import org.gvsig.fmap.geom.primitive.OrientablePrimitive;
44
import org.gvsig.fmap.geom.primitive.Point;
45
import org.gvsig.fmap.geom.primitive.Surface;
46
import org.gvsig.fmap.geom.type.GeometryType;
47
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
48
import org.gvsig.tools.ToolsLocator;
49
import org.gvsig.tools.dynobject.DynObject;
50
import org.gvsig.tools.exception.BaseException;
51
import org.gvsig.tools.i18n.I18nManager;
52
import org.gvsig.tools.service.spi.ProviderServices;
53
import org.gvsig.vectorediting.lib.api.DrawingStatus;
54
import org.gvsig.vectorediting.lib.api.DrawingStatus.Status;
55
import org.gvsig.vectorediting.lib.api.EditingServiceParameter;
56
import org.gvsig.vectorediting.lib.api.EditingServiceParameter.TYPE;
57
import org.gvsig.vectorediting.lib.api.exceptions.DrawServiceException;
58
import org.gvsig.vectorediting.lib.api.exceptions.FinishServiceException;
59
import org.gvsig.vectorediting.lib.api.exceptions.InvalidEntryException;
60
import org.gvsig.vectorediting.lib.api.exceptions.StartServiceException;
61
import org.gvsig.vectorediting.lib.api.exceptions.VectorEditingException;
62
import org.gvsig.vectorediting.lib.spi.AbstractEditingProvider;
63
import org.gvsig.vectorediting.lib.spi.DefaultDrawingStatus;
64
import org.gvsig.vectorediting.lib.spi.DefaultEditingServiceParameter;
65
import org.gvsig.vectorediting.lib.spi.EditingProvider;
66
import org.gvsig.vectorediting.lib.spi.EditingProviderFactory;
67
import org.gvsig.vectorediting.lib.spi.EditingProviderLocator;
68
import org.gvsig.vectorediting.lib.spi.EditingProviderManager;
69
import org.gvsig.vectorediting.lib.spi.EditingProviderServices;
70

    
71
public class PolylineEditingProvider extends AbstractEditingProvider implements
72
    EditingProvider {
73

    
74
    protected EditingProviderServices editingProviderServices =
75
        (EditingProviderServices) getProviderServices();
76

    
77
    protected EditingServiceParameter points;
78

    
79
    protected Map<String, String> options;
80

    
81
    private boolean arcMode;
82

    
83
    private boolean finishPolyline;
84

    
85
    private boolean closeGeometry;
86

    
87
    private List<MyPolyLinePoint> values;
88

    
89
    protected FeatureStore featureStore;
90

    
91
    public PolylineEditingProvider(ProviderServices providerServices,
92
        DynObject parameters) {
93
        super(providerServices);
94

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

    
100
        I18nManager i18nManager = ToolsLocator.getI18nManager();
101

    
102
        options = new LinkedHashMap<String, String>();
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

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

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

    
116
        arcMode = false;
117
        finishPolyline = false;
118
        closeGeometry = false;
119
    }
120

    
121
    /**
122
     * Calculates polyline with stored values and last position received as
123
     * parameter. If last position is null calculates only with stored values.
124
     *
125
     * @param lastPosition
126
     *            of polyline.
127
     * @return A drawing status value with a list of geometries. See
128
     *         {@link DrawingStatus#getGeometries()}.
129
     */
130
    private DrawingStatus calculatePolyline(Point lastPosition)
131
        throws VectorEditingException {
132
        DefaultDrawingStatus drawingStatus = new DefaultDrawingStatus();
133
        EditingProviderManager editingProviderManager =
134
            EditingProviderLocator.getProviderManager();
135
        ISymbol lineSymbolEditing = editingProviderManager.getSymbol("line-symbol-editing");
136
        ISymbol auxiliaryLineSymbolEditing = editingProviderManager.getSymbol("auxiliary-line-symbol-editing");
137
        ISymbol auxiliaryPointSymbolEditing = editingProviderManager.getSymbol("auxiliary-point-symbol-editing");
138

    
139

    
140
        Double antm = null;
141
        Double antb = null;
142
        Double m = null;
143
        Double b = null;
144
        Point center = null;
145
        double radius = 0.0;
146
        double startAngle = 0.0;
147
        double endAngle = 0.0;
148
        double angleExt = 0.0;
149
        boolean right = false;
150
        boolean addGeom = false;
151

    
152
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
153

    
154
        Curve lineAntPointToPoint = null;
155

    
156
        if (values.size() >= 1) {
157
            for (int i = 0; i < values.size(); i++) {
158

    
159
                MyPolyLinePoint polyLinePoint = values.get(i);
160
                MyPolyLinePoint polyLineNextPoint = getNextPoint(i);
161

    
162
                Point point = polyLinePoint.getPoint();
163
                Point nextPoint;
164

    
165
                if (polyLineNextPoint == null) {
166
                    nextPoint = lastPosition;
167
                    addGeom = true;
168
                } else {
169
                    nextPoint = polyLineNextPoint.getPoint();
170
                }
171

    
172
                if (nextPoint == null) {
173
                    return drawingStatus;
174
                }
175
                if (polyLinePoint.isArcMode()) {
176
                    try {
177
                        EditingProviderServices editingProviderServices =
178
                            ((EditingProviderServices) getProviderServices());
179
                        int subtype =
180
                            editingProviderServices.getSubType(featureStore);
181

    
182
                        lineAntPointToPoint =
183
                            editingProviderServices.createLine(point,
184
                                nextPoint, subtype);
185

    
186
                        Double[] lineParams =
187
                            editingProviderServices.getLineParams(point,
188
                                nextPoint);
189
                        m = lineParams[0];
190
                        b = lineParams[1];
191

    
192
                        Point[] pointPerpendicular =
193
                            editingProviderServices.getPerpendicular(antm,
194
                                antb, point, subtype);
195
                        Line linePointPerpendicular =
196
                            geomManager.createLine(subtype);
197
                        linePointPerpendicular.setPoints(pointPerpendicular[0],
198
                            pointPerpendicular[1]);
199

    
200
                        Point midPoint =
201
                            editingProviderServices.getMidPoint(point,
202
                                nextPoint, subtype);
203
                        Point[] bisector =
204
                            editingProviderServices.getPerpendicular(m, b,
205
                                midPoint, subtype);
206
                        Line lineBisector = geomManager.createLine(subtype);
207
                        lineBisector.setPoints(bisector[0], bisector[1]);
208

    
209
                        center =
210
                            editingProviderServices.getIntersection(bisector,
211
                                pointPerpendicular, subtype);
212

    
213
                        if (center != null) {
214
                            startAngle =
215
                                editingProviderServices.getAngle(center, point);
216
                            endAngle =
217
                                editingProviderServices.getAngle(center,
218
                                    nextPoint);
219

    
220
                            radius = center.distance(point);
221
                        } else {
222
                            String msg =
223
                                String.format(
224
                                    "Can't get intersection between bisector"
225
                                        + " [(%1$s,%2$s),(%3$s,%4$s)]"
226
                                        + " and perperdicular"
227
                                        + " [(%5$s,%6$s),(%7$s,%8$s)]",
228
                                    bisector[0].getX(), bisector[0].getY(),
229
                                    bisector[1].getX(), bisector[1].getY(),
230
                                    pointPerpendicular[0].getX(),
231
                                    pointPerpendicular[0].getY(),
232
                                    pointPerpendicular[1].getX(),
233
                                    pointPerpendicular[1].getY());
234

    
235
                            throw new DrawServiceException(msg, null);
236
                        }
237

    
238
                    } catch (Exception e) {
239
                        throw new DrawServiceException(e);
240
                    }
241

    
242
                    if (right) {
243
                        if (nextPoint.getX() >= point.getX()) {
244
                            if (m >= antm) {
245
                                angleExt =
246
                                    editingProviderServices.angleDistance(
247
                                        endAngle, startAngle);
248
                                right = !(nextPoint.getY() >= center.getY());
249
                            } else {
250
                                angleExt =
251
                                    -editingProviderServices.angleDistance(
252
                                        startAngle, endAngle);
253
                                right = (nextPoint.getY() >= center.getY());
254
                            }
255
                        } else {
256
                            if (m >= antm) {
257
                                angleExt =
258
                                    -editingProviderServices.angleDistance(
259
                                        startAngle, endAngle);
260
                                right = (nextPoint.getY() >= center.getY());
261
                            } else {
262
                                angleExt =
263
                                    editingProviderServices.angleDistance(
264
                                        endAngle, startAngle);
265
                                right = !(nextPoint.getY() >= center.getY());
266
                            }
267
                        }
268
                    } else {
269
                        if (nextPoint.getX() < point.getX()) {
270
                            if (m >= antm) {
271
                                angleExt =
272
                                    editingProviderServices.angleDistance(
273
                                        endAngle, startAngle);
274
                                right = !(nextPoint.getY() >= center.getY());
275
                            } else {
276
                                angleExt =
277
                                    -editingProviderServices.angleDistance(
278
                                        startAngle, endAngle);
279
                                right = (nextPoint.getY() >= center.getY());
280
                            }
281
                        } else {
282
                            if (m >= antm) {
283
                                angleExt =
284
                                    -editingProviderServices.angleDistance(
285
                                        startAngle, endAngle);
286
                                right = (nextPoint.getY() >= center.getY());
287
                            } else {
288
                                angleExt =
289
                                    editingProviderServices.angleDistance(
290
                                        endAngle, startAngle);
291
                                right = !(nextPoint.getY() >= center.getY());
292
                            }
293
                        }
294
                    }
295

    
296
                    Curve arco = null;
297
                    try {
298
                        int subtype =
299
                            editingProviderServices.getSubType(featureStore);
300
                        arco =
301
                            editingProviderServices.createArc(center, radius,
302
                                startAngle, angleExt, subtype);
303
                        Curve inverseArc =
304
                            (Curve) GeometryLocator.getGeometryManager()
305
                                .create(TYPES.CURVE, subtype);
306
                        if (!point.equals(arco.getVertex(0))) {
307
                            for (int j = arco.getNumVertices() - 1; j >= 0; j--) {
308
                                inverseArc.addVertex(arco.getVertex(j));
309
                            }
310
                            arco = inverseArc;
311
                        }
312
                    } catch (Exception e) {
313
                        throw new DrawServiceException(e);
314
                    }
315

    
316
                    antm =
317
                        -(nextPoint.getX() - center.getX())
318
                            / (nextPoint.getY() - center.getY());
319
                    if (antm == Double.POSITIVE_INFINITY) {
320
                        antb = Double.NEGATIVE_INFINITY;
321
                        if (nextPoint.getX() == 0) {
322
                            antb = 0.0;
323
                        }
324
                    } else if (antm == Double.NEGATIVE_INFINITY) {
325
                        antb = Double.POSITIVE_INFINITY;
326
                        if (nextPoint.getX() == 0) {
327
                            antb = 0.0;
328
                        }
329
                    } else {
330
                        antb = nextPoint.getY() - (antm * nextPoint.getX());
331
                    }
332

    
333
                    // Draw geometries.
334
                    if (addGeom) {
335
                        drawingStatus.addStatus(point, auxiliaryPointSymbolEditing, "");
336
                        drawingStatus.addStatus(nextPoint, auxiliaryPointSymbolEditing, "");
337
                        drawingStatus.addStatus(center, auxiliaryPointSymbolEditing, "");
338
                        drawingStatus.addStatus(lineAntPointToPoint, auxiliaryLineSymbolEditing, "");
339

    
340
                    }
341
                    drawingStatus.addStatus(arco, lineSymbolEditing, "");
342

    
343
                } else {
344
                    try {
345
                        int subtype =
346
                            editingProviderServices.getSubType(featureStore);
347
                        Curve geometry =
348
                            editingProviderServices.createLine(point,
349
                                nextPoint, subtype);
350
                        if (addGeom) {
351
                            drawingStatus.addStatus(point, auxiliaryPointSymbolEditing, "");
352
                            drawingStatus.addStatus(nextPoint, auxiliaryPointSymbolEditing, "");
353
                        }
354
                        drawingStatus.addStatus(geometry, lineSymbolEditing, "");
355

    
356
                    } catch (Exception e) {
357
                        throw new DrawServiceException(e);
358
                    }
359
                    Double[] antLineParams =
360
                        editingProviderServices.getLineParams(point, nextPoint);
361
                    antm = antLineParams[0];
362
                    antb = antLineParams[1];
363
                    right = (nextPoint.getX() >= point.getX());
364
                }
365
            }
366
            return drawingStatus;
367
        }
368
        return null;
369
    }
370

    
371
    protected Geometry closeGeometryIfNecessary(Geometry geometry) {
372
        if (!isClose(geometry) && (geometry != null)) {
373

    
374
            if (geometry instanceof Surface) {
375
                Surface surface = (Surface) geometry;
376
                Point firstp = surface.getVertex(0);
377
                firstp = (Point) firstp.cloneGeometry();
378
                surface.addVertex(firstp);
379
                return surface;
380
            } else if (geometry instanceof Curve) {
381
                Curve line = (Curve) geometry;
382
                Point firstp = line.getVertex(0);
383
                firstp = (Point) firstp.cloneGeometry();
384
                line.addVertex(firstp);
385
                return line;
386
            }
387
        }
388
        return geometry;
389
    }
390

    
391
    public DrawingStatus getDrawingStatus(Point mousePosition)
392
        throws DrawServiceException {
393

    
394
        try {
395
            return calculatePolyline(mousePosition);
396

    
397
        } catch (Exception e) {
398
            throw new DrawServiceException(e);
399
        }
400
    }
401

    
402
    public void finishAndStore() throws FinishServiceException {
403
        try {
404
            Geometry geometry = finish();
405
            if (geometry != null) {
406
                editingProviderServices.insertGeometryIntoFeatureStore(
407
                    geometry, featureStore);
408
            }
409
        } catch (Exception e) {
410
            throw new FinishServiceException(e);
411
        }
412
    }
413

    
414
    public Geometry finish() throws FinishServiceException {
415
        try {
416
            GeometryManager geomManager = GeometryLocator.getGeometryManager();
417
            GeometryType storeGeomType =
418
                editingProviderServices.getGeomType(featureStore);
419
            Line line = geomManager.createLine(storeGeomType.getSubType());
420
            calculateFinalGeometry(storeGeomType, line);
421

    
422
            if (closeGeometry) {
423
                line = (Line) closeGeometryIfNecessary(line);
424
            }
425

    
426
            if (storeGeomType.isTypeOf(MULTICURVE)) {
427
                MultiCurve multiCurve =
428
                    geomManager.createMultiCurve(storeGeomType.getSubType());
429
                multiCurve.addCurve(line);
430
                return multiCurve;
431
            } else {
432
                return line;
433
            }
434

    
435
        } catch (BaseException e) {
436
            throw new FinishServiceException(e);
437
        }
438
    }
439

    
440
    /**
441
     * Calculate the final geometry reversing the geometries of the
442
     * drawingStatus if needed.
443
     *
444
     * @param geometryType
445
     * @param orientablePrimitive
446
     * @throws DataException
447
     * @throws CreateGeometryException
448
     * @throws VectorEditingException
449
     */
450
    protected void calculateFinalGeometry(GeometryType geometryType,
451
        OrientablePrimitive orientablePrimitive) throws DataException,
452
        CreateGeometryException, VectorEditingException {
453
        DrawingStatus drawingStatus = calculatePolyline(null);
454
        Point vertexAnt = null;
455
        for (Geometry geometry : drawingStatus.getGeometries()) {
456
            if (geometry instanceof Curve) {
457
                Curve curve = (Curve) geometry;
458
                for (int i = 0; i < curve.getNumVertices(); i++) {
459
                    if ((vertexAnt == null)
460
                        || !vertexAnt.equals(curve.getVertex(i))) {
461
                        orientablePrimitive.addVertex(curve.getVertex(i));
462
                        vertexAnt = curve.getVertex(i);
463
                    }
464
                }
465
            }
466
        }
467
    }
468

    
469
    public String getName() {
470
        return PolylineEditingProviderFactory.PROVIDER_NAME;
471
    }
472

    
473
    private MyPolyLinePoint getNextPoint(int i) {
474
        if (!values.isEmpty() && (i < (values.size() - 1))) {
475
            return values.get(i + 1);
476
        }
477
        return null;
478
    }
479

    
480
    public List<EditingServiceParameter> getParameters() {
481
        List<EditingServiceParameter> list =
482
            new ArrayList<EditingServiceParameter>();
483
        list.add(points);
484
        return list;
485
    }
486

    
487
    private boolean isClose(Geometry geometry) {
488

    
489
        if (geometry != null) {
490

    
491
            if (geometry instanceof OrientablePrimitive) {
492
                OrientablePrimitive orientablePrimitive =
493
                    (OrientablePrimitive) geometry;
494
                Point firstPoint = orientablePrimitive.getVertex(0);
495
                Point lastPoint =
496
                    orientablePrimitive.getVertex(orientablePrimitive
497
                        .getNumVertices() - 1);
498
                if (firstPoint.equals(lastPoint)) {
499
                    return true;
500
                }
501
            }
502
        }
503
        return false;
504
    }
505

    
506
    public EditingServiceParameter next() {
507
        if (finishPolyline) {
508
            return null;
509
        } else {
510
            return points;
511
        }
512

    
513
    }
514

    
515
    public void start() throws StartServiceException {
516
        // Stop service;
517
        stop();
518

    
519
        values = new ArrayList<MyPolyLinePoint>();
520
    }
521

    
522
    public void stop() {
523
        if (values != null) {
524
            values.clear();
525
        }
526
        arcMode = false;
527
        finishPolyline = false;
528
        closeGeometry = false;
529
    }
530

    
531
    private void validateAndInsertValue(EditingServiceParameter param,
532
        Object value) throws InvalidEntryException {
533
        if (value instanceof String) {
534
            String option = (String) value;
535
            I18nManager i18nManager = ToolsLocator.getI18nManager();
536

    
537
            if (option.equalsIgnoreCase(i18nManager
538
                .getTranslation("key_finish"))) {
539
                finishPolyline = true;
540
                return;
541
            }
542

    
543
            if (values.size() >= 2) {
544

    
545
                if (option.equalsIgnoreCase(i18nManager
546
                    .getTranslation("key_arc_mode"))) {
547

    
548
                    arcMode = true;
549

    
550
                } else if (option.equalsIgnoreCase(i18nManager
551
                    .getTranslation("key_line_mode"))) {
552

    
553
                    arcMode = false;
554

    
555
                } else if (option.equalsIgnoreCase(i18nManager
556
                    .getTranslation("key_close"))) {
557

    
558
                    closeGeometry = true;
559
                    finishPolyline = true;
560
                }
561
            } else {
562
                throw new InvalidEntryException(null);
563
            }
564

    
565
            if (values.size() > 0) {
566
                values.get(values.size() - 1).setArcMode(arcMode);
567
                return;
568
            }
569

    
570
        } else if ((param == points) && (value instanceof Point)) {
571
            values.add(new MyPolyLinePoint((Point) value, arcMode));
572
            return;
573
        }
574
        throw new InvalidEntryException(null);
575
    }
576

    
577
    public void setValue(Object value) throws InvalidEntryException {
578
        EditingServiceParameter param = next();
579
        validateAndInsertValue(param, value);
580
    }
581

    
582
}