Statistics
| Revision:

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

History | View | Annotate | Download (22.3 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.offset.lib.prov.offset;
26

    
27
import java.awt.Color;
28
import java.util.ArrayList;
29
import java.util.HashMap;
30
import java.util.LinkedHashMap;
31
import java.util.List;
32
import java.util.Map;
33

    
34
import org.gvsig.fmap.dal.exception.DataException;
35
import org.gvsig.fmap.dal.feature.EditableFeature;
36
import org.gvsig.fmap.dal.feature.Feature;
37
import org.gvsig.fmap.dal.feature.FeatureSelection;
38
import org.gvsig.fmap.dal.feature.FeatureStore;
39
import org.gvsig.fmap.geom.Geometry;
40
import org.gvsig.fmap.geom.GeometryException;
41
import org.gvsig.fmap.geom.GeometryLocator;
42
import org.gvsig.fmap.geom.GeometryManager;
43
import org.gvsig.fmap.geom.aggregate.Aggregate;
44
import org.gvsig.fmap.geom.aggregate.MultiCurve;
45
import org.gvsig.fmap.geom.aggregate.MultiPoint;
46
import org.gvsig.fmap.geom.aggregate.MultiSurface;
47
import org.gvsig.fmap.geom.operation.GeometryOperationException;
48
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
49
import org.gvsig.fmap.geom.primitive.Arc;
50
import org.gvsig.fmap.geom.primitive.Circle;
51
import org.gvsig.fmap.geom.primitive.Circumference;
52
import org.gvsig.fmap.geom.primitive.Curve;
53
import org.gvsig.fmap.geom.primitive.Ellipse;
54
import org.gvsig.fmap.geom.primitive.FilledSpline;
55
import org.gvsig.fmap.geom.primitive.Line;
56
import org.gvsig.fmap.geom.primitive.PeriEllipse;
57
import org.gvsig.fmap.geom.primitive.Point;
58
import org.gvsig.fmap.geom.primitive.Polygon;
59
import org.gvsig.fmap.geom.primitive.Spline;
60
import org.gvsig.fmap.geom.primitive.Surface;
61
import org.gvsig.fmap.mapcontext.MapContextLocator;
62
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
63
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolManager;
64
import org.gvsig.tools.ToolsLocator;
65
import org.gvsig.tools.dispose.DisposableIterator;
66
import org.gvsig.tools.dynobject.DynObject;
67
import org.gvsig.tools.i18n.I18nManager;
68
import org.gvsig.tools.service.spi.ProviderServices;
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.spi.AbstractEditingProvider;
77
import org.gvsig.vectorediting.lib.spi.DefaultDrawingStatus;
78
import org.gvsig.vectorediting.lib.spi.DefaultEditingServiceParameter;
79
import org.gvsig.vectorediting.lib.spi.EditingProvider;
80
import org.gvsig.vectorediting.lib.spi.EditingProviderFactory;
81
import org.gvsig.vectorediting.lib.spi.EditingProviderLocator;
82
import org.gvsig.vectorediting.lib.spi.EditingProviderManager;
83
import org.gvsig.vectorediting.lib.spi.EditingProviderServices;
84

    
85
public class OffsetEditingProvider extends AbstractEditingProvider implements
86
    EditingProvider {
87

    
88
    private final Double PRECISION = new Double(1.0e-5);
89

    
90
    private I18nManager i18nManager = ToolsLocator.getI18nManager();
91

    
92
    private EditingServiceParameter selectionParameter;
93

    
94
    private EditingServiceParameter offsetParameter;
95

    
96
    private EditingServiceParameter deleteOriginalGeometriesParameter;
97

    
98
    private boolean deleteOriginalGeometries = false;
99

    
100
    private Map<EditingServiceParameter, Object> values;
101

    
102
    private Map<String, String> options;
103

    
104
    private FeatureStore featureStore;
105

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

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

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

    
119
        this.options = new LinkedHashMap<String, String>();
120
        options.put(i18nManager.getTranslation("short_yes"),
121
            "delete_original_geometries");
122
        options.put(i18nManager.getTranslation("short_no"),
123
            "keep_original_geometries");
124

    
125
        EditingProviderServices editingProviderServices =
126
            (EditingProviderServices) getProviderServices();
127

    
128
        String consoleMsg =
129
            editingProviderServices.makeConsoleMessage(
130
                "delete_original_geometries_question", options);
131

    
132
        this.deleteOriginalGeometriesParameter =
133
            new DefaultEditingServiceParameter("Delete original geometries",
134
                consoleMsg, options, TYPE.OPTION);
135

    
136
    }
137

    
138
    public EditingServiceParameter next() {
139

    
140
        if (values.get(selectionParameter) == null) {
141
            return selectionParameter;
142
        } else if (values.get(offsetParameter) == null) {
143
            return offsetParameter;
144
        } else if (values.get(deleteOriginalGeometriesParameter) == null) {
145
            return this.deleteOriginalGeometriesParameter;
146
        }
147

    
148
        return null;
149
    }
150

    
151
    public DrawingStatus getDrawingStatus(Point mousePosition) throws DrawServiceException {
152
        DefaultDrawingStatus drawingStatus = new DefaultDrawingStatus();
153
        EditingProviderManager editingProviderManager =
154
            EditingProviderLocator.getProviderManager();
155
//        ISymbol auxiliaryLineSymbolEditing = editingProviderManager.getSymbol("auxiliary-line-symbol-editing");
156
        ISymbol auxiliaryPointSymbolEditing = editingProviderManager.getSymbol("auxiliary-point-symbol-editing");
157
        ISymbol auxiliaryLineSymbolEditingDirection = editingProviderManager.getSymbol("auxiliary-line-symbol-editing-direction");
158
        ISymbol lineSymbolEditing = editingProviderManager.getSymbol("line-symbol-editing");
159
        ISymbol polygonSymbolEditing = editingProviderManager.getSymbol("polygon-symbol-editing");
160
        
161
        
162
        
163
        FeatureSelection selected =
164
            (FeatureSelection) values.get(selectionParameter);
165
        try {
166
            if ((selected != null) && !selected.isEmpty()) {
167
                Point point = null;
168
                double distance = 0.0;
169
                Object offsetValue = values.get(offsetParameter);
170
                if (offsetValue != null){
171
                    if (offsetValue instanceof Point) {
172
                        point = (Point) offsetValue;
173
                    } else {
174
                        distance = (Double) offsetValue;
175
                    }
176
                } else {
177
                    point = mousePosition;
178
                    distance = getMinDistance(selected, point);
179
                }
180

    
181

    
182
                DisposableIterator it;
183
                it = selected.fastIterator();
184

    
185
                while (it.hasNext()) {
186
                    Feature feat = (Feature) it.next();
187
                    Geometry transformedGeometry = feat.getDefaultGeometry().offset(distance);
188

    
189
                    ISymbol symbol = null;
190
                    if (transformedGeometry instanceof Curve || transformedGeometry instanceof MultiCurve) {
191
                        symbol = lineSymbolEditing;
192
                        drawingStatus.addStatus(feat.getDefaultGeometry(), auxiliaryLineSymbolEditingDirection, "Direction");
193
                    } else if (transformedGeometry instanceof Surface || transformedGeometry instanceof MultiSurface) {
194
                        symbol = polygonSymbolEditing;
195
                    } else if (transformedGeometry instanceof Point || transformedGeometry instanceof MultiPoint) {
196
                        symbol = auxiliaryPointSymbolEditing;
197
                    }
198
                    if (transformedGeometry instanceof Aggregate) {
199
                        int primitivesNumber = ((Aggregate) transformedGeometry).getPrimitivesNumber();
200
                        for (int i = 0; i < primitivesNumber; i++) {
201
                            drawingStatus.addStatus(((Aggregate) transformedGeometry).getPrimitiveAt(i), symbol, "");
202
                        }
203
                    } else {
204
                        drawingStatus.addStatus(transformedGeometry, symbol, "");
205
                    }
206
                }
207
                it.dispose();
208
            }
209
            return drawingStatus;
210
        } catch (Exception e) {
211
            throw new DrawServiceException(e);
212
        }
213
    }
214

    
215
    /**
216
     * @param selected
217
     * @param point
218
     * @return
219
     * @throws DataException
220
     * @throws GeometryOperationException
221
     * @throws GeometryOperationNotSupportedException
222
     * @throws GeometryException
223
     */
224
    private double getMinDistance(FeatureSelection selected, Point point) throws DataException, GeometryOperationNotSupportedException, GeometryOperationException, GeometryException {
225
        double minorDistance=Double.POSITIVE_INFINITY;
226
        DisposableIterator it;
227
        it = selected.fastIterator();
228
        while (it.hasNext()) {
229
            Feature feat = (Feature) it.next();
230
            Geometry geometry = feat.getDefaultGeometry();
231
            double distance = getDistance(geometry, point);
232
            if(distance < minorDistance){
233
                minorDistance = distance;
234
            }
235
        }
236
        it.dispose();
237
        return minorDistance;
238

    
239
    }
240

    
241
    /**
242
     * @param geometry
243
     * @param point
244
     * @return
245
     * @throws GeometryOperationException
246
     * @throws GeometryOperationNotSupportedException
247
     * @throws GeometryException
248
     */
249
    private double getDistance(Geometry geometry, Point point) throws GeometryOperationNotSupportedException, GeometryOperationException, GeometryException {
250
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
251
        if(geometry instanceof Arc){
252
            Arc arc = (Arc)geometry;
253
            Point center = arc.getCenterPoint();
254
            double radius = center.distance(arc.getInitPoint());
255
            double distance = center.distance(point)-radius;
256
            return distance;
257
        }
258

    
259
        if(geometry instanceof Circle){
260
            Circle circle = (Circle)geometry;
261
            return circle.getCenter().distance(point)-circle.getRadious();
262
        }
263
        if(geometry instanceof Circumference){
264
            Circumference circumference = (Circumference)geometry;
265
            return circumference.getCenter().distance(point)-circumference.getRadious();
266
        }
267
        if(geometry instanceof PeriEllipse){
268
            double minDistance = Double.POSITIVE_INFINITY;
269
            PeriEllipse ellipse = (PeriEllipse)geometry;
270
            Geometry[] closestPoints = point.closestPoints(ellipse);
271
            if (closestPoints!=null){
272
                for (int i = 0; i < closestPoints.length; i++) {
273
                    Geometry closestPoint = closestPoints[i];
274
                    if (!point.equals(closestPoint)) {
275
                        double distance = closestPoint.distance(point);
276
                        if (distance < minDistance) {
277
                            minDistance = distance;
278
                        }
279
                    }
280
                }
281
            }
282
            Ellipse auxEllipse = (Ellipse)geomManager.create(Geometry.TYPES.ELLIPSE, geometry.getGeometryType().getSubType());
283
            auxEllipse.setPoints(ellipse.getAxis1Start(), ellipse.getAxis1End(), ellipse.getAxis2Dist());
284
            if(auxEllipse.contains(point)){
285
                return -minDistance;
286
            }
287
            return minDistance;
288
        }
289
        if(geometry instanceof Ellipse){
290
            Ellipse ellipse = (Ellipse)geometry;
291
            PeriEllipse auxPeriEllipse = (PeriEllipse)geomManager.create(Geometry.TYPES.PERIELLIPSE, geometry.getGeometryType().getSubType());
292
            auxPeriEllipse.setPoints(ellipse.getAxis1Start(), ellipse.getAxis1End(), ellipse.getAxis2Dist());
293
            double distance = getDistance(auxPeriEllipse, point);
294
//            if(ellipse.contains(point)){
295
//                return -distance;
296
//            }
297

    
298
            return distance;
299
        }
300

    
301
        if(geometry instanceof Spline || geometry instanceof FilledSpline ){
302
            return getDistance(geometry.toLines().getPrimitiveAt(0), point);
303
        }
304

    
305
        if(geometry instanceof Line){
306
            Line line = (Line)geometry;
307
            double minDistance = Double.POSITIVE_INFINITY;
308
            Geometry[] closestPoints = point.closestPoints(line);
309
            Point closestPoint = null;
310
            if (closestPoints!=null){
311
                for (int i=0;i<closestPoints.length;i++){
312
                    Point p=(Point)closestPoints[i];
313
                    if (!point.equals(p)) {
314
                        double distance = p.distance(point);
315
                        if (distance < minDistance) {
316
                            minDistance = distance;
317
                            closestPoint = p;
318
                        }
319
                    }
320
                }
321
            }
322
            if(closestPoint != null){
323
                for(int i=0; i<line.getNumVertices()-1; i++){
324
                    Line segment = (Line) geomManager.create(Geometry.TYPES.LINE, geometry.getGeometryType().getSubType());
325
                    segment.addVertex(line.getVertex(i));
326
                    segment.addVertex(line.getVertex(i+1));
327
                    if(segment.isWithinDistance(closestPoint, PRECISION)){
328
                        if(line.getVertex(0).equals(line.getVertex(line.getNumVertices()-1))){ //isClosed
329
                            if(line.toPolygons().contains(point)){
330
                                return -minDistance;
331
                            };
332
                            return minDistance;
333
                        } else {
334
                            return getDirectedDistance(closestPoint, point, segment);
335
                        }
336
                    }
337
                }
338
            }
339
        }
340

    
341
        if(geometry instanceof Polygon){
342
            Polygon polygon = (Polygon)geometry;
343
            if(!polygon.contains(point)){
344
                double minDistance = Double.POSITIVE_INFINITY;
345
                Geometry[] closestPoints = point.closestPoints(polygon);
346
                Point closestPoint = null;
347
                if (closestPoints!=null){
348
                    for (int i=0;i<closestPoints.length;i++){
349
                        Point p=(Point)closestPoints[i];
350
                        if (!point.equals(p)) {
351
                            double distance = p.distance(point);
352
                            if (distance < minDistance) {
353
                                minDistance = distance;
354
                                closestPoint = p;
355
                            }
356
                        }
357
                    }
358
                }
359
                if(closestPoint != null){
360
                    return closestPoint.distance(point);
361
                }
362
            } else {
363
                Line auxLine = (Line) polygon.toLines().getPrimitiveAt(0);
364
                if(auxLine!=null){
365
                    return getDistance(auxLine, point);
366
                }
367
            }
368
        }
369

    
370
        if(geometry instanceof Aggregate){
371
            double minDistance = Double.POSITIVE_INFINITY;
372
            Aggregate aggregate2 = (Aggregate)geometry;
373
            for(int i=0; i<aggregate2.getPrimitivesNumber(); i++){
374
                double distance = getDistance(aggregate2.getPrimitiveAt(i),point);
375
                if(distance<minDistance){
376
                    minDistance = distance;
377
                }
378
            }
379
            return minDistance;
380
        }
381
        return 0.0;
382
    }
383

    
384
    public void stop() {
385
        values.clear();
386
    }
387

    
388
    private void validateAndInsertValue(EditingServiceParameter param,
389
        Object value) throws InvalidEntryException {
390
        if (param == selectionParameter) {
391
            if (value instanceof FeatureSelection) {
392
                values.put(param, value);
393
                return;
394
            }
395
        } else if (param == offsetParameter) {
396
            if (value instanceof Point) {
397
                try {
398
                    values.put(param, getMinDistance((FeatureSelection) values.get(selectionParameter), (Point) value));
399
                } catch (Exception e) {
400
                    throw new InvalidEntryException(e);
401
                }
402
                return;
403
            }
404
            if (value instanceof Double) {
405
                values.put(param, value);
406
            }
407
        } else if (param == deleteOriginalGeometriesParameter) {
408
            if (value instanceof String) {
409
                if (((String) value).trim().equalsIgnoreCase(
410
                    i18nManager.getTranslation("short_yes"))) {
411
                    deleteOriginalGeometries = true;
412
                } else if (((String) value).trim().equalsIgnoreCase(
413
                    i18nManager.getTranslation("short_no"))) {
414
                    deleteOriginalGeometries = false;
415
                } else {
416
                    throw new InvalidEntryException(null);
417
                }
418
                values.put(param, value);
419
            }
420
        }
421

    
422
    }
423

    
424
    public List<EditingServiceParameter> getParameters() {
425
        List<EditingServiceParameter> list =
426
            new ArrayList<EditingServiceParameter>();
427
        list.add(selectionParameter);
428
        list.add(offsetParameter);
429
        return list;
430
    }
431

    
432
    public void setValue(Object value) throws InvalidEntryException {
433
        EditingServiceParameter param = next();
434
        validateAndInsertValue(param, value);
435
    }
436

    
437
    public void finishAndStore() throws FinishServiceException {
438

    
439
        FeatureSelection selected =
440
            (FeatureSelection) values.get(selectionParameter);
441
        try {
442
            if (!selected.isEmpty()) {
443
                double distance = (Double) values.get(offsetParameter);
444
                    DisposableIterator it;
445
                    it = selected.fastIterator();
446

    
447
                    while (it.hasNext()) {
448
                        Feature feature = (Feature) it.next();
449
                        Geometry geom;
450
                        try {
451
                            geom = feature.getDefaultGeometry().offset(distance);
452
                        } catch (GeometryOperationNotSupportedException e) {
453
                            throw new FinishServiceException(e);
454
                        } catch (GeometryOperationException e) {
455
                            throw new FinishServiceException(e);
456
                        }
457

    
458
                        if (this.deleteOriginalGeometries) {
459
                            // Se sustituye la geometr?a original por la
460
                            // calculada
461
                            EditableFeature editableFeature =
462
                                feature.getEditable();
463
                            editableFeature.setDefaultGeometry(geom);
464
                            ((EditingProviderServices) getProviderServices())
465
                                .updateFeatureInFeatureStore(editableFeature,
466
                                    featureStore);
467
                        } else {
468
                            // Se crea una feature nueva copiando los valores de
469
                            // la feature original excepto aquellos que sean PK
470
                            EditingProviderServices editingProviderServices =
471
                                (EditingProviderServices) getProviderServices();
472
                            EditableFeature editableFeature =
473
                                editingProviderServices
474
                                    .getFeatureCopyWithoutPK(featureStore,
475
                                        feature);
476
                            editableFeature.setDefaultGeometry(geom);
477
                            editingProviderServices
478
                                .insertFeatureIntoFeatureStore(editableFeature,
479
                                    featureStore);
480
                        }
481

    
482
                    }
483
                    it.dispose();
484
                    featureStore.getFeatureSelection().deselectAll();
485
                }
486
        } catch (DataException e) {
487
            throw new FinishServiceException(e);
488
        }
489
    }
490

    
491
    private Double getDirectedDistance(Point pointInLine, Point distancePoint, Line line)
492
        throws GeometryOperationNotSupportedException, GeometryOperationException{
493
        Double distance=distancePoint.distance(pointInLine);
494
        EditingProviderServices editingProviderServices =
495
            (EditingProviderServices) getProviderServices();
496
        Double angle = editingProviderServices.getAngle(pointInLine, distancePoint);
497
        double angleLine = editingProviderServices.getAngle(line.getVertex(0), line.getVertex(1));
498

    
499
        Double angleDifference=angle - angleLine;
500
        if ( angleDifference<0 ){
501
            angleDifference+=2*Math.PI;
502
        }
503
        if (angleDifference > Math.PI ) {
504
            distance = -distance;
505
        }
506
        return distance;
507
    }
508

    
509
    public Geometry finish() throws FinishServiceException {
510
        return null;
511
    }
512

    
513
    public void start() throws StartServiceException {
514
        this.values = new HashMap<EditingServiceParameter, Object>();
515
        FeatureSelection selected = null;
516
        if (featureStore != null) {
517
            try {
518
                selected =
519
                    (FeatureSelection) featureStore.getFeatureSelection()
520
                        .clone();
521
            } catch (DataException e) {
522
                throw new StartServiceException(e);
523
            } catch (CloneNotSupportedException e) {
524
                // Do nothing
525
            }
526
            if ((selected != null) && (selected.getSelectedCount() > 0)) {
527
                values.put(selectionParameter, selected);
528
            }
529
        }
530
    }
531

    
532
    public String getName() {
533
        return OffsetEditingProviderFactory.PROVIDER_NAME;
534
    }
535
}