diff --git a/GO_Sync/src/main/java/edu/usf/cutr/go_sync/gui/MainForm.form b/GO_Sync/src/main/java/edu/usf/cutr/go_sync/gui/MainForm.form index e7800803..d23b96fe 100644 --- a/GO_Sync/src/main/java/edu/usf/cutr/go_sync/gui/MainForm.form +++ b/GO_Sync/src/main/java/edu/usf/cutr/go_sync/gui/MainForm.form @@ -1208,7 +1208,7 @@ - + @@ -1225,18 +1225,26 @@ - + + - + + + + + + + - + + @@ -2896,7 +2904,7 @@ - + diff --git a/GO_Sync/src/main/java/edu/usf/cutr/go_sync/gui/MainForm.java b/GO_Sync/src/main/java/edu/usf/cutr/go_sync/gui/MainForm.java index 1aeb8e05..12457f26 100644 --- a/GO_Sync/src/main/java/edu/usf/cutr/go_sync/gui/MainForm.java +++ b/GO_Sync/src/main/java/edu/usf/cutr/go_sync/gui/MainForm.java @@ -208,6 +208,7 @@ private void initComponents() { routeMemberOptionPanel = new javax.swing.JPanel(); skipNodesWithRoleEmptyCb = new javax.swing.JCheckBox(); skipNodesWithRoleStopCb = new javax.swing.JCheckBox(); + skipNodesWithRoleStopWithoutMatchinPlatformCb = new javax.swing.JCheckBox(); removePlatformsNotInGtfsFromOSMRelationCb = new javax.swing.JCheckBox(); gtfsDataPanel = new javax.swing.JPanel(); rbURL = new javax.swing.JRadioButton(); @@ -443,18 +444,24 @@ private void initComponents() { gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; optionsPanel.add(routeOptionsPanel, gridBagConstraints); - routeMemberOptionPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Route members options")); + routeMemberOptionPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Route members options (applies only to PTv2 relations)")); routeMemberOptionPanel.setLayout(new javax.swing.BoxLayout(routeMemberOptionPanel, javax.swing.BoxLayout.Y_AXIS)); skipNodesWithRoleEmptyCb.setSelected(true); - skipNodesWithRoleEmptyCb.setText("Remove nodes with empty role (required for PTv2)"); + skipNodesWithRoleEmptyCb.setText("Remove nodes having empty role (mandatory for PTv2)"); + skipNodesWithRoleEmptyCb.setEnabled(false); routeMemberOptionPanel.add(skipNodesWithRoleEmptyCb); - skipNodesWithRoleStopCb.setText("Remove nodes with role 'stop' (only if PTv2 is enabled)"); + skipNodesWithRoleStopCb.setText("Remove all nodes having role 'stop'"); skipNodesWithRoleStopCb.setActionCommand("Remove nodes with 'stop' role"); routeMemberOptionPanel.add(skipNodesWithRoleStopCb); - removePlatformsNotInGtfsFromOSMRelationCb.setText("Remove platform nodes without Gtfs match (only if PTv2 is enabled)"); + skipNodesWithRoleStopWithoutMatchinPlatformCb.setSelected(true); + skipNodesWithRoleStopWithoutMatchinPlatformCb.setText("Remove nodes having role 'stop' that don't match a platform (recommended)"); + routeMemberOptionPanel.add(skipNodesWithRoleStopWithoutMatchinPlatformCb); + + removePlatformsNotInGtfsFromOSMRelationCb.setSelected(true); + removePlatformsNotInGtfsFromOSMRelationCb.setText("Remove platforms without Gtfs match (recommended)"); routeMemberOptionPanel.add(removePlatformsNotInGtfsFromOSMRelationCb); gridBagConstraints = new java.awt.GridBagConstraints(); @@ -672,7 +679,7 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { .addGroup(revertChangesetPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(revertChangesetField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(changesetLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 373, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 376, Short.MAX_VALUE) .addComponent(revertButton) .addContainerGap()) ); @@ -787,19 +794,23 @@ private void compareButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN processingOptions.add(ProcessingOptions.SKIP_GTFS_STATIONS); } if (skipNodesWithRoleEmptyCb.isSelected()) { - processingOptions.add(ProcessingOptions.SKIP_NODES_WITH_ROLE_EMPTY); + processingOptions.add(ProcessingOptions.SKIP_NODES_HAVING_ROLE_EMPTY); } if (createAsPTv2Cb.isSelected()) { processingOptions.add(ProcessingOptions.CREATE_ROUTE_AS_PTV2); + processingOptions.add(ProcessingOptions.SKIP_NODES_HAVING_ROLE_EMPTY); } if (removePlatformsNotInGtfsFromOSMRelationCb.isSelected()) { - processingOptions.add(ProcessingOptions.REMOVE_PLATFORMS_NOT_IN_GTFS_TRIP_FROM_OSM_RELATION); + processingOptions.add(ProcessingOptions.SKIP_NODES_HAVING_ROLE_PLATFORM_NOT_IN_GTFS_TRIP_FROM_OSM_RELATION); } if (dontReplaceExistingOSMRouteColorCb.isSelected()) { processingOptions.add(ProcessingOptions.DONT_REPLACE_EXISING_OSM_ROUTE_COLOR); } if (skipNodesWithRoleStopCb.isSelected()) { - processingOptions.add(ProcessingOptions.SKIP_NODES_WITH_ROLE_STOP); + processingOptions.add(ProcessingOptions.SKIP_NODES_HAVING_ROLE_STOP_ALL); + } + if (skipNodesWithRoleStopWithoutMatchinPlatformCb.isSelected()) { + processingOptions.add(ProcessingOptions.SKIP_NODES_HAVING_ROLE_STOP_WITHOUT_MATCHING_PLATFORM); } if (dontAddGtfsRouteTextColorCb.isSelected()) { processingOptions.add(ProcessingOptions.DONT_ADD_GTFS_ROUTE_TEXT_COLOR_TO_ROUTE); @@ -1121,6 +1132,7 @@ public void propertyChange(PropertyChangeEvent evt) { private javax.swing.JCheckBox skipGtfsStationsCb; private javax.swing.JCheckBox skipNodesWithRoleEmptyCb; private javax.swing.JCheckBox skipNodesWithRoleStopCb; + private javax.swing.JCheckBox skipNodesWithRoleStopWithoutMatchinPlatformCb; private javax.swing.JPanel stopOptionsPanel; private javax.swing.JTextArea taskOutput; private javax.swing.JLabel threshold_label; diff --git a/GO_Sync/src/main/java/edu/usf/cutr/go_sync/gui/ReportViewer.java b/GO_Sync/src/main/java/edu/usf/cutr/go_sync/gui/ReportViewer.java index 6380c364..5b38af74 100644 --- a/GO_Sync/src/main/java/edu/usf/cutr/go_sync/gui/ReportViewer.java +++ b/GO_Sync/src/main/java/edu/usf/cutr/go_sync/gui/ReportViewer.java @@ -21,6 +21,7 @@ import edu.usf.cutr.go_sync.object.Stop; import edu.usf.cutr.go_sync.osm.HttpRequest; import edu.usf.cutr.go_sync.tag_defs; +import edu.usf.cutr.go_sync.task.CompareData; import edu.usf.cutr.go_sync.task.UploadData; import edu.usf.cutr.go_sync.tools.OsmDistance; import java.awt.Color; @@ -1168,99 +1169,145 @@ private void updateMemberList(Route selectedNewRoute, Route selectedOsmRoute, St LinkedHashSet newMembersWaysOnly = new LinkedHashSet(); LinkedHashSet tempem = new LinkedHashSet(); ArrayList skippedMembersIndex = new ArrayList<>(); - ArrayList skippedMembersIndexNodes = new ArrayList<>(); int indexInNewMember = 0; - for (RelationMember m : aRoute.getOsmMembers()) { - if (m.getRef().startsWith("-")) { - skippedMembersIndex.add(indexInNewMember); - } - newMembers.add(m); - indexInNewMember++; - } + newMembers.addAll(aRoute.getOsmMembers()); tempem.addAll(osmMembers); - EnumSet strategy = MainForm.processingOptions; - - int indexInNewMemberNodes = indexInNewMember; - for (RelationMember m : tempem) { RelationMember matchMember = aRoute.getOsmMember(m.getRef()); if (matchMember != null) { matchMember.setStatus("both GTFS dataset and OSM server"); } else { if (PTversion != null && PTversion.equals("2")) { + // Rearrange nodes & ways so that nodes (platforms, stops...) come before ways (ways with empty role) if (m.getType().equals("node")) { - if (strategy.contains(ProcessingOptions.SKIP_NODES_WITH_ROLE_EMPTY)) { - if (m.getRole().isEmpty()) { - skippedMembersIndexNodes.add(indexInNewMemberNodes); - } - } - if (strategy.contains(ProcessingOptions.SKIP_NODES_WITH_ROLE_STOP)) { - if (m.getRole().equals("stop") || m.getRole().equals("stop_exit_only") || m.getRole().equals("stop_entry_only")) { - skippedMembersIndexNodes.add(indexInNewMemberNodes); - } - } - if (strategy.contains(ProcessingOptions.REMOVE_PLATFORMS_NOT_IN_GTFS_TRIP_FROM_OSM_RELATION)) { - if (m.getRole().equals("platform") || m.getRole().equals("platform_exit_only") || m.getRole().equals("platform_entry_only")) { - skippedMembersIndexNodes.add(indexInNewMemberNodes); - } - } newMembersNodesOnly.add(m); - indexInNewMemberNodes++; } if (m.getType().equals("way")) { - if (m.getRole().equals("platform") || m.getRole().equals("platform_exit_only") || m.getRole().equals("platform_entry_only")) { - // Ways can also be set as platforms. Support this case too. They should be at the top with the other platforms/stops. - if (strategy.contains(ProcessingOptions.REMOVE_PLATFORMS_NOT_IN_GTFS_TRIP_FROM_OSM_RELATION)) { - if (m.getRole().equals("platform") || m.getRole().equals("platform_exit_only") || m.getRole().equals("platform_entry_only")) { - skippedMembersIndexNodes.add(indexInNewMemberNodes); - } - } + // Ways can also be set as platforms. Support this case too. They should be at the top with the other platforms/stops. + if (m.getRoleForFinalOutput().equals("platform") || m.getRoleForFinalOutput().equals("platform_exit_only") || m.getRoleForFinalOutput().equals("platform_entry_only")) { newMembersNodesOnly.add(m); - indexInNewMemberNodes++; } else { - // roles "backward", "forward" & "reverse" should not be used anymore on public transport routes - // https://wiki.openstreetmap.org/wiki/Relation:route - if (m.getRole().equals("backward") || m.getRole().equals("forward") || m.getRole().equals("reverse")) { - m.setRole(""); - } newMembersWaysOnly.add(m); } } } else { newMembers.add(m); - indexInNewMember++; } } } if (PTversion != null && PTversion.equals("2")) { - newMembers.addAll(newMembersNodesOnly); - newMembers.addAll(newMembersWaysOnly); - skippedMembersIndex.addAll(skippedMembersIndexNodes); - } + // For PTv2 group platform/stops together + int index = 0; + LinkedHashSet platforms = new LinkedHashSet(); + platforms.addAll(newMembers); + LinkedHashSet stops = new LinkedHashSet(); + for (RelationMember m : newMembersNodesOnly) { + + // Fix member role in case it doesn't match the real public_transport value of the member (eg. member having role stop, while it actually is a platform). + String roleSuffix = ""; + if (m.getRole().endsWith("_exit_only")) { + roleSuffix = "_exit_only"; + } else if (m.getRole().endsWith("_entry_only")) { + roleSuffix = "_entry_only"; + } + switch (m.getRefOsmPublicTransportType()) { + case "stop_position": + if (!m.getRole().startsWith("stop")) { + m.setRole("stop" + roleSuffix); + } + break; + case "platform": + if (!m.getRole().startsWith("platform")) { + m.setRole("platform" + roleSuffix); + } + break; + default: + break; + } - indexInNewMember = newMembers.size(); - if (!osmMembers.containsAll(newMembers)) { - for (RelationMember m : osmMembers) { - boolean addToSkippedMembersIndex = false; - if (strategy.contains(ProcessingOptions.SKIP_NODES_WITH_ROLE_EMPTY)) { - if (m.getType().equals("node") && m.getRole().isEmpty()) { - addToSkippedMembersIndex = true; - } + if (m.getRoleForFinalOutput().equals("platform") || m.getRoleForFinalOutput().equals("platform_exit_only") || m.getRoleForFinalOutput().equals("platform_entry_only")) { + platforms.add(m); } - if (strategy.contains(ProcessingOptions.SKIP_NODES_WITH_ROLE_STOP)) { - if (m.getType().equals("node") && m.getRole().isEmpty()) { - addToSkippedMembersIndex = true; - } + if (m.getRoleForFinalOutput().equals("stop") || m.getRoleForFinalOutput().equals("stop_exit_only") || m.getRoleForFinalOutput().equals("stop_entry_only")) { + stops.add(m); } - if (strategy.contains(ProcessingOptions.REMOVE_PLATFORMS_NOT_IN_GTFS_TRIP_FROM_OSM_RELATION)) { - if (m.getRole().equals("platform") || m.getRole().equals("platform_exit_only") || m.getRole().equals("platform_entry_only")) { - addToSkippedMembersIndex = true; + index++; + } + + LinkedHashSet newMembersNodesOnlyGrouped = new LinkedHashSet(); + LinkedHashSet addedStops = new LinkedHashSet(); + for (RelationMember p : platforms) { + newMembersNodesOnlyGrouped.add(p); + if (shouldSkipMember(PTversion, p, null, aRoute.getOsmMembers())) { + // if p will be skipped (eg. if it is platform not in gtfs) don't proceed with trying to add the nearby stop. + // Otherwise if the stop matches a platform that is not part of the gtfs trip but currently present in the OSM relation, + // it will be kept, even if the platform is not in the final relation for upload (which is not wanted). + continue; + } + for (RelationMember s : stops) { + double dist = OsmDistance.distVincenty(p.getLat(), p.getLon(), s.getLat(), s.getLon()); + if (dist < CompareData.MAX_PLATFORM_STOP_DISTANCE) { + newMembersNodesOnlyGrouped.add(s); + switch (p.getRole()) { + case "platform": + s.setRole("stop"); + break; + case "platform_exit_only": + s.setRole("stop_exit_only"); + break; + case "platform_entry_only": + s.setRole("stop_entry_only"); + break; + default: + break; + } + addedStops.add(s); } } + } + + LinkedHashSet remainingStops = new LinkedHashSet(); + remainingStops.addAll(stops); + remainingStops.removeAll(addedStops); + + // For PTv2: we must have first the nodes, then the ways. + newMembers.clear(); + newMembers.addAll(newMembersNodesOnlyGrouped); + newMembers.addAll(remainingStops); + newMembers.addAll(newMembersWaysOnly); + + // Mark members to be removed & apply other modifications as asked in processingOptions. + for (RelationMember m : newMembers) { + if (m.getType().equals("way") && (m.getRole().equals("backward") || m.getRole().equals("forward") || m.getRole().equals("reverse"))) { + // roles "backward", "forward" & "reverse" should not be used anymore on public transport PTv2 routes + // https://wiki.openstreetmap.org/wiki/Relation:route + m.setRole(""); + } + if (shouldSkipMember(PTversion, m, remainingStops, aRoute.getOsmMembers())) { + skippedMembersIndex.add(indexInNewMember); + } + indexInNewMember++; + } + } + + // Skip members the OSM id of which is negative + indexInNewMember = 0; + for (RelationMember m : newMembers) { + if (m.getRef().startsWith("-")) { + skippedMembersIndex.add(indexInNewMember); + } + indexInNewMember++; + } + + indexInNewMember = newMembers.size(); + if (!newMembers.containsAll(osmMembers)) { + //System.out.println("Adding osm members not yet in new Members."); + for (RelationMember m : osmMembers) { + boolean addToSkippedMembersIndex = shouldSkipMember(PTversion, m, null, aRoute.getOsmMembers()); if (newMembers.add(m)) { if (addToSkippedMembersIndex) { skippedMembersIndex.add(indexInNewMember); @@ -1323,7 +1370,7 @@ private void updateMemberList(Route selectedNewRoute, Route selectedOsmRoute, St String status = t.getStatus(); if(status.equals(criteria) || criteria.equals("all")) { String v = t.getGtfsId(); - String suffix = " (" + t.getType() + "/" + t.getRole() + "/" + t.getRef() + ")"; + String suffix = " (" + t.getType() + "/" + t.getRoleForFinalOutput() + "/" + t.getRef() + ")"; if (v == null || v.equals("none") || v.equals("")) { v = suffix.strip(); } else { @@ -1349,6 +1396,47 @@ private void updateMemberList(Route selectedNewRoute, Route selectedOsmRoute, St totalNewMembersLabel.setText(Integer.toString(newMembersForSave.size())); } + private boolean shouldSkipMember(String PTversion, RelationMember m, LinkedHashSet remainingStops, LinkedHashSet agencyMembers) { + if (!PTversion.equals("2")) { + return false; + } + + if (remainingStops != null && remainingStops.contains(m)) { + if (MainForm.processingOptions.contains(ProcessingOptions.SKIP_NODES_HAVING_ROLE_STOP_WITHOUT_MATCHING_PLATFORM)) { + return true; + } + } + if (m.getType().equals("node")) { + if (MainForm.processingOptions.contains(ProcessingOptions.SKIP_NODES_HAVING_ROLE_EMPTY)) { + if (m.getRole().isEmpty()) { + return true; + } + } + if (MainForm.processingOptions.contains(ProcessingOptions.SKIP_NODES_HAVING_ROLE_STOP_ALL)) { + if (m.getRoleForFinalOutput().equals("stop") || m.getRoleForFinalOutput().equals("stop_exit_only") || m.getRoleForFinalOutput().equals("stop_entry_only")) { + return true; + } + } + if (MainForm.processingOptions.contains(ProcessingOptions.SKIP_NODES_HAVING_ROLE_PLATFORM_NOT_IN_GTFS_TRIP_FROM_OSM_RELATION)) { + if (!agencyMembers.contains(m) + && (m.getRoleForFinalOutput().equals("platform") || m.getRoleForFinalOutput().equals("platform_exit_only") || m.getRoleForFinalOutput().equals("platform_entry_only"))) { + return true; + } + } + } + if (m.getType().equals("way")) { + if (m.getRoleForFinalOutput().equals("platform") || m.getRoleForFinalOutput().equals("platform_exit_only") || m.getRoleForFinalOutput().equals("platform_entry_only")) { + if (MainForm.processingOptions.contains(ProcessingOptions.SKIP_NODES_HAVING_ROLE_PLATFORM_NOT_IN_GTFS_TRIP_FROM_OSM_RELATION)) { + if (!agencyMembers.contains(m) + && (m.getRoleForFinalOutput().equals("platform") || m.getRoleForFinalOutput().equals("platform_exit_only") || m.getRoleForFinalOutput().equals("platform_entry_only"))) { + return true; + } + } + } + } + return false; + } + private void updateRouteCategory(Route[] selectedCategory){ gtfsRoutes = selectedCategory; Arrays.sort(gtfsRoutes); diff --git a/GO_Sync/src/main/java/edu/usf/cutr/go_sync/gui/object/RouteMemberTableModel.java b/GO_Sync/src/main/java/edu/usf/cutr/go_sync/gui/object/RouteMemberTableModel.java index f718d8ce..19366626 100644 --- a/GO_Sync/src/main/java/edu/usf/cutr/go_sync/gui/object/RouteMemberTableModel.java +++ b/GO_Sync/src/main/java/edu/usf/cutr/go_sync/gui/object/RouteMemberTableModel.java @@ -26,7 +26,7 @@ */ public class RouteMemberTableModel extends AbstractTableModel { private String[] columnNames = {"GTFS Member List", - "OSM Member List", + "OSM Member List (ordered by 'New Member List' if PTv2)", "New Member List"}; private Object[][] data; diff --git a/GO_Sync/src/main/java/edu/usf/cutr/go_sync/object/ProcessingOptions.java b/GO_Sync/src/main/java/edu/usf/cutr/go_sync/object/ProcessingOptions.java index 3e41185a..904bdaa3 100644 --- a/GO_Sync/src/main/java/edu/usf/cutr/go_sync/object/ProcessingOptions.java +++ b/GO_Sync/src/main/java/edu/usf/cutr/go_sync/object/ProcessingOptions.java @@ -29,9 +29,10 @@ public enum ProcessingOptions { DONT_ADD_GTFS_AGENCY_ID_TO_ROUTE, // For Route Members - SKIP_NODES_WITH_ROLE_EMPTY, - SKIP_NODES_WITH_ROLE_STOP, + SKIP_NODES_HAVING_ROLE_EMPTY, + SKIP_NODES_HAVING_ROLE_STOP_ALL, + SKIP_NODES_HAVING_ROLE_STOP_WITHOUT_MATCHING_PLATFORM, CREATE_ROUTE_AS_PTV2, - REMOVE_PLATFORMS_NOT_IN_GTFS_TRIP_FROM_OSM_RELATION; + SKIP_NODES_HAVING_ROLE_PLATFORM_NOT_IN_GTFS_TRIP_FROM_OSM_RELATION; } diff --git a/GO_Sync/src/main/java/edu/usf/cutr/go_sync/object/RelationMember.java b/GO_Sync/src/main/java/edu/usf/cutr/go_sync/object/RelationMember.java index d6cfd7d2..82b1457d 100644 --- a/GO_Sync/src/main/java/edu/usf/cutr/go_sync/object/RelationMember.java +++ b/GO_Sync/src/main/java/edu/usf/cutr/go_sync/object/RelationMember.java @@ -23,10 +23,15 @@ */ public class RelationMember { private String ref, type, role, status, gtfsId=""; - public RelationMember(String ref, String type, String role){ + private String lat, lon; + private String refOsmPublicTransportType; + public RelationMember(String ref, String type, String role, String lat, String lon, String refOsmPublicTransportType) { this.ref = ref; this.type = type; this.role = role; + this.lat = lat; + this.lon = lon; + this.refOsmPublicTransportType = refOsmPublicTransportType; } public RelationMember(RelationMember rm){ @@ -35,6 +40,9 @@ public RelationMember(RelationMember rm){ this.role = rm.getRole(); this.gtfsId = rm.getGtfsId(); this.status = rm.getStatus(); + this.lat = rm.getLat(); + this.lon = rm.getLon(); + this.refOsmPublicTransportType = rm.getRefOsmPublicTransportType(); } public String getRef(){ @@ -49,6 +57,30 @@ public String getRole(){ return role; } + public String getRoleForFinalOutput() { + // Get the role/public_transport_type from the referenced osm object. + String cur_role = role; + String new_role = role; + if (refOsmPublicTransportType == null) { + return role; + } + if (!refOsmPublicTransportType.equals("stop_position") && !refOsmPublicTransportType.equals("platform")) { + return role; + } + if (refOsmPublicTransportType.equals("stop_position")) { + new_role = "stop"; + } + if (refOsmPublicTransportType.equals("platform")) { + new_role = "platform"; + } + if (role.endsWith("_exit_only")) { + return new_role + "_exit_only"; + } else if (role.endsWith("_entry_only")) { + return new_role + "_entry_only"; + } + return role; + } + public void setRole(String role) { this.role = role; } @@ -61,6 +93,14 @@ public String getGtfsId(){ return gtfsId; } + public String getRefOsmPublicTransportType() { + return refOsmPublicTransportType; + } + + public void setRefOsmPublicTransportType(String refOsmPublicTransportType) { + this.refOsmPublicTransportType = refOsmPublicTransportType; + } + public int compareTo(Object o){ RelationMember rm = (RelationMember) o; if(this.ref.equals(rm.getRef()) && this.type.equals(rm.getType())){ @@ -83,6 +123,22 @@ public String getStatus(){ return status; } + public String getLat() { + return lat; + } + + public String getLon() { + return lon; + } + + public void setLat(String lat) { + this.lat = lat; + } + + public void setLon(String lon) { + this.lon = lon; + } + @Override public boolean equals(Object o){ if (o instanceof RelationMember) { diff --git a/GO_Sync/src/main/java/edu/usf/cutr/go_sync/osm/HttpRequest.java b/GO_Sync/src/main/java/edu/usf/cutr/go_sync/osm/HttpRequest.java index 55c2065e..25a287c8 100644 --- a/GO_Sync/src/main/java/edu/usf/cutr/go_sync/osm/HttpRequest.java +++ b/GO_Sync/src/main/java/edu/usf/cutr/go_sync/osm/HttpRequest.java @@ -199,11 +199,27 @@ public ArrayList getExistingBusStopsTags(){ public ArrayList getExistingBusRelations(String left, String bottom, String right, String top) throws InterruptedException{ // String urlSuffix = "/api/0.6/relation[route=bus][bbox="+left+","+bottom+","+right+","+top+"]"; // String[] hosts = {"http://open.mapquestapi.com/xapi","http://www.informationfreeway.org"}; - String urlSuffix = "?relation[route=bus][bbox="+left+","+bottom+","+right+","+top+"]"; - String[] hosts = {"http://www.overpass-api.de/api/xapi_meta","http://overpass.openstreetmap.ru/cgi/xapi_meta"}; + + String content = ""; + content += ""; + content += ""; + content += ""; + content += ""; + content += ""; + content += ""; + content += ""; + content += ""; + content += ""; + content = content.replace("left", left).replace("right", right).replace("bottom", bottom).replace("north", top); + System.out.println(content); + + //String urlSuffix = "?relation[route=bus][bbox="+left+","+bottom+","+right+","+top+"]"; + //String[] hosts = {"http://www.overpass-api.de/api/xapi_meta","http://overpass.openstreetmap.ru/cgi/xapi_meta"}; + String[] hosts = {"http://overpass-api.de/api/interpreter", "http://api.openstreetmap.fr/oapi/interpreter", "http://overpass.osm.rambler.ru/cgi/interpreter",}; try { // get data from server - String s = sendRequest(hosts, urlSuffix, "GET", ""); + //String s = sendRequest(hosts, urlSuffix, "GET", ""); + String s = sendRequest(hosts, "", "POST", content); InputSource inputSource = new InputSource(new StringReader(s)); // get data from file - need to remove this for REAL APPLICATION // InputSource inputSource = new InputSource("DataFromServerRELATION.osm"); diff --git a/GO_Sync/src/main/java/edu/usf/cutr/go_sync/task/CompareData.java b/GO_Sync/src/main/java/edu/usf/cutr/go_sync/task/CompareData.java index 4438d96c..b1f5147f 100644 --- a/GO_Sync/src/main/java/edu/usf/cutr/go_sync/task/CompareData.java +++ b/GO_Sync/src/main/java/edu/usf/cutr/go_sync/task/CompareData.java @@ -123,7 +123,7 @@ public class CompareData extends OsmTask{ // private final double DELTA = 0.001; // ~400m in Lat and 400m in Lon 0.00001 ~= 1.108m in Lat and 0.983 in Lon // private final double RANGE = 100; // FIXME bus stop is within 400 meters - + public static final double MAX_PLATFORM_STOP_DISTANCE = 30.0; // in meters. private String fileNameInStops; private String fileNameInTrips; @@ -634,11 +634,14 @@ public void compareRouteData() throws InterruptedException{ // Add gtfs stops as members String OsmNodeId = String.valueOf(-count); String gtfsStopId = rvstop.getValue().getStop_id(); + String type; if (osmStopIdByGtfsStopId.containsKey(gtfsStopId)) { OsmNodeId = osmStopIdByGtfsStopId.get(rvstop.getValue().getStop_id()); + type = osmStopTypeByGtfsStopId.get(gtfsStopId); } else { - + type = "node"; } + String role; if (!rvstop.getValue().getDrop_off_type().equals("1") && rvstop.getValue().getPickup_type().equals("1")) { @@ -650,10 +653,24 @@ public void compareRouteData() throws InterruptedException{ role = "platform"; } + String lat, lon, publicTransportType; + if (osmIdToOSMNodexIndex.get(OsmNodeId) == null) { + lat = "0"; + lon = "0"; + publicTransportType = "platform"; + } else { + lat = OSMNodes.get(osmIdToOSMNodexIndex.get(OsmNodeId)).getLat(); + lon = OSMNodes.get(osmIdToOSMNodexIndex.get(OsmNodeId)).getLon(); + publicTransportType = (String) OSMTags.get(osmIdToOSMNodexIndex.get(OsmNodeId)).get(tag_defs.OSM_STOP_TYPE_KEY); + } + RelationMember rm = new RelationMember( OsmNodeId, - osmStopTypeByGtfsStopId.get(gtfsStopId), - role); + type, + role, + lat, + lon, + publicTransportType); rm.setStatus("GTFS dataset"); rm.setGtfsId(gtfsStopId); r.addOsmMember(rm); diff --git a/GO_Sync/src/main/java/edu/usf/cutr/go_sync/tools/parser/RouteParser.java b/GO_Sync/src/main/java/edu/usf/cutr/go_sync/tools/parser/RouteParser.java index 123af6cd..ac5063b5 100644 --- a/GO_Sync/src/main/java/edu/usf/cutr/go_sync/tools/parser/RouteParser.java +++ b/GO_Sync/src/main/java/edu/usf/cutr/go_sync/tools/parser/RouteParser.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Hashtable; import edu.usf.cutr.go_sync.object.RelationMember; +import java.util.HashMap; import java.util.LinkedHashSet; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.Attributes; @@ -37,11 +38,23 @@ public class RouteParser extends DefaultHandler { //xmlTags ----------- xmlMembers private ArrayList xmlTags; private ArrayList> xmlMembers; - public RouteParser(){ + private HashMap nodes, ways, nodeWayPtValue; + boolean inWay, inNode; + String nodeWayId; + int ndcount; + + public RouteParser() { xmlRelations = new ArrayList(); xmlTags = new ArrayList(); xmlMembers = new ArrayList>(); + nodes = new HashMap<>(); + ways = new HashMap<>(); + nodeWayPtValue = new HashMap<>(); + inWay = false; + inNode = false; + ndcount = 0; } + @Override public void startElement(String namespaceURI, String localName, String qname, Attributes attributes) throws SAXException { if (qname.equals("relation")) { AttributesImpl attImpl = new AttributesImpl(attributes); @@ -49,16 +62,40 @@ public RouteParser(){ tempTag = new Hashtable(); // start to collect tags of that relation tempMembers = new LinkedHashSet(); } - if (tempTag!=null && qname.equals("tag")) { - AttributesImpl attImpl = new AttributesImpl(attributes); - tempTag.put(attImpl.getValue("k"), attImpl.getValue("v")); // insert key and value of that tag into Hashtable + if (qname.equals("tag")) { + if (tempTag != null) { + AttributesImpl attImpl = new AttributesImpl(attributes); + tempTag.put(attImpl.getValue("k"), attImpl.getValue("v")); // insert key and value of that tag into Hashtable + } + if (inNode || inWay) { + AttributesImpl attImpl = new AttributesImpl(attributes); + if (attImpl.getValue("k").equals("public_transport")) { + nodeWayPtValue.put(nodeWayId, attImpl.getValue("v")); + } + } } if (tempMembers!=null && qname.equals("member")) { AttributesImpl attImpl = new AttributesImpl(attributes); - RelationMember rm = new RelationMember(attImpl.getValue("ref"),attImpl.getValue("type"),attImpl.getValue("role")); + RelationMember rm = new RelationMember(attImpl.getValue("ref"), attImpl.getValue("type"), attImpl.getValue("role"), "", "", "unknown"); rm.setStatus("OSM server"); tempMembers.add(rm); } + if (qname.equals("node")) { + inNode = true; + AttributesImpl attImpl = new AttributesImpl(attributes); + nodeWayId = attImpl.getValue("id"); + nodes.put(attImpl.getValue("id"), attImpl.getValue("lat") + ";" + attImpl.getValue("lon")); + } + if (qname.equals("way")) { + inWay = true; + AttributesImpl attImpl = new AttributesImpl(attributes); + nodeWayId = attImpl.getValue("id"); + } + if (qname.equals("nd") && inWay && ndcount == 0) { + ndcount++; + AttributesImpl attImpl = new AttributesImpl(attributes); + ways.put(nodeWayId, attImpl.getValue("ref")); + } } @Override public void endElement (String uri, String localName, String qName) throws SAXException { @@ -68,6 +105,44 @@ public RouteParser(){ tempTag = null; tempMembers = null; } + if (qName.equals("way")) { + inWay = false; + ndcount = 0; + } + if (qName.equals("node")) { + inNode = false; + ndcount = 0; + } + } + + @Override + public void endDocument() throws SAXException { + super.endDocument(); + HashMap waysWithGeo = new HashMap<>(); + for (HashMap.Entry way : ways.entrySet()) { + waysWithGeo.put(way.getKey(), nodes.get(way.getValue())); + } + + for (LinkedHashSet hs : xmlMembers) { + for (RelationMember m : hs) { + String nodeId = nodes.get(m.getRef()); + //System.out.println(String.format("Id: %s / nodeId: %s", m.getRef(), nodeId)); + if (nodeId != null) { + m.setLat(nodeId.split(";")[0]); + m.setLon(nodeId.split(";")[1]); + } else { + String wayId = waysWithGeo.get(m.getRef()); + //System.out.println(String.format("Id: %s / wayId: %s", m.getRef(), wayId)); + if (wayId != null) { + m.setLat(wayId.split(";")[0]); + m.setLon(wayId.split(";")[1]); + } + } + if (nodeWayPtValue.containsKey(m.getRef())) { + m.setRefOsmPublicTransportType(nodeWayPtValue.get(m.getRef())); + } + } + } } public ArrayList getRelations(){