source: osm/applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/ReconstructRouteAction.java

Last change on this file was 36217, checked in by GerdP, 2 years ago

fix #23521: fix some memory leaks

  • dispose dialogs
  • either avoid to create clones of ways or relations or use setNodes(null) / setMembers(null)
  • replaces most ChangeCommand instances by better specialized alternatives
  • add some comments
  • fix some checkstyle / sonar issues
  • Property svn:eol-style set to native
File size: 9.7 KB
RevLine 
[32395]1// License: GPL. For details, see LICENSE file.
[30841]2package relcontext.actions;
3
[32395]4import static org.openstreetmap.josm.tools.I18n.tr;
5
[30841]6import java.awt.event.ActionEvent;
7import java.util.ArrayList;
8import java.util.LinkedHashMap;
9import java.util.List;
10import java.util.Map;
[36102]11import java.util.Objects;
[32395]12
[30841]13import javax.swing.AbstractAction;
[32395]14
[36217]15import org.openstreetmap.josm.command.ChangeMembersCommand;
[34551]16import org.openstreetmap.josm.data.UndoRedoHandler;
[30841]17import org.openstreetmap.josm.data.coor.EastNorth;
18import org.openstreetmap.josm.data.osm.Node;
19import org.openstreetmap.josm.data.osm.OsmPrimitive;
20import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
21import org.openstreetmap.josm.data.osm.Relation;
22import org.openstreetmap.josm.data.osm.RelationMember;
23import org.openstreetmap.josm.data.osm.Way;
24import org.openstreetmap.josm.gui.dialogs.relation.sort.RelationSorter;
25import org.openstreetmap.josm.tools.Geometry;
26import org.openstreetmap.josm.tools.ImageProvider;
[32395]27
[30841]28import relcontext.ChosenRelation;
29import relcontext.ChosenRelationListener;
30
31/**
32 * Build in order stop/platforms, stop/platforms ... route
33 * @author freeExec
34 */
[32398]35public class ReconstructRouteAction extends AbstractAction implements ChosenRelationListener {
[36217]36 private final transient ChosenRelation rel;
[32395]37
[36217]38 /**
39 * Reconstruct route relation to scheme of public_transport.
40 * @param rel chosen relation
41 */
[32398]42 public ReconstructRouteAction(ChosenRelation rel) {
[30841]43 super(tr("Reconstruct route"));
44 putValue(SMALL_ICON, ImageProvider.get("dialogs", "filter"));
45 putValue(LONG_DESCRIPTION, "Reconstruct route relation to scheme of public_transport");
46 this.rel = rel;
47 rel.addChosenRelationListener(this);
48 setEnabled(isSuitableRelation(rel.get()));
49 }
[32395]50
51 @Override
52 public void actionPerformed(ActionEvent e) {
[30841]53 Relation r = rel.get();
[36217]54 List<RelationMember> recMembers = new ArrayList<>();
[32395]55
[30841]56 Map<OsmPrimitive, RelationMember> stopMembers = new LinkedHashMap<>();
57 Map<String, List<RelationMember>> platformMembers = new LinkedHashMap<>();
58
59 List<RelationMember> routeMembers = new ArrayList<>();
60 List<RelationMember> wtfMembers = new ArrayList<>();
[32395]61
[30841]62 int mCount = r.getMembersCount();
63 for (int i = 0; i < mCount; i++) {
64 RelationMember m = r.getMember(i);
65 if (PublicTransportHelper.isMemberStop(m)) {
66 RelationMember rm = new RelationMember(
[32395]67 m.hasRole() ? m.getRole() : PublicTransportHelper.STOP,
68 m.getMember());
[30841]69 stopMembers.put(rm.getMember(), rm);
[32398]70 } else if (PublicTransportHelper.isMemberPlatform(m)) {
[30841]71 RelationMember rm = new RelationMember(
[32395]72 m.hasRole() ? m.getRole() : PublicTransportHelper.PLATFORM,
73 m.getMember());
[30841]74 String platformName = PublicTransportHelper.getNameViaStoparea(rm);
[32395]75 if (platformName == null) {
76 platformName = "";
77 }
78 if (platformMembers.containsKey(platformName)) {
79 platformMembers.get(platformName).add(rm);
80 } else {
[30841]81 List<RelationMember> nList = new ArrayList<>();
82 nList.add(rm);
83 platformMembers.put(platformName, nList);
[32395]84 }
[32398]85 } else if (PublicTransportHelper.isMemberRouteway(m)) {
[32395]86 routeMembers.add(new RelationMember(m));
87 } else {
88 wtfMembers.add(new RelationMember(m));
89 }
[30841]90 }
[32395]91
[30841]92 routeMembers = RelationSorter.sortMembersByConnectivity(routeMembers);
[32395]93
[30841]94 Node lastNode = null;
95 for (int rIndex = 0; rIndex < routeMembers.size(); rIndex++) {
[32398]96 Way w = (Way) routeMembers.get(rIndex).getMember();
[30841]97 boolean dirForward = false;
98 if (lastNode == null) { // first segment
99 if (routeMembers.size() > 2) {
[32398]100 Way nextWay = (Way) routeMembers.get(rIndex + 1).getMember();
[36102]101 if (Objects.equals(w.lastNode(), nextWay.lastNode()) || Objects.equals(w.lastNode(), nextWay.firstNode())) {
[30841]102 dirForward = true;
103 lastNode = w.lastNode();
[32395]104 } else {
105 lastNode = w.firstNode();
106 }
[30841]107 } // else one segment - direction unknown
108 } else {
[32398]109 if (lastNode.equals(w.firstNode())) {
110 dirForward = true; lastNode = w.lastNode();
111 } else {
[32395]112 lastNode = w.firstNode();
113 }
[30841]114 }
115 final int wayNodeBeginIndex = (dirForward ? 0 : w.getNodesCount() - 1);
116 final int wayNodeEndIndex = (dirForward ? w.getNodesCount() - 1 : 0);
117 final int increment = (dirForward ? 1 : -1);
[32395]118 for (int nIndex = wayNodeBeginIndex;
[30841]119 nIndex != wayNodeEndIndex;
120 nIndex += increment) {
121 Node refNode = w.getNode(nIndex);
[36217]122 if (!(PublicTransportHelper.isNodeStop(refNode) && stopMembers.containsKey(refNode)))
123 continue;
124 recMembers.add(stopMembers.get(refNode));
125 stopMembers.remove(refNode);
126 String stopName = PublicTransportHelper.getNameViaStoparea(refNode);
127 if (stopName == null) {
128 stopName = "";
129 }
130 boolean existsPlatform = platformMembers.containsKey(stopName);
131 if (!existsPlatform) {
132 stopName = ""; // find of the nameless
133 }
134 if (existsPlatform || platformMembers.containsKey(stopName)) {
135 List<RelationMember> lMember = platformMembers.get(stopName);
136 if (lMember.size() == 1) {
137 recMembers.add(lMember.get(0));
138 lMember.remove(0);
139 } else {
140 // choose closest
141 RelationMember candidat = getClosestPlatform(lMember, refNode);
142 if (candidat != null) {
143 recMembers.add(candidat);
144 lMember.remove(candidat);
[32395]145 }
[30841]146 }
[36217]147 if (lMember.isEmpty()) {
148 platformMembers.remove(stopName);
149 }
[30841]150 }
151 }
152 }
[32395]153
[30841]154 for (RelationMember stop : stopMembers.values()) {
[36217]155 recMembers.add(stop);
[30841]156 String stopName = PublicTransportHelper.getNameViaStoparea(stop);
157 boolean existsPlatform = platformMembers.containsKey(stopName);
[32398]158 if (!existsPlatform) {
159 stopName = ""; // find of the nameless
160 }
[32395]161 if (existsPlatform || platformMembers.containsKey(stopName)) {
[30841]162 List<RelationMember> lMember = platformMembers.get(stopName);
163 if (lMember.size() == 1) {
[36217]164 recMembers.add(lMember.get(0));
[30841]165 lMember.remove(0);
166 } else {
[32395]167 // choose closest
[30841]168 RelationMember candidat = getClosestPlatform(lMember, stop.getNode());
169 if (candidat != null) {
[36217]170 recMembers.add(candidat);
[30841]171 lMember.remove(candidat);
172 }
173 }
[32395]174 if (lMember.isEmpty()) {
175 platformMembers.remove(stopName);
176 }
[30841]177 }
178 }
[32395]179
180 for (List<RelationMember> lPlatforms : platformMembers.values()) {
181 for (RelationMember platform : lPlatforms) {
[36217]182 recMembers.add(platform);
[32395]183 }
184 }
185
186 for (RelationMember route : routeMembers) {
[36217]187 recMembers.add(route);
[32395]188 }
189 for (RelationMember wtf : wtfMembers) {
[36217]190 recMembers.add(wtf);
[32395]191 }
[36217]192 UndoRedoHandler.getInstance().add(new ChangeMembersCommand(r, recMembers));
[30841]193 }
[32395]194
195 private static final double maxSqrDistBetweenStopAndPlatform = 2000; // ~ 26m
[36217]196
197 private static RelationMember getClosestPlatform(List<RelationMember> members, Node stop) {
[30841]198 if (stop == null || members.isEmpty()) return null;
199 double maxDist = maxSqrDistBetweenStopAndPlatform;
200 RelationMember result = null;
201 for (RelationMember member : members) {
202 if (member.getType() == OsmPrimitiveType.NODE) {
203 Node node = member.getNode();
204 double sqrDist = stop.getEastNorth().distanceSq(node.getEastNorth());
205 if (sqrDist < maxDist) {
206 maxDist = sqrDist;
207 result = member;
208 }
209 } else if (member.getType() == OsmPrimitiveType.WAY) {
210 Way way = member.getWay();
211 EastNorth closest = Geometry.closestPointToSegment(
[32395]212 way.firstNode().getEastNorth(),
213 way.lastNode().getEastNorth(),
214 stop.getEastNorth()
215 );
[30841]216 double sqrDist = stop.getEastNorth().distanceSq(closest);
217 if (sqrDist < maxDist) {
218 maxDist = sqrDist;
219 result = member;
220 }
221 }
222 }
223 return result;
224 }
[32395]225
226 @Override
227 public void chosenRelationChanged(Relation oldRelation, Relation newRelation) {
228 setEnabled(isSuitableRelation(newRelation));
229 }
230
[36217]231 private static boolean isSuitableRelation(Relation newRelation) {
[30841]232 return !(newRelation == null || !"route".equals(newRelation.get("type")) || newRelation.getMembersCount() == 0);
233 }
234}
Note: See TracBrowser for help on using the repository browser.