001: /*
002: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
003: * for visualizing and manipulating spatial features with geometry and attributes.
004: *
005: * JUMP is Copyright (C) 2003 Vivid Solutions
006: *
007: * This program implements extensions to JUMP and is
008: * Copyright (C) Stefan Steiniger.
009: *
010: * This program is free software; you can redistribute it and/or
011: * modify it under the terms of the GNU General Public License
012: * as published by the Free Software Foundation; either version 2
013: * of the License, or (at your option) any later version.
014: *
015: * This program is distributed in the hope that it will be useful,
016: * but WITHOUT ANY WARRANTY; without even the implied warranty of
017: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
018: * GNU General Public License for more details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with this program; if not, write to the Free Software
022: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
023: *
024: * For more information, contact:
025: * Stefan Steiniger
026: * perriger@gmx.de
027: */
028: /*****************************************************
029: * created: by Vivid Solutions
030: * last modified: 22.05.2005 by sstein
031: * 28.01.2006 new MultiInputDialog without cancel button
032: *
033: * description:
034: * draws a circle for a given radius (showing the circle on mouse endpoint)
035: *
036: *****************************************************/package org.openjump.core.ui.plugin.edittoolbox.cursortools;
037:
038: import java.awt.BasicStroke;
039: import java.awt.Container;
040: import java.awt.Cursor;
041: import java.awt.Frame;
042: import java.awt.Shape;
043: import java.awt.event.MouseEvent;
044: import java.awt.geom.NoninvertibleTransformException;
045: import java.awt.geom.Point2D;
046: import java.util.ArrayList;
047: import java.util.Collection;
048: import java.util.Enumeration;
049: import java.util.Iterator;
050: import java.util.List;
051:
052: import javax.swing.AbstractButton;
053: import javax.swing.Icon;
054: import javax.swing.ImageIcon;
055:
056: import org.openjump.core.ui.MultiInputDialogWithoutCancel;
057:
058: import com.vividsolutions.jts.geom.Coordinate;
059: import com.vividsolutions.jts.geom.Envelope;
060: import com.vividsolutions.jts.geom.Geometry;
061: import com.vividsolutions.jts.geom.GeometryCollection;
062: import com.vividsolutions.jts.geom.GeometryFactory;
063: import com.vividsolutions.jts.geom.Point;
064: import com.vividsolutions.jts.geom.Polygon;
065: import com.vividsolutions.jts.operation.buffer.BufferOp;
066: import com.vividsolutions.jts.operation.valid.IsValidOp;
067: import com.vividsolutions.jump.I18N;
068: import com.vividsolutions.jump.feature.Feature;
069: import com.vividsolutions.jump.feature.FeatureCollection;
070: import com.vividsolutions.jump.workbench.WorkbenchContext;
071: import com.vividsolutions.jump.workbench.model.Layer;
072: import com.vividsolutions.jump.workbench.plugin.PlugInContext;
073: import com.vividsolutions.jump.workbench.ui.EditTransaction;
074: import com.vividsolutions.jump.workbench.ui.GUIUtil;
075: import com.vividsolutions.jump.workbench.ui.LayerNamePanelProxy;
076: import com.vividsolutions.jump.workbench.ui.LayerViewPanel;
077: import com.vividsolutions.jump.workbench.ui.LayerViewPanelContext;
078: import com.vividsolutions.jump.workbench.ui.MultiInputDialog;
079: import com.vividsolutions.jump.workbench.ui.WorkbenchFrame;
080: import com.vividsolutions.jump.workbench.ui.cursortool.AbstractCursorTool;
081: import com.vividsolutions.jump.workbench.ui.cursortool.CursorTool;
082: import com.vividsolutions.jump.workbench.ui.cursortool.DragTool;
083: import com.vividsolutions.jump.workbench.ui.cursortool.MultiClickTool;
084: import com.vividsolutions.jump.workbench.ui.cursortool.NClickTool;
085: import com.vividsolutions.jump.workbench.ui.cursortool.editing.DrawPointTool;
086: import com.vividsolutions.jump.workbench.ui.cursortool.editing.FeatureDrawingUtil;
087: import com.vividsolutions.jump.workbench.ui.images.IconLoader;
088:
089: public class DrawCircleWithGivenRadiusTool extends NClickTool {
090:
091: //---- from DragTool -----------------
092: /** Modify using #setDestination */
093: protected Coordinate modelDestination = null;
094: //------------------------------------
095: private FeatureDrawingUtil featureDrawingUtil;
096: private Shape selectedFeaturesShape;
097: private GeometryFactory geometryFactory = new GeometryFactory();
098: private boolean valuesWereSet = false;
099: private double radius = 50.0; //in m
100: private Point mp = null;
101: private int points = 8;
102: private double tolerance = 0.1;
103: private int deactivateCount = 0;
104: //private String T1 = "Circle Radius";
105: private String T1 = I18N
106: .get("org.openjump.core.ui.plugin.edittoolbox.cursortools.DrawCircleWithGivenRadiusTool.Cirlce-Radius")
107: + ":";
108: //private String T2 = "Number of segments per circle quarter";
109: private String T2 = I18N
110: .get("org.openjump.core.ui.plugin.edittoolbox.cursortools.DrawCircleWithGivenRadiusTool.Number-of-segments-per-circle-quarter")
111: + ":";
112: //private String name = "Draw circle with given radius and center.";
113: private String name = I18N
114: .get("org.openjump.core.ui.plugin.edittoolbox.cursortools.DrawCircleWithGivenRadiusTool.Draw-circle-with-given-radius-and-center");
115: //private String sidebarstring = "Draws a circle by specifiying the radius, the number of segments per circle quarter and the center position by mouse click";
116: //private String sidebarstring = I18N.get("org.openjump.core.ui.plugin.edittoolbox.cursortools.DrawCircleWithGivenRadiusTool.Draws-a-circle-by-specifiying-the-radius-the-number-of-segments-per-circle-quarter-and-the-centre-position-by-mouse-click");
117: private String sidebarstring = I18N
118: .get("org.openjump.core.ui.plugin.edittoolbox.cursortools.DrawCircleWithGivenRadiusTool.Draws-a-circle-by-specifiying-the-radius-and-the-circle-accuracy-and-the-centre-position-by-mouse-click");
119: private String sAccuracy = I18N
120: .get("org.openjump.core.ui.plugin.edittoolbox.cursortools.DrawCircleWithGivenRadiusTool.Circle-Accuracy");
121: private String sReset = I18N
122: .get("org.openjump.core.ui.plugin.edittoolbox.cursortools.DrawCircleWithGivenRadiusTool.too-small-tolerance-reset-to-300-segments");
123:
124: private DrawCircleWithGivenRadiusTool(
125: FeatureDrawingUtil featureDrawingUtil) {
126: super (1);
127: this .featureDrawingUtil = featureDrawingUtil;
128: setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT,
129: BasicStroke.JOIN_BEVEL, 0, new float[] { 3, 3 }, 0));
130: this .allowSnapping();
131:
132: }
133:
134: public static CursorTool create(
135: LayerNamePanelProxy layerNamePanelProxy) {
136: FeatureDrawingUtil featureDrawingUtil = new FeatureDrawingUtil(
137: layerNamePanelProxy);
138:
139: return featureDrawingUtil.prepare(
140: new DrawCircleWithGivenRadiusTool(featureDrawingUtil),
141: true);
142: }
143:
144: /****************** events ********************************/
145: protected void gestureFinished() throws Exception {
146: reportNothingToUndoYet();
147:
148: Point p = new GeometryFactory().createPoint(this
149: .getModelDestination());
150: this .mp = p;
151: //-- calculate number of points per quarter
152: double tmp = Math.acos((this .radius - this .tolerance)
153: / this .radius);
154: if (tmp != 0) {
155: int pts = (int) Math.floor((Math.PI / tmp) / 4.0);
156: if (pts < 3) {
157: pts = 3;
158: }
159: if (pts > 300) {
160: pts = 300;
161: AbstractCursorTool.workbenchFrame(this .getPanel())
162: .warnUser(sReset);
163: }
164: this .points = pts;
165: }
166: //-------------------
167: //points-1 = segments
168: Geometry circle = BufferOp.bufferOp(p, this .radius,
169: this .points - 1);
170: this .checkCircle(circle);
171:
172: if (circle instanceof Polygon) {
173: featureDrawingUtil.drawRing((Polygon) circle,
174: isRollingBackInvalidEdits(), this , getPanel());
175: }
176: }
177:
178: protected boolean checkCircle(Geometry circle)
179: throws NoninvertibleTransformException {
180: IsValidOp isValidOp = new IsValidOp(circle);
181:
182: if (!isValidOp.isValid()) {
183: getPanel().getContext().warnUser(
184: isValidOp.getValidationError().getMessage());
185:
186: if (getWorkbench().getBlackboard().get(
187: EditTransaction.ROLLING_BACK_INVALID_EDITS_KEY,
188: false)) {
189: return false;
190: }
191: }
192:
193: return true;
194: }
195:
196: public void activate(LayerViewPanel layerViewPanel) {
197: super .activate(layerViewPanel);
198: try {
199: if (this .valuesWereSet == false) {
200: this .makeDialogThings(layerViewPanel);
201: this .valuesWereSet = true;
202: }
203: Envelope viewportEnvelope = layerViewPanel.getViewport()
204: .getEnvelopeInModelCoordinates();
205: double x = viewportEnvelope.getMinX()
206: + viewportEnvelope.getWidth() / 2;
207: double y = viewportEnvelope.getMinY()
208: + viewportEnvelope.getHeight() / 2;
209: Coordinate initCoords = new Coordinate(x, y);
210: this .calcuateCircle(initCoords, layerViewPanel);
211: } catch (Exception e) {
212: //System.out.println("DrawCirclyByRadiusTool: Exception eaten");
213: System.out.println(e);
214: }
215: }
216:
217: public void deactivate() {
218: //System.out.println("deactivate");
219: super .deactivate();
220: this .deactivateCount = this .deactivateCount + 1;
221: if (this .deactivateCount == 2) {
222: this .valuesWereSet = false; //-- to show dialog if tool is again activated
223: this .deactivateCount = 0;
224: }
225: }
226:
227: public Cursor getCursor() {
228: return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
229: }
230:
231: public String getName() {
232: return name;
233: }
234:
235: public Icon getIcon() {
236: return new ImageIcon(getClass().getResource(
237: "DrawCircleByRadius.gif"));
238: }
239:
240: /**
241: * overwritten super method to show the circle on any mouse move
242: */
243: public void mouseMoved(MouseEvent e) {
244: try {
245: setViewDestination(e.getPoint());
246: redrawShape();
247: } catch (Throwable t) {
248: getPanel().getContext().handleThrowable(t);
249: }
250: }
251:
252: /****************** other methods ********************************/
253:
254: /**
255: * changed to get circle around mouse pointer
256: */
257: protected Shape getShape() {
258: this .calcuateCircle(this .modelDestination, this .getPanel());
259: return this .selectedFeaturesShape;
260: }
261:
262: /**
263: * called from constructor and by mouse move event<p>
264: * calculates a cirle around the mouse pointer and converts it to a java shape
265: * @param middlePoint coordinates of the circle
266: */
267: private void calcuateCircle(Coordinate middlePoint,
268: LayerViewPanel panel) {
269: //--calculate circle;
270: Point p = new GeometryFactory().createPoint(middlePoint);
271: this .mp = p;
272: Geometry buffer = p.buffer(this .radius);
273:
274: Geometry[] geomArray = new Geometry[1];
275: geomArray[0] = buffer;
276: GeometryCollection gc = geometryFactory
277: .createGeometryCollection(geomArray);
278: try {
279: this .selectedFeaturesShape = panel.getJava2DConverter()
280: .toShape(gc);
281: } catch (NoninvertibleTransformException e) {
282: System.out
283: .println("DrawCircleWithGivenRadiusTool:Exception "
284: + e);
285: }
286: }
287:
288: public boolean makeDialogThings(LayerViewPanel panel)
289: throws Exception {
290: LayerViewPanelContext context = (LayerViewPanelContext) panel
291: .getContext();
292: WorkbenchFrame fr = (WorkbenchFrame) (context);
293: MultiInputDialogWithoutCancel dialog = new MultiInputDialogWithoutCancel(
294: fr, getName(), true);
295: setDialogValues(dialog);
296: GUIUtil.centreOnWindow(dialog);
297: dialog.setVisible(true);
298: if (!dialog.wasOKPressed()) {
299: return false;
300: }
301: getDialogValues(dialog);
302: return true;
303: }
304:
305: private void setDialogValues(MultiInputDialogWithoutCancel dialog) {
306: dialog.setSideBarDescription(this .sidebarstring);
307: dialog.addDoubleField(T1, this .radius, 7, T1);
308: dialog.addDoubleField(this .sAccuracy, this .tolerance, 7,
309: this .sAccuracy);
310: }
311:
312: private void getDialogValues(MultiInputDialogWithoutCancel dialog) {
313: this .radius = dialog.getDouble(T1);
314: this .tolerance = dialog.getDouble(this .sAccuracy);
315: }
316:
317: //----------- from drag tool ------------//
318:
319: protected void setViewDestination(Point2D destination)
320: throws NoninvertibleTransformException {
321: this .setModelDestination(getPanel().getViewport()
322: .toModelCoordinate(destination));
323: }
324:
325: protected void setModelDestination(Coordinate destination) {
326: this.modelDestination = snap(destination);
327: }
328: }
|