root / trunk / extensions / extCAD / src / com / iver / cit / gvsig / gui / cad / tools / SplitGeometryCADTool.java @ 29723
History | View | Annotate | Download (15 KB)
1 | 28054 | vcaballero | /*
|
---|---|---|---|
2 | * Created on 10-abr-2006
|
||
3 | *
|
||
4 | * gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
|
||
5 | *
|
||
6 | * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
|
||
7 | *
|
||
8 | * This program is free software; you can redistribute it and/or
|
||
9 | * modify it under the terms of the GNU General Public License
|
||
10 | * as published by the Free Software Foundation; either version 2
|
||
11 | * of the License, or (at your option) any later version.
|
||
12 | *
|
||
13 | * This program is distributed in the hope that it will be useful,
|
||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
16 | * GNU General Public License for more details.
|
||
17 | *
|
||
18 | * You should have received a copy of the GNU General Public License
|
||
19 | * along with this program; if not, write to the Free Software
|
||
20 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,USA.
|
||
21 | *
|
||
22 | * For more information, contact:
|
||
23 | *
|
||
24 | * Generalitat Valenciana
|
||
25 | * Conselleria d'Infraestructures i Transport
|
||
26 | * Av. Blasco Ib??ez, 50
|
||
27 | * 46010 VALENCIA
|
||
28 | * SPAIN
|
||
29 | *
|
||
30 | * +34 963862235
|
||
31 | * gvsig@gva.es
|
||
32 | * www.gvsig.gva.es
|
||
33 | *
|
||
34 | * or
|
||
35 | *
|
||
36 | * IVER T.I. S.A
|
||
37 | * Salamanca 50
|
||
38 | * 46005 Valencia
|
||
39 | * Spain
|
||
40 | *
|
||
41 | * +34 963163400
|
||
42 | * dac@iver.es
|
||
43 | */
|
||
44 | /* CVS MESSAGES:
|
||
45 | *
|
||
46 | * $Id:
|
||
47 | * $Log:
|
||
48 | */
|
||
49 | package com.iver.cit.gvsig.gui.cad.tools; |
||
50 | |||
51 | import java.awt.Graphics; |
||
52 | import java.awt.Graphics2D; |
||
53 | import java.awt.Image; |
||
54 | import java.awt.event.InputEvent; |
||
55 | import java.awt.event.MouseEvent; |
||
56 | import java.awt.geom.Point2D; |
||
57 | import java.awt.geom.Rectangle2D; |
||
58 | import java.util.ArrayList; |
||
59 | import java.util.List; |
||
60 | |||
61 | import org.apache.log4j.Logger; |
||
62 | |||
63 | import statemap.State; |
||
64 | |||
65 | import com.hardcode.gdbms.driver.exceptions.ReadDriverException; |
||
66 | import com.iver.andami.PluginServices; |
||
67 | import com.iver.andami.messages.NotificationManager; |
||
68 | import com.iver.cit.gvsig.exceptions.expansionfile.ExpansionFileReadException; |
||
69 | import com.iver.cit.gvsig.exceptions.expansionfile.ExpansionFileWriteException; |
||
70 | import com.iver.cit.gvsig.exceptions.validate.ValidateRowException; |
||
71 | import com.iver.cit.gvsig.fmap.core.DefaultFeature; |
||
72 | import com.iver.cit.gvsig.fmap.core.FShape; |
||
73 | import com.iver.cit.gvsig.fmap.core.GeneralPathX; |
||
74 | import com.iver.cit.gvsig.fmap.core.IFeature; |
||
75 | import com.iver.cit.gvsig.fmap.core.IGeometry; |
||
76 | import com.iver.cit.gvsig.fmap.core.ShapeFactory; |
||
77 | import com.iver.cit.gvsig.fmap.core.v02.FConverter; |
||
78 | import com.iver.cit.gvsig.fmap.edition.DefaultRowEdited; |
||
79 | import com.iver.cit.gvsig.fmap.edition.EditionEvent; |
||
80 | import com.iver.cit.gvsig.fmap.edition.IRowEdited; |
||
81 | import com.iver.cit.gvsig.fmap.edition.VectorialEditableAdapter; |
||
82 | import com.iver.cit.gvsig.fmap.layers.FBitSet; |
||
83 | import com.iver.cit.gvsig.fmap.layers.FLyrVect; |
||
84 | import com.iver.cit.gvsig.fmap.layers.SpatialCache; |
||
85 | import com.iver.cit.gvsig.gui.cad.DefaultCADTool; |
||
86 | import com.iver.cit.gvsig.gui.cad.exception.CommandException; |
||
87 | import com.iver.cit.gvsig.gui.cad.tools.smc.SplitGeometryCADToolContext; |
||
88 | import com.iver.cit.gvsig.gui.cad.tools.split.SplitStrategy; |
||
89 | import com.iver.cit.gvsig.layers.VectorialLayerEdited; |
||
90 | import com.vividsolutions.jts.geom.Coordinate; |
||
91 | import com.vividsolutions.jts.geom.Geometry; |
||
92 | import com.vividsolutions.jts.geom.GeometryCollection; |
||
93 | import com.vividsolutions.jts.geom.GeometryFactory; |
||
94 | import com.vividsolutions.jts.geom.LineString; |
||
95 | 29723 | vcaballero | import com.vividsolutions.jts.geom.MultiLineString; |
96 | import com.vividsolutions.jts.geom.MultiPoint; |
||
97 | import com.vividsolutions.jts.geom.MultiPolygon; |
||
98 | import com.vividsolutions.jts.geom.Point; |
||
99 | import com.vividsolutions.jts.geom.Polygon; |
||
100 | 28054 | vcaballero | import com.vividsolutions.jts.geom.PrecisionModel; |
101 | |||
102 | |||
103 | /**
|
||
104 | * CAD Tool which splits the selected geometries of a vectorial editing
|
||
105 | * layer with a digitized polyline.
|
||
106 | *
|
||
107 | *
|
||
108 | * @author Alvaro Zabala
|
||
109 | *
|
||
110 | */
|
||
111 | public class SplitGeometryCADTool extends DefaultCADTool { |
||
112 | |||
113 | private static Logger logger = Logger.getLogger(SplitGeometryCADTool.class.getName()); |
||
114 | |||
115 | /**
|
||
116 | * String representation of this tool (used for example to active the tool
|
||
117 | * in mapcontrol)
|
||
118 | */
|
||
119 | public static final String SPLIT_GEOMETRY_TOOL_NAME = "_split_geometry"; |
||
120 | |||
121 | |||
122 | |||
123 | /**
|
||
124 | * finite state machine for this CAD tool
|
||
125 | */
|
||
126 | protected SplitGeometryCADToolContext _fsm;
|
||
127 | |||
128 | |||
129 | |||
130 | /**
|
||
131 | * Flag to mark if the digitized line has been finished.
|
||
132 | */
|
||
133 | protected boolean digitizingFinished = false; |
||
134 | |||
135 | /**
|
||
136 | * Collection of digitized geometries
|
||
137 | */
|
||
138 | protected List<Point2D> clickedPoints; |
||
139 | |||
140 | |||
141 | /**
|
||
142 | * Default Constructor
|
||
143 | */
|
||
144 | public SplitGeometryCADTool(){
|
||
145 | |||
146 | } |
||
147 | |||
148 | |||
149 | /**
|
||
150 | * Initialization method.
|
||
151 | */
|
||
152 | public void init() { |
||
153 | digitizingFinished = false;
|
||
154 | _fsm = new SplitGeometryCADToolContext(this); |
||
155 | setNextTool(SplitGeometryCADTool.SPLIT_GEOMETRY_TOOL_NAME); |
||
156 | } |
||
157 | |||
158 | |||
159 | |||
160 | public boolean isDigitizingFinished() { |
||
161 | return digitizingFinished;
|
||
162 | } |
||
163 | |||
164 | public String toString() { |
||
165 | return SplitGeometryCADTool.SPLIT_GEOMETRY_TOOL_NAME;
|
||
166 | } |
||
167 | |||
168 | |||
169 | |||
170 | public void finishDigitizedLine(){ |
||
171 | } |
||
172 | public ArrayList getSelectedRows(){ |
||
173 | VectorialLayerEdited vle = getVLE(); |
||
174 | ArrayList selection = vle.getSelectedRow();
|
||
175 | if( selection.size() == 0){ |
||
176 | VectorialEditableAdapter vea = vle.getVEA(); |
||
177 | try {
|
||
178 | FBitSet bitset = vea.getSelection(); |
||
179 | for (int j = bitset.nextSetBit(0);j >= 0;j = bitset.nextSetBit(j + 1)){ |
||
180 | IRowEdited rowEd = vea.getRow(j); |
||
181 | selection.add(rowEd); |
||
182 | } |
||
183 | } catch (ExpansionFileReadException e) {
|
||
184 | e.printStackTrace(); |
||
185 | } catch (ReadDriverException e) {
|
||
186 | e.printStackTrace(); |
||
187 | } |
||
188 | }//selection size
|
||
189 | return selection;
|
||
190 | } |
||
191 | // public ArrayList getSelectedRows(){
|
||
192 | // return (ArrayList) CADUtil.getSelectedFeatures(getVLE());
|
||
193 | // }
|
||
194 | public Coordinate[] getPoint2DAsCoordinates(Point2D[] point2d) { |
||
195 | Coordinate[] solution = new Coordinate[point2d.length]; |
||
196 | for (int i = 0; i < point2d.length; i++) { |
||
197 | solution[i] = new Coordinate(point2d[i].getX(), point2d[i].getY());
|
||
198 | } |
||
199 | return solution;
|
||
200 | } |
||
201 | public void splitSelectedGeometryWithDigitizedLine(){ |
||
202 | Point2D[] clickedPts = new Point2D[this.clickedPoints.size()]; |
||
203 | clickedPoints.toArray(clickedPts); |
||
204 | Coordinate[] digitizedCoords = getPoint2DAsCoordinates(clickedPts);
|
||
205 | LineString splittingLs = new GeometryFactory(
|
||
206 | new PrecisionModel(10000)).createLineString(digitizedCoords); |
||
207 | |||
208 | ArrayList selectedRows = getSelectedRows();
|
||
209 | IRowEdited editedRow = null;
|
||
210 | VectorialLayerEdited vle = getVLE(); |
||
211 | VectorialEditableAdapter vea = vle.getVEA(); |
||
212 | getCadToolAdapter().getMapControl().getMapContext().beginAtomicEvent(); |
||
213 | vea.startComplexRow(); |
||
214 | List<Integer> indices = new ArrayList<Integer>(); |
||
215 | 29042 | vcaballero | ArrayList auxSelectedRows=new ArrayList(selectedRows); |
216 | try {
|
||
217 | vle.clearSelection(false);
|
||
218 | } catch (ReadDriverException e1) {
|
||
219 | e1.printStackTrace(); |
||
220 | } |
||
221 | 29723 | vcaballero | |
222 | 29042 | vcaballero | for (int i = 0; i < auxSelectedRows.size(); i++) { |
223 | editedRow = (IRowEdited) auxSelectedRows.get(i); |
||
224 | 28054 | vcaballero | IFeature feat = (IFeature) editedRow.getLinkedRow().cloneRow(); |
225 | IGeometry ig = feat.getGeometry(); |
||
226 | Geometry jtsGeo = FConverter.java2d_to_jts((FShape)ig.getInternalShape()); |
||
227 | 28976 | vcaballero | if (jtsGeo==null) |
228 | return;
|
||
229 | 28054 | vcaballero | try {
|
230 | Geometry splitGeo = SplitStrategy.splitOp(jtsGeo, splittingLs); |
||
231 | if(splitGeo instanceof GeometryCollection |
||
232 | && ((GeometryCollection)splitGeo).getNumGeometries()>1){
|
||
233 | |||
234 | //Saving originals polygons index
|
||
235 | indices.add(new Integer(editedRow.getIndex())); |
||
236 | //and then, we add new features for each split geometry
|
||
237 | GeometryCollection gc = (GeometryCollection)splitGeo; |
||
238 | 29723 | vcaballero | ArrayList<Geometry> geoms0=new ArrayList<Geometry>(); |
239 | ArrayList<Geometry> geoms1=new ArrayList<Geometry>(); |
||
240 | if (gc.getNumGeometries()>2){ |
||
241 | Geometry[] splitGroups=createSplitGroups(jtsGeo,splittingLs);
|
||
242 | if (splitGroups.length==0){ |
||
243 | continue;
|
||
244 | } |
||
245 | |||
246 | for(int j = 0; j < gc.getNumGeometries(); j++){ |
||
247 | Geometry g = gc.getGeometryN(j); |
||
248 | if (splitGroups[0].contains(g)){ |
||
249 | geoms0.add(g); |
||
250 | }else{
|
||
251 | geoms1.add(g); |
||
252 | } |
||
253 | } |
||
254 | }else if (gc.getNumGeometries()==2){ |
||
255 | geoms0.add(gc.getGeometryN(0));
|
||
256 | geoms1.add(gc.getGeometryN(1));
|
||
257 | }else{
|
||
258 | continue;
|
||
259 | } |
||
260 | GeometryCollection gc0=createMulti(geoms0,gc.getFactory()); |
||
261 | |||
262 | IGeometry fmapGeo = FConverter.jts_to_igeometry(gc0); |
||
263 | 28830 | vcaballero | DefaultFeature df = null;
|
264 | 28054 | vcaballero | int newIdx = 0; |
265 | 29723 | vcaballero | // if (j==0){
|
266 | 28054 | vcaballero | newIdx=editedRow.getIndex(); |
267 | try {
|
||
268 | 28830 | vcaballero | df = new DefaultFeature(fmapGeo, feat.getAttributes(),feat.getID());
|
269 | 28067 | vcaballero | vea.modifyRow(newIdx, df, getName(), |
270 | 28054 | vcaballero | EditionEvent.GRAPHIC); |
271 | } catch (ValidateRowException e) {
|
||
272 | NotificationManager.addError(e.getMessage(),e); |
||
273 | } catch (ExpansionFileWriteException e) {
|
||
274 | NotificationManager.addError(e.getMessage(),e); |
||
275 | } catch (ReadDriverException e) {
|
||
276 | NotificationManager.addError(e.getMessage(),e); |
||
277 | } |
||
278 | 29723 | vcaballero | // }else{
|
279 | GeometryCollection gc1=createMulti(geoms1,gc.getFactory()); |
||
280 | fmapGeo = FConverter.jts_to_igeometry(gc1); |
||
281 | 28054 | vcaballero | try {
|
282 | 28830 | vcaballero | String newFID = vea.getNewFID();
|
283 | df = new DefaultFeature(fmapGeo, feat.getAttributes(),newFID);
|
||
284 | 28054 | vcaballero | newIdx = vea.addRow(df, getName(), EditionEvent.GRAPHIC); |
285 | SpatialCache spatialCache=((FLyrVect)vle.getLayer()).getSpatialCache(); |
||
286 | IGeometry geometry = df.getGeometry(); |
||
287 | Rectangle2D r = geometry.getBounds2D();
|
||
288 | if (geometry.getGeometryType() == FShape.POINT) {
|
||
289 | r = new Rectangle2D.Double(r.getX(),r.getY(),1,1); |
||
290 | } |
||
291 | spatialCache.insert(r,geometry); |
||
292 | } catch (ValidateRowException e) {
|
||
293 | NotificationManager.addError(e); |
||
294 | } catch (ReadDriverException e) {
|
||
295 | NotificationManager.addError(e); |
||
296 | } |
||
297 | 29723 | vcaballero | // }
|
298 | 28054 | vcaballero | DefaultRowEdited newRowEdited = new DefaultRowEdited(df,
|
299 | IRowEdited.STATUS_ADDED, |
||
300 | newIdx); |
||
301 | vle.addSelectionCache(newRowEdited); |
||
302 | 29723 | vcaballero | // }//for j
|
303 | 28054 | vcaballero | }//if splitGeo
|
304 | } catch (Exception ex) { |
||
305 | PluginServices.getLogger().error("Error splitting geom "+editedRow.getIndex(), ex);
|
||
306 | } |
||
307 | } |
||
308 | vea.endComplexRow(getName()); |
||
309 | |||
310 | getCadToolAdapter().getMapControl().getMapContext().endAtomicEvent(); |
||
311 | } |
||
312 | |||
313 | 29723 | vcaballero | private GeometryCollection createMulti(ArrayList<Geometry> geoms,GeometryFactory factory) { |
314 | if (geoms.size()==0) |
||
315 | return null; |
||
316 | if (geoms.get(0) instanceof Polygon){ |
||
317 | return new MultiPolygon((Polygon[])geoms.toArray(new Polygon[0]),factory); |
||
318 | }else if (geoms.get(0) instanceof LineString){ |
||
319 | return new MultiLineString((LineString[])geoms.toArray(new LineString[0]),factory); |
||
320 | }else if (geoms.get(0) instanceof Point){ |
||
321 | return new MultiPoint((Point[])geoms.toArray(new Point[0]),factory); |
||
322 | } |
||
323 | return null; |
||
324 | } |
||
325 | |||
326 | |||
327 | private Geometry[] createSplitGroups(Geometry splitGeo, LineString splittingLs) { |
||
328 | try{
|
||
329 | Geometry[] geomsJTS=new Geometry[2]; |
||
330 | Geometry r=splitGeo.getEnvelope(); |
||
331 | Geometry splitG = SplitStrategy.splitOp(r, splittingLs); |
||
332 | if(splitG instanceof GeometryCollection |
||
333 | && ((GeometryCollection)splitG).getNumGeometries()>1){
|
||
334 | GeometryCollection gc = (GeometryCollection)splitG; |
||
335 | for(int j = 0; j < gc.getNumGeometries(); j++){ |
||
336 | geomsJTS[j]=gc.getGeometryN(j); |
||
337 | } |
||
338 | } |
||
339 | return geomsJTS;
|
||
340 | }catch (Exception e) { |
||
341 | NotificationManager.showMessageError(PluginServices.getText(this, "line_not_cross_rectangle"), e); |
||
342 | } |
||
343 | return null; |
||
344 | } |
||
345 | |||
346 | 28054 | vcaballero | public void end(){ |
347 | getCadToolAdapter().refreshEditedLayer(); |
||
348 | init(); |
||
349 | } |
||
350 | |||
351 | public void addOption(String s) { |
||
352 | State actualState = _fsm.getPreviousState(); |
||
353 | String status = actualState.getName();
|
||
354 | if (s.equals(PluginServices.getText(this, "cancel"))) { |
||
355 | init(); |
||
356 | return;
|
||
357 | } |
||
358 | if (status.equals("TopologicalEdition.FirstPoint")) { |
||
359 | return;
|
||
360 | } |
||
361 | init(); |
||
362 | |||
363 | } |
||
364 | |||
365 | public void addPoint(double x, double y, InputEvent event) { |
||
366 | |||
367 | State actualState = _fsm.getPreviousState(); |
||
368 | String status = actualState.getName();
|
||
369 | if (status.equals("SplitGeometry.FirstPoint")) { |
||
370 | clickedPoints = new ArrayList<Point2D>(); |
||
371 | clickedPoints.add(new Point2D.Double(x,y)); |
||
372 | } else if (status.equals("SplitGeometry.DigitizingLine")) { |
||
373 | clickedPoints.add(new Point2D.Double(x,y)); |
||
374 | if (event != null && ((MouseEvent) event).getClickCount() == 2) { |
||
375 | digitizingFinished = true;
|
||
376 | finishDigitizedLine(); |
||
377 | splitSelectedGeometryWithDigitizedLine(); |
||
378 | end(); |
||
379 | } |
||
380 | } |
||
381 | } |
||
382 | |||
383 | public void addValue(double d) { |
||
384 | } |
||
385 | |||
386 | |||
387 | /**
|
||
388 | * Draws a polyline with the clicked digitized points in the specified graphics.
|
||
389 | *
|
||
390 | * @param g2 graphics on to draw the polyline
|
||
391 | * @param x last x mouse pointer position
|
||
392 | * @param y last y mouse pointer position
|
||
393 | */
|
||
394 | protected void drawPolyLine(Graphics2D g, double x, double y) { |
||
395 | GeneralPathX gpx = |
||
396 | new GeneralPathX(GeneralPathX.WIND_EVEN_ODD,
|
||
397 | clickedPoints.size()); |
||
398 | Point2D firstPoint = clickedPoints.get(0); |
||
399 | gpx.moveTo(firstPoint.getX(), firstPoint.getY()); |
||
400 | for (int i = 1; i < clickedPoints.size(); i++) { |
||
401 | Point2D clickedPoint = clickedPoints.get(i);
|
||
402 | gpx.lineTo(clickedPoint.getX(), clickedPoint.getY()); |
||
403 | |||
404 | } |
||
405 | gpx.lineTo(x, y); |
||
406 | ShapeFactory.createPolyline2D(gpx).draw((Graphics2D) g,
|
||
407 | getCadToolAdapter().getMapControl().getViewPort(), |
||
408 | DefaultCADTool.geometrySelectSymbol); |
||
409 | } |
||
410 | |||
411 | |||
412 | |||
413 | |||
414 | public void drawOperation(Graphics g, double x, double y) { |
||
415 | 29723 | vcaballero | try{
|
416 | State actualState = _fsm.getState(); |
||
417 | String status = actualState.getName();
|
||
418 | drawRectangleOfSplit((Graphics2D) g);
|
||
419 | // draw splitting line
|
||
420 | if ((status.equals("SplitGeometry.DigitizingLine"))) { |
||
421 | drawPolyLine((Graphics2D) g, x, y);
|
||
422 | } |
||
423 | }catch (Exception e) { |
||
424 | // TODO: handle exception
|
||
425 | } |
||
426 | // draw selection
|
||
427 | try {
|
||
428 | Image imgSel = getVLE().getSelectionImage();
|
||
429 | if (imgSel != null) |
||
430 | g.drawImage(imgSel, 0, 0, null); |
||
431 | } catch (Exception e) { |
||
432 | PluginServices.getLogger().error("Error drawing Editing Selection", e);
|
||
433 | } |
||
434 | } |
||
435 | 28054 | vcaballero | |
436 | 29723 | vcaballero | private void drawRectangleOfSplit(Graphics2D g) { |
437 | ArrayList selectedRows = getSelectedRows();
|
||
438 | for (int i = 0; i < selectedRows.size(); i++) { |
||
439 | IRowEdited editedRow = (IRowEdited) selectedRows.get(i); |
||
440 | IFeature feat = (IFeature) editedRow.getLinkedRow(); |
||
441 | IGeometry ig = feat.getGeometry(); |
||
442 | Geometry jtsG=ig.toJTSGeometry(); |
||
443 | if (jtsG !=null && jtsG instanceof GeometryCollection && jtsG.getNumGeometries()>1){ |
||
444 | Rectangle2D r=ig.getBounds2D();
|
||
445 | GeneralPathX gpx = new GeneralPathX();
|
||
446 | gpx.moveTo(r.getX(), r.getY()); |
||
447 | gpx.lineTo(r.getMaxX(), r.getY()); |
||
448 | gpx.lineTo(r.getMaxX(), r.getMaxY()); |
||
449 | gpx.lineTo(r.getX(), r.getMaxY()); |
||
450 | gpx.closePath(); |
||
451 | ShapeFactory.createPolygon2D(gpx).draw((Graphics2D) g,
|
||
452 | getCadToolAdapter().getMapControl().getViewPort(), |
||
453 | DefaultCADTool.axisReferencesSymbol); |
||
454 | } |
||
455 | } |
||
456 | 28054 | vcaballero | |
457 | } |
||
458 | |||
459 | 29723 | vcaballero | |
460 | 28054 | vcaballero | public String getName() { |
461 | return PluginServices.getText(this, "split_geometry_shell"); |
||
462 | } |
||
463 | |||
464 | |||
465 | public void transition(double x, double y, InputEvent event) { |
||
466 | try {
|
||
467 | _fsm.addPoint(x, y, event); |
||
468 | } catch (Exception e) { |
||
469 | init(); |
||
470 | } |
||
471 | |||
472 | } |
||
473 | |||
474 | |||
475 | public void transition(double d) { |
||
476 | _fsm.addValue(d); |
||
477 | } |
||
478 | |||
479 | public void transition(String s) throws CommandException { |
||
480 | if (!super.changeCommand(s)) { |
||
481 | _fsm.addOption(s); |
||
482 | } |
||
483 | } |
||
484 | } |