21 |
21 |
*/
|
22 |
22 |
package org.gvsig.editing.gui.cad.tools;
|
23 |
23 |
|
|
24 |
import java.awt.Color;
|
|
25 |
import java.awt.Component;
|
24 |
26 |
import java.awt.Image;
|
25 |
27 |
import java.awt.event.InputEvent;
|
26 |
28 |
import java.awt.event.MouseEvent;
|
... | ... | |
28 |
30 |
import java.util.ArrayList;
|
29 |
31 |
import java.util.List;
|
30 |
32 |
|
|
33 |
import javax.swing.JOptionPane;
|
|
34 |
|
31 |
35 |
import com.vividsolutions.jts.geom.Coordinate;
|
32 |
36 |
import com.vividsolutions.jts.geom.Geometry;
|
33 |
37 |
import com.vividsolutions.jts.geom.GeometryCollection;
|
... | ... | |
40 |
44 |
import com.vividsolutions.jts.geom.Polygon;
|
41 |
45 |
import com.vividsolutions.jts.geom.PrecisionModel;
|
42 |
46 |
|
|
47 |
import org.slf4j.Logger;
|
|
48 |
import org.slf4j.LoggerFactory;
|
|
49 |
|
43 |
50 |
import org.gvsig.andami.PluginServices;
|
44 |
|
import org.gvsig.andami.messages.NotificationManager;
|
|
51 |
import org.gvsig.andami.ui.mdiManager.IWindow;
|
|
52 |
import org.gvsig.app.ApplicationLocator;
|
45 |
53 |
import org.gvsig.editing.gui.cad.DefaultCADTool;
|
46 |
54 |
import org.gvsig.editing.gui.cad.exception.CommandException;
|
47 |
55 |
import org.gvsig.editing.gui.cad.tools.smc.SplitGeometryCADToolContext;
|
... | ... | |
62 |
70 |
import org.gvsig.fmap.geom.util.Converter;
|
63 |
71 |
import org.gvsig.fmap.mapcontext.layers.SpatialCache;
|
64 |
72 |
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
|
|
73 |
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
|
65 |
74 |
import org.gvsig.fmap.mapcontrol.MapControlDrawer;
|
|
75 |
import org.gvsig.i18n.Messages;
|
|
76 |
import org.gvsig.symbology.SymbologyLocator;
|
|
77 |
import org.gvsig.symbology.SymbologyManager;
|
|
78 |
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill.ISimpleFillSymbol;
|
66 |
79 |
import org.gvsig.tools.dispose.DisposableIterator;
|
67 |
80 |
import org.gvsig.tools.dispose.DisposeUtils;
|
68 |
81 |
import org.gvsig.tools.locator.LocatorException;
|
69 |
82 |
|
70 |
83 |
import statemap.State;
|
|
84 |
import statemap.StateUndefinedException;
|
71 |
85 |
|
72 |
86 |
/**
|
73 |
87 |
* CAD Tool which splits the selected geometries of a vectorial editing
|
... | ... | |
79 |
93 |
*/
|
80 |
94 |
public class SplitGeometryCADTool extends DefaultCADTool {
|
81 |
95 |
|
|
96 |
private static Logger logger =
|
|
97 |
LoggerFactory.getLogger(SplitGeometryCADTool.class);
|
82 |
98 |
/**
|
83 |
99 |
* String representation of this tool (used for example to active the tool
|
84 |
100 |
* in mapcontrol)
|
... | ... | |
101 |
117 |
protected List<Point2D> clickedPoints;
|
102 |
118 |
|
103 |
119 |
/**
|
|
120 |
* used to draw helping rectangle (bbox)
|
|
121 |
*/
|
|
122 |
protected ISymbol rectSymbol = null;
|
|
123 |
/**
|
104 |
124 |
* Initialization method.
|
105 |
125 |
*/
|
106 |
126 |
public void init() {
|
... | ... | |
129 |
149 |
}
|
130 |
150 |
|
131 |
151 |
public void splitSelectedGeometryWithDigitizedLine() {
|
|
152 |
|
|
153 |
// comprobar bucle, probar interseccion?
|
132 |
154 |
Point2D[] clickedPts = new Point2D[this.clickedPoints.size()];
|
133 |
155 |
clickedPoints.toArray(clickedPts);
|
134 |
156 |
Coordinate[] digitizedCoords = getPoint2DAsCoordinates(clickedPts);
|
... | ... | |
160 |
182 |
if (gc.getNumGeometries() > 2) {
|
161 |
183 |
Geometry[] splitGroups =
|
162 |
184 |
createSplitGroups(jtsGeo, splittingLs);
|
|
185 |
|
|
186 |
if (splitGroups == null) {
|
|
187 |
|
|
188 |
String _tit = Messages.getText("split_geometry");
|
|
189 |
String _msg = Messages.getText("_Split_line_must_start_and_end_outside_bbox");
|
|
190 |
Component parent = getCurrentWindow();
|
|
191 |
JOptionPane.showMessageDialog(
|
|
192 |
parent,
|
|
193 |
_msg,
|
|
194 |
_tit,
|
|
195 |
JOptionPane.WARNING_MESSAGE);
|
|
196 |
// cancel splitting
|
|
197 |
break;
|
|
198 |
}
|
|
199 |
|
163 |
200 |
if (splitGroups.length == 0) {
|
164 |
201 |
continue;
|
165 |
202 |
}
|
166 |
203 |
|
167 |
204 |
for (int j = 0; j < gc.getNumGeometries(); j++) {
|
168 |
205 |
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 |
|
}
|
|
206 |
|
|
207 |
if (isRatherInside(g, splitGroups[0])) {
|
|
208 |
geoms0.add(g);
|
|
209 |
} else {
|
|
210 |
geoms1.add(g);
|
175 |
211 |
}
|
176 |
212 |
}
|
177 |
|
} else
|
|
213 |
} else {
|
178 |
214 |
if (gc.getNumGeometries() == 2) {
|
179 |
215 |
geoms0.add(gc.getGeometryN(0));
|
180 |
216 |
geoms1.add(gc.getGeometryN(1));
|
181 |
217 |
} else {
|
182 |
218 |
continue;
|
183 |
219 |
}
|
|
220 |
}
|
184 |
221 |
GeometryCollection gc0 =
|
185 |
222 |
createMulti(geoms0, gc.getFactory());
|
186 |
223 |
|
... | ... | |
226 |
263 |
}
|
227 |
264 |
}
|
228 |
265 |
|
|
266 |
/**
|
|
267 |
* @return
|
|
268 |
*/
|
|
269 |
private Component getCurrentWindow() {
|
|
270 |
|
|
271 |
IWindow iw = PluginServices.getMDIManager().getActiveWindow();
|
|
272 |
if (iw instanceof Component) {
|
|
273 |
return (Component) iw;
|
|
274 |
} else {
|
|
275 |
return null;
|
|
276 |
}
|
|
277 |
}
|
|
278 |
|
229 |
279 |
private GeometryCollection createMulti(ArrayList<Geometry> geoms,
|
230 |
280 |
GeometryFactory factory) {
|
231 |
281 |
if (geoms.size() == 0)
|
... | ... | |
260 |
310 |
}
|
261 |
311 |
return geomsJTS;
|
262 |
312 |
} catch (Exception e) {
|
263 |
|
NotificationManager.showMessageError(
|
264 |
|
PluginServices.getText(this, "line_not_cross_rectangle"), e);
|
|
313 |
logger.info("Warning: Found split line which does not leave bbox. User will be prompted.");
|
265 |
314 |
}
|
266 |
315 |
return null;
|
267 |
316 |
}
|
... | ... | |
370 |
419 |
ig.getEnvelope().getGeometry().getGeneralPath(),
|
371 |
420 |
SUBTYPES.GEOM2D);
|
372 |
421 |
|
373 |
|
renderer
|
374 |
|
.draw(geom, mapControlManager.getAxisReferenceSymbol());
|
|
422 |
renderer.draw(geom, getRectangleOfSplitSymbol());
|
375 |
423 |
}
|
376 |
424 |
}
|
377 |
425 |
} finally {
|
... | ... | |
379 |
427 |
}
|
380 |
428 |
}
|
381 |
429 |
|
|
430 |
/**
|
|
431 |
* @return
|
|
432 |
*/
|
|
433 |
private ISymbol getRectangleOfSplitSymbol() {
|
|
434 |
|
|
435 |
if (rectSymbol == null) {
|
|
436 |
SymbologyManager sm = SymbologyLocator.getSymbologyManager();
|
|
437 |
ISimpleFillSymbol resp = sm.createSimpleFillSymbol();
|
|
438 |
resp.setColor(Color.RED);
|
|
439 |
resp.setFillColor(new Color(0,0,0, 100));
|
|
440 |
rectSymbol = resp;
|
|
441 |
}
|
|
442 |
return rectSymbol;
|
|
443 |
}
|
|
444 |
|
382 |
445 |
public void drawOperation(MapControlDrawer renderer, double x, double y) {
|
383 |
|
State actualState = _fsm.getState();
|
384 |
|
String status = actualState.getName();
|
|
446 |
|
|
447 |
// decide whether user line must be drawn
|
|
448 |
boolean draw_user_poly_line = false;
|
385 |
449 |
try {
|
|
450 |
State currentState = _fsm.getState();
|
|
451 |
if (currentState != null) {
|
|
452 |
String status = currentState.getName();
|
|
453 |
if (status != null && status.equals("SplitGeometry.DigitizingLine")) {
|
|
454 |
draw_user_poly_line = true;
|
|
455 |
}
|
|
456 |
}
|
|
457 |
} catch (StateUndefinedException sue) {
|
|
458 |
// this happens when state is null
|
|
459 |
// because the line has been finished and we must not draw it
|
|
460 |
draw_user_poly_line = false;
|
|
461 |
}
|
|
462 |
|
|
463 |
// =======================================================
|
|
464 |
|
|
465 |
try {
|
386 |
466 |
drawRectangleOfSplit(renderer);
|
387 |
|
// draw splitting line
|
388 |
|
if ((status.equals("SplitGeometry.DigitizingLine"))) {
|
|
467 |
|
|
468 |
// possibly draw splitting line
|
|
469 |
if (draw_user_poly_line) {
|
389 |
470 |
drawPolyLine(renderer, x, y);
|
390 |
471 |
}
|
391 |
472 |
|
... | ... | |
393 |
474 |
Image imgSel = getVLE().getSelectionImage();
|
394 |
475 |
renderer.drawImage(imgSel, 0, 0);
|
395 |
476 |
} catch (Exception e) {
|
396 |
|
PluginServices.getLogger().error("Error drawing Editing Selection",
|
397 |
|
e);
|
|
477 |
|
|
478 |
logger.info("Error while drawing split tool.", e);
|
|
479 |
ApplicationLocator.getManager().message(
|
|
480 |
Messages.getText("_Drawing_error") + e.getMessage(),
|
|
481 |
JOptionPane.ERROR_MESSAGE);
|
398 |
482 |
}
|
399 |
483 |
}
|
400 |
484 |
|
... | ... | |
430 |
514 |
protected int[] getSupportedGeometryTypes() {
|
431 |
515 |
return null;
|
432 |
516 |
}
|
|
517 |
|
|
518 |
/**
|
|
519 |
* This method decides if geometrya is inside geometry b
|
|
520 |
* by more than 50%. This is useful because it will be
|
|
521 |
* used to assign each geometry to one of two possible containers
|
|
522 |
*
|
|
523 |
* @param a
|
|
524 |
* @param b must be a multi(polygon)
|
|
525 |
* @return
|
|
526 |
*/
|
|
527 |
private static boolean isRatherInside(Geometry a, Geometry b) {
|
|
528 |
|
|
529 |
if (a instanceof Polygon || a instanceof MultiPolygon) {
|
|
530 |
return polygonIsRatherInside(a, b);
|
|
531 |
} else {
|
|
532 |
if (a instanceof LineString || a instanceof MultiLineString) {
|
|
533 |
return lineIsRatherInside(a, b);
|
|
534 |
} else {
|
|
535 |
if (a instanceof MultiPoint) {
|
|
536 |
|
|
537 |
MultiPoint mp = (MultiPoint) a;
|
|
538 |
int n = mp.getNumPoints();
|
|
539 |
int inn = 0;
|
|
540 |
Geometry itemg = null;
|
|
541 |
for (int i=0; i<n; i++) {
|
|
542 |
itemg = mp.getGeometryN(i);
|
|
543 |
if (isRatherInside(itemg, b)) {
|
|
544 |
inn++;
|
|
545 |
}
|
|
546 |
}
|
|
547 |
return inn > (n/2);
|
|
548 |
} else {
|
|
549 |
// last case: should be a point
|
|
550 |
return b.contains(a);
|
|
551 |
}
|
|
552 |
}
|
|
553 |
}
|
|
554 |
|
|
555 |
}
|
|
556 |
|
|
557 |
|
|
558 |
|
|
559 |
/**
|
|
560 |
* This method decides if a polygon is inside another
|
|
561 |
* by more than 50%. This is useful because it will be
|
|
562 |
* used to assign each polygon to one of two possible containers
|
|
563 |
*
|
|
564 |
* @param a
|
|
565 |
* @param b
|
|
566 |
* @return whether a is 'rather' contained by b
|
|
567 |
*/
|
|
568 |
private static boolean polygonIsRatherInside(Geometry a, Geometry b) {
|
|
569 |
|
|
570 |
if (a == null || b == null || a.isEmpty() || b.isEmpty()) {
|
|
571 |
return false;
|
|
572 |
}
|
|
573 |
|
|
574 |
double area_a = a.getArea();
|
|
575 |
|
|
576 |
if (area_a == 0) {
|
|
577 |
return false;
|
|
578 |
}
|
|
579 |
|
|
580 |
Geometry a_inters_b = null;
|
|
581 |
|
|
582 |
a_inters_b = a.intersection(b);
|
|
583 |
if (a_inters_b == null || a_inters_b.isEmpty()) {
|
|
584 |
return false;
|
|
585 |
}
|
|
586 |
|
|
587 |
double area_aib = a_inters_b.getArea();
|
|
588 |
|
|
589 |
if (area_aib == 0) {
|
|
590 |
return false;
|
|
591 |
}
|
|
592 |
|
|
593 |
return area_aib > (0.5d * area_a);
|
|
594 |
}
|
|
595 |
|
|
596 |
/**
|
|
597 |
*
|
|
598 |
* @param a assumed to be a (multi)linestring
|
|
599 |
* @param b the (possibly) containing polygon
|
|
600 |
* @return
|
|
601 |
*/
|
|
602 |
private static boolean lineIsRatherInside(Geometry a, Geometry b) {
|
|
603 |
|
|
604 |
if (a == null || b == null || a.isEmpty() || b.isEmpty()) {
|
|
605 |
return false;
|
|
606 |
}
|
|
607 |
|
|
608 |
double len_a = a.getLength();
|
|
609 |
|
|
610 |
if (len_a == 0) {
|
|
611 |
return false;
|
|
612 |
}
|
|
613 |
|
|
614 |
Geometry a_inters_b = null;
|
|
615 |
|
|
616 |
a_inters_b = a.intersection(b);
|
|
617 |
if (a_inters_b == null || a_inters_b.isEmpty()) {
|
|
618 |
return false;
|
|
619 |
}
|
|
620 |
|
|
621 |
double len_aib = a_inters_b.getLength();
|
|
622 |
|
|
623 |
if (len_aib == 0) {
|
|
624 |
return false;
|
|
625 |
}
|
|
626 |
|
|
627 |
return len_aib > (0.5d * len_a);
|
|
628 |
}
|
433 |
629 |
}
|