package pl.edu.agh.dao; import static com.google.common.collect.Lists.newArrayList; import java.util.List; import org.hibernate.SQLQuery; import org.springframework.stereotype.Component; import pl.edu.agh.model.Way; import pl.edu.agh.model.WayWithSpeedInfo; import pl.edu.agh.spatial.GeometryHelper; import pl.edu.agh.spatial.SpatialTypes; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.Point; @Component public class WayHibernateDao extends AbstractDao implements WayDao { private static final String EMPTY = ""; private static final int MOTORWAY_CLASS_ID = 101; private static final int PRIMARY_LINK_CLASS_ID = 107; private static final int SECONDARY_CLASS_ID = 108; private static final int TETRIARY_CLASS_ID = 109; private static final int ROUNDABOUNT_CLASS_ID = 401; private static final double BOUNDING_BOX_SIZE = 0.1; private static final double MAX_RADIUS = 0.17247492; private static final double PRIMARY_RADIUS = 0.08623746; private static final double SECONDARY_RADIUS = 0.04311873; private static final double TETRIARY_RADIUS = 0.021559365; @Override public Way findNearestWay(Point point) { SQLQuery query = getCurrentSession().createSQLQuery( "select way.*, " + Way.DISCRIMINATOR_VALUE + " as discriminator from " + Way.TABLE_NAME + " as way where the_geom && :box order by ST_Distance(the_geom, :point)"); query.setMaxResults(1); query.setParameter("point", point, SpatialTypes.GEOMETRY); query.setParameter("box", GeometryHelper.getExpandedEnvelopeAsGeometry(point, BOUNDING_BOX_SIZE), SpatialTypes.GEOMETRY); query.addEntity("way", Way.class); return (Way) query.uniqueResult(); } @SuppressWarnings("unchecked") @Override public List<Way> findRoute(Integer startIndex, Integer endIndex, boolean useTrafficDataToRoute) { SQLQuery query = getCurrentSession() .createSQLQuery( "select way.*, " + Way.DISCRIMINATOR_VALUE + " as discriminator from astar_sp_delta_cc_directed(:ways_view_name, :start_index, :end_index, :box_size, :cost_column, :is_directed, :has_reverse_cost) as route inner join " + Way.TABLE_NAME + " as way on route.gid = way.gid"); query.setString("ways_view_name", useTrafficDataToRoute ? Way.WAYS_WITH_TRAFFIC_COSTS_VIEW_NAME : Way.WAYS_WITH_LENGTH_COSTS_VIEW_NAME); query.setInteger("start_index", startIndex); query.setInteger("end_index", endIndex); query.setDouble("box_size", BOUNDING_BOX_SIZE); query.setString("cost_column", Way.VIEW_COL_COST); query.setBoolean("is_directed", true); query.setBoolean("has_reverse_cost", true); query.addEntity("way", Way.class); return (List<Way>) query.list(); } @SuppressWarnings("unchecked") @Override public List<WayWithSpeedInfo> getTrafficData(Point point, double radius) { if (radius > MAX_RADIUS) { return newArrayList(); } SQLQuery query = getCurrentSession() .createSQLQuery( "select way.*, traffic.direct_way_speed, traffic.reverse_way_speed, " + WayWithSpeedInfo.DISCRIMINATOR_VALUE + " as discriminator from " + Way.TABLE_NAME + " as way inner join traffic_info as traffic on way.gid = traffic.way_gid where way.the_geom && :box" + getWayClassCondition(radius)); query.setParameter("box", GeometryHelper.getExpandedEnvelopeAsGeometry(point, radius), SpatialTypes.GEOMETRY); query.addEntity("way", WayWithSpeedInfo.class); return (List<WayWithSpeedInfo>) query.list(); } private String getWayClassCondition(double radius) { if (radius >= PRIMARY_RADIUS) { return " and way.class_id between " + MOTORWAY_CLASS_ID + " and " + PRIMARY_LINK_CLASS_ID; } if (radius >= SECONDARY_RADIUS) { return " and (way.class_id between " + MOTORWAY_CLASS_ID + " and " + SECONDARY_CLASS_ID + " or way.class_id = " + ROUNDABOUNT_CLASS_ID + ")"; } if (radius >= TETRIARY_RADIUS) { return " and (way.class_id between " + MOTORWAY_CLASS_ID + " and " + TETRIARY_CLASS_ID + " or way.class_id = " + ROUNDABOUNT_CLASS_ID + ")"; } return EMPTY; } @SuppressWarnings("unchecked") @Override public List<Way> getWaysInsideBox(Geometry box) { SQLQuery query = getCurrentSession().createSQLQuery( "select way.*, " + Way.DISCRIMINATOR_VALUE + " as discriminator from " + Way.TABLE_NAME + " as way where the_geom && :box"); query.setParameter("box", box, SpatialTypes.GEOMETRY); query.addEntity("way", Way.class); return (List<Way>) query.list(); } }