/* * uDig - User Friendly Desktop Internet GIS client * (C) MangoSystem - www.mangosystem.com * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html). */ package org.locationtech.udig.processingtoolbox.styler; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.io.FilenameUtils; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.jface.operation.IRunnableWithProgress; import org.geotools.coverage.grid.GridCoverage2D; import org.geotools.data.DataUtilities; import org.geotools.data.Parameter; import org.geotools.data.collection.ListFeatureCollection; import org.geotools.data.shapefile.ShapefileDataStoreFactory; import org.geotools.data.simple.SimpleFeatureCollection; import org.geotools.data.simple.SimpleFeatureSource; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.geometry.jts.JTS; import org.geotools.process.ProcessException; import org.geotools.process.spatialstatistics.GlobalGStatisticsProcess.GStatisticsProcessResult; import org.geotools.process.spatialstatistics.GlobalGearysCProcess.GearysCProcessResult; import org.geotools.process.spatialstatistics.GlobalLeesLProcess.LeesLProcessResult; import org.geotools.process.spatialstatistics.GlobalLeesSProcess.LeesSProcessResult; import org.geotools.process.spatialstatistics.GlobalMoransIProcess.MoransIProcessResult; import org.geotools.process.spatialstatistics.JoinCountStatisticsProcess.JoinCountProcessResult; import org.geotools.process.spatialstatistics.core.FeatureTypes; import org.geotools.process.spatialstatistics.core.FeatureTypes.SimpleShapeType; import org.geotools.process.spatialstatistics.core.FormatUtils; import org.geotools.process.spatialstatistics.core.HistogramProcessResult; import org.geotools.process.spatialstatistics.core.Params; import org.geotools.process.spatialstatistics.operations.DataStatisticsOperation.DataStatisticsResult; import org.geotools.process.spatialstatistics.operations.PearsonOperation.PearsonResult; import org.geotools.process.spatialstatistics.pattern.NNIOperation.NearestNeighborResult; import org.geotools.process.spatialstatistics.pattern.QuadratOperation.QuadratResult; import org.geotools.process.spatialstatistics.storage.DataStoreFactory; import org.geotools.process.spatialstatistics.storage.ShapeExportOperation; import org.geotools.process.spatialstatistics.styler.GraduatedColorStyleBuilder; import org.geotools.process.spatialstatistics.styler.GraduatedSymbolStyleBuilder; import org.geotools.process.spatialstatistics.styler.SSStyleBuilder; import org.geotools.process.spatialstatistics.transformation.ForceCRSFeatureCollection; import org.geotools.styling.Style; import org.geotools.util.logging.Logging; import org.locationtech.udig.catalog.CatalogPlugin; import org.locationtech.udig.catalog.ICatalog; import org.locationtech.udig.catalog.IGeoResource; import org.locationtech.udig.catalog.IService; import org.locationtech.udig.catalog.util.GeoToolsAdapters; import org.locationtech.udig.processingtoolbox.ToolboxPlugin; import org.locationtech.udig.processingtoolbox.ToolboxView; import org.locationtech.udig.processingtoolbox.internal.Messages; import org.locationtech.udig.processingtoolbox.tools.HtmlWriter; import org.locationtech.udig.project.IMap; import org.locationtech.udig.project.internal.Layer; import org.locationtech.udig.project.ui.ApplicationGIS; import org.locationtech.udig.style.sld.SLDContent; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.geometry.BoundingBox; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.util.ProgressListener; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.LinearRing; /** * ProcessExecutorOperation * * @author Minpa Lee, MangoSystem * * @source $URL$ */ public class ProcessExecutorOperation implements IRunnableWithProgress { protected static final Logger LOGGER = Logging.getLogger(ProcessExecutorOperation.class); final String lineSeparator = System.getProperty("line.separator"); //$NON-NLS-1$ private IMap map; private org.geotools.process.ProcessFactory factory; private org.opengis.feature.type.Name processName; private Map<String, Object> inputParams = new HashMap<String, Object>(); private Map<String, Object> outputParams = new HashMap<String, Object>(); private String windowTitle; private StringBuffer outputBuffer = new StringBuffer(); public ProcessExecutorOperation(IMap map, org.geotools.process.ProcessFactory factory, org.opengis.feature.type.Name processName, Map<String, Object> inputParams, Map<String, Object> outputParams) { this.map = map; this.factory = factory; this.processName = processName; this.inputParams = inputParams; this.outputParams = outputParams; this.windowTitle = factory.getTitle(processName).toString(); } public String getOutputText() { return outputBuffer.toString(); } @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { int increment = 10; monitor.beginTask(Messages.Task_Running, 100); monitor.worked(increment); try { monitor.setTaskName(String.format(Messages.Task_Executing, windowTitle)); ToolboxPlugin.log(String.format(Messages.Task_Executing, windowTitle)); ProgressListener subMonitor = GeoToolsAdapters.progress(SubMonitor.convert(monitor, Messages.Task_Internal, 60)); org.geotools.process.Process process = factory.create(processName); final Map<String, Object> result = process.execute(inputParams, subMonitor); monitor.worked(increment); monitor.setTaskName(Messages.Task_AddingLayer); outputBuffer.setLength(0); if (result != null) { Map<String, Parameter<?>> resultInfo = factory.getResultInfo(processName, null); for (Entry<String, Object> entrySet : result.entrySet()) { final Object val = entrySet.getValue(); if (val == null) { continue; } if (val instanceof SimpleFeatureCollection) { postProcessing((SimpleFeatureCollection) val, outputParams.get(entrySet.getKey()), resultInfo.get(entrySet.getKey()).metadata, monitor); } else if (val instanceof Geometry) { postProcessing(geometryToFeatures((Geometry) val, processName.toString()), outputParams.get(entrySet.getKey()), resultInfo.get(entrySet.getKey()).metadata, monitor); } else if (val instanceof BoundingBox) { Geometry boundingBox = JTS.toGeometry((BoundingBox) val); boundingBox.setUserData(((BoundingBox) val).getCoordinateReferenceSystem()); postProcessing(geometryToFeatures(boundingBox, processName.toString()), outputParams.get(entrySet.getKey()), resultInfo.get(entrySet.getKey()).metadata, monitor); } else if (val instanceof GridCoverage2D) { ToolboxPlugin.log(Messages.Task_AddingLayer); try { File outputFile = new File(outputParams.get(entrySet.getKey()) .toString()); GridCoverage2D output = MapUtils.saveAsGeoTiff((GridCoverage2D) val, outputFile); if (ToolboxView.getAddLayerAutomatically()) { MapUtils.addGridCoverageToMap(map, output, outputFile, null); } } catch (IllegalArgumentException e) { ToolboxPlugin.log(e.getMessage()); } catch (IndexOutOfBoundsException e) { ToolboxPlugin.log(e.getMessage()); } catch (IOException e) { ToolboxPlugin.log(e.getMessage()); } } else { postProcessing(val); } monitor.worked(increment); } } monitor.worked(increment); } catch (ProcessException e) { // always show log boolean showLog = ToolboxView.getShowLog(); ToolboxView.setShowLog(true); ToolboxPlugin.log(e.getMessage()); ToolboxView.setShowLog(showLog); } finally { ToolboxPlugin.log(String.format(Messages.Task_Completed, windowTitle)); monitor.done(); } } private void postProcessing(Object value) { HtmlWriter writer = new HtmlWriter(windowTitle); if (value instanceof DataStatisticsResult) { writer.writeDataStatistics((DataStatisticsResult) value); } else if (value instanceof GStatisticsProcessResult) { writer.writeGStatistics((GStatisticsProcessResult) value); } else if (value instanceof MoransIProcessResult) { writer.writeMoransI((MoransIProcessResult) value); } else if (value instanceof GearysCProcessResult) { writer.writeGearysC((GearysCProcessResult) value); } else if (value instanceof LeesSProcessResult) { writer.writeLeesS((LeesSProcessResult) value); } else if (value instanceof LeesLProcessResult) { writer.writeLeesL((LeesLProcessResult) value); } else if (value instanceof NearestNeighborResult) { writer.writeNearestNeighbor((NearestNeighborResult) value); } else if (value instanceof PearsonResult) { writer.writePearson((PearsonResult) value); } else if (value instanceof JoinCountProcessResult) { writer.writeJoinCount((JoinCountProcessResult) value); } else if (value instanceof HistogramProcessResult) { writer.writeHistogramProcess((HistogramProcessResult) value); } else if (value instanceof QuadratResult) { writer.writeQuadratProcess((QuadratResult) value); } else if (Number.class.isAssignableFrom(value.getClass())) { writer.writeH2(FormatUtils.format(Double.parseDouble(value.toString()))); } else { writer.writeH2(value.toString()); } outputBuffer.append(writer.getHTML()); } private void postProcessing(SimpleFeatureCollection source, Object outputPath, Map<String, Object> outputMeta, IProgressMonitor monitor) { // check crs CoordinateReferenceSystem crs = source.getSchema().getCoordinateReferenceSystem(); if (crs == null) { ToolboxPlugin .log("Warning: Output CRS will be used coordinate reference system of the current map"); //$NON-NLS-1$ source = new ForceCRSFeatureCollection(source, map.getViewportModel().getCRS()); } // write shapefile monitor.setTaskName(Messages.Task_WritingResult); File filePath = new File(outputPath.toString()); String typeName = FilenameUtils.getBaseName(filePath.getPath()); SimpleFeatureSource featureSource = null; try { Map<String, Object> params = new HashMap<String, Object>(); File file = new File(filePath.getParent()); params.put(ShapefileDataStoreFactory.URLP.key, DataUtilities.fileToURL(file)); params.put(ShapefileDataStoreFactory.CREATE_SPATIAL_INDEX.key, false); params.put(ShapefileDataStoreFactory.DBFCHARSET.key, ToolboxPlugin.defaultCharset()); ShapeExportOperation exportOp = ShapeExportOperation.getDefault(); exportOp.setOutputDataStore(DataStoreFactory.getDataStore(params)); exportOp.setOutputTypeName(typeName); featureSource = exportOp.execute(source); source = featureSource.getFeatures(); } catch (IOException e) { ToolboxPlugin.log(e.getMessage()); } if (featureSource == null) { return; } if (!ToolboxView.getAddLayerAutomatically()) { return; } monitor.setTaskName(Messages.Task_AddingLayer); ToolboxPlugin.log(Messages.Task_AddingLayer); SimpleFeatureType schema = featureSource.getSchema(); SSStyleBuilder ssBuilder = new SSStyleBuilder(schema); ssBuilder.setOpacity(0.8f); Style style = ssBuilder.getDefaultFeatureStyle(); if (ToolboxView.getUseDefaultStyle()) { if (outputMeta.containsKey(Params.STYLES)) { // KVP(Params.STYLES, "renderer.fieldname") // renderer = LISA, UniqueValues, ClassBreaks, Density, Distance, Interpolation // ClassBreaks = EqualInterval, Quantile, NaturalBreaks, StdDev try { String value = outputMeta.get(Params.STYLES).toString(); String[] splits = value.split("\\."); //$NON-NLS-1$ String styleName = splits[0].toUpperCase(); String functionName = null; if (styleName.startsWith("LISA")) { //$NON-NLS-1$ style = ssBuilder.getLISAStyle("COType"); //$NON-NLS-1$ } else if (styleName.startsWith("CL") || styleName.startsWith("JE") //$NON-NLS-1$ //$NON-NLS-2$ || styleName.startsWith("NA")) { //$NON-NLS-1$ functionName = "JenksNaturalBreaksFunction"; //$NON-NLS-1$ } else if (styleName.startsWith("E")) { //$NON-NLS-1$ functionName = "EqualIntervalFunction"; //$NON-NLS-1$ } else if (styleName.startsWith("S")) { //$NON-NLS-1$ functionName = "StandardDeviationFunction"; //$NON-NLS-1$ } else if (styleName.startsWith("Q")) { //$NON-NLS-1$ functionName = "QuantileFunction"; //$NON-NLS-1$ } if (functionName != null && splits.length == 2) { String fieldName = splits[1]; // inputParams if (schema.indexOf(fieldName) == -1) { fieldName = inputParams.get(fieldName).toString(); } if (schema.indexOf(fieldName) != -1) { Class<?> binding = schema.getDescriptor(fieldName).getType() .getBinding(); if (Number.class.isAssignableFrom(binding)) { SimpleShapeType shapeType = FeatureTypes.getSimpleShapeType(source); if (shapeType == SimpleShapeType.POINT) { GraduatedSymbolStyleBuilder builder = new GraduatedSymbolStyleBuilder(); builder.setMethodName(functionName); style = builder.createStyle(source, fieldName); } else { GraduatedColorStyleBuilder builder = new GraduatedColorStyleBuilder(); style = builder.createStyle(source, fieldName, functionName, 5, "Blues"); //$NON-NLS-1$ } } } } } catch (Exception e) { ToolboxPlugin.log(e.getMessage()); } } else { if (source.getSchema().indexOf("COType") != -1) { //$NON-NLS-1$ style = ssBuilder.getLISAStyle("COType"); //$NON-NLS-1$ } else if (source.getSchema().indexOf("GiZScore") != -1) { //$NON-NLS-1$ style = ssBuilder.getZScoreStdDevStyle("GiZScore"); //$NON-NLS-1$ } } } try { CatalogPlugin catalogPlugin = CatalogPlugin.getDefault(); ICatalog localCatalog = catalogPlugin.getLocalCatalog(); URL resourceId = DataUtilities.fileToURL(filePath); List<IService> services = catalogPlugin.getServiceFactory().createService(resourceId); for (IService service : services) { localCatalog.add(service); for (IGeoResource resource : service.resources(new NullProgressMonitor())) { List<IGeoResource> resourceList = Collections.singletonList(resource); final int pos = map.getMapLayers().size(); Layer layer = (Layer) ApplicationGIS.addLayersToMap(map, resourceList, pos) .get(0); layer.setName(typeName); layer.setVisible(true); if (style != null) { // put the style on the blackboard layer.getStyleBlackboard().put(SLDContent.ID, style); layer.getStyleBlackboard().setSelected(new String[] { SLDContent.ID }); } // refresh layer.refresh(layer.getBounds(new NullProgressMonitor(), null)); } } } catch (MalformedURLException e) { LOGGER.log(Level.FINER, e.getMessage(), e); } catch (IOException e) { LOGGER.log(Level.FINER, e.getMessage(), e); } } private SimpleFeatureCollection geometryToFeatures(Geometry source, String layerName) { CoordinateReferenceSystem crs = map.getViewportModel().getCRS(); if (source.getUserData() != null && CoordinateReferenceSystem.class .isAssignableFrom(source.getUserData().getClass())) { crs = (CoordinateReferenceSystem) source.getUserData(); } Geometry geometry = source; if (source instanceof LinearRing) { geometry = source.getFactory().createPolygon((LinearRing) source, null); geometry.setUserData(source.getUserData()); } SimpleFeatureType schema = FeatureTypes.getDefaultType(layerName, geometry.getClass(), crs); ListFeatureCollection features = new ListFeatureCollection(schema); SimpleFeatureBuilder builder = new SimpleFeatureBuilder(schema); SimpleFeature feature = builder.buildFeature(null); feature.setDefaultGeometry(geometry); features.add(feature); return features; } }