/**
* 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.transit_data_federation.impl.beans;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.onebusaway.container.cache.Cacheable;
import org.onebusaway.geospatial.model.CoordinatePoint;
import org.onebusaway.geospatial.model.EncodedPolylineBean;
import org.onebusaway.geospatial.services.PolylineEncoder;
import org.onebusaway.gtfs.model.AgencyAndId;
import org.onebusaway.transit_data.model.ListBean;
import org.onebusaway.transit_data_federation.model.ShapePoints;
import org.onebusaway.transit_data_federation.services.AgencyAndIdLibrary;
import org.onebusaway.transit_data_federation.services.beans.ShapeBeanService;
import org.onebusaway.transit_data_federation.services.shapes.ShapePointService;
import org.onebusaway.transit_data_federation.services.transit_graph.TransitGraphDao;
import org.onebusaway.transit_data_federation.services.transit_graph.TripEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
class ShapeBeanServiceImpl implements ShapeBeanService {
private static Logger _log = LoggerFactory.getLogger(ShapeBeanServiceImpl.class);
private ShapePointService _shapePointService;
private TransitGraphDao _transitGraphDao;
@Autowired
public void setShapePointService(ShapePointService shapePointService) {
_shapePointService = shapePointService;
}
@Autowired
public void setTransitGraphDao(TransitGraphDao transitGraphDao) {
_transitGraphDao = transitGraphDao;
}
@Cacheable
public EncodedPolylineBean getPolylineForShapeId(AgencyAndId id) {
ShapePoints shapePoints = _shapePointService.getShapePointsForShapeId(id);
if (shapePoints == null)
return null;
return PolylineEncoder.createEncodings(shapePoints.getLats(),
shapePoints.getLons(), -1);
}
@Cacheable
public List<EncodedPolylineBean> getMergedPolylinesForShapeIds(
Collection<AgencyAndId> shapeIds) {
List<EncodedPolylineBean> polylines = new ArrayList<EncodedPolylineBean>();
if (shapeIds.isEmpty())
return polylines;
List<CoordinatePoint> currentLine = new ArrayList<CoordinatePoint>();
Set<Edge> edges = new HashSet<Edge>();
for (AgencyAndId shapeId : shapeIds) {
ShapePoints shapePoints = _shapePointService.getShapePointsForShapeId(shapeId);
if (shapePoints == null) {
_log.warn("no shape points for shapeId=" + shapeId);
continue;
}
double[] lats = shapePoints.getLats();
double[] lons = shapePoints.getLons();
CoordinatePoint prev = null;
for (int i = 0; i < shapePoints.getSize(); i++) {
CoordinatePoint loc = new CoordinatePoint(lats[i], lons[i]);
if (prev != null && !prev.equals(loc)) {
Edge edge = new Edge(prev, loc);
if (!edges.add(edge)) {
if (currentLine.size() > 1)
polylines.add(PolylineEncoder.createEncodings(currentLine));
currentLine.clear();
}
}
if (prev == null || !prev.equals(loc))
currentLine.add(loc);
prev = loc;
}
if (currentLine.size() > 1)
polylines.add(PolylineEncoder.createEncodings(currentLine));
currentLine.clear();
}
return polylines;
}
@Override
public ListBean<String> getShapeIdsForAgencyId(String agencyId) {
Set<AgencyAndId> shapeIds = new HashSet<AgencyAndId>();
for (TripEntry trip : _transitGraphDao.getAllTrips()) {
AgencyAndId shapeId = trip.getShapeId();
if (shapeId == null || !shapeId.hasValues())
continue;
if (!shapeId.getAgencyId().equals(agencyId))
continue;
shapeIds.add(shapeId);
}
List<String> ids = new ArrayList<String>();
for (AgencyAndId shapeId : shapeIds) {
String id = AgencyAndIdLibrary.convertToString(shapeId);
ids.add(id);
}
Collections.sort(ids);
return new ListBean<String>(ids, false);
}
/****
* Private Methods
****/
private static int compare(CoordinatePoint a, CoordinatePoint b) {
int rc = Double.compare(a.getLat(), b.getLat());
if (rc == 0)
rc = Double.compare(a.getLon(), b.getLon());
return rc;
}
private static class Edge {
private final CoordinatePoint _a;
private final CoordinatePoint _b;
public Edge(CoordinatePoint a, CoordinatePoint b) {
int rc = compare(a, b);
if (rc <= 0) {
_a = a;
_b = b;
} else {
_a = b;
_b = a;
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((_a == null) ? 0 : _a.hashCode());
result = prime * result + ((_b == null) ? 0 : _b.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Edge other = (Edge) obj;
if (_a == null) {
if (other._a != null)
return false;
} else if (!_a.equals(other._a))
return false;
if (_b == null) {
if (other._b != null)
return false;
} else if (!_b.equals(other._b))
return false;
return true;
}
}
}