package ru.rodsoft.openstreetmap.josm.plugins.customizepublictransportstop; import java.util.ArrayList; import java.util.List; import static org.openstreetmap.josm.tools.I18n.tr; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.command.AddCommand; import org.openstreetmap.josm.command.ChangeCommand; import org.openstreetmap.josm.command.ChangePropertyCommand; import org.openstreetmap.josm.command.Command; import org.openstreetmap.josm.command.SequenceCommand; import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.data.osm.Node; import org.openstreetmap.josm.data.osm.OsmPrimitive; import org.openstreetmap.josm.data.osm.Relation; import org.openstreetmap.josm.data.osm.RelationMember; import org.openstreetmap.josm.data.osm.Way; /** * Operation of creation and customizing stop area relation and its members under user selection * @author Rodion Scherbakov */ public class CustomizeStopAreaOperation extends StopAreaOperationBase { /** * Operation name in undo list */ private static final String TAG_ASSIGN_COMMAND_NAME = "Stop area tag assign"; /** * Constructor of operation object * @param currentDataSet Current Josm data set */ public CustomizeStopAreaOperation(DataSet currentDataSet) { super(currentDataSet); } /** * Forming commands for josm for saving name and name:en attributes stop of area members and relation attributes * @param target Stop area member or relation * @param commands List of commands * @param stopArea Stop area object * @return Resulting list of commands */ public List<Command> nameTagAssign(OsmPrimitive target, List<Command> commands, StopArea stopArea) { if(commands == null) commands = new ArrayList<Command>(); commands = assignTag(commands, target, OSMTags.NAME_TAG, "".equals(stopArea.name) ? null : stopArea.name); commands = assignTag(commands, target, OSMTags.NAME_EN_TAG, "".equals(stopArea.nameEn) ? null : stopArea.nameEn); return commands; } /** * Clear transport type tags * @param target Josm object for tag clearing * @param commands Command list * @return Resulting list of commands */ protected List<Command> transportTypeTagClearing(OsmPrimitive target, List<Command> commands) { commands = clearTag(commands, target, OSMTags.BUS_TAG); commands = clearTag(commands, target, OSMTags.SHARE_TAXI_TAG); commands = clearTag(commands, target, OSMTags.TROLLEYBUS_TAG); commands = clearTag(commands, target, OSMTags.TRAM_TAG); commands = clearTag(commands, target, OSMTags.TRAIN_TAG); return commands; } /** * Assign transport type tags to node * @param target Josm object for tag assigning * @param commands Command list * @param stopArea Stop area object * @param isStopPoint Flag of stop point * @return Resulting list of commands */ protected List<Command> transportTypeTagAssign(OsmPrimitive target, List<Command> commands, StopArea stopArea, Boolean isStopPoint) { if(commands == null) commands = new ArrayList<Command>(); if(isStopPoint) { if(stopArea.isTrainStop || stopArea.isTrainStation) { commands = clearTag(commands, target, OSMTags.BUS_TAG); commands = clearTag(commands, target, OSMTags.SHARE_TAXI_TAG); commands = clearTag(commands, target, OSMTags.TROLLEYBUS_TAG); commands = clearTag(commands, target, OSMTags.TRAM_TAG); commands = assignTag(commands, target, OSMTags.TRAIN_TAG, OSMTags.YES_TAG_VALUE); } else { commands = assignTag(commands, target, OSMTags.BUS_TAG, stopArea.isBus ? OSMTags.YES_TAG_VALUE : null); commands = assignTag(commands, target, OSMTags.SHARE_TAXI_TAG, stopArea.isShareTaxi ? OSMTags.YES_TAG_VALUE : null); commands = assignTag(commands, target, OSMTags.TROLLEYBUS_TAG, stopArea.isTrolleybus ? OSMTags.YES_TAG_VALUE : null); commands = assignTag(commands, target, OSMTags.TRAM_TAG, stopArea.isTram ? OSMTags.YES_TAG_VALUE : null); commands = assignTag(commands, target, OSMTags.TRAIN_TAG, stopArea.isTrainStation || stopArea.isTrainStop ? OSMTags.YES_TAG_VALUE : null); } } else { if(stopArea.isAssignTransportType) { commands = assignTag(commands, target, OSMTags.BUS_TAG, stopArea.isBus ? OSMTags.YES_TAG_VALUE : null); commands = assignTag(commands, target, OSMTags.SHARE_TAXI_TAG, stopArea.isShareTaxi ? OSMTags.YES_TAG_VALUE : null); commands = assignTag(commands, target, OSMTags.TROLLEYBUS_TAG, stopArea.isTrolleybus ? OSMTags.YES_TAG_VALUE : null); commands = assignTag(commands, target, OSMTags.TRAM_TAG, stopArea.isTram ? OSMTags.YES_TAG_VALUE : null); commands = assignTag(commands, target, OSMTags.TRAIN_TAG, stopArea.isTrainStation || stopArea.isTrainStop ? OSMTags.YES_TAG_VALUE : null); } else { commands = transportTypeTagClearing(target, commands); } } return commands; } /** * Forming commands for josm for saving general attributes of stop area members and relation * @param target Stop area member or relation * @param commands List of commands * @param stopArea Stop area object * @return Resulting list of commands */ public List<Command> generalTagAssign(OsmPrimitive target, List<Command> commands, StopArea stopArea) { if(commands == null) commands = new ArrayList<Command>(); commands = nameTagAssign(target,commands, stopArea); commands = assignTag(commands, target, OSMTags.NETWORK_TAG, "".equals(stopArea.network) ? null : stopArea.network); commands = assignTag(commands, target, OSMTags.OPERATOR_TAG, "".equals(stopArea.operator) ? null : stopArea.operator); commands = assignTag(commands, target, OSMTags.SERVICE_TAG, null == stopArea.service || OSMTags.CITY_NETWORK_TAG_VALUE.equals(stopArea.service) ? null : stopArea.service); return commands; } /** * Forming commands for josm for saving stop position attributes * @param target Stop position node * @param commands Original command list * @param stopArea Stop area object * @param isFirst true, if target is first stop position in stop area * @return Resulting command list */ public List<Command> stopPointTagAssign(OsmPrimitive target, List<Command> commands, StopArea stopArea, Boolean isFirst) { if(commands == null) commands = new ArrayList<Command>(); commands = generalTagAssign(target, commands, stopArea); commands = transportTypeTagAssign(target, commands, stopArea, true); if(isFirst) { if(stopArea.isTrainStop) { commands = assignTag(commands, target, OSMTags.RAILWAY_TAG, OSMTags.HALT_TAG_VALUE); } else if(stopArea.isTrainStation) { commands = assignTag(commands, target, OSMTags.RAILWAY_TAG, OSMTags.STATION_TAG_VALUE); } else if(stopArea.isTram) commands = assignTag(commands, target, OSMTags.RAILWAY_TAG, OSMTags.TRAM_STOP_TAG_VALUE); else commands = clearTag(commands, target, OSMTags.RAILWAY_TAG); } else { commands = clearTag(commands, target, OSMTags.RAILWAY_TAG); } if(compareTag(target, OSMTags.HIGHWAY_TAG, OSMTags.BUS_STOP_TAG_VALUE)) commands = clearTag(commands, target, OSMTags.HIGHWAY_TAG); if(compareTag(target, OSMTags.AMENITY_TAG, OSMTags.BUS_STATION_TAG_VALUE)) commands = clearTag(commands, target, OSMTags.AMENITY_TAG); commands = assignTag(commands, target, OSMTags.PUBLIC_TRANSPORT_TAG, OSMTags.STOP_POSITION_TAG_VALUE); return commands; } /** * Forming commands for josm for saving platform attributes * @param target Platform node or way * @param commands Original command list * @param stopArea Stop area object * @param isSelected true, if this platform is selected in editor * @param isFirst true, if this platform is first in stop area * @return Resulting command list */ public List<Command> platformTagAssign(OsmPrimitive target, List<Command> commands, StopArea stopArea, Boolean isFirst) { if(commands == null) commands = new ArrayList<Command>(); commands = generalTagAssign(target, commands, stopArea); commands = transportTypeTagAssign(target, commands, stopArea, false); if(compareTag(target, OSMTags.RAILWAY_TAG, OSMTags.HALT_TAG_VALUE) || compareTag(target, OSMTags.RAILWAY_TAG, OSMTags.STATION_TAG_VALUE)) commands = clearTag(commands, target, OSMTags.RAILWAY_TAG); if(target instanceof Way && (stopArea.isTrainStop || stopArea.isTrainStation || stopArea.isTram)) commands = assignTag(commands, target, OSMTags.RAILWAY_TAG, OSMTags.PLATFORM_TAG_VALUE); if(stopArea.isBus || stopArea.isShareTaxi || stopArea.isTrolleybus) { if(target instanceof Way) commands = assignTag(commands, target, OSMTags.HIGHWAY_TAG, OSMTags.PLATFORM_TAG_VALUE); else if(isFirst && !stopArea.isBusStation) commands = assignTag(commands, target, OSMTags.HIGHWAY_TAG, OSMTags.BUS_STOP_TAG_VALUE); } commands = assignTag(commands, target, OSMTags.PUBLIC_TRANSPORT_TAG, OSMTags.PLATFORM_TAG_VALUE); if(target == stopArea.selectedObject) { commands = assignTag(commands, target, OSMTags.BENCH_TAG, stopArea.isBench ? OSMTags.YES_TAG_VALUE : null); commands = assignTag(commands, target, OSMTags.SHELTER_TAG, stopArea.isShelter ? OSMTags.YES_TAG_VALUE : null); commands = assignTag(commands, target, OSMTags.COVERED_TAG, stopArea.isCovered ? OSMTags.YES_TAG_VALUE : null); commands = assignTag(commands, target, OSMTags.AREA_TAG, stopArea.isArea ? OSMTags.YES_TAG_VALUE : null); } return commands; } /** * Forming commands for josm for saving attributes of non stop position or platform * @param target Member of stop area relation * @param commands Original command list * @param stopArea Stop area object * @return Resulting command list */ public List<Command> otherMemberTagAssign(OsmPrimitive target, List<Command> commands, StopArea stopArea) { if(commands == null) commands = new ArrayList<Command>(); commands = nameTagAssign(target, commands, stopArea); commands = clearTag(commands, target, OSMTags.NETWORK_TAG); commands = clearTag(commands, target, OSMTags.OPERATOR_TAG); commands = clearTag(commands, target, OSMTags.SERVICE_TAG); if(compareTag(target, OSMTags.RAILWAY_TAG, OSMTags.HALT_TAG_VALUE) || compareTag(target, OSMTags.RAILWAY_TAG, OSMTags.STATION_TAG_VALUE)) commands = clearTag(commands, target, OSMTags.RAILWAY_TAG); return commands; } /** * Forming commands for josm for saving stop area relation attributes * @param commands Original command list * @param stopArea Stop area object * @return Resulting command list */ private List<Command> createStopAreaRelation(List<Command> commands, StopArea stopArea) { if(commands == null) commands = new ArrayList<Command>(); Relation newRelation = new Relation(); for(Node node : stopArea.stopPoints) { newRelation.addMember(new RelationMember(OSMTags.STOP_ROLE, node)); } for(OsmPrimitive platform : stopArea.platforms) { newRelation.addMember(new RelationMember(OSMTags.PLATFORM_ROLE, platform)); } for(OsmPrimitive otherMember : stopArea.otherMembers) { newRelation.addMember(new RelationMember("", otherMember)); } Main.main.undoRedo.add(new AddCommand(newRelation)); commands = generalTagAssign(newRelation, commands, stopArea); commands = assignTag(commands, newRelation, OSMTags.TYPE_TAG, OSMTags.PUBLIC_TRANSPORT_TAG); commands = assignTag(commands, newRelation, OSMTags.PUBLIC_TRANSPORT_TAG, OSMTags.STOP_AREA_TAG_VALUE); return commands; } /** * Adding of new stop area members to relation * @param commands Original command list * @param targetRelation Stop area relation * @param member Stop area relation member * @param roleName Role name * @return Resulting command list */ public static List<Command> addNewRelationMember(List<Command> commands, Relation targetRelation, OsmPrimitive member, String roleName) { if(commands == null) commands = new ArrayList<Command>(); for(RelationMember relationMember : targetRelation.getMembers()) { if(relationMember.getMember() == member) { if(relationMember.getRole() == roleName) { return commands; } return commands; } } targetRelation.addMember(new RelationMember(roleName, member)); commands.add(new ChangeCommand(targetRelation, targetRelation)); return commands; } /** * Adding new stop area members to relation * @param commands Original command list * @param stopArea Stop area object * @return Resulting command list */ private List<Command> addNewRelationMembers(List<Command> commands, StopArea stopArea) { if(commands == null) commands = new ArrayList<Command>(); for(OsmPrimitive stopPoint : stopArea.stopPoints) { commands = addNewRelationMember(commands, stopArea.stopAreaRelation, stopPoint, OSMTags.STOP_ROLE); } for(OsmPrimitive platform : stopArea.platforms) { commands = addNewRelationMember(commands, stopArea.stopAreaRelation, platform, OSMTags.PLATFORM_ROLE); } for(OsmPrimitive otherMember : stopArea.otherMembers) { commands = addNewRelationMember(commands, stopArea.stopAreaRelation, otherMember, null); } return commands; } /** * Testing, is josm object bus stop node or contains bus stop node, defined by tag and its value * @param member Josm object * @param tag Tag name * @param tagValue Tag value * @return true, if josm object is bus stop node or contains bus stop node */ private Node searchBusStop(OsmPrimitive member, String tag, String tagValue) { if(member instanceof Node) { if(compareTag(member, tag, tagValue)) { return (Node)member; } } else { Way memberWay = (Way) member; for(Node node : memberWay.getNodes()) { if(compareTag(node, tag, tagValue)) { return node; } } } return null; } /** * Testing, do stop area contains bus stop node, defined by tag and its value * @param tag Tag name * @param tagValue Tag value * @return true, if stop area contains bus stop node */ public Node searchBusStop(StopArea stopArea, String tag, String tagValue) { for(OsmPrimitive platform : stopArea.platforms) { Node busStopNode = searchBusStop(platform, tag, tagValue); if(busStopNode != null) return busStopNode; } for(OsmPrimitive otherMember : stopArea.otherMembers) { Node busStopNode = searchBusStop(otherMember, tag, tagValue); if(busStopNode != null) return busStopNode; } return null; } /** * Testing, must stop area to have separate bus stop node * @param stopArea Stop area object * @param firstPlatform First platform of stop area JOSM object * @return True, stop area must to have separate bus stop node */ public boolean needSeparateBusStop(StopArea stopArea, OsmPrimitive firstPlatform) { if(((stopArea.isBus || stopArea.isShareTaxi || stopArea.isTrolleybus) && (firstPlatform instanceof Way))) { return true; } return false; } /** * Clear excess tags from JOSM object and its nodes * @param commands Original command list * @param target JOSM object * @param tag Tag name * @param tagValue Tag value * @return Resulting command list */ private List<Command> clearExcessTags(List<Command> commands, OsmPrimitive target, String tag, String tagValue) { if(commands == null) commands = new ArrayList<Command>(); if(compareTag(target, tag, tagValue)) { commands = clearTag(commands, target, tag); } if(target instanceof Way) { Way memberWay = (Way) target; for(Node node : memberWay.getNodes()) { if(compareTag(node, tag, tagValue)) { commands = clearTag(commands, target, tag); } } } return commands; } /** * Clear excess tags from JOSM object and its nodes * @param commands Command list * @param stopArea Stop area object * @param tag Tag name * @param tagValue Tag value * @return Resulting command list */ public List<Command> clearExcessTags(List<Command> commands, StopArea stopArea, String tag, String tagValue) { if(commands == null) commands = new ArrayList<Command>(); for(OsmPrimitive stopPoint : stopArea.stopPoints) { clearExcessTags(commands, stopPoint, tag, tagValue); } for(OsmPrimitive platform : stopArea.platforms) { clearExcessTags(commands, platform, tag, tagValue); } for(OsmPrimitive otherMember : stopArea.otherMembers) { clearExcessTags(commands, otherMember, tag, tagValue); } return commands; } /** * Create separate bus stop node or assign bus stop tag to platform node * @param commands Original command list * @param stopArea Stop area object * @param firstPlatform First platform in stop area relation * @param tag Tag name * @param tagValue Tag value * @return Resulting command list */ protected List<Command> createSeparateBusStopNode(List<Command> commands, StopArea stopArea, OsmPrimitive firstPlatform, String tag, String tagValue) { if(commands == null) commands = new ArrayList<Command>(); LatLon centerOfPlatform = getCenterOfWay(firstPlatform); if(firstPlatform instanceof Way) { if(centerOfPlatform != null) { Node newNode =new Node(); newNode.setCoor(centerOfPlatform); Main.main.undoRedo.add(new AddCommand(newNode)); Main.main.undoRedo.add(new ChangePropertyCommand(newNode, tag, tagValue)); commands = assignTag(commands, newNode, tag, tagValue); stopArea.otherMembers.add(newNode); } } else { commands = assignTag(commands, firstPlatform, tag, tagValue); } return commands; } /** * Forming commands for JOSM for saving stop area members and relation attributes * @param stopArea Stop area object * @return Resulting command list */ public List<Command> customize(StopArea stopArea) { try { List<Command> commands = new ArrayList<Command>(); Node separateBusStopNode = searchBusStop(stopArea, OSMTags.AMENITY_TAG, OSMTags.BUS_STATION_TAG_VALUE); if(separateBusStopNode == null) separateBusStopNode = searchBusStop(stopArea, OSMTags.HIGHWAY_TAG, OSMTags.BUS_STOP_TAG_VALUE); if(stopArea.isBusStation) { commands = clearExcessTags(commands, stopArea, OSMTags.HIGHWAY_TAG, OSMTags.BUS_STOP_TAG_VALUE); } else { commands = clearExcessTags(commands, stopArea, OSMTags.AMENITY_TAG, OSMTags.BUS_STATION_TAG_VALUE); } if(!(stopArea.isBus || stopArea.isShareTaxi || stopArea.isTrolleybus)) { commands = clearExcessTags(commands, stopArea, OSMTags.HIGHWAY_TAG, OSMTags.BUS_STOP_TAG_VALUE); } if(stopArea.stopPoints.size() == 0) { CreateNewStopPointOperation createNewStopPointOperation = new CreateNewStopPointOperation(getCurrentDataSet()); createNewStopPointOperation.performCustomizing(stopArea); } Boolean isFirst = true; for(Node node : stopArea.stopPoints) { commands = stopPointTagAssign(node, commands, stopArea, isFirst); isFirst = false; } isFirst = true; OsmPrimitive firstPlatform = null; for(OsmPrimitive platform : stopArea.platforms) { commands = platformTagAssign(platform, commands, stopArea, isFirst); if(isFirst) firstPlatform = platform; isFirst = false; } if(needSeparateBusStop(stopArea, firstPlatform)) { if(stopArea.isBusStation) { if(separateBusStopNode == null) { commands = createSeparateBusStopNode(commands, stopArea, firstPlatform, OSMTags.AMENITY_TAG, OSMTags.BUS_STATION_TAG_VALUE); } else { commands = assignTag(commands, separateBusStopNode, OSMTags.AMENITY_TAG, OSMTags.BUS_STATION_TAG_VALUE); } } else { if(separateBusStopNode == null) { commands = createSeparateBusStopNode(commands, stopArea, firstPlatform, OSMTags.HIGHWAY_TAG, OSMTags.BUS_STOP_TAG_VALUE); } else { commands = assignTag(commands, separateBusStopNode, OSMTags.HIGHWAY_TAG, OSMTags.BUS_STOP_TAG_VALUE); } } } else { if(stopArea.isBusStation) { commands = assignTag(commands, firstPlatform, OSMTags.AMENITY_TAG, OSMTags.BUS_STATION_TAG_VALUE); } else if(stopArea.isBus || stopArea.isTrolleybus || stopArea.isShareTaxi) { commands = assignTag(commands, firstPlatform, OSMTags.HIGHWAY_TAG, OSMTags.BUS_STOP_TAG_VALUE); } } for(OsmPrimitive otherMember : stopArea.otherMembers) { commands = otherMemberTagAssign(otherMember, commands, stopArea); } if(stopArea.stopAreaRelation == null) { if(stopArea.stopPoints.size() + stopArea.platforms.size() + stopArea.otherMembers.size() > 1) { commands = createStopAreaRelation(commands, stopArea); } } else { commands = generalTagAssign(stopArea.stopAreaRelation, commands, stopArea); commands = transportTypeTagClearing(stopArea.stopAreaRelation, commands); commands = addNewRelationMembers(commands, stopArea); } return commands; } catch(Exception ex) { MessageBox.ok(ex.getMessage()); } return null; } /** * Construct and executing command list for customizing of stop area relation and its members * @param stopArea Stop area object * @return Stop area object */ @Override public StopArea performCustomizing(StopArea stopArea) { List<Command> commands = customize(stopArea); if(commands != null && !commands.isEmpty()) try { Main.main.undoRedo.add(new SequenceCommand(tr(TAG_ASSIGN_COMMAND_NAME), commands)); return stopArea; } catch(Exception ex) { } return stopArea; } }