/** * Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org> * * 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 org.onebusaway.geospatial.grid; import org.onebusaway.geospatial.model.CoordinateBounds; import org.onebusaway.geospatial.model.EncodedPolygonBean; import org.onebusaway.geospatial.services.SphericalGeometryLibrary; import org.onebusaway.utility.filter.IFilter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class TimedGridFactory { private GridFactoryImpl _grid; private double _velocity; private double _sourceLat; private double _sourceLon; private long _time; private long _timeRemaining; public TimedGridFactory(double gridLatStep, double gridLonStep, double velocity) { _grid = new GridFactoryImpl(gridLatStep,gridLonStep); _velocity = velocity; } public void addPoint(double lat, double lon, long time, long timeRemaining) { _sourceLat = lat; _sourceLon = lon; _time = time; _timeRemaining = timeRemaining; double distanceRemaining = timeRemaining * _velocity; CoordinateBounds bounds = SphericalGeometryLibrary.bounds(lat, lon, distanceRemaining); _grid.addBounds(bounds); _sourceLat = Double.NaN; _sourceLon = Double.NaN; _time = 0; _timeRemaining = 0; } public Map<Integer, List<EncodedPolygonBean>> getPolygonsByTime( int segmentSizeInMinutes) { return _grid.getPolygonsByTime(segmentSizeInMinutes); } private class GridFactoryImpl extends GridFactory { public GridFactoryImpl(double gridLatStep, double gridLonStep) { super(gridLatStep,gridLonStep); } public Map<Integer, List<EncodedPolygonBean>> getPolygonsByTime( int segmentSizeInMinutes) { Map<Integer, List<Grid.Entry<Object>>> indicesByTime = new HashMap<Integer, List<Grid.Entry<Object>>>(); for (Grid.Entry<Object> entry : _grid.getEntries()) { Long value = (Long) entry.getValue(); int t = (int) (value / (1000 * 60 * segmentSizeInMinutes)); get(indicesByTime,t).add(entry); } Map<Integer, List<EncodedPolygonBean>> results = new HashMap<Integer, List<EncodedPolygonBean>>(); for (Map.Entry<Integer, List<Grid.Entry<Object>>> entry : indicesByTime.entrySet()) { BoundaryFactory factory = new BoundaryFactory(); factory.setPruneAllButCorners(true); int offset = entry.getKey(); long tFrom = offset * segmentSizeInMinutes * 60 * 1000; long tTo = (offset + 1) * segmentSizeInMinutes * 60 * 1000; TimeRangeFilter filter = new TimeRangeFilter(tFrom, tTo); FilteredGrid<Object> filtered = new FilteredGrid<Object>(_grid, filter); List<Boundary> boundaries = factory.getBoundaries(filtered, entry.getValue()); List<EncodedPolygonBean> beans = getBoundariesAsBeans(boundaries); results.put(offset, beans); } return results; } @Override protected void addCell(GridIndex index, Object value) { if (Double.isNaN(_sourceLat) || Double.isNaN(_sourceLon)) throw new IllegalStateException(); CoordinateBounds bounds = getIndexAsBounds(index); double lat2 = (bounds.getMinLat() + bounds.getMaxLat()) / 2; double lon2 = (bounds.getMinLon() + bounds.getMaxLon()) / 2; double d = SphericalGeometryLibrary.distance(_sourceLat, _sourceLon, lat2, lon2); double t = d == 0 ? 0 : d / _velocity; if (t > _timeRemaining) return; long time = (long) (t + _time); Long currentTime = (Long) _grid.get(index); if (currentTime == null || currentTime > time) super.addCell(index, new Long(time)); } private List<Grid.Entry<Object>> get( Map<Integer, List<Grid.Entry<Object>>> map, Integer key) { List<Grid.Entry<Object>> list = map.get(key); if (list == null) { list = new ArrayList<Grid.Entry<Object>>(); map.put(key, list); } return list; } } private static class TimeRangeFilter implements IFilter<Object> { private long _from; private long _to; public TimeRangeFilter(long from, long to) { _from = from; _to = to; } public boolean isEnabled(Object object) { Long time = (Long) object; return _from <= time && time < _to; } } }