package net.osmand.plus.mapcontextmenu.controllers; import android.view.View; import android.view.View.OnClickListener; import net.osmand.data.LatLon; import net.osmand.data.PointDescription; import net.osmand.data.QuadRect; import net.osmand.data.RotatedTileBox; import net.osmand.data.TransportRoute; import net.osmand.data.TransportStop; import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.mapcontextmenu.MapContextMenu; import net.osmand.plus.mapcontextmenu.MenuBuilder; import net.osmand.plus.mapcontextmenu.MenuController; import net.osmand.plus.resources.TransportIndexRepository; import net.osmand.plus.views.TransportStopsLayer; import net.osmand.util.Algorithms; import net.osmand.util.MapUtils; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; public class TransportStopController extends MenuController { public enum TransportStopType { BUS(R.drawable.mx_route_bus_ref, R.drawable.mx_route_bus_ref), FERRY(R.drawable.mx_route_ferry_ref, R.drawable.mx_route_ferry_ref), FUNICULAR(R.drawable.mx_route_funicular_ref, R.drawable.mx_route_funicular_ref), LIGHT_RAIL(R.drawable.mx_route_light_rail_ref, R.drawable.mx_route_light_rail_ref), MONORAIL(R.drawable.mx_route_monorail_ref, R.drawable.mx_route_monorail_ref), RAILWAY(R.drawable.mx_route_railway_ref, R.drawable.mx_route_railway_ref), SHARE_TAXI(R.drawable.mx_route_share_taxi_ref, R.drawable.mx_route_share_taxi_ref), TRAIN(R.drawable.mx_route_train_ref, R.drawable.mx_route_train_ref), TRAM(R.drawable.mx_route_tram_ref, R.drawable.mx_railway_tram_stop), TROLLEYBUS(R.drawable.mx_route_trolleybus_ref, R.drawable.mx_route_trolleybus_ref), SUBWAY(R.drawable.mx_subway_station, R.drawable.mx_subway_station); final int resId; final int topResId; TransportStopType(int resId, int topResId) { this.resId = resId; this.topResId = topResId; } public int getResourceId() { return resId; } public int getTopResourceId() { return topResId; } public boolean isTopType() { return this == TRAM || this == SUBWAY; } public static TransportStopType findType(String typeName) { String tName = typeName.toUpperCase(); for (TransportStopType t : values()) { if (t.name().equals(tName)) { return t; } } return null; } } private TransportStop transportStop; private List<TransportStopRoute> routes = new ArrayList<>(); private TransportStopType topType; public TransportStopController(MapActivity mapActivity, PointDescription pointDescription, TransportStop transportStop) { super(new MenuBuilder(mapActivity), pointDescription, mapActivity); this.transportStop = transportStop; processTransportStop(); } @Override protected void setObject(Object object) { if (object instanceof TransportStop) { this.transportStop = (TransportStop) object; processTransportStop(); } } @Override protected Object getObject() { return transportStop; } @Override public int getLeftIconId() { if (topType == null) { return R.drawable.mx_public_transport; } else { return topType.getTopResourceId(); } } @Override public boolean needStreetName() { return Algorithms.isEmpty(getNameStr()); } @Override public boolean displayDistanceDirection() { return true; } @Override public String getTypeStr() { return getPointDescription().getTypeName(); } @Override public void addPlainMenuItems(String typeStr, PointDescription pointDescription, final LatLon latLon) { addPlainMenuItems(builder, latLon); super.addPlainMenuItems(typeStr, pointDescription, latLon); } public void addPlainMenuItems(MenuBuilder builder, final LatLon latLon) { for (final TransportStopRoute r : routes) { OnClickListener listener = new OnClickListener() { @Override public void onClick(View arg0) { MapContextMenu mm = getMapActivity().getContextMenu(); PointDescription pd = new PointDescription(PointDescription.POINT_TYPE_TRANSPORT_ROUTE, r.getDescription(getMapActivity().getMyApplication(), false)); mm.show(latLon, pd, r); TransportStopsLayer stopsLayer = getMapActivity().getMapLayers().getTransportStopsLayer(); stopsLayer.setRoute(r.route); int cz = r.calculateZoom(0, getMapActivity().getMapView().getCurrentRotatedTileBox()); getMapActivity().changeZoom(cz - getMapActivity().getMapView().getZoom()); } }; if (r.type == null) { builder.addPlainMenuItem(R.drawable.ic_action_polygom_dark, r.getDescription(getMapActivity().getMyApplication(), true), false, false, listener ); } else { builder.addPlainMenuItem(r.type.getResourceId(), r.getDescription(getMapActivity().getMyApplication(), true), false, false, listener); } } } private void processTransportStop() { routes.clear(); List<TransportIndexRepository> reps = getMapActivity().getMyApplication() .getResourceManager().searchTransportRepositories(transportStop.getLocation().getLatitude(), transportStop.getLocation().getLongitude()); boolean useEnglishNames = getMapActivity().getMyApplication().getSettings().usingEnglishNames(); for (TransportIndexRepository t : reps) { if (t.acceptTransportStop(transportStop)) { boolean empty = transportStop.getReferencesToRoutes() == null || transportStop.getReferencesToRoutes().length == 0; if(!empty) { addRoutes(useEnglishNames, t, transportStop, transportStop, 0); } ArrayList<TransportStop> ls = new ArrayList<>(); QuadRect ll = MapUtils.calculateLatLonBbox(transportStop.getLocation().getLatitude(), transportStop.getLocation().getLongitude(), 150); t.searchTransportStops(ll.top, ll.left, ll.bottom, ll.right, -1, ls, null); for(TransportStop tstop : ls) { if(tstop.getId().longValue() != transportStop.getId().longValue() || empty) { addRoutes(useEnglishNames, t, tstop, transportStop, (int) MapUtils.getDistance(tstop.getLocation(), transportStop.getLocation())); } } } } Collections.sort(routes, new Comparator<TransportStopRoute>() { @Override public int compare(TransportStopRoute o1, TransportStopRoute o2) { if(o1.distance != o2.distance) { return Algorithms.compare(o1.distance, o2.distance); } int i1 = Algorithms.extractFirstIntegerNumber(o1.desc); int i2 = Algorithms.extractFirstIntegerNumber(o2.desc); if(i1 != i2) { return Algorithms.compare(i1, i2); } return o1.desc.compareTo(o2.desc); } }); } private void addRoutes(boolean useEnglishNames, TransportIndexRepository t, TransportStop s, TransportStop refStop, int dist) { Collection<TransportRoute> rts = t.getRouteForStop(s); if (rts != null) { for (TransportRoute rs : rts) { TransportStopType type = TransportStopType.findType(rs.getType()); TransportStopRoute r = new TransportStopRoute(); if (topType == null && type != null && type.isTopType()) { topType = type; } r.type = type; r.desc = rs.getRef() + " " + (useEnglishNames ? rs.getEnName(true) : rs.getName()); r.route = rs; r.refStop = refStop; r.stop = s; r.distance = dist; this.routes.add(r); } } } public static class TransportStopRoute { public TransportStop refStop; public TransportStopType type; public String desc; public TransportRoute route; public TransportStop stop; public int distance; public boolean showWholeRoute; public String getDescription(OsmandApplication ctx, boolean useDistance) { if (useDistance && distance > 0) { String nm = OsmAndFormatter.getFormattedDistance(distance, ctx); if (refStop != null && !refStop.getName().equals(stop.getName())) { nm = refStop.getName() + ", " + nm; } return desc + " (" + nm + ")"; } return desc; } public int calculateZoom(int startPosition, RotatedTileBox currentRotatedTileBox) { RotatedTileBox cp = currentRotatedTileBox.copy(); boolean notContains = true; while (cp.getZoom() > 12 && notContains) { notContains = false; List<TransportStop> sts = route.getForwardStops(); for(int i = startPosition; i < sts.size(); i++) { TransportStop st = sts.get(startPosition); if (!cp.containsLatLon(st.getLocation())) { notContains = true; break; } } cp.setZoom(cp.getZoom() - 1); } return cp.getZoom(); } } }