Statistics
| Revision:

root / branches / v2_0_0_prep / extensions / extEditing / src / org / gvsig / editing / gui / cad / tools / SplitGeometryCADTool.java @ 38378

History | View | Annotate | Download (16.2 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
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
 */
22
package org.gvsig.editing.gui.cad.tools;
23

    
24
import java.awt.Image;
25
import java.awt.event.InputEvent;
26
import java.awt.event.MouseEvent;
27
import java.awt.geom.Point2D;
28
import java.util.ArrayList;
29
import java.util.List;
30

    
31
import com.vividsolutions.jts.geom.Coordinate;
32
import com.vividsolutions.jts.geom.Geometry;
33
import com.vividsolutions.jts.geom.GeometryCollection;
34
import com.vividsolutions.jts.geom.GeometryFactory;
35
import com.vividsolutions.jts.geom.LineString;
36
import com.vividsolutions.jts.geom.MultiLineString;
37
import com.vividsolutions.jts.geom.MultiPoint;
38
import com.vividsolutions.jts.geom.MultiPolygon;
39
import com.vividsolutions.jts.geom.Point;
40
import com.vividsolutions.jts.geom.Polygon;
41
import com.vividsolutions.jts.geom.PrecisionModel;
42

    
43
import org.gvsig.andami.PluginServices;
44
import org.gvsig.andami.messages.NotificationManager;
45
import org.gvsig.editing.gui.cad.DefaultCADTool;
46
import org.gvsig.editing.gui.cad.exception.CommandException;
47
import org.gvsig.editing.gui.cad.tools.smc.SplitGeometryCADToolContext;
48
import org.gvsig.editing.gui.cad.tools.split.SplitStrategy;
49
import org.gvsig.editing.layers.VectorialLayerEdited;
50
import org.gvsig.fmap.dal.exception.DataException;
51
import org.gvsig.fmap.dal.feature.EditableFeature;
52
import org.gvsig.fmap.dal.feature.Feature;
53
import org.gvsig.fmap.dal.feature.FeatureStore;
54
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
55
import org.gvsig.fmap.geom.GeometryLocator;
56
import org.gvsig.fmap.geom.exception.CreateGeometryException;
57
import org.gvsig.fmap.geom.operation.GeometryOperationException;
58
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
59
import org.gvsig.fmap.geom.primitive.Envelope;
60
import org.gvsig.fmap.geom.primitive.GeneralPathX;
61
import org.gvsig.fmap.geom.type.GeometryType;
62
import org.gvsig.fmap.geom.util.Converter;
63
import org.gvsig.fmap.mapcontext.layers.SpatialCache;
64
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
65
import org.gvsig.fmap.mapcontrol.MapControlDrawer;
66
import org.gvsig.tools.dispose.DisposableIterator;
67
import org.gvsig.tools.dispose.DisposeUtils;
68
import org.gvsig.tools.locator.LocatorException;
69

    
70
import statemap.State;
71

    
72
/**
73
 * CAD Tool which splits the selected geometries of a vectorial editing
74
 * layer with a digitized polyline.
75
 * 
76
 * 
77
 * @author Alvaro Zabala
78
 * 
79
 */
80
public class SplitGeometryCADTool extends DefaultCADTool {
81

    
82
    /**
83
     * String representation of this tool (used for example to active the tool
84
     * in mapcontrol)
85
     */
86
    public static final String SPLIT_GEOMETRY_TOOL_NAME = "_split_geometry";
87

    
88
    /**
89
     * finite state machine for this CAD tool
90
     */
91
    protected SplitGeometryCADToolContext _fsm;
92

    
93
    /**
94
     * Flag to mark if the digitized line has been finished.
95
     */
96
    protected boolean digitizingFinished = false;
97

    
98
    /**
99
     * Collection of digitized geometries
100
     */
101
    protected List<Point2D> clickedPoints;
102

    
103
    /**
104
     * Initialization method.
105
     */
106
    public void init() {
107
        digitizingFinished = false;
108
        _fsm = new SplitGeometryCADToolContext(this);
109
        setNextTool(SplitGeometryCADTool.SPLIT_GEOMETRY_TOOL_NAME);
110
    }
111

    
112
    public boolean isDigitizingFinished() {
113
        return digitizingFinished;
114
    }
115

    
116
    public String toString() {
117
        return SplitGeometryCADTool.SPLIT_GEOMETRY_TOOL_NAME;
118
    }
119

    
120
    public void finishDigitizedLine() {
121
    }
122

    
123
    public Coordinate[] getPoint2DAsCoordinates(Point2D[] point2d) {
124
        Coordinate[] solution = new Coordinate[point2d.length];
125
        for (int i = 0; i < point2d.length; i++) {
126
            solution[i] = new Coordinate(point2d[i].getX(), point2d[i].getY());
127
        }
128
        return solution;
129
    }
130

    
131
    public void splitSelectedGeometryWithDigitizedLine() {
132
        Point2D[] clickedPts = new Point2D[this.clickedPoints.size()];
133
        clickedPoints.toArray(clickedPts);
134
        Coordinate[] digitizedCoords = getPoint2DAsCoordinates(clickedPts);
135
        LineString splittingLs =
136
            new GeometryFactory(new PrecisionModel(10000))
137
                .createLineString(digitizedCoords);
138
        DisposableIterator selected = null;
139
        try {
140
            VectorialLayerEdited vle = getVLE();
141
            FeatureStore store = vle.getFeatureStore();
142
            selected = store.getFeatureSelection().iterator();
143

    
144
            getCadToolAdapter().getMapControl().getMapContext()
145
                .beginAtomicEvent();
146
            store.beginEditingGroup(getName());
147
            while (selected.hasNext()) {
148
                Feature feature = (Feature) selected.next();
149
                org.gvsig.fmap.geom.Geometry ig = feature.getDefaultGeometry();
150
                Geometry jtsGeo = (Geometry)ig.invokeOperation("toJTS", null);
151
                if (jtsGeo == null)
152
                    return;
153
                Geometry splitGeo = SplitStrategy.splitOp(jtsGeo, splittingLs);
154
                if (splitGeo instanceof GeometryCollection
155
                    && ((GeometryCollection) splitGeo).getNumGeometries() > 1) {
156

    
157
                    GeometryCollection gc = (GeometryCollection) splitGeo;
158
                    ArrayList<Geometry> geoms0 = new ArrayList<Geometry>();
159
                    ArrayList<Geometry> geoms1 = new ArrayList<Geometry>();
160
                    if (gc.getNumGeometries() > 2) {
161
                        Geometry[] splitGroups =
162
                            createSplitGroups(jtsGeo, splittingLs);
163
                        if (splitGroups.length == 0) {
164
                            continue;
165
                        }
166

    
167
                        for (int j = 0; j < gc.getNumGeometries(); j++) {
168
                            Geometry g = gc.getGeometryN(j);
169
                            for (int k=0 ; k<=splitGroups.length ; k++){
170
                            if (splitGroups[k].contains(g)) {
171
                                    geoms0.add(g);
172
                                } else {
173
                                    geoms1.add(g);
174
                                }
175
                            }
176
                        }
177
                    } else
178
                        if (gc.getNumGeometries() == 2) {
179
                            geoms0.add(gc.getGeometryN(0));
180
                            geoms1.add(gc.getGeometryN(1));
181
                        } else {
182
                            continue;
183
                        }
184
                    GeometryCollection gc0 =
185
                        createMulti(geoms0, gc.getFactory());
186

    
187
                    // for(int j = 0; j < gc.getNumGeometries(); j++){
188
                    // Geometry g = gc.getGeometryN(j);
189
                    org.gvsig.fmap.geom.Geometry fmapGeo =
190
                        Converter.jtsToGeometry(gc0);
191

    
192
                    // if (j==0){
193
                    EditableFeature eFeature = feature.getEditable();
194
                    eFeature.setGeometry(store.getDefaultFeatureType()
195
                        .getDefaultGeometryAttributeName(), fmapGeo);
196
                    store.update(eFeature);
197
                    // }else{
198
                    GeometryCollection gc1 =
199
                        createMulti(geoms1, gc.getFactory());
200
                    fmapGeo = Converter.jtsToGeometry(gc1);
201

    
202
                    EditableFeature newFeature =
203
                        store.createNewFeature(store.getDefaultFeatureType(),
204
                            feature);
205
                    newFeature.setGeometry(store.getDefaultFeatureType()
206
                        .getDefaultGeometryAttributeName(), fmapGeo);
207
                    store.insert(newFeature);
208
                    SpatialCache spatialCache =
209
                        ((FLyrVect) vle.getLayer()).getSpatialCache();
210
                    Envelope envelope = fmapGeo.getEnvelope();
211
                    spatialCache.insert(envelope, fmapGeo);
212
                    // }
213
                    // }//for j
214
                }// if splitGeo
215

    
216
            }
217

    
218
            store.endEditingGroup();
219

    
220
            getCadToolAdapter().getMapControl().getMapContext()
221
                .endAtomicEvent();
222
        } catch (Exception ex) {
223
            PluginServices.getLogger().error("Error splitting geom", ex);
224
        } finally {
225
            DisposeUtils.dispose(selected);
226
        }
227
    }
228

    
229
    private GeometryCollection createMulti(ArrayList<Geometry> geoms,
230
        GeometryFactory factory) {
231
        if (geoms.size() == 0)
232
            return null;
233
        if (geoms.get(0) instanceof Polygon) {
234
            return new MultiPolygon((Polygon[]) geoms.toArray(new Polygon[0]),
235
                factory);
236
        } else
237
            if (geoms.get(0) instanceof LineString) {
238
                return new MultiLineString(
239
                    (LineString[]) geoms.toArray(new LineString[0]), factory);
240
            } else
241
                if (geoms.get(0) instanceof Point) {
242
                    return new MultiPoint(
243
                        (Point[]) geoms.toArray(new Point[0]), factory);
244
                }
245
        return null;
246
    }
247

    
248
    private Geometry[] createSplitGroups(Geometry splitGeo,
249
        LineString splittingLs) {
250
        try {
251
            Geometry[] geomsJTS = new Geometry[2];
252
            Geometry r = splitGeo.getEnvelope();
253
            Geometry splitG = SplitStrategy.splitOp(r, splittingLs);
254
            if (splitG instanceof GeometryCollection
255
                && ((GeometryCollection) splitG).getNumGeometries() > 1) {
256
                GeometryCollection gc = (GeometryCollection) splitG;
257
                for (int j = 0; j < gc.getNumGeometries(); j++) {
258
                    geomsJTS[j] = gc.getGeometryN(j);
259
                }
260
            }
261
            return geomsJTS;
262
        } catch (Exception e) {
263
            NotificationManager.showMessageError(
264
                PluginServices.getText(this, "line_not_cross_rectangle"), e);
265
        }
266
        return null;
267
    }
268

    
269
    public void end() {
270
        getCadToolAdapter().refreshEditedLayer();
271
        init();
272
    }
273

    
274
    public void addOption(String s) {
275
        State actualState = _fsm.getPreviousState();
276
        String status = actualState.getName();
277
        if (s.equals(PluginServices.getText(this, "cancel"))) {
278
            init();
279
            return;
280
        }
281
        if (status.equals("TopologicalEdition.FirstPoint")) {
282
            return;
283
        }
284
        init();
285

    
286
    }
287

    
288
    public void addPoint(double x, double y, InputEvent event) {
289

    
290
        State actualState = _fsm.getPreviousState();
291
        String status = actualState.getName();
292
        if (status.equals("SplitGeometry.FirstPoint")) {
293
            clickedPoints = new ArrayList<Point2D>();
294
            clickedPoints.add(new Point2D.Double(x, y));
295
        } else
296
            if (status.equals("SplitGeometry.DigitizingLine")) {
297
                clickedPoints.add(new Point2D.Double(x, y));
298
                if (event != null && ((MouseEvent) event).getClickCount() == 2) {
299
                    digitizingFinished = true;
300
                    finishDigitizedLine();
301
                    splitSelectedGeometryWithDigitizedLine();
302
                    end();
303
                }
304
            }
305
    }
306

    
307
    public void addValue(double d) {
308
    }
309

    
310
    /**
311
     * Draws a polyline with the clicked digitized points in the specified
312
     * graphics.
313
     * 
314
     * @param g2
315
     *            graphics on to draw the polyline
316
     * @param x
317
     *            last x mouse pointer position
318
     * @param y
319
     *            last y mouse pointer position
320
     */
321
    protected void drawPolyLine(MapControlDrawer renderer, double x, double y) {
322
        GeneralPathX gpx =
323
            new GeneralPathX(GeneralPathX.WIND_EVEN_ODD, clickedPoints.size());
324
        Point2D firstPoint = clickedPoints.get(0);
325
        gpx.moveTo(firstPoint.getX(), firstPoint.getY());
326
        for (int i = 1; i < clickedPoints.size(); i++) {
327
            Point2D clickedPoint = clickedPoints.get(i);
328
            gpx.lineTo(clickedPoint.getX(), clickedPoint.getY());
329

    
330
        }
331
        gpx.lineTo(x, y);
332
        org.gvsig.fmap.geom.Geometry geom;
333
        try {
334
            geom =
335
                GeometryLocator.getGeometryManager().createCurve(gpx,
336
                    SUBTYPES.GEOM2D);
337
            renderer.draw(geom, mapControlManager.getGeometrySelectionSymbol());
338
        } catch (LocatorException e) {
339
            e.printStackTrace();
340
        } catch (CreateGeometryException e) {
341
            e.printStackTrace();
342
        }
343
    }
344

    
345
    private void drawRectangleOfSplit(MapControlDrawer renderer)
346
        throws GeometryOperationNotSupportedException,
347
        GeometryOperationException, DataException,
348
        CreateGeometryException {
349
        VectorialLayerEdited vle = getVLE();
350
        FeatureStore store = vle.getFeatureStore();
351
        DisposableIterator selected = null;
352

    
353
        try {
354
            selected = store.getFeatureSelection().iterator();
355
            while (selected.hasNext()) {
356
                Feature feature = (Feature) selected.next();
357
                org.gvsig.fmap.geom.Geometry ig = feature.getDefaultGeometry();
358
                Geometry jtsG = (Geometry)ig.invokeOperation("toJTS", null);
359
                if (jtsG != null && jtsG instanceof GeometryCollection
360
                    && jtsG.getNumGeometries() > 1) {
361
                    
362
                    /*
363
                    org.gvsig.fmap.geom.Geometry r =
364
                        ig.getEnvelope().getGeometry();
365
                        */
366
                    // get perimeter of envelope to prevent
367
                    // opaque rectangle
368
                    org.gvsig.fmap.geom.Geometry geom =
369
                        GeometryLocator.getGeometryManager().createCurve(
370
                            ig.getEnvelope().getGeometry().getGeneralPath(),
371
                            SUBTYPES.GEOM2D);
372
                    
373
                    renderer
374
                        .draw(geom, mapControlManager.getAxisReferenceSymbol());
375
                }
376
            }
377
        } finally {
378
            DisposeUtils.dispose(selected);
379
        }
380
    }
381

    
382
    public void drawOperation(MapControlDrawer renderer, double x, double y) {
383
        State actualState = _fsm.getState();
384
        String status = actualState.getName();
385
        try {
386
            drawRectangleOfSplit(renderer);
387
            // draw splitting line
388
            if ((status.equals("SplitGeometry.DigitizingLine"))) {
389
                drawPolyLine(renderer, x, y);
390
            }
391

    
392
            // draw selection
393
            Image imgSel = getVLE().getSelectionImage();
394
            renderer.drawImage(imgSel, 0, 0);
395
        } catch (Exception e) {
396
            PluginServices.getLogger().error("Error drawing Editing Selection",
397
                e);
398
        }
399
    }
400

    
401
    public String getName() {
402
        return PluginServices.getText(this, "split_geometry_shell");
403
    }
404

    
405
    public void transition(double x, double y, InputEvent event) {
406
        try {
407
            _fsm.addPoint(x, y, event);
408
        } catch (Exception e) {
409
            init();
410
        }
411

    
412
    }
413

    
414
    public void transition(double d) {
415
        _fsm.addValue(d);
416
    }
417

    
418
    public void transition(String s) throws CommandException {
419
        if (!super.changeCommand(s)) {
420
            _fsm.addOption(s);
421
        }
422
    }
423

    
424
    @Override
425
    public boolean isApplicable(GeometryType geometryType) {
426
        return true;
427
    }
428

    
429
    @Override
430
    protected int[] getSupportedGeometryTypes() {
431
        return null;
432
    }
433
}