001: package net.refractions.udig.tool.info;
002:
003: import java.awt.Color;
004: import java.awt.Point;
005: import java.awt.Rectangle;
006: import java.util.ArrayList;
007: import java.util.Iterator;
008: import java.util.List;
009:
010: import net.refractions.udig.project.ui.commands.AbstractDrawCommand;
011: import net.refractions.udig.project.ui.render.displayAdapter.MapMouseEvent;
012: import net.refractions.udig.project.ui.tool.SimpleTool;
013: import net.refractions.udig.tool.info.internal.Messages;
014:
015: import org.eclipse.core.runtime.IProgressMonitor;
016: import org.eclipse.jface.action.IStatusLineManager;
017: import org.geotools.geometry.jts.JTS;
018: import org.opengis.referencing.operation.TransformException;
019:
020: import com.vividsolutions.jts.geom.Coordinate;
021:
022: public class DistanceTool extends SimpleTool {
023: public DistanceTool() {
024: super (MOUSE | MOTION);
025: }
026:
027: List<Point> points = new ArrayList<Point>();
028: DistanceFeedbackCommand command;
029: private Point now;
030:
031: @Override
032: protected void onMouseMoved(MapMouseEvent e) {
033: now = e.getPoint();
034: if (command == null || points.isEmpty())
035: return;
036: Rectangle area = command.getValidArea();
037: if (area != null)
038: getContext().getViewportPane().repaint(area.x, area.y,
039: area.width, area.height);
040: else {
041: getContext().getViewportPane().repaint();
042: }
043: }
044:
045: public void onMouseReleased(MapMouseEvent e) {
046: Point current = e.getPoint();
047: if (points.isEmpty()
048: || !current.equals(points.get(points.size() - 1)))
049: points.add(current);
050: if (command == null || !command.isValid()) {
051: command = new DistanceFeedbackCommand();
052: getContext().sendASyncCommand(command);
053: }
054: }
055:
056: @Override
057: protected void onMouseDoubleClicked(MapMouseEvent e) {
058: disposeCommand();
059: displayResult();
060: points.clear();
061: }
062:
063: /**
064: *
065: */
066: private void disposeCommand() {
067: if (command != null) {
068: command.setValid(false);
069: Rectangle area = command.getValidArea();
070: if (area != null)
071: getContext().getViewportPane().repaint(area.x, area.y,
072: area.width, area.height);
073: else {
074: getContext().getViewportPane().repaint();
075: }
076: command = null;
077: }
078: }
079:
080: private void displayResult() {
081: try {
082: double distance = distance();
083: displayOnStatusBar(distance);
084: } catch (Exception e1) {
085: InfoPlugin.log("", e1); //$NON-NLS-1$
086: displayError();
087: }
088: }
089:
090: @Override
091: public void setActive(boolean active) {
092: super .setActive(active);
093: final IStatusLineManager statusBar = getContext()
094: .getActionBars().getStatusLineManager();
095:
096: disposeCommand();
097:
098: if (statusBar == null)
099: return; // shouldn't happen if the tool is being used.
100: getContext().updateUI(new Runnable() {
101: public void run() {
102: statusBar.setErrorMessage(null);
103: statusBar.setMessage(null);
104: }
105: });
106: }
107:
108: private double distance() throws TransformException {
109: if (points.isEmpty())
110: return 0;
111: Iterator<Point> iter = points.iterator();
112: Point start = iter.next();
113: double distance = 0;
114: while (iter.hasNext()) {
115: Point current = iter.next();
116: Coordinate begin = getContext().pixelToWorld(start.x,
117: start.y);
118: Coordinate end = getContext().pixelToWorld(current.x,
119: current.y);
120: distance += JTS.orthodromicDistance(begin, end,
121: getContext().getCRS());
122: start = current;
123: }
124:
125: if (now != null) {
126: Point current = now;
127: Coordinate begin = getContext().pixelToWorld(start.x,
128: start.y);
129: Coordinate end = getContext().pixelToWorld(current.x,
130: current.y);
131: distance += JTS.orthodromicDistance(begin, end,
132: getContext().getCRS());
133: start = current;
134: }
135: return distance;
136: }
137:
138: private void displayError() {
139: final IStatusLineManager statusBar = getContext()
140: .getActionBars().getStatusLineManager();
141:
142: if (statusBar == null)
143: return; // shouldn't happen if the tool is being used.
144:
145: getContext().updateUI(new Runnable() {
146: public void run() {
147: statusBar.setErrorMessage(Messages.DistanceTool_error);
148: }
149: });
150: }
151:
152: private void displayOnStatusBar(double distance) {
153: final IStatusLineManager statusBar = getContext()
154: .getActionBars().getStatusLineManager();
155:
156: if (statusBar == null)
157: return; // shouldn't happen if the tool is being used.
158: final String message = createMessage(distance);
159: getContext().updateUI(new Runnable() {
160: public void run() {
161: statusBar.setErrorMessage(null);
162: statusBar.setMessage(message);
163: }
164: });
165: }
166:
167: /**
168: * @param distance
169: * @return
170: */
171: private String createMessage(double distance) {
172: String message = Messages.DistanceTool_distance;
173:
174: if (distance > 100000.0) {
175: message = message.concat((int) (distance / 1000.0) + "km"); //$NON-NLS-1$
176: } else if (distance > 10000.0) { //km + m
177: message = message
178: .concat(round(distance / 1000.0, 1) + "km"); //$NON-NLS-1$
179: } else if (distance > 1000.0) { //km + m
180: message = message
181: .concat(round(distance / 1000.0, 2) + "km"); //$NON-NLS-1$
182: } else if (distance > 100.0) { //m
183: message = message.concat(round(distance, 1) + "m"); //$NON-NLS-1$
184: } else if (distance > 1.0) { //m
185: message = message.concat(round(distance, 2) + "m"); //$NON-NLS-1$
186: } else { //mm
187: message = message
188: .concat(round(distance * 1000.0, 1) + "mm"); //$NON-NLS-1$
189: }
190:
191: return message;
192: }
193:
194: /**
195: * Truncates a double to the given number of decimal places. Note:
196: * truncation at zero decimal places will still show up as x.0, since we're
197: * using the double type.
198: *
199: * @param value
200: * number to round-off
201: * @param decimalPlaces
202: * number of decimal places to leave
203: * @return the rounded value
204: */
205: private double round(double value, int decimalPlaces) {
206: double divisor = Math.pow(10, decimalPlaces);
207: double newVal = value * divisor;
208: newVal = (Long.valueOf(Math.round(newVal)).intValue())
209: / divisor;
210: return newVal;
211: }
212:
213: class DistanceFeedbackCommand extends AbstractDrawCommand {
214:
215: public Rectangle getValidArea() {
216: return null;
217: }
218:
219: public void run(IProgressMonitor monitor) throws Exception {
220: if (points.isEmpty())
221: return;
222: graphics.setColor(Color.BLACK);
223: Iterator<Point> iter = points.iterator();
224: Point start = iter.next();
225: while (iter.hasNext()) {
226: Point current = iter.next();
227: graphics.drawLine(start.x, start.y, current.x,
228: current.y);
229: start = current;
230: }
231: if (start == null || now == null)
232: return;
233: graphics.drawLine(start.x, start.y, now.x, now.y);
234:
235: displayResult();
236: }
237:
238: }
239:
240: public void reset() {
241: points.clear();
242: if (command != null) {
243: command.setValid(false);
244: Rectangle area = command.getValidArea();
245: if (area != null)
246: getContext().getViewportPane().repaint(area.x, area.y,
247: area.width, area.height);
248: else {
249: getContext().getViewportPane().repaint();
250: }
251: command = null;
252: }
253: }
254: }
|