Skip to content

Commit

Permalink
Support forward and backward directions on traffic_sign nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
tordanik committed Sep 18, 2024
1 parent b7c905b commit 0e520ad
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
Expand Down Expand Up @@ -306,23 +304,28 @@ private void createSignFromSeparateNode(MapNode node) {
private void createSignFromHighwayNode(MapNode node) {

String tagValue = "";
ForwardBackward signDirection;
@Nullable ForwardBackward relativeSignDirection;

// TODO: allow traffic_sign:forward and traffic_sign:backward to be tagged at the same time

if (node.getTags().containsKey("traffic_sign:forward")) {
tagValue = node.getTags().getValue("traffic_sign:forward");
signDirection = FORWARD;
relativeSignDirection = FORWARD;
} else if (node.getTags().containsKey("traffic_sign:backward")) {
tagValue = node.getTags().getValue("traffic_sign:backward");
signDirection = BACKWARD;
} else if (node.getTags().containsKey("traffic_sign")) {
tagValue = node.getTags().getValue("traffic_sign");
signDirection = FORWARD;
relativeSignDirection = BACKWARD;
} else {
//in case of highway=give_way/stop, treat sign as if it was mapped as forward:
//affect vehicles moving in the way's direction if no explicit direction tag is defined
signDirection = FORWARD;
if (node.getTags().containsKey("traffic_sign")) {
tagValue = node.getTags().getValue("traffic_sign");
}
// sign direction is relevant even if no traffic_sign is present (for highway=give_way/stop)
if (node.getTags().containsAny(List.of("direction", "traffic_sign:direction"), List.of("forward"))) {
relativeSignDirection = FORWARD;
} else if (node.getTags().containsAny(List.of("direction", "traffic_sign:direction"), List.of("backward"))) {
relativeSignDirection = BACKWARD;
} else {
relativeSignDirection = null;
}
}

/* get the list of traffic signs from the tag's value */
Expand All @@ -343,14 +346,14 @@ private void createSignFromHighwayNode(MapNode node) {

MapWaySegment segment = node.getConnectedWaySegments().get(0);
LeftRight side = RoadModule.getDrivingSide(segment, config);
double direction = calculateDirection(node);
double direction = calculateDirection(node, relativeSignDirection);

List<VectorXZ> positions = new ArrayList<>();

positions.add(calculateSignPosition(node, segment, side, signDirection, true));
positions.add(calculateSignPosition(node, segment, side, relativeSignDirection, true));

if (node.getTags().contains("side", "both")) {
positions.add(calculateSignPosition(node, segment, side.invert(), signDirection, true));
positions.add(calculateSignPosition(node, segment, side.invert(), relativeSignDirection, true));
}

/* create a visual representation of the group of signs at each position */
Expand Down Expand Up @@ -724,11 +727,12 @@ private static double calculateDirection(MapWaySegment segment, ForwardBackward
}

/**
* Calculates the direction for traffic sign nodes that are part of ways.
* Same as {@link #calculateDirection(MapWaySegment, ForwardBackward)} but also parses the node's
* tags for the direction specification and takes into account the
* highway=give_way/stop special case. To be used on nodes that are part of ways.
* highway=give_way/stop special case.
*/
private static double calculateDirection(MapNode node) {
private static double calculateDirection(MapNode node, @Nullable ForwardBackward relativeDirection) {

if (node.getConnectedWaySegments().isEmpty()) {
ConversionLog.warn("Node " + node + " is not part of a way.");
Expand All @@ -740,32 +744,16 @@ private static double calculateDirection(MapNode node) {
//Direction the way the node is part of, is facing
VectorXZ wayDir = node.getConnectedWaySegments().get(0).getDirection();

if (nodeTags.containsKey("direction")) {

if (!nodeTags.containsAny(List.of("direction"), List.of("forward", "backward"))) {
//get direction mapped as angle or cardinal direction
return parseDirection(nodeTags, PI);
} else if (nodeTags.contains("direction", "backward")) {
return wayDir.angle();
}

} else if (nodeTags.containsKey("traffic_sign:forward") || nodeTags.containsKey("traffic_sign:backward")) {

String regex = "traffic_sign:(forward|backward)";
Pattern pattern = Pattern.compile(regex);
Matcher matcher;
//Explicit direction mapped as angle or cardinal direction (if any)
Double direction = parseDirection(nodeTags);

for (Tag tag : nodeTags) {

matcher = pattern.matcher(tag.key);

if (matcher.matches()) {

if (matcher.group(1).equals("backward")) {
return wayDir.angle();
}
}
}
if (direction != null) {
return direction;
} else if (relativeDirection != null) {
return switch (relativeDirection) {
case FORWARD -> wayDir.invert().angle();
case BACKWARD -> wayDir.angle();
};
} else if (nodeTags.containsAny(List.of("highway"), List.of("give_way", "stop"))) {

/*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
package org.osm2world.core.world.modules.traffic_sign;

import static java.lang.Math.PI;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyMap;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.osm2world.core.world.modules.traffic_sign.TrafficSignModule.findClosestJunction;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.configuration.MapConfiguration;
import org.junit.Test;
import org.osm2world.core.ConversionFacade;
import org.osm2world.core.map_data.creation.LatLon;
import org.osm2world.core.map_data.creation.MetricMapProjection;
import org.osm2world.core.map_data.data.MapNode;
import org.osm2world.core.map_data.data.MapWay;
import org.osm2world.core.map_data.data.TagSet;
Expand All @@ -17,6 +24,66 @@

public class TrafficSignModuleTest {

@Test
public void testSignFromHighwayNode() throws IOException {

List<TagSet> inputs = List.of(
TagSet.of("traffic_sign", "DE:240", "direction", "backward"),
TagSet.of("traffic_sign", "DE:240", "traffic_sign:direction", "backward"),
TagSet.of("traffic_sign:backward", "DE:240"),
TagSet.of("traffic_sign", "DE:240", "direction", "forward"),
TagSet.of("traffic_sign", "DE:240", "traffic_sign:direction", "forward"),
TagSet.of("traffic_sign:forward", "DE:240"),
TagSet.of("traffic_sign", "DE:240", "direction", "NW"),
TagSet.of("traffic_sign", "DE:240", "direction", "backward", "side", "both")

);

List<List<TrafficSignGroup>> results = new ArrayList<>();

for (TagSet signTags : inputs) {

/* prepare fake map data */

TestMapDataGenerator generator = new TestMapDataGenerator();

MapNode nodeBefore = generator.createNode(0, 0);
MapNode nodeSign = generator.createNode(1, 1, signTags);
MapNode nodeAfter = generator.createNode(2, 2);

generator.createWay(List.of(nodeBefore, nodeSign, nodeAfter), TagSet.of("highway", "tertiary"));

/* generate models */

var proj = new MetricMapProjection(new LatLon(0, 0));
var result = new ConversionFacade().createRepresentations(
proj, generator.createMapData(), null, null, null);

/* extract results */

results.add(nodeSign.getRepresentations().stream()
.filter(it -> it instanceof TrafficSignGroup)
.map(TrafficSignGroup.class::cast)
.toList());

}

/* check the results */

assertEquals(PI * 0.25, results.get(0).get(0).direction, 0.01);
assertEquals(PI * 0.25, results.get(1).get(0).direction, 0.01);
assertEquals(PI * 0.25, results.get(2).get(0).direction, 0.01);
assertEquals(PI * 1.25, results.get(3).get(0).direction, 0.01);
assertEquals(PI * 1.25, results.get(4).get(0).direction, 0.01);
assertEquals(PI * 1.25, results.get(5).get(0).direction, 0.01);
assertEquals(PI * 1.75, results.get(6).get(0).direction, 0.01);

assertEquals(2, results.get(7).size());
assertEquals(PI * 0.25, results.get(7).get(0).direction, 0.01);
assertEquals(PI * 0.25, results.get(7).get(1).direction, 0.01);

}

@Test
public void zeroConnectedJunctions() throws Exception {

Expand Down

0 comments on commit 0e520ad

Please sign in to comment.