001: /* uDig - User Friendly Desktop Internet GIS client
002: * http://udig.refractions.net
003: * (C) 2004, Refractions Research Inc.
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation;
008: * version 2.1 of the License.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: */
015: package net.refractions.udig.tool.edit;
016:
017: import java.io.File;
018: import java.io.IOException;
019: import java.util.List;
020: import java.util.NoSuchElementException;
021:
022: import net.refractions.udig.catalog.CatalogPlugin;
023: import net.refractions.udig.catalog.IGeoResource;
024: import net.refractions.udig.catalog.IService;
025: import net.refractions.udig.project.ILayer;
026: import net.refractions.udig.project.internal.Layer;
027: import net.refractions.udig.project.internal.LayerFactory;
028: import net.refractions.udig.project.internal.Map;
029: import net.refractions.udig.tool.edit.internal.Messages;
030: import net.refractions.udig.ui.PlatformGIS;
031: import net.refractions.udig.ui.operations.IOp;
032:
033: import org.eclipse.core.runtime.IProgressMonitor;
034: import org.eclipse.jface.dialogs.Dialog;
035: import org.eclipse.jface.dialogs.MessageDialog;
036: import org.eclipse.jface.window.Window;
037: import org.eclipse.swt.SWT;
038: import org.eclipse.swt.events.SelectionEvent;
039: import org.eclipse.swt.events.SelectionListener;
040: import org.eclipse.swt.layout.GridData;
041: import org.eclipse.swt.layout.GridLayout;
042: import org.eclipse.swt.widgets.Combo;
043: import org.eclipse.swt.widgets.Composite;
044: import org.eclipse.swt.widgets.Control;
045: import org.eclipse.swt.widgets.Display;
046: import org.eclipse.swt.widgets.Label;
047: import org.eclipse.swt.widgets.Shell;
048: import org.geotools.data.DataStore;
049: import org.geotools.data.FeatureReader;
050: import org.geotools.data.FeatureSource;
051: import org.geotools.data.FeatureStore;
052: import org.geotools.data.shapefile.indexed.IndexedShapefileDataStoreFactory;
053: import org.geotools.feature.Feature;
054: import org.geotools.feature.FeatureCollection;
055: import org.geotools.feature.FeatureCollections;
056: import org.geotools.feature.FeatureIterator;
057: import org.geotools.feature.FeatureType;
058: import org.geotools.feature.FeatureTypes;
059: import org.geotools.feature.GeometryAttributeType;
060: import org.geotools.feature.IllegalAttributeException;
061:
062: import com.vividsolutions.jts.geom.Geometry;
063: import com.vividsolutions.jts.geom.LineString;
064: import com.vividsolutions.jts.geom.Polygon;
065:
066: /**
067: * Cuts the polygons in layer 1 out of the polygons in layer 2.
068: *
069: * @author jones
070: * @since 1.1.0
071: */
072: public class DifferenceOp implements IOp {
073:
074: @SuppressWarnings("unchecked")
075: public void op(final Display display, Object target,
076: IProgressMonitor monitor) throws Exception {
077: final ILayer[] layers = (ILayer[]) target;
078: final int[] value = new int[1];
079: final ILayer[] from = new ILayer[1];
080: final ILayer[] diff = new ILayer[1];
081: PlatformGIS.syncInDisplayThread(new Runnable() {
082: public void run() {
083: LayerSelection selection = new LayerSelection(display
084: .getActiveShell(), layers);
085: value[0] = selection.open();
086: from[0] = selection.fromLayer;
087: diff[0] = selection.diffLayer;
088: }
089: });
090: if (value[0] == Window.CANCEL)
091: return;
092: ILayer fromLayer = from[0];
093: ILayer diffLayer = diff[0];
094:
095: if (!fromLayer.hasResource(FeatureSource.class)) {
096: MessageDialog.openError(display.getActiveShell(),
097: Messages.differenceOp_inputError1, fromLayer
098: .getName()
099: + Messages.differenceOp_inputError2);
100: return;
101: }
102: if (!diffLayer.hasResource(FeatureSource.class)) {
103: MessageDialog.openError(display.getActiveShell(),
104: Messages.differenceOp_inputError1, diffLayer
105: .getName()
106: + Messages.differenceOp_inputError2);
107: return;
108: }
109:
110: IndexedShapefileDataStoreFactory dsfac = new IndexedShapefileDataStoreFactory();
111: File tmp = File.createTempFile(layers[0].getName()
112: + "_" + layers[1].getName() + "_diff", ".shp"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
113: DataStore ds = dsfac.createDataStore(tmp.toURL());
114: final FeatureType newSchema = FeatureTypes.newFeatureType(
115: fromLayer.getSchema().getAttributeTypes(), "diff"); //$NON-NLS-1$
116: ds.createSchema(newSchema);
117:
118: final FeatureSource fromSource = fromLayer.getResource(
119: FeatureSource.class, monitor);
120: final FeatureSource diffSource = diffLayer.getResource(
121: FeatureSource.class, monitor);
122: if (isGeometryCollection(fromSource.getSchema()
123: .getDefaultGeometry())) {
124: MessageDialog.openError(display.getActiveShell(),
125: Messages.differenceOp_inputError, fromLayer
126: .getName()
127: + Messages.differenceOp_multiGeoms);
128: return;
129: }
130: if (isGeometryCollection(diffSource.getSchema()
131: .getDefaultGeometry())) {
132: MessageDialog.openError(display.getActiveShell(),
133: Messages.differenceOp_inputError, fromLayer
134: .getName()
135: + Messages.differenceOp_multiGeoms);
136: return;
137: }
138:
139: final FeatureCollection diffFeatures = FeatureCollections
140: .newCollection();
141: diffFeatures.addAll(diffSource.getFeatures());
142:
143: FeatureStore destStore = (FeatureStore) ds
144: .getFeatureSource("diff"); //$NON-NLS-1$
145: destStore.addFeatures(new FeatureReader() {
146: // TODO this needs an undo
147: // ((FeatureStore)fromSource).setFeatures(new FeatureReader() {
148: FeatureCollection coll = fromSource.getFeatures();
149: FeatureIterator iter = coll.features();
150: FeatureIterator peek = coll.features();
151: boolean hasNextCalled = false;
152:
153: public FeatureType getFeatureType() {
154: return newSchema;
155: }
156:
157: private Geometry diff(Feature f) {
158: Geometry geom = f.getDefaultGeometry();
159: FeatureIterator i = diffFeatures.features();
160: try {
161: while (i.hasNext()) {
162: Feature diff = i.next();
163: Geometry g = geom.difference(diff
164: .getDefaultGeometry());
165: if (g.isEmpty()) {
166: return null;
167: }
168: geom = g;
169: }
170: } finally {
171: i.close();
172: }
173: return geom;
174: }
175:
176: public Feature next() throws IOException,
177: IllegalAttributeException, NoSuchElementException {
178: Feature source = iter.next();
179: Geometry geom = diff(source);
180: if (geom == null || !hasNextCalled) {
181: throw new NoSuchElementException("Use hasNext()."); //$NON-NLS-1$
182: }
183:
184: if (geom instanceof LineString) {
185: geom = geom.getFactory().createMultiLineString(
186: new LineString[] { (LineString) geom });
187: }
188: if (geom instanceof Polygon) {
189: geom = geom.getFactory().createMultiPolygon(
190: new Polygon[] { (Polygon) geom });
191: }
192: source.setDefaultGeometry(geom);
193:
194: hasNextCalled = false;
195: return source;
196: }
197:
198: public boolean hasNext() throws IOException {
199: if (hasNextCalled) {
200: return iter.hasNext();
201: }
202:
203: // pointer chase forward to the next different geometry
204: try {
205: Geometry g = null;
206: while (g == null) {
207: if (!peek.hasNext()) {
208: return false;
209: }
210: Feature f = peek.next();
211: g = diff(f);
212:
213: if (g == null) {
214: iter.next();
215: } else {
216: return true;
217: }
218: }
219: } finally {
220: hasNextCalled = true;
221: }
222: return false;
223: }
224:
225: public void close() throws IOException {
226: iter.close();
227: peek.close();
228: }
229: });
230:
231: // add the diff shapefile as a udig resource
232: List<IService> services = CatalogPlugin.getDefault()
233: .getServiceFactory().acquire(tmp.toURL());
234:
235: IService service = services.get(0);
236: CatalogPlugin.getDefault().getLocalCatalog().add(service);
237: List resources = service.members(null);
238:
239: IGeoResource resource = (IGeoResource) resources.get(0);
240:
241: Map map = ((Map) layers[0].getMap());
242: LayerFactory factory = map.getLayerFactory();
243: Layer outLayer = factory.createLayer(resource);
244: map.getLayersInternal().add(outLayer);
245: }
246:
247: static class LayerSelection extends Dialog {
248:
249: private ILayer[] layers;
250: Combo fromCombo;
251: Combo diffCombo;
252: ILayer fromLayer;
253: ILayer diffLayer;
254:
255: protected LayerSelection(Shell parentShell, ILayer[] layers) {
256: super (parentShell);
257: this .layers = layers;
258: fromLayer = layers[0];
259: diffLayer = layers[1];
260: }
261:
262: @Override
263: protected Control createDialogArea(Composite parent) {
264: Composite comp = (Composite) super .createDialogArea(parent);
265: Composite c = new Composite(comp, SWT.NONE);
266: c.setLayout(new GridLayout(2, true));
267:
268: String[] names = new String[] { layers[0].getName(),
269: layers[1].getName() };
270:
271: Label layer2 = new Label(c, SWT.NONE);
272: layer2
273: .setLayoutData(new GridData(
274: GridData.FILL_HORIZONTAL));
275: layer2.setText("Subtract: "); //$NON-NLS-1$
276:
277: diffCombo = new Combo(c, SWT.DEFAULT);
278: diffCombo.setLayoutData(new GridData(GridData.FILL_BOTH));
279: diffCombo.setItems(names);
280: diffCombo.select(1);
281:
282: Label layer1 = new Label(c, SWT.NONE);
283: layer1
284: .setLayoutData(new GridData(
285: GridData.FILL_HORIZONTAL));
286: layer1.setText("From: "); //$NON-NLS-1$
287:
288: fromCombo = new Combo(c, SWT.DEFAULT);
289: fromCombo.setLayoutData(new GridData(GridData.FILL_BOTH));
290: fromCombo.setItems(names);
291: fromCombo.select(0);
292:
293: diffCombo.addSelectionListener(new SelectionListener() {
294:
295: public void widgetSelected(SelectionEvent e) {
296: widgetDefaultSelected(e);
297: }
298:
299: public void widgetDefaultSelected(SelectionEvent e) {
300: diffLayer = layers[diffCombo.getSelectionIndex()];
301: }
302:
303: });
304:
305: fromCombo.addSelectionListener(new SelectionListener() {
306:
307: public void widgetSelected(SelectionEvent e) {
308: widgetDefaultSelected(e);
309: }
310:
311: public void widgetDefaultSelected(SelectionEvent e) {
312: fromLayer = layers[fromCombo.getSelectionIndex()];
313: }
314:
315: });
316: return c;
317: }
318: }
319:
320: // this is lifted from Geometry, where it's a protected method.
321: protected boolean isGeometryCollection(GeometryAttributeType g) {
322: // Don't use instanceof because we want to allow subclasses
323: return g.getClass().getName().equals(
324: "com.vividsolutions.jts.geom.GeometryCollection"); //$NON-NLS-1$
325: }
326: }
|