/* * Copyright 2013 Serdar. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.fub.maps.project.aggregator.pipeline.processes; import de.fub.agg2graph.graph.RamerDouglasPeuckerFilter; import de.fub.agg2graph.input.CleaningOptions; import de.fub.agg2graph.input.GPSCleaner; import de.fub.agg2graph.structs.GPSSegment; import de.fub.agg2graph.ui.gui.RenderingOptions; import de.fub.agg2graphui.layers.GPSSegmentLayer; import de.fub.maps.project.aggregator.pipeline.AbstractAggregationProcess; import de.fub.maps.project.aggregator.xml.ProcessDescriptor; import de.fub.maps.project.aggregator.xml.Properties; import de.fub.maps.project.aggregator.xml.Property; import de.fub.maps.project.aggregator.xml.PropertySection; import de.fub.maps.project.aggregator.xml.PropertySet; import de.fub.maps.project.api.process.ProcessPipeline.ProcessEvent; import de.fub.maps.project.api.statistics.StatisticProvider; import de.fub.maps.project.utils.AggregatorUtils; import java.awt.Color; import java.awt.Component; import java.awt.Image; import java.util.ArrayList; import java.util.List; import javax.swing.JComponent; import org.netbeans.api.annotations.common.StaticResource; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; import org.openide.util.ImageUtilities; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; /** * Process unit implementation, which handles the cleaning process of an * Aggregator. * * @author Serdar */ @NbBundle.Messages({ "CLT_CleanProcess_Name=Cleaner", "CLT_CleanProcess_Description=A simple GPS segment cleaner", "CLT_CLeanProcess_PropertySet_Setting_Name=Cleaning Settings", "CLT_CleanProcess_PropertySet_Setting_Description=No description available", "CLT_CleanProcess_PropertySet_RDPSetting_Name=Raimer Douglas Peucker Filter Settings", "CLT_CleanProcess_PropertySet_RDPSetting_Description=No description available" }) @ServiceProvider(service = AbstractAggregationProcess.class) public final class CleanProcess extends AbstractAggregationProcess<List<GPSSegment>, List<GPSSegment>> implements StatisticProvider { @StaticResource private static final String ICON_PATH = "de/fub/maps/project/aggregator/pipeline/processes/datasourceProcessIcon.png"; private static final Image IMAGE = ImageUtilities.loadImage(ICON_PATH); private static final String PROPERTY_SET_ID_CLEAN_SETTINGS = "clean.process.settings"; private static final String PROPERTY_SET_ID_RAMER_DOUGLAS_PEUCKER_SETTINGS = "clean.process.rdp.settings"; private ArrayList<GPSSegment> cleanSegmentList = new ArrayList<GPSSegment>(); private List<GPSSegment> inputList = new ArrayList<GPSSegment>(); private GPSCleaner gpsCleaner = new GPSCleaner(); private GPSSegmentLayer gPSSegmentLayer; private int totalCleanSegmentCount = 0; private int totalCleanGPSPointCount = 0; private int totalSmoothedGPSPointCount = 0; public CleanProcess() { init(); } private void init() { RenderingOptions renderingOptions = new RenderingOptions(); renderingOptions.setColor(new Color(39, 172, 88)); // green renderingOptions.setRenderingType(RenderingOptions.RenderingType.ALL); renderingOptions.setzIndex(0); renderingOptions.setOpacity(1); gPSSegmentLayer = new GPSSegmentLayer(getName(), "Clean gps data", renderingOptions); getLayers().add(gPSSegmentLayer); } @Override public void setProcessDescriptor(ProcessDescriptor processDescriptor) { super.setProcessDescriptor(processDescriptor); if (processDescriptor != null) { PropertySet propertySet = getPropertySet(PROPERTY_SET_ID_CLEAN_SETTINGS); if (propertySet != null) { createCleaningOptions(propertySet.getProperties()); } } } private void createCleaningOptions(List<Property> properties) { gpsCleaner.setCleaningOptions(AggregatorUtils.createValue(CleaningOptions.class, properties)); } private PropertySet getPropertySet(String name) { if (getProcessDescriptor() != null) { Properties properties = getProcessDescriptor().getProperties(); if (!properties.getSections().isEmpty()) { return getPropertySet(name, properties); } } return null; } private PropertySet getPropertySet(String name, Properties properties) { if (!properties.getSections().isEmpty()) { PropertySection propertySection = properties.getSections().iterator().next(); for (int i = 0; i < propertySection.getPropertySet().size(); i++) { PropertySet propertySet = propertySection.getPropertySet().get(i); if (name.equals(propertySet.getName())) { return propertySet; } } } return null; } private RamerDouglasPeuckerFilter getFilterInstance() { RamerDouglasPeuckerFilter filter = null; PropertySet propertySet = getPropertySet(PROPERTY_SET_ID_RAMER_DOUGLAS_PEUCKER_SETTINGS); if (propertySet != null) { filter = AggregatorUtils.createValue(RamerDouglasPeuckerFilter.class, propertySet.getProperties()); } else { filter = new RamerDouglasPeuckerFilter(5); } return filter; } @Override protected void start() { totalCleanGPSPointCount = 0; totalCleanSegmentCount = 0; totalSmoothedGPSPointCount = 0; ProgressHandle handle = ProgressHandleFactory.createHandle(getName()); if (inputList != null) { handle.start(inputList.size()); try { gPSSegmentLayer.clearRenderObjects(); RamerDouglasPeuckerFilter rdpf = getFilterInstance(); int progess = 0; for (GPSSegment segment : inputList) { if (canceled.get()) { fireProcessCanceledEvent(); break; } List<GPSSegment> clean = gpsCleaner.clean(segment); totalCleanSegmentCount += clean.size(); for (GPSSegment cleanSegment : clean) { if (canceled.get()) { fireProcessCanceledEvent(); break; } totalCleanGPSPointCount += cleanSegment.size(); // run through Douglas-Peucker here (slightly modified // perhaps to avoid too long edges) GPSSegment smoothSegment = rdpf.simplify(cleanSegment); totalSmoothedGPSPointCount += (cleanSegment.size() - smoothSegment.size()); cleanSegmentList.add(smoothSegment); gPSSegmentLayer.add(smoothSegment); } fireProcessProgressEvent(new ProcessEvent<CleanProcess>(CleanProcess.this, "Cleaning...", (int) ((100d / inputList.size()) * (++progess)))); handle.progress(progess); } } finally { handle.finish(); } } } @Override public List<GPSSegment> getResult() { synchronized (RUN_MUTEX) { return cleanSegmentList; } } @Override public void setInput(List<GPSSegment> input) { this.inputList = input; } @Override public String getName() { if (getProcessDescriptor() != null) { return getProcessDescriptor().getDisplayName(); } return "Clean"; } @Override public String getDescription() { if (getProcessDescriptor() != null) { return getProcessDescriptor().getDescription(); } return "Clean Process"; } @Override public Image getIcon() { return IMAGE; } @Override public JComponent getSettingsView() { return null; } @Override public List<StatisticSection> getStatisticData() throws StatisticNotAvailableException { List<StatisticSection> statisticSections = new ArrayList<StatisticProvider.StatisticSection>(); statisticSections.add(getPerformanceData()); StatisticSection section = new StatisticSection("Cleaning Statistics", "Statistical data of the cleaning process."); //NO18N statisticSections.add(section); section.getStatisticsItemList().add( new StatisticItem("Clean GPS Point Count", String.valueOf(totalCleanGPSPointCount), "Total count of GPS points after cleaning.")); //NO18N section.getStatisticsItemList().add( new StatisticItem("Clean Segment Count", String.valueOf(totalCleanSegmentCount), "Total count of GPS segments after cleaning.")); //NO18N section.getStatisticsItemList().add( new StatisticItem("Clean GPS Point/Segment Ratio", String.valueOf(totalCleanGPSPointCount / (double) totalCleanSegmentCount), "The ratio of cleaned points to cleaned segements.")); //NO18N section.getStatisticsItemList().add( new StatisticItem("Smoothed GPS Points", String.valueOf(totalSmoothedGPSPointCount), "Total count of GPS points that filter by the RDP-Filter.")); //NO18N return statisticSections; } @Override public boolean cancel() { canceled.set(true); return canceled.get(); } @Override public Component getVisualRepresentation() { return null; } @Override protected ProcessDescriptor createProcessDescriptor() { ProcessDescriptor descriptor = new ProcessDescriptor(); descriptor.setJavaType(CleanProcess.class.getName()); descriptor.setDisplayName(Bundle.CLT_CleanProcess_Name()); descriptor.setDescription(Bundle.CLT_CleanProcess_Description()); PropertySection propertySection = new PropertySection(); propertySection.setId(CleanProcess.class.getName()); propertySection.setName(Bundle.CLT_CleanProcess_Name()); propertySection.setDescription(Bundle.CLT_CleanProcess_Description()); descriptor.getProperties().getSections().add(propertySection); PropertySet propertySet = new PropertySet(); propertySet.setId(PROPERTY_SET_ID_CLEAN_SETTINGS); propertySet.setName(Bundle.CLT_CLeanProcess_PropertySet_Setting_Name()); propertySet.setDescription(Bundle.CLT_CleanProcess_PropertySet_Setting_Description()); Property property = new Property(); property.setId("filterBySegmentLength"); property.setName("minSegmentLength"); property.setDescription("No description available"); property.setJavaType(Boolean.class.getName()); property.setValue(Boolean.TRUE.toString()); propertySet.getProperties().add(property); property = new Property(); property.setId("minSegmentLength"); property.setName("minSegmentLength"); property.setDescription("No description available"); property.setJavaType(Long.class.getName()); property.setValue(String.valueOf(1)); propertySet.getProperties().add(property); property = new Property(); property.setId("maxSegmentLength"); property.setName("maxSegmentLength"); property.setDescription("No description available"); property.setJavaType(Long.class.getName()); property.setValue(String.valueOf(100)); propertySet.getProperties().add(property); property = new Property(); property.setId("filterByEdgeLength"); property.setName("filterByEdgeLength"); property.setDescription("No description available"); property.setJavaType(Boolean.class.getName()); property.setValue(Boolean.TRUE.toString()); propertySet.getProperties().add(property); property = new Property(); property.setId("minEdgeLength"); property.setName("minEdgeLength"); property.setDescription("No description available"); property.setJavaType(Double.class.getName()); property.setValue("" + 0.3); propertySet.getProperties().add(property); property = new Property(); property.setId("maxEdgeLength"); property.setName("maxEdgeLength"); property.setDescription("No description available"); property.setJavaType(Double.class.getName()); property.setValue("" + 750); propertySet.getProperties().add(property); property = new Property(); property.setId("filterByEdgeLengthIncrease"); property.setName("filterByEdgeLengthIncrease"); property.setDescription("No description available"); property.setJavaType(Boolean.class.getName()); property.setValue(Boolean.TRUE.toString()); propertySet.getProperties().add(property); property = new Property(); property.setId("minEdgeLengthIncreaseFactor"); property.setName("minEdgeLengthIncreaseFactor"); property.setDescription("No description available"); property.setJavaType(Double.class.getName()); property.setValue("10"); propertySet.getProperties().add(property); property = new Property(); property.setId("minEdgeLengthAfterIncrease"); property.setName("minEdgeLengthAfterIncrease"); property.setDescription("No description available"); property.setJavaType(Double.class.getName()); property.setValue("30"); propertySet.getProperties().add(property); property = new Property(); property.setId("filterZigzag"); property.setName("filterZigzag"); property.setDescription("No description available"); property.setJavaType(Boolean.class.getName()); property.setValue(Boolean.TRUE.toString()); propertySet.getProperties().add(property); property = new Property(); property.setId("maxZigzagAngle"); property.setName("maxZigzagAngle"); property.setDescription("No description available"); property.setJavaType(Double.class.getName()); property.setValue("30"); propertySet.getProperties().add(property); property = new Property(); property.setId("filterFakeCircle"); property.setName("filterFakeCircle"); property.setDescription("No description available"); property.setJavaType(Boolean.class.getName()); property.setValue(Boolean.TRUE.toString()); propertySet.getProperties().add(property); property = new Property(); property.setId("maxFakeCircleAngle"); property.setName("maxFakeCircleAngle"); property.setDescription("No description available"); property.setJavaType(Double.class.getName()); property.setValue("50"); propertySet.getProperties().add(property); property = new Property(); property.setId("filterOutliers"); property.setName("filterOutliers"); property.setDescription("No description available"); property.setJavaType(Boolean.class.getName()); property.setValue(Boolean.FALSE.toString()); propertySet.getProperties().add(property); property = new Property(); property.setId("maxNumOutliers"); property.setName("maxNumOutliers"); property.setDescription("No description available"); property.setJavaType(Integer.class.getName()); property.setValue("2"); propertySet.getProperties().add(property); propertySection.getPropertySet().add(propertySet); propertySet = new PropertySet(); propertySet.setId(PROPERTY_SET_ID_RAMER_DOUGLAS_PEUCKER_SETTINGS); propertySet.setName(Bundle.CLT_CleanProcess_PropertySet_RDPSetting_Name()); propertySet.setDescription(Bundle.CLT_CleanProcess_PropertySet_RDPSetting_Description()); property = new Property(); property.setId("epsilon"); property.setName("epsilon"); property.setDescription("No description available"); property.setJavaType(Double.class.getName()); property.setValue("5"); propertySet.getProperties().add(property); property = new Property(); property.setId("maxSegmentLength"); property.setName("maxSegmentLength"); property.setDescription("No description available"); property.setJavaType(Double.class.getName()); property.setValue("100"); propertySet.getProperties().add(property); propertySection.getPropertySet().add(propertySet); return descriptor; } }