source: subversion/applications/editors/josm/plugins/measurement/src/org/openstreetmap/josm/plugins/measurement/MeasurementDialog.java

Last change on this file was 34529, checked in by donvip, 8 months ago

update to JOSM 14153

  • Property svn:eol-style set to native
File size: 11.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.plugins.measurement;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Dimension;
7import java.awt.GridLayout;
8import java.awt.event.ActionEvent;
9import java.awt.event.KeyEvent;
10import java.text.DecimalFormat;
11import java.util.Arrays;
12import java.util.Collection;
13
14import javax.swing.AbstractAction;
15import javax.swing.JLabel;
16import javax.swing.JPanel;
17
18import org.openstreetmap.josm.data.SystemOfMeasurement;
19import org.openstreetmap.josm.data.SystemOfMeasurement.SoMChangeListener;
20import org.openstreetmap.josm.data.osm.DataSelectionListener;
21import org.openstreetmap.josm.data.osm.DataSet;
22import org.openstreetmap.josm.data.osm.Node;
23import org.openstreetmap.josm.data.osm.OsmPrimitive;
24import org.openstreetmap.josm.data.osm.Way;
25import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
26import org.openstreetmap.josm.data.osm.event.DataChangedEvent;
27import org.openstreetmap.josm.data.osm.event.DataSetListener;
28import org.openstreetmap.josm.data.osm.event.NodeMovedEvent;
29import org.openstreetmap.josm.data.osm.event.PrimitivesAddedEvent;
30import org.openstreetmap.josm.data.osm.event.PrimitivesRemovedEvent;
31import org.openstreetmap.josm.data.osm.event.RelationMembersChangedEvent;
32import org.openstreetmap.josm.data.osm.event.SelectionEventManager;
33import org.openstreetmap.josm.data.osm.event.TagsChangedEvent;
34import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
35import org.openstreetmap.josm.gui.MainApplication;
36import org.openstreetmap.josm.gui.SideButton;
37import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
38import org.openstreetmap.josm.gui.help.HelpUtil;
39import org.openstreetmap.josm.gui.util.GuiHelper;
40import org.openstreetmap.josm.tools.ImageProvider;
41import org.openstreetmap.josm.tools.Shortcut;
42import org.openstreetmap.josm.tools.SubclassFilteredCollection;
43
44/**
45 * A small tool dialog for displaying the current measurement data.
46 *
47 * @author ramack
48 */
49public class MeasurementDialog extends ToggleDialog implements DataSelectionListener, DataSetListener, SoMChangeListener {
50    private static final long serialVersionUID = 4708541586297950021L;
51
52    /**
53     * The reset button
54     */
55    private SideButton resetButton;
56
57    /**
58     * The measurement label for the path length
59     */
60    protected JLabel pathLengthLabel;
61
62    /**
63     * The measurement label for the currently selected segments
64     */
65    protected JLabel selectLengthLabel;
66
67    /**
68     * The measurement label for area of the currently selected loop
69     */
70    protected JLabel selectAreaLabel;
71
72    /**
73     * The measurement label for radius if the currently selected loop is a circle.
74     */
75    protected JLabel selectRadiusLabel;
76
77    /**
78     * The measurement label for the segment angle, actually updated, if 2 nodes are selected
79     */
80    protected JLabel segAngleLabel;
81
82    private DataSet ds;
83
84    private Collection<Way> ways;
85    private Collection<Node> nodes;
86
87    /**
88     * Constructor
89     */
90    public MeasurementDialog()
91    {
92        super(tr("Measured values"), "measure", tr("Open the measurement window."),
93                Shortcut.registerShortcut("subwindow:measurement", tr("Toggle: {0}", tr("Measured values")),
94                        KeyEvent.VK_U, Shortcut.CTRL_SHIFT), 150);
95
96        resetButton = new SideButton(new AbstractAction() {
97            {
98                putValue(NAME, tr("Reset"));
99                new ImageProvider("dialogs", "select").getResource().attachImageIcon(this, true);
100                putValue(SHORT_DESCRIPTION, tr("Reset current measurement results and delete measurement path."));
101                putValue("help", HelpUtil.ht("/Dialog/Measurement#Reset"));
102            }
103            @Override
104            public void actionPerformed(ActionEvent e)
105            {
106                resetValues();
107            }
108        });
109
110        JPanel valuePanel = new JPanel(new GridLayout(0,2));
111
112        valuePanel.add(new JLabel(tr("Path Length")));
113
114        pathLengthLabel = new JLabel(getDistText(0));
115        valuePanel.add(pathLengthLabel);
116
117        valuePanel.add(new JLabel(tr("Selection Length")));
118
119        selectLengthLabel = new JLabel(getDistText(0));
120        valuePanel.add(selectLengthLabel);
121
122        valuePanel.add(new JLabel(tr("Selection Area")));
123
124        selectAreaLabel = new JLabel(getAreaText(0));
125        valuePanel.add(selectAreaLabel);
126
127        valuePanel.add(new JLabel(tr("Selection Radius")));
128
129        selectRadiusLabel = new JLabel(getRadiusText(0));
130        valuePanel.add(selectRadiusLabel);
131
132        JLabel angle = new JLabel(tr("Angle"));
133        angle.setToolTipText(tr("Angle between two selected Nodes"));
134        valuePanel.add(angle);
135
136        segAngleLabel = new JLabel("- \u00b0");
137        valuePanel.add(segAngleLabel);
138
139        this.setPreferredSize(new Dimension(0, 92));
140
141        createLayout(valuePanel, false, Arrays.asList(new SideButton[] {
142                resetButton
143        }));
144
145        SelectionEventManager.getInstance().addSelectionListener(this);
146        SystemOfMeasurement.addSoMChangeListener(this);
147    }
148
149    protected String getDistText(double v) {
150        return SystemOfMeasurement.getSystemOfMeasurement().getDistText(v, new DecimalFormat("#0.000"), 1e-3);
151    }
152
153    protected String getAreaText(double v) {
154        return SystemOfMeasurement.getSystemOfMeasurement().getAreaText(v, new DecimalFormat("#0.000"), 1e-3);
155    }
156
157    protected String getRadiusText(double v) {
158        return SystemOfMeasurement.getSystemOfMeasurement().getDistText(v, new DecimalFormat("#0.000"), 1e-3);
159    }
160
161    protected String getAngleText(double v) {
162        return new DecimalFormat("#0.0").format(v) + " \u00b0";
163    }
164
165    /**
166     * Cleans the active Measurement Layer
167     */
168    public void resetValues(){
169        MeasurementPlugin.getCurrentLayer().reset();
170    }
171
172    @Override
173    public void selectionChanged(SelectionChangeEvent event) {
174        refresh(event.getSelection());
175    }
176
177    private void refresh(Collection<? extends OsmPrimitive> selection) {
178        double length = 0.0;
179        double segAngle = 0.0;
180        double area = 0.0;
181        double radius = 0.0;
182        Node lastNode = null;
183        // Don't mix up way and nodes computation (fix #6872). Priority given to ways
184        ways = new SubclassFilteredCollection<>(selection, Way.class::isInstance);
185        if (ways.isEmpty()) {
186            nodes = new SubclassFilteredCollection<>(selection, Node.class::isInstance);
187            for (Node n : nodes) {
188                if (n.getCoor() != null) {
189                    if (lastNode == null) {
190                        lastNode = n;
191                    } else {
192                        length += lastNode.getCoor().greatCircleDistance(n.getCoor());
193                        segAngle = MeasurementLayer.angleBetween(lastNode.getCoor(), n.getCoor());
194                        lastNode = n;
195                    }
196                }
197            }
198        } else {
199            nodes = null;
200            for (Way w : ways) {
201                Node lastN = null;
202                double wayArea = 0.0;
203                Double firstSegLength = null;
204                boolean isCircle = true;
205                for (Node n: w.getNodes()) {
206                    if (lastN != null && lastN.getCoor() != null && n.getCoor() != null) {
207                        final double segLength = lastN.getCoor().greatCircleDistance(n.getCoor());
208                        if (firstSegLength == null) {
209                            firstSegLength = segLength;
210                        }
211                        if (isCircle && Math.abs(firstSegLength - segLength) > 0.000001) {
212                            isCircle = false;
213                        }
214                        length += segLength;
215                        //http://local.wasp.uwa.edu.au/~pbourke/geometry/polyarea/
216                        wayArea += (MeasurementLayer.calcX(n.getCoor()) * MeasurementLayer.calcY(lastN.getCoor()))
217                                - (MeasurementLayer.calcY(n.getCoor()) * MeasurementLayer.calcX(lastN.getCoor()));
218                        segAngle = MeasurementLayer.angleBetween(lastN.getCoor(), n.getCoor());
219                    }
220                    lastN = n;
221                }
222                if (lastN != null && lastN.equals(w.getNodes().iterator().next()))
223                    wayArea = Math.abs(wayArea / 2);
224                else
225                    wayArea = 0;
226                area += wayArea;
227            }
228            if (ways.size() == 1 && area > 0.0) {
229                radius = length / (2 * Math.PI);
230            }
231        }
232
233        final String lengthLabel = getDistText(length);
234        final String angleLabel = getAngleText(segAngle);
235        final String areaLabel = getAreaText(area);
236        final String radiusLabel = getRadiusText(radius);
237
238        GuiHelper.runInEDT(new Runnable() {
239            @Override
240            public void run() {
241                selectLengthLabel.setText(lengthLabel);
242                segAngleLabel.setText(angleLabel);
243                selectAreaLabel.setText(areaLabel);
244                selectRadiusLabel.setText(radiusLabel);
245            }
246        });
247
248        DataSet currentDs = MainApplication.getLayerManager().getEditDataSet();
249
250        if (ds != currentDs) {
251            if (ds != null) {
252                ds.removeDataSetListener(this);
253            }
254            if (currentDs != null) {
255                currentDs.addDataSetListener(this);
256            }
257            ds = currentDs;
258        }
259    }
260
261    @Override
262    public void destroy() {
263        super.destroy();
264        SystemOfMeasurement.removeSoMChangeListener(this);
265        SelectionEventManager.getInstance().removeSelectionListener(this);
266        if (ds != null) {
267            ds.removeDataSetListener(this);
268            ds = null;
269        }
270    }
271
272    private boolean waysContain(Node n) {
273        if (ways != null) {
274            for (Way w : ways) {
275                if (w.containsNode(n)) {
276                    return true;
277                }
278            }
279        }
280        return false;
281    }
282
283    @Override public void nodeMoved(NodeMovedEvent event) {
284        Node n = event.getNode();
285        // Refresh selection if a node belonging to a selected member has moved (example: scale action)
286        if ((nodes != null && nodes.contains(n)) || waysContain(n)) {
287            refresh(event.getDataset().getSelected());
288        }
289    }
290
291    @Override public void wayNodesChanged(WayNodesChangedEvent event) {
292        if (ways.contains(event.getChangedWay())) {
293            refresh(event.getDataset().getSelected());
294        }
295    }
296
297    @Override public void primitivesAdded(PrimitivesAddedEvent event) {}
298    @Override public void primitivesRemoved(PrimitivesRemovedEvent event) {}
299    @Override public void tagsChanged(TagsChangedEvent event) {}
300    @Override public void relationMembersChanged(RelationMembersChangedEvent event) {}
301    @Override public void otherDatasetChange(AbstractDatasetChangedEvent event) {}
302    @Override public void dataChanged(DataChangedEvent event) {}
303
304    @Override
305    public void systemOfMeasurementChanged(String oldSoM, String newSoM) {
306        // Refresh selection to take into account new system of measurement
307        DataSet currentDs = MainApplication.getLayerManager().getEditDataSet();
308        if (currentDs != null) {
309            refresh(currentDs.getSelected());
310        }
311    }
312}
Note: See TracBrowser for help on using the repository browser.