/* * 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.tasks.eval; import com.infomatiq.jsi.Rectangle; import com.infomatiq.jsi.rtree.RTree; import de.fub.agg2graph.structs.GPSSegment; import de.fub.agg2graph.structs.ILocation; import gnu.trove.TIntProcedure; import java.awt.geom.Area; import java.awt.geom.Rectangle2D; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Properties; import java.util.concurrent.atomic.AtomicInteger; /** * * @author Serdar */ public class GpsSegmentTree { private RTree rtree = new RTree(); private final AtomicInteger itemID = new AtomicInteger(0); private final Object MUTEX = new Object(); private final HashMap<Integer, GPSSegment> META_DATA = new HashMap<Integer, GPSSegment>(500); public GpsSegmentTree() { init(); } private void init() { reset(); } public void addSegments(Collection<GPSSegment> segments) { for (GPSSegment segment : segments) { addSegment(segment); } } public void addSegment(GPSSegment segment) { synchronized (MUTEX) { Rectangle boundingBox = getBoundingBox(segment); int id = itemID.getAndIncrement(); rtree.add(boundingBox, id); META_DATA.put(id, segment); } } public void reset() { itemID.set(0); META_DATA.clear(); Properties p = new Properties(); p.setProperty("MinNodeEntries", "10"); p.setProperty("MaxNodeEntries", "50"); rtree = new RTree(); rtree.init(p); } public Collection<GPSSegment> getIntersectingSegment(GPSSegment segment) { synchronized (MUTEX) { // compute the bounding box of the specified segment Rectangle boundingBox = getBoundingBox(segment); // create a callback GPSSegmentSeachProcedure gpsSegmentSeachProcedure = new GPSSegmentSeachProcedure(); // search rtree.intersects(boundingBox, gpsSegmentSeachProcedure); // return results return gpsSegmentSeachProcedure.getSegments(); } } private Rectangle getBoundingBox(GPSSegment segment) { Area area = new Area(); for (ILocation location : segment) { // the added shape must have at least a size > 0 area.add(new Area(new Rectangle2D.Double(location.getLon(), location.getLat(), 0.0000000001, 0.0000000001))); } Rectangle2D boundingBox = area.getBounds2D(); float minLong = (float) boundingBox.getMinX(); float maxLat = (float) boundingBox.getMinY(); float maxLong = (float) boundingBox.getMaxX(); float minLat = (float) boundingBox.getMaxY(); Rectangle rectangle = new Rectangle(minLong, maxLat, maxLong, minLat); return rectangle; } private class GPSSegmentSeachProcedure implements TIntProcedure { private HashSet<GPSSegment> segments = new HashSet<GPSSegment>(100); public GPSSegmentSeachProcedure() { } @Override public boolean execute(int value) { GPSSegment segment = META_DATA.get(value); if (segment != null) { segments.add(segment); } return true; } public Collection<GPSSegment> getSegments() { return segments; } } }