/* * 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.plugins.mapmatcher; import de.fub.agg2graph.structs.GPSCalc; import de.fub.agg2graph.structs.GPSSegment; import de.fub.agg2graph.structs.ILocation; import de.fub.maps.project.plugins.tasks.eval.GpsSegmentTree; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map.Entry; import java.util.logging.Level; import java.util.logging.Logger; import org.openide.util.lookup.ServiceProvider; /** * * @author Serdar */ @ServiceProvider(service = MapMatcher.class) public class CurveToCurveMapMatcher implements MapMatcher { private final GpsSegmentTree TREE = new GpsSegmentTree(); @Override public List<MapMatchSegment> findMatch(Collection<GPSSegment> roadTobeMatched, Collection<GPSSegment> roadNetwork) { TREE.reset(); List<MapMatchSegment> resultList = new ArrayList<MapMatchSegment>(roadNetwork.size()); HashMap<GPSSegment, List<GPSSegment>> candidateSegmentMap = findCandidateSegment(roadTobeMatched, roadNetwork); for (Entry<GPSSegment, List<GPSSegment>> entry : candidateSegmentMap.entrySet()) { GPSSegment segment = entry.getKey(); List<GPSSegment> candidateSegments = entry.getValue(); MapMatchSegment minMatchSegment = null; for (GPSSegment candidateSegment : candidateSegments) { MapMatchSegment mapMatchSegment = createMapMatchSegment(segment, candidateSegment); if (minMatchSegment == null || mapMatchSegment.getMapMatchCost() < minMatchSegment.getMapMatchCost()) { minMatchSegment = mapMatchSegment; } } if (minMatchSegment != null) { resultList.add(minMatchSegment); } } return resultList; } private HashMap<GPSSegment, List<GPSSegment>> findCandidateSegment(Collection<GPSSegment> roadTobeMatched, Collection<GPSSegment> roadNetwork) { // initialize tree TREE.addSegments(roadNetwork); HashMap<GPSSegment, List<GPSSegment>> candidateSegmentMap = new HashMap<GPSSegment, List<GPSSegment>>(); for (GPSSegment segment : roadTobeMatched) { if (!candidateSegmentMap.containsKey(segment)) { candidateSegmentMap.put(segment, new ArrayList<GPSSegment>()); } Collection<GPSSegment> searchSpace = TREE.getIntersectingSegment(segment); // we try to find the closest roadSegment for each point // in segment for (ILocation point : segment) { // initialize variables GPSSegment candidateSegment = null; double minDistance = Double.MAX_VALUE; for (GPSSegment roadSegment : searchSpace) { double distance = getMinimumDistance(point, roadSegment); if (distance < minDistance) { // current roadPoint is the closest point // set current roadSegment as candidateSegment minDistance = distance; candidateSegment = roadSegment; } } if (candidateSegment != null) { candidateSegmentMap.get(segment).add(candidateSegment); } } } return candidateSegmentMap; } // computes the minimal distance between point and segment private double getMinimumDistance(ILocation point, GPSSegment segment) { double minDistance = Double.MAX_VALUE; for (ILocation roadPoint : segment) { double distance = GPSCalc.getDistVincentyFast( point.getLat(), point.getLon(), roadPoint.getLat(), roadPoint.getLon()); if (distance < minDistance) { minDistance = distance; } } return minDistance; } private MapMatchSegment createMapMatchSegment(GPSSegment segment, GPSSegment candidateSegment) { MapMatchSegment mapMatchSegment = new MapMatchSegment(); for (ILocation point : segment) { double minDistance = Double.MAX_VALUE; ILocation matchPoint = null; ILocation lastLocation = null; for (ILocation roadPoint : candidateSegment) { double distance = 0; if (lastLocation == null) { distance = GPSCalc .getDistVincentyFast( point.getLat(), point.getLon(), roadPoint.getLat(), roadPoint.getLon()); } else { // project point to edge lastpoint - roadPoint ILocation projectionPoint = GPSCalc.getProjectionPoint(point, lastLocation, roadPoint); if (projectionPoint != null) { distance = GPSCalc.getDistVincentyFast(point.getLat(), point.getLon(), projectionPoint.getLat(), projectionPoint.getLon()); roadPoint = projectionPoint; } else { LOG.log(Level.SEVERE, "Point {0} has no projection to segment {1} - {2}", new Object[]{point, lastLocation, roadPoint}); } } if (distance < minDistance) { minDistance = distance; matchPoint = roadPoint; } lastLocation = roadPoint; } if (matchPoint != null) { MapMatchResult mapMatchResult = new MapMatchResult(point, matchPoint, minDistance); mapMatchSegment.getSegment().add(mapMatchResult); } } return mapMatchSegment; } private static final Logger LOG = Logger.getLogger(CurveToCurveMapMatcher.class.getName()); }