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: * Copyright (C) 2003 Vivid Solutions
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: *
021: * For more information, contact:
022: *
023: * Vivid Solutions
024: * Suite #1A
025: * 2328 Government Street
026: * Victoria BC V8T 5G5
027: * Canada
028: *
029: * (250)385-6040
030: * www.vividsolutions.com
031: */
032:
033: package com.vividsolutions.jump.plugin.edit;
034:
035: import java.awt.*;
036: import java.util.*;
037: import java.util.List;
038:
039: import javax.swing.*;
040: import javax.swing.event.*;
041:
042: import com.vividsolutions.jump.I18N;
043: import com.vividsolutions.jump.geom.precision.*;
044: import com.vividsolutions.jts.geom.*;
045: import com.vividsolutions.jump.feature.*;
046: import com.vividsolutions.jump.task.*;
047: import com.vividsolutions.jump.util.*;
048: import com.vividsolutions.jump.workbench.*;
049: import com.vividsolutions.jump.workbench.model.*;
050: import com.vividsolutions.jump.workbench.plugin.*;
051: import com.vividsolutions.jump.workbench.ui.*;
052:
053: public class PrecisionReducerPlugIn extends ThreadedBasePlugIn {
054:
055: private static final double EXAMPLE_VALUE = 1234567.123123123123;
056:
057: private final static String LAYER = I18N
058: .get("ui.plugin.edit.PrecisionReducerPlugIn.Layer");
059: private final static String DECIMAL_PLACES = I18N
060: .get("ui.plugin.edit.PrecisionReducerPlugIn.Decimal-Places");
061: private final static String SCALE_FACTOR = I18N
062: .get("ui.plugin.edit.PrecisionReducerPlugIn.Scale-Factor");
063:
064: private MultiInputDialog dialog;
065: private JTextField decimalPlacesField;
066: private JTextField scaleFactorField;
067: private JLabel exampleLabel;
068: private String layerName;
069: private int decimalPlaces = 0;
070: private int scaleFactor = 1;
071:
072: public PrecisionReducerPlugIn() {
073: }
074:
075: /**
076: * Returns a very brief description of this task.
077: * @return the name of this task
078: */
079: public String getName() {
080: return I18N
081: .get("ui.plugin.edit.PrecisionReducerPlugIn.Precision-Reducer");
082: }
083:
084: public EnableCheck createEnableCheck(
085: WorkbenchContext workbenchContext) {
086: EnableCheckFactory checkFactory = new EnableCheckFactory(
087: workbenchContext);
088: return new MultiEnableCheck()
089: .add(
090: checkFactory
091: .createWindowWithLayerManagerMustBeActiveCheck())
092: .add(checkFactory.createAtLeastNLayersMustExistCheck(1))
093: .add(
094: checkFactory
095: .createAtLeastNLayersMustBeEditableCheck(1));
096: }
097:
098: public boolean execute(PlugInContext context) throws Exception {
099: dialog = new MultiInputDialog(context.getWorkbenchFrame(),
100: getName(), true);
101: setDialogValues(dialog, context);
102: GUIUtil.centreOnWindow(dialog);
103: dialog.setVisible(true);
104: if (!dialog.wasOKPressed()) {
105: return false;
106: }
107: getDialogValues(dialog);
108: return true;
109: }
110:
111: public void run(TaskMonitor monitor, PlugInContext context)
112: throws Exception {
113: monitor.allowCancellationRequests();
114:
115: monitor
116: .report(I18N
117: .get("ui.plugin.edit.PrecisionReducerPlugIn.Reducing-Precision")
118: + "...");
119:
120: Layer layer = dialog.getLayer(LAYER);
121: FeatureCollection fc = layer.getFeatureCollectionWrapper();
122:
123: List[] bad = reducePrecision(fc, monitor);
124: layer.fireAppearanceChanged();
125:
126: if (monitor.isCancelRequested())
127: return;
128:
129: if (bad[0].size() > 0) {
130: Layer lyr = context
131: .getLayerManager()
132: .addLayer(
133: StandardCategoryNames.QA,
134: I18N
135: .get("ui.plugin.edit.PrecisionReducerPlugIn.Invalid-Input-Geometries"),
136: FeatureDatasetFactory
137: .createFromGeometry(bad[0]));
138: LayerStyleUtil.setLinearStyle(lyr, Color.red, 2, 0);
139: lyr.fireAppearanceChanged();
140:
141: Layer lyr2 = context
142: .getLayerManager()
143: .addLayer(
144: StandardCategoryNames.QA,
145: I18N
146: .get("ui.plugin.edit.PrecisionReducerPlugIn.Invalid-Reduced-Geometries"),
147: FeatureDatasetFactory
148: .createFromGeometry(bad[1]));
149: lyr2.getBasicStyle().setFillColor(ColorUtil.GOLD);
150: lyr2.getBasicStyle().setLineColor(
151: Layer.defaultLineColor(ColorUtil.GOLD));
152: lyr2.fireAppearanceChanged();
153: }
154: }
155:
156: private NumberPrecisionReducer createNumberPrecisionReducer() {
157: double sf = scaleFactor;
158: // scaleFactor and decimalPlaces should be in synch, but if they are not use decimalPlaces
159: if (scaleFactor != NumberPrecisionReducer
160: .scaleFactorForDecimalPlaces(decimalPlaces))
161: sf = NumberPrecisionReducer
162: .scaleFactorForDecimalPlaces(decimalPlaces);
163:
164: return new NumberPrecisionReducer(sf);
165: }
166:
167: /**
168: * @return an array of two Lists.
169: * The first contains the geometries which reduced to invalid geometries.
170: * The second contains the invalid geometries created
171: */
172: private List[] reducePrecision(FeatureCollection fc,
173: TaskMonitor monitor) {
174: List[] bad = { new ArrayList(), new ArrayList() };
175: int total = fc.size();
176: int count = 0;
177: for (Iterator i = fc.iterator(); i.hasNext();) {
178: monitor
179: .report(
180: count++,
181: total,
182: I18N
183: .get("ui.plugin.edit.PrecisionReducerPlugIn.features"));
184:
185: Feature f = (Feature) i.next();
186: Geometry g = f.getGeometry();
187: Geometry g2 = (Geometry) g.clone();
188: GeometryPrecisionReducer pr = new GeometryPrecisionReducer(
189: createNumberPrecisionReducer());
190: pr.reduce(g2);
191: if (g2.isValid()) {
192: f.setGeometry(g2);
193: } else {
194: bad[0].add(g.clone());
195: bad[1].add(g2);
196: }
197: }
198: return bad;
199: }
200:
201: private void setDialogValues(MultiInputDialog dialog,
202: PlugInContext context) {
203: dialog.setSideBarImage(new ImageIcon(getClass().getResource(
204: "PrecisionReducer.png")));
205: dialog
206: .setSideBarDescription(I18N
207: .get("ui.plugin.edit.PrecisionReducerPlugIn.Reduces-the-precision-of-the-coordinates-in-a-layer"));
208: String fieldName = LAYER;
209: JComboBox addLayerComboBox = dialog.addLayerComboBox(fieldName,
210: context.getCandidateLayer(0), null, context
211: .getLayerManager());
212:
213: scaleFactorField = dialog
214: .addIntegerField(
215: SCALE_FACTOR,
216: scaleFactor,
217: 8,
218: I18N
219: .get("ui.plugin.edit.PrecisionReducerPlugIn.The-scale-factor-to-multiply-by-before-rounding-(-Negative-for-left-of-decimal-point-,-0-if-not-used-)"));
220: scaleFactorField.getDocument().addDocumentListener(
221: new ScaleFactorDocumentListener());
222:
223: decimalPlacesField = dialog
224: .addIntegerField(
225: DECIMAL_PLACES,
226: decimalPlaces,
227: 4,
228: I18N
229: .get("ui.plugin.edit.PrecisionReducerPlugIn.The-number-of-decimal-places-to-round-to-(-Negative-for-left-of-decimal-point-)"));
230: decimalPlacesField.getDocument().addDocumentListener(
231: new DecimalPlacesDocumentListener());
232:
233: dialog.addLabel("");
234: dialog.addLabel(I18N
235: .get("ui.plugin.edit.PrecisionReducerPlugIn.Example")
236: + " " + EXAMPLE_VALUE);
237: exampleLabel = dialog.addLabel("");
238:
239: updateExample();
240: }
241:
242: private int parseValidInt(String text) {
243: int i = 0;
244: try {
245: i = Integer.parseInt(text);
246: } catch (NumberFormatException ex) {
247: // leave decPlaces value as 0
248: }
249: return i;
250: }
251:
252: private void decimalPlacesChanged() {
253: decimalPlaces = parseValidInt(decimalPlacesField.getText());
254: double sf = NumberPrecisionReducer
255: .scaleFactorForDecimalPlaces(decimalPlaces);
256: scaleFactorField.setText("" + (int) sf);
257: updateExample();
258: }
259:
260: private void scaleFactorChanged() {
261: scaleFactor = parseValidInt(scaleFactorField.getText());
262: // can't update decimalPlaces because it will cause an event cycle
263: //decimalPlacesField.setText("");
264: updateExample();
265: }
266:
267: private void updateExample() {
268: NumberPrecisionReducer cpr = new NumberPrecisionReducer(
269: scaleFactor);
270: double exampleOutput = cpr.reducePrecision(EXAMPLE_VALUE);
271: exampleLabel.setText(" ==> " + exampleOutput);
272: }
273:
274: private void getDialogValues(MultiInputDialog dialog) {
275: Layer layer = dialog.getLayer(LAYER);
276: layerName = layer.getName();
277: decimalPlaces = dialog.getInteger(DECIMAL_PLACES);
278: scaleFactor = dialog.getInteger(SCALE_FACTOR);
279: }
280:
281: class DecimalPlacesDocumentListener implements DocumentListener {
282: public void insertUpdate(DocumentEvent e) {
283: decimalPlacesChanged();
284: }
285:
286: public void removeUpdate(DocumentEvent e) {
287: decimalPlacesChanged();
288: }
289:
290: public void changedUpdate(DocumentEvent e) {
291: decimalPlacesChanged();
292: }
293: }
294:
295: class ScaleFactorDocumentListener implements DocumentListener {
296: public void insertUpdate(DocumentEvent e) {
297: scaleFactorChanged();
298: }
299:
300: public void removeUpdate(DocumentEvent e) {
301: scaleFactorChanged();
302: }
303:
304: public void changedUpdate(DocumentEvent e) {
305: scaleFactorChanged();
306: }
307: }
308:
309: }
|