/* * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI * for visualizing and manipulating spatial features with geometry and attributes. * * JUMP is Copyright (C) 2003 Vivid Solutions * * This program implements extensions to JUMP and is * Copyright (C) 2004 Integrated Systems Analysts, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * For more information, contact: * * Integrated Systems Analysts, Inc. * 630C Anchors St., Suite 101 * Fort Walton Beach, Florida * USA * * (850)862-7321 */ package org.openjump.core.ui.plugin.edittoolbox.cursortools; import java.awt.Shape; import java.awt.geom.GeneralPath; import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.Point2D; import java.util.ArrayList; import javax.swing.Icon; import javax.swing.ImageIcon; import org.openjump.core.geomutils.Circle; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Polygon; import com.vividsolutions.jts.operation.valid.IsValidOp; import com.vividsolutions.jump.I18N; import com.vividsolutions.jump.workbench.ui.EditTransaction; import com.vividsolutions.jump.workbench.ui.LayerNamePanelProxy; import com.vividsolutions.jump.workbench.ui.cursortool.CursorTool; import com.vividsolutions.jump.workbench.ui.cursortool.editing.FeatureDrawingUtil; public class DrawConstrainedCircleTool extends ConstrainedMultiClickTool { private FeatureDrawingUtil featureDrawingUtil; final static String drawConstrainedCircle =I18N.get("org.openjump.core.ui.plugin.edittoolbox.cursortools.DrawConstrainedCircleTool.Draw-Constrained-Circle"); final static String theCircleMustHaveAtLeast2Points=I18N.get("org.openjump.core.ui.plugin.edittoolbox.cursortools.DrawConstrainedCircleTool.The-circle-must-have-at-least-2-points"); private DrawConstrainedCircleTool(FeatureDrawingUtil featureDrawingUtil) { drawClosed = true; this.featureDrawingUtil = featureDrawingUtil; } public static CursorTool create(LayerNamePanelProxy layerNamePanelProxy) { FeatureDrawingUtil featureDrawingUtil = new FeatureDrawingUtil(layerNamePanelProxy); return featureDrawingUtil.prepare(new DrawConstrainedCircleTool( featureDrawingUtil), true); } public String getName() { return drawConstrainedCircle; } public Icon getIcon() { return new ImageIcon(getClass().getResource("DrawCircleConstrained.gif")); } protected void gestureFinished() throws Exception { reportNothingToUndoYet(); if (!checkCircle()) { return; } execute(featureDrawingUtil.createAddCommand(getCircle(), isRollingBackInvalidEdits(), getPanel(), this)); } protected Polygon getCircle() throws NoninvertibleTransformException { // Subject 1.04: How do I generate a circle through three points? // // Let the three given points be a, b, c. Use _0 and _1 to represent // x and y coordinates. The coordinates of the center p=(p_0,p_1) of // the circle determined by a, b, and c are: // // A = b_0 - a_0; // B = b_1 - a_1; // C = c_0 - a_0; // D = c_1 - a_1; // // E = A*(a_0 + b_0) + B*(a_1 + b_1); // F = C*(a_0 + c_0) + D*(a_1 + c_1); // // G = 2.0*(A*(c_1 - b_1)-B*(c_0 - b_0)); // // p_0 = (D*E - B*F) / G; // p_1 = (A*F - C*E) / G; // // If G is zero then the three points are collinear and no finite-radius // circle through them exists. Otherwise, the radius of the circle is: // // r^2 = (a_0 - p_0)^2 + (a_1 - p_1)^2 // // Reference: // [O' Rourke (C)] p. 201. Simplified by Jim Ward. double angle = 360.0; ArrayList points = new ArrayList(getCoordinates()); if (getCoordinates().size() == 2) { Circle circle = new Circle((Coordinate) points.get(0), ((Coordinate) points.get(0)).distance((Coordinate) points.get(1))); return circle.getPoly(); } else { Coordinate a = (Coordinate) points.get(0); Coordinate b = (Coordinate) points.get(1); Coordinate c = (Coordinate) points.get(2); return getCircle3points(a, b, c); } } private Polygon getCircle3points(Coordinate a, Coordinate b, Coordinate c){ double A = b.x - a.x; double B = b.y - a.y; double C = c.x - a.x; double D = c.y - a.y; double E = A * (a.x + b.x) + B * (a.y + b.y); double F = C * (a.x + c.x) + D * (a.y + c.y); double G = 2.0 * (A * (c.y - b.y ) - B * (c.x - b.x)); if (G != 0.0) { double px = (D * E - B * F) / G; double py = (A * F - C * E) / G; Coordinate center = new Coordinate(px, py); double radius = Math.sqrt((a.x - px) * (a.x - px) + (a.y - py) * (a.y - py)); Circle circle = new Circle(center, radius); return circle.getPoly(); } else //points are colinear; use second for center; third for the radius { Circle circle = new Circle(b, (b).distance(c)); return circle.getPoly(); } } protected boolean checkCircle() throws NoninvertibleTransformException { if (getCoordinates().size() < 2) { getPanel().getContext().warnUser(theCircleMustHaveAtLeast2Points); return false; } IsValidOp isValidOp = new IsValidOp(getCircle()); if (!isValidOp.isValid()) { getPanel().getContext().warnUser(isValidOp.getValidationError() .getMessage()); if (getWorkbench().getBlackboard().get(EditTransaction.ROLLING_BACK_INVALID_EDITS_KEY, false)) { return false; } } return true; } /* * (non-Javadoc) * @see com.vividsolutions.jump.workbench.ui.cursortool.AbstractCursorTool#getShape() */ protected Shape getShape() throws NoninvertibleTransformException { if (coordinates.size() > 1) { GeneralPath shape = new GeneralPath(); Coordinate a = (Coordinate) coordinates.get(0); Coordinate b = (Coordinate) coordinates.get(1); Coordinate c = tentativeCoordinate; Polygon polygon = getCircle3points(a, b, c); Coordinate[] polygonCoordinates = polygon.getCoordinates(); Coordinate firstCoordinate = (Coordinate) polygonCoordinates[0]; Point2D firstPoint = getPanel().getViewport().toViewPoint(firstCoordinate); shape.moveTo((float) firstPoint.getX(), (float) firstPoint.getY()); for (int i = 1, n = polygonCoordinates.length; i < n; i++) { Point2D nextPoint = getPanel().getViewport().toViewPoint( polygonCoordinates[i]); shape.lineTo((int) nextPoint.getX(), (int) nextPoint.getY()); } return shape; } return super.getShape(); } }