Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
964b254
Add action to extract new relation from a subset of members of an exi…
floscher Aug 24, 2020
7d0ad20
Added code to
PolyglotOpenstreetmap Aug 24, 2020
3da4860
Added code to
PolyglotOpenstreetmap Aug 24, 2020
12411a3
Now it works the way I wanted it to work. I'll keep testing it more t…
PolyglotOpenstreetmap Aug 24, 2020
ce6106d
I succeeded in making it work the way I want and I incorporated Flori…
PolyglotOpenstreetmap Aug 26, 2020
e3ff059
The relation wasn't added if member 1-... were selected, so if the fi…
PolyglotOpenstreetmap Aug 26, 2020
7616d42
refactored to extract the methods that do the work. I may want to use…
PolyglotOpenstreetmap Aug 26, 2020
4d1af91
renamed bus.png to bus. It's not a bus.svg, which is detected automat…
PolyglotOpenstreetmap Aug 26, 2020
eca82d5
refactored, it works OK most of the time, but when extracting from a …
PolyglotOpenstreetmap Aug 27, 2020
92e1bab
Sometimes there is an exception. What I find odd is that this happens…
PolyglotOpenstreetmap Sep 8, 2020
0d4b9d9
If the route relation that is divide into 2 route relations is alread…
PolyglotOpenstreetmap Sep 9, 2020
10955a9
It worked almost the way I wanted it at some point. Trying to iron ou…
PolyglotOpenstreetmap Sep 15, 2020
f96c6de
Add custom icon for the extract relation action
floscher Sep 15, 2020
da27d28
I got it back to a point that I'm almost happy with the result. Some …
PolyglotOpenstreetmap Sep 17, 2020
01d9ea2
it's somewhat stable now, although there are still many things that d…
PolyglotOpenstreetmap Sep 18, 2020
ec66b9d
I didn't like the nondescript A and B from Pair, so I created a new C…
PolyglotOpenstreetmap Sep 20, 2020
d36c864
Changed colours and lineIdentifiers to TreeSet. lineIdentifiers need …
PolyglotOpenstreetmap Sep 20, 2020
1feb68c
No need to user .contains anymore, now that it's using TreeSet
PolyglotOpenstreetmap Sep 20, 2020
1443a9a
I fixed the problem where identical sub route relations where created…
PolyglotOpenstreetmap Sep 20, 2020
74b0e75
some reshuffling and minor changes
PolyglotOpenstreetmap Sep 20, 2020
acec22f
removed some code duplication
PolyglotOpenstreetmap Sep 21, 2020
2b6b7f4
removed code duplication in those 3 constructors. Now there are 4 of …
PolyglotOpenstreetmap Sep 21, 2020
69f8bdd
added some Javadoc
PolyglotOpenstreetmap Sep 21, 2020
68654bf
Create unit test for extracting PT segment
PolyglotOpenstreetmap Sep 21, 2020
0c178a8
Rename PTSegmentToExtract to RouteSegmentToExtract
floscher Oct 27, 2020
ccf71f5
created unit test for bus line 601. It's a circular line, which reuse…
PolyglotOpenstreetmap Sep 27, 2020
e4a522d
I removed the code from the Action file, it's now in the RouteSegment…
PolyglotOpenstreetmap Sep 27, 2020
a1ef4f9
Wrote test cases for 1 complete itinerary and started on cases for an…
PolyglotOpenstreetmap Oct 1, 2020
5372fa0
renamed WayTriplet to WaySequence as it can contain 4 consecutive way…
PolyglotOpenstreetmap Oct 1, 2020
742265a
All the unit tests are working up to this point. Rewrote isItineraryI…
PolyglotOpenstreetmap Oct 5, 2020
deb7c6d
Added some more unit tests and needed to check that if one of the par…
PolyglotOpenstreetmap Oct 6, 2020
28f11b6
Added a lookup for itineraryWays per relation, so it only needs to be…
PolyglotOpenstreetmap Oct 7, 2020
4bd2b71
In some cases the membershipcount is needed of all the (parent) route…
PolyglotOpenstreetmap Oct 8, 2020
4bcfa3f
Added another line, which has variants with an extra spoon, which nee…
PolyglotOpenstreetmap Oct 10, 2020
af2ab8c
Added connectivity checks to WaySequence and wrote JavaDoc for its me…
PolyglotOpenstreetmap Oct 11, 2020
04acfb0
I have no idea how to resolve this exception. It always complains abo…
PolyglotOpenstreetmap Oct 16, 2020
d33a855
as route relations get converted to superroute relations, sub route r…
PolyglotOpenstreetmap Oct 16, 2020
5448f8f
Added tests for cycle route.
PolyglotOpenstreetmap Oct 16, 2020
41a9649
Rewrote the entire test suite. It works with an array of known values…
PolyglotOpenstreetmap Oct 20, 2020
11a99a3
During live testing I get an Index out of bounds exception, when proc…
PolyglotOpenstreetmap Oct 21, 2020
6b01f01
Moved isItineraryInSameDirection to WaySequence class.
PolyglotOpenstreetmap Oct 23, 2020
977d54d
Some refactoring
PolyglotOpenstreetmap Oct 23, 2020
dbdd778
resolved some warnings from IntelliJ
PolyglotOpenstreetmap Oct 23, 2020
4c3ce56
Simplify dataset loading in RouteSegmentToExtractTest
floscher Oct 27, 2020
f66483b
Tried to sanitize the RouteSegmentToExtractTest class. I didn't test …
PolyglotOpenstreetmap Oct 23, 2020
2b52d4d
Some changes made while doing pair programming with Florian.
PolyglotOpenstreetmap Oct 23, 2020
12158e8
Running the loop down to 0 seems to work better when splitting in seg…
PolyglotOpenstreetmap Oct 23, 2020
5e6e728
Changed the order of creation of clonedRelation. The way it was, it w…
PolyglotOpenstreetmap Oct 25, 2020
d8e83b5
Merge master branch into extract_relation
floscher Oct 28, 2020
4305ff8
reduced file size of test file to 5.5 MB by purging ways. The relatio…
PolyglotOpenstreetmap Oct 29, 2020
616e955
Reworked the tests. For removing members from a relation, it makes mo…
PolyglotOpenstreetmap Nov 2, 2020
ac95d6d
In ExtractRelationMembersToNewRelationAction I made an attempt to get…
PolyglotOpenstreetmap Nov 4, 2020
0355688
It seems like I succeeded in suppressing the IndexOutOfBounds excepti…
PolyglotOpenstreetmap Nov 6, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
plugin.author=Biswesh Mohapatra <biswesh123@gmail.com>, simon04, Rodion Scherbakov
plugin.author=Polyglot <winfixit@gmail.com>, simon04, Rodion Scherbakov
plugin.class=org.openstreetmap.josm.plugins.pt_assistant.PTAssistantPlugin
plugin.description=Provides validation and fixing for public transport route according to version 2 of the public transport schema
# plugin.description=Displays stops of selected public transport routes as graph
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public static CustomizeStopAction createCustomizeStopAction() {
// CHECKSTYLE.OFF: LineLength
CustomizeStopAction action = new CustomizeStopAction(
tr("Customize stop"),
"bus.png",
"bus",
tr("Customize stop under osm public transit standard v2"),
Shortcut.registerShortcut("tools:customizestop", tr("Public Transport: {0}", tr("Customize stop")), KeyEvent.VK_U, Shortcut.DIRECT),
true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.openstreetmap.josm.plugins.pt_assistant.actions.DoubleSplitAction;
import org.openstreetmap.josm.plugins.pt_assistant.actions.EdgeSelectionAction;
import org.openstreetmap.josm.plugins.pt_assistant.actions.ExtractPlatformNodeAction;
import org.openstreetmap.josm.plugins.pt_assistant.actions.ExtractRelationMembersToNewRelationAction;
import org.openstreetmap.josm.plugins.pt_assistant.actions.PTWizardAction;
import org.openstreetmap.josm.plugins.pt_assistant.actions.RoutingAction;
import org.openstreetmap.josm.plugins.pt_assistant.actions.SortPTRouteMembersAction;
Expand Down Expand Up @@ -191,7 +192,8 @@ public int order() {

@Override
public List<AbstractRelationEditorAction> getActions(IRelationEditorActionAccess editorAccess) {
return Arrays.asList(new SortPTRouteMembersAction(editorAccess));
return Arrays.asList(new SortPTRouteMembersAction(editorAccess),
new ExtractRelationMembersToNewRelationAction(editorAccess));
}
};
RelationEditorHooks.addActionsToMembers(group1);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
package org.openstreetmap.josm.plugins.pt_assistant.actions;

import static java.lang.Thread.sleep;
import static java.util.Collections.emptyList;

import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.swing.JCheckBox;
import javax.swing.JOptionPane;
import javax.swing.JTextField;

import org.openstreetmap.josm.command.ChangeCommand;
import org.openstreetmap.josm.command.Command;
import org.openstreetmap.josm.command.SequenceCommand;
import org.openstreetmap.josm.data.UndoRedoHandler;
import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
import org.openstreetmap.josm.data.osm.Relation;
import org.openstreetmap.josm.data.osm.RelationMember;
import org.openstreetmap.josm.gui.MainApplication;
import org.openstreetmap.josm.gui.dialogs.relation.IRelationEditor;
import org.openstreetmap.josm.gui.dialogs.relation.MemberTableModel;
import org.openstreetmap.josm.gui.dialogs.relation.RelationDialogManager;
import org.openstreetmap.josm.gui.dialogs.relation.RelationEditor;
import org.openstreetmap.josm.gui.dialogs.relation.actions.AbstractRelationEditorAction;
import org.openstreetmap.josm.gui.dialogs.relation.actions.IRelationEditorActionAccess;
import org.openstreetmap.josm.gui.dialogs.relation.actions.IRelationEditorUpdateOn;
import org.openstreetmap.josm.gui.layer.LayerManager;
import org.openstreetmap.josm.gui.layer.OsmDataLayer;
import org.openstreetmap.josm.plugins.pt_assistant.data.RouteSegmentToExtract;
import org.openstreetmap.josm.plugins.pt_assistant.utils.RouteUtils;
import org.openstreetmap.josm.tools.I18n;
import org.openstreetmap.josm.tools.ImageProvider;
import org.openstreetmap.josm.tools.Utils;

/*
Extracts selected members to a new route relation
and substitutes them with this new route relation
in the original relation

* @author Florian, Polyglot
*/
public class ExtractRelationMembersToNewRelationAction extends AbstractRelationEditorAction {
public ExtractRelationMembersToNewRelationAction(IRelationEditorActionAccess editorAccess) {
super(editorAccess, IRelationEditorUpdateOn.MEMBER_TABLE_SELECTION,
IRelationEditorUpdateOn.MEMBER_TABLE_CHANGE,
IRelationEditorUpdateOn.TAG_CHANGE);
new ImageProvider("dialogs/relation", "extract_relation").getResource().attachImageIcon(this);
}

@Override
public void actionPerformed(ActionEvent actionEvent) {
final MemberTableModel memberTableModel = editorAccess.getMemberTableModel();
IRelationEditor editor = editorAccess.getEditor();
final Relation originalRelation = editor.getRelation();

final Collection<RelationMember> selectedMembers = memberTableModel.getSelectedMembers();

List<Command> commands = new ArrayList<>();

String title = I18n.tr("Extract part from relation?");
String question = I18n.tr(
"Do you want to create a new relation with the {0} selected members?",
selectedMembers.size()
);
List<Relation> parentRelations = new ArrayList<>(Utils.filteredCollection(originalRelation.getReferrers(), Relation.class));
parentRelations.removeIf(parentRelation -> !Objects.equals(parentRelation.get("type"), "superroute"));
final int numberOfParentRelations = parentRelations.size();
final JCheckBox cbReplaceInSuperrouteRelations = new JCheckBox(I18n.tr(
"This route is a member of {0} superroute {1}, add the extracted relation there instead of in this relation?",
numberOfParentRelations,
I18n.trn("relation", "relations", numberOfParentRelations)));
final JCheckBox cbConvertToSuperroute = new JCheckBox(I18n.tr("Convert this relation to superroute"));
final JCheckBox cbProposed = new JCheckBox(I18n.tr("subrelation is proposed (wenslijn)"));
final JCheckBox cbDeviation = new JCheckBox(I18n.tr("subrelation is deviation (omleiding)"));
final JCheckBox cbFindAllSegmentsAutomatically = new JCheckBox(I18n.tr("Process complete route relation for segments and extract into multiple sub route relations"));
final JTextField tfNameTag = new JTextField(getEditor().getRelation().get("name"));
ArrayList<Object> paramsList = new ArrayList<>();
paramsList.add(question);
paramsList.add(tfNameTag);
// Only show cbReplaceInSuperrouteRelations when it's relevant
if (numberOfParentRelations > 0) {
// check the check box
cbReplaceInSuperrouteRelations.setSelected(true);
paramsList.add(cbReplaceInSuperrouteRelations);
}
if (originalRelation.hasTag("cycle_network", "cycle_highway")) {
paramsList.add(cbDeviation);
paramsList.add(cbProposed);
}
paramsList.add(cbConvertToSuperroute);
if (RouteUtils.isVersionTwoPTRoute(originalRelation)) {
cbConvertToSuperroute.setSelected(true);
cbFindAllSegmentsAutomatically.setSelected(true);
paramsList.add(cbFindAllSegmentsAutomatically);
}
paramsList.add(cbConvertToSuperroute);
Object[] params = paramsList.toArray(new Object[0]); // paramsList.size()]);
if (
JOptionPane.showConfirmDialog(
getMemberTable(),
params,
title,
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE
) == JOptionPane.OK_OPTION
) {
if (cbFindAllSegmentsAutomatically.isSelected()) {
// To avoid an IndexOutOfBoundsError, let's close this relation editor...
OsmDataLayer layer = MainApplication.getLayerManager().getEditLayer();
RelationEditor ed = RelationDialogManager.getRelationDialogManager().getEditorForRelation(layer, originalRelation);
if (ed != null) {
ed.dispose();
}
final Relation clonedRelation = new Relation(originalRelation);
splitInSegments(clonedRelation, cbConvertToSuperroute.isSelected());
commands.add(new ChangeCommand(originalRelation, clonedRelation));
UndoRedoHandler.getInstance().add(
new SequenceCommand(I18n.tr("Replace ways with segment relations"), commands));

// After changing the relation, let's open a fresh editor
// oddly it shows the old state of the relation
// even though I made a detour over the relation's id
RelationEditor newEditor = RelationEditor.getEditor(
getEditor().getLayer(),
(Relation) originalRelation.getDataSet().getPrimitiveById(originalRelation.getId(), OsmPrimitiveType.RELATION),
emptyList());
newEditor.setVisible(true);
newEditor.setAlwaysOnTop(true);

// alas, when reloading there is still the pesky IndexOudOfBounds
// Closing the relation editor interactively
// and reopening it, DOES show the new state
// this is driving me crazy. Why is it a problem that the length
// of the memberList becomes shorter?
try {
newEditor.reloadDataFromRelation();
} catch (IndexOutOfBoundsException e) {
System.out.print(e);
// no idea what to do here
// the exception was caught, the relation editor
// shows the new situation, sometimes instantaneously, sometimes after a few seconds

// I don't see this one as often anymore:
// java.lang.IllegalArgumentException: Width and height must be >= 0

// But it does still happen.

// This also shows (almost all the time):
// WARNING: row index is bigger than sorter's row count. Most likely this is a wrong sorter usage.
}
} else {
Relation clonedRelation = new Relation(originalRelation);
RouteSegmentToExtract segment = new RouteSegmentToExtract(clonedRelation,
Arrays.stream(memberTableModel.getSelectedIndices()).boxed().collect(Collectors.toList()));
segment.put("name", tfNameTag.getText());
if (cbProposed.isSelected()) {
segment.put("state", "proposed");
segment.put("name", tfNameTag.getText() + " (wenslijn)");
}
if (cbDeviation.isSelected()) {
segment.put("name", tfNameTag.getText() + " (omleiding)");
}
Relation extractedRelation = segment.extractToRelation(
Arrays.asList("type", "route", "cycle_network", "network", "operator", "ref"),
true,
true);
if (extractedRelation != null) {
if (extractedRelation.isNew() && cbConvertToSuperroute.isSelected()) {
clonedRelation.put("type", "superroute");
}
commands.add(new ChangeCommand(originalRelation, clonedRelation));
if (cbReplaceInSuperrouteRelations.isSelected()) {
addExtractedRelationToParentSuperrouteRelations(
originalRelation, commands, parentRelations,
segment.getIndices(), extractedRelation);
}
UndoRedoHandler.getInstance().add(
new SequenceCommand(I18n.tr("Extract ways to relation"), commands));

RelationEditor extraEditor = RelationEditor.getEditor(
getEditor().getLayer(), extractedRelation, emptyList());
extraEditor.setVisible(true);
extraEditor.setAlwaysOnTop(true);
}
editor.reloadDataFromRelation();
}
}
}

public void splitInSegments(Relation relation, Boolean convertToSuperroute) {
ArrayList<RelationMember> segmentRelationsList = new ArrayList<>();
ArrayList<Integer> indicesToRemoveList = new ArrayList<>();
final List<RelationMember> members = relation.getMembers();
RouteSegmentToExtract segment = new RouteSegmentToExtract(relation);
// segment.setActiveDataSet(relation.getDataSet());
RouteSegmentToExtract newSegment;
for (int i = 0; i < members.size(); i++) {
newSegment = segment.addPTWayMember(i);
if (newSegment != null) {
Relation extractedRelation = segment.extractToRelation(Arrays.asList("type", "route"),
false, false);
if (extractedRelation != null) {
segmentRelationsList.add(new RelationMember("", extractedRelation));
}
segment = newSegment;
}
if (i < relation.getMembersCount() && RouteUtils.isPTWay(relation.getMembers().get(i))) {
indicesToRemoveList.add(0, i);
}
}
if (convertToSuperroute) {
relation.put("type", "superroute");
}
for (Integer integer : indicesToRemoveList) {
relation.removeMember(integer);
}
segmentRelationsList.forEach(relation::addMember);
}
/** This method modifies clonedRelation in place if substituteWaysWithRelation is true
* and if ways are extracted into a new relation
* It takes a list of (preferably) consecutive indices
* If there is already a relation with the same members in the same order
* it returns a pointer to that relation
* otherwise it returns a new relation with a negative id,
* which still needs to be added using addCommand()*/

private void addExtractedRelationToParentSuperrouteRelations(Relation originalRelation, List<Command> commands, List<Relation> parentRelations, List<Integer> selectedIndices, Relation extractedRelation) {
for (Relation superroute : parentRelations) {
int index = 0;
for (RelationMember member : superroute.getMembers()) {
if (member.getMember().getId() == originalRelation.getId()) {
Relation clonedParentRelation = new Relation(superroute);
if (selectedIndices.get(0) != 0) {
// if the user selected a block that didn't start with
// the first member, add the extracted relation after
// the position where this relation was in the parent
index++;
}
index = RouteSegmentToExtract.limitIntegerTo(index, superroute.getMembersCount());
clonedParentRelation.addMember(index, new RelationMember("", extractedRelation));
commands.add(new ChangeCommand(superroute, clonedParentRelation));
break;
}
index++;
}
}
}

@Override
public boolean isExpertOnly() {
return true;
}

@Override
protected void updateEnabledState() {
final boolean newEnabledState = !editorAccess.getSelectionTableModel().getSelection().isEmpty()
&& Optional.ofNullable(editorAccess.getTagModel().get("type")).filter(it -> it.getValue().matches("route|superroute")).isPresent();
// && !editorAccess.getEditor().isDirtyRelation(); // This seems to cause a problem

if (newEnabledState) {
putValue(SHORT_DESCRIPTION, I18n.tr("Extract selected part of the route into new relation"));
} else {
putValue(SHORT_DESCRIPTION, I18n.tr("Extract into new relation (needs type=route/superroute tag and at least one selected relation member)"));
}
setEnabled(newEnabledState);
}
}
Loading