/** * ***************************************************************************** * Copyright 2013 Sebastian Müller * * 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.agg2graph.agg.strategy; import de.fub.agg2graph.agg.AggConnection; import de.fub.agg2graph.agg.AggNode; import de.fub.agg2graph.agg.AggregationStrategyFactory; import de.fub.agg2graph.agg.IMergeHandler; import de.fub.agg2graph.agg.MergeHandlerFactory; import de.fub.agg2graph.agg.TraceDistanceFactory; import de.fub.agg2graph.structs.GPSEdge; import de.fub.agg2graph.structs.GPSPoint; import de.fub.agg2graph.structs.GPSSegment; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Iterator; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; public class GpxmergeAggregationStrategy extends AbstractAggregationStrategy { private static final Logger LOG = Logger.getLogger(GpxmergeAggregationStrategy.class.getName()); private double maxInitDistance = 100; private double maxPathDifference = 2; /** * Preferably use the {@link AggregationStrategyFactory} for creating * instances of this class. */ public GpxmergeAggregationStrategy() { traceDistance = TraceDistanceFactory.getObject(); baseMergeHandler = MergeHandlerFactory.getObject(); } public double getMaxInitDistance() { return maxInitDistance; } public void setMaxInitDistance(double maxInitDistance) { this.maxInitDistance = maxInitDistance; } public double getMaxPathDifference() { return maxPathDifference; } public void setMaxPathDifference(double maxPathDifference) { this.maxPathDifference = maxPathDifference; } @Override public void aggregate(GPSSegment segment, boolean isAgg) { LOG.setLevel(Level.ALL); matches = new ArrayList<IMergeHandler>(); // insert first segment without changes if (aggContainer.getCachingStrategy() == null || aggContainer.getCachingStrategy().getNodeCount() == 0) { int i = 0; while (i < segment.size()) { AggNode node = new AggNode(segment.get(i), aggContainer); node.setID(MessageFormat.format("A-{0}", segment.get(i).getID())); addNodeToAgg(aggContainer, node); lastNode = node; i++; } return; } lastNode = null; int i = 0; // step 1: find starting point // get close edges, within x meters (merge candidates) Set<AggConnection> nearEdges = null; while (i < segment.size() - 1) { GPSPoint firstPoint = segment.get(i); GPSPoint secondPoint = segment.get(i + 1); GPSEdge currentEdge = new GPSEdge(firstPoint, secondPoint); nearEdges = aggContainer.getCachingStrategy().getCloseConnections( currentEdge, maxInitDistance); boolean addNode = true; LOG.warning(MessageFormat.format("{0} near edges", nearEdges.size())); if (!nearEdges.isEmpty()) { IMergeHandler mergeHandler = null; mergeHandler = baseMergeHandler.getCopy(); mergeHandler.setAggContainer(aggContainer); Iterator<AggConnection> itNear = nearEdges.iterator(); Double grade = Double.MAX_VALUE; AggConnection bestConn = null; while (itNear.hasNext()) { AggConnection near = itNear.next(); Object[] distReturn = traceDistance.getPathDifference( near.toPointList(), currentEdge.toPointList(), 0, mergeHandler); double dist = (Double) distReturn[0]; if (dist < grade && dist < maxPathDifference) { grade = dist; bestConn = near; } } if (bestConn != null) { addNode = false; mergeHandler.addAggNodes(bestConn); mergeHandler.addGPSPoints(currentEdge); mergeHandler.setDistance(grade); if (!mergeHandler.isEmpty()) { matches.add(mergeHandler); mergeHandler.processSubmatch(); // connect to previous node aggContainer .connect(lastNode, mergeHandler.getInNode()); mergeHandler.setBeforeNode(lastNode); // remember outgoing node (for later connection) lastNode = mergeHandler.getOutNode(); } } } if (addNode) { AggNode node = new AggNode(firstPoint, aggContainer); node.setID(MessageFormat.format("A-{0}", firstPoint.getID())); addNodeToAgg(aggContainer, node); lastNode = node; } i++; } // step 2 and 3 of 3: ghost points, merge everything for (IMergeHandler match : matches) { if (!match.isEmpty()) { match.mergePoints(); } } } }