Skip to content

Commit

Permalink
#278 monitor route analysis - wip
Browse files Browse the repository at this point in the history
  • Loading branch information
vmarc committed Feb 2, 2024
1 parent c5753fa commit b9b3736
Show file tree
Hide file tree
Showing 9 changed files with 194 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -118,21 +118,124 @@ class StructureElementAnalyzer(wayMembers: Seq[WayMember], traceEnabled: Boolean
}

private def processRoundabout(): Unit = {
val calculatedStartNodeId = currentElementFragments.lastOption.map(_.endNodeId) match {
case None => elements.lastOption.map(_.endNodeId)
case Some(endNodeId) => Some(endNodeId)
}
val calculatedStartNodeId = lastForwardFragment.map(_.endNodeId)

calculatedStartNodeId match {
case None =>
throw new Exception("The roundabout is the first fragment of the current element: decide how to handle")
// TODO look ahead at the next way member for a connection
contextNextWayMember match {
case None =>
// The roundabout is the first fragment of the current element and there is no next element

val nodeIds = contextCurrentWayMember.way.nodes.map(_.id)

val forwardFragment = StructureFragment(contextCurrentWayMember.way, nodeIds)
lastForwardFragment = Some(forwardFragment)
val forwardElement = StructureElement.from(Seq(forwardFragment), Some(ElementDirection.Down))
elements.addOne(forwardElement)

val backwardFragment = StructureFragment(contextCurrentWayMember.way, nodeIds.reverse)
lastBackwardFragment = Some(backwardFragment)
val backwardElement = StructureElement.from(Seq(backwardFragment), Some(ElementDirection.Up))
elements.addOne(backwardElement)

case Some(nextWayMember) =>

// The roundabout is the first fragment of the current element

val connectingNodeIds1 = contextCurrentWayMember.way.nodes.map(_.id)

val connectingNodeIds2 = if (nextWayMember.way.tags.has("junction", "roundabout")) {
nextWayMember.way.nodes.map(_.id)
}
else {
if (nextWayMember.hasRoleForward) {
Seq(nextWayMember.way.nodes.head.id)
}
else if (nextWayMember.hasRoleBackward) {
Seq(nextWayMember.way.nodes.last.id)
}
else {
// bidirectional fragment
Seq(
nextWayMember.way.nodes.head.id,
nextWayMember.way.nodes.last.id
)
}
}

val connectingNodeId = connectingNodeIds1.flatMap { nodeId1 =>
connectingNodeIds2
.filter(nodeId2 => nodeId1 == nodeId2)
.headOption
}.headOption

connectingNodeId match {
case None =>

if (traceEnabled) {
trace(s" current roundabout way does not connect to next way")
}

finalizeCurrentElement()
val nodeIds = contextCurrentWayMember.way.nodes.map(_.id)

val forwardFragment = StructureFragment(contextCurrentWayMember.way, nodeIds)
lastForwardFragment = Some(forwardFragment)
val forwardElement = StructureElement.from(Seq(forwardFragment), Some(ElementDirection.Down))
elements.addOne(forwardElement)

val backwardFragment = StructureFragment(contextCurrentWayMember.way, nodeIds.reverse)
lastBackwardFragment = Some(backwardFragment)
val backwardElement = StructureElement.from(Seq(backwardFragment), Some(ElementDirection.Up))
elements.addOne(backwardElement)

case Some(nodeId) =>

finalizeCurrentElement()
val wayNodeIds = contextCurrentWayMember.way.nodes.map(_.id)
// TODO for walking routes, should choose shortest path here instead of adding both forward and backward element
StructureUtil.roundaboutNodeIds(wayNodeIds.head, nodeId, wayNodeIds) match {
case None => throw new Exception("internal error TODO better message")
case Some(nodeIds) =>
val forwardFragment = StructureFragment(contextCurrentWayMember.way, nodeIds)
lastForwardFragment = Some(forwardFragment)
val element = StructureElement.from(Seq(forwardFragment), Some(ElementDirection.Down))
elements.addOne(element)
}

StructureUtil.roundaboutNodeIds(nodeId, wayNodeIds.head, wayNodeIds) match {
case None => throw new Exception("internal error TODO better message")
case Some(nodeIds) =>
val backwardFragment = StructureFragment(contextCurrentWayMember.way, nodeIds)
lastBackwardFragment = Some(backwardFragment)
val element = StructureElement.from(Seq(backwardFragment), Some(ElementDirection.Up))
elements.addOne(element)
}
}
}

case Some(startNodeId) =>

contextNextWayMember match {
case None =>
throw new Exception("The roundabout is the last element in the relation: decide how to handle")
// TODO create and add fragment from the entire roundabout?

val wayNodeIds = contextCurrentWayMember.way.nodes.map(_.id)
StructureUtil.roundaboutNodeIds(startNodeId, wayNodeIds) match {
case None =>
throw new Exception("internal error TODO better message")
case Some(nodeIds) =>

finalizeCurrentElement()
val forwardFragment = StructureFragment(contextCurrentWayMember.way, nodeIds)
lastForwardFragment = Some(forwardFragment)
val forwardElement = StructureElement.from(Seq(forwardFragment), Some(ElementDirection.Down))
elements.addOne(forwardElement)

val backwardFragment = StructureFragment(contextCurrentWayMember.way, nodeIds.reverse)
lastBackwardFragment = Some(backwardFragment)
val element = StructureElement.from(Seq(backwardFragment), Some(ElementDirection.Up))
elements.addOne(element)
}

case Some(nextWayMember) =>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ object StructureUtil {

val startIndex = reducedNodeIds.indexOf(startNodeId)
if (startIndex >= 0) {
Some(reducedNodeIds.drop(startIndex) ++ reducedNodeIds.takeWhile(_ != startNodeId))
Some(reducedNodeIds.drop(startIndex) ++ reducedNodeIds.takeWhile(_ != startNodeId) :+ startNodeId)
}
else {
None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import kpn.core.util.UnitTest
class StructureUtilTest extends UnitTest {

test("roundaboutNodeIds startNodeId") {
StructureUtil.roundaboutNodeIds(1, Seq(1, 2, 3, 4, 5, 1)) should equal(Some(Seq(1, 2, 3, 4, 5)))
StructureUtil.roundaboutNodeIds(2, Seq(1, 2, 3, 4, 5, 1)) should equal(Some(Seq(2, 3, 4, 5, 1)))
StructureUtil.roundaboutNodeIds(4, Seq(1, 2, 3, 4, 5, 1)) should equal(Some(Seq(4, 5, 1, 2, 3)))
StructureUtil.roundaboutNodeIds(5, Seq(1, 2, 3, 4, 5, 1)) should equal(Some(Seq(5, 1, 2, 3, 4)))
StructureUtil.roundaboutNodeIds(1, Seq(1, 2, 3, 4, 5, 1)) should equal(Some(Seq(1, 2, 3, 4, 5, 1)))
StructureUtil.roundaboutNodeIds(2, Seq(1, 2, 3, 4, 5, 1)) should equal(Some(Seq(2, 3, 4, 5, 1, 2)))
StructureUtil.roundaboutNodeIds(4, Seq(1, 2, 3, 4, 5, 1)) should equal(Some(Seq(4, 5, 1, 2, 3, 4)))
StructureUtil.roundaboutNodeIds(5, Seq(1, 2, 3, 4, 5, 1)) should equal(Some(Seq(5, 1, 2, 3, 4, 5)))
StructureUtil.roundaboutNodeIds(6, Seq(1, 2, 3, 4, 5, 1)) should equal(None)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ class Structure_04_SingleWayRoundaboutLoopTest extends UnitTest {
}

test("elements") {
pending
setup.elementGroups().shouldMatchTo(
Seq(
Seq(
"1>1" // TODO correct?
"1>1 (Down)",
"1>1 (Up)",
)
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ class Structure_05_SingleWayRoundaboutNotALoopTest extends UnitTest {
setup.elementGroups().shouldMatchTo(
Seq(
Seq(
"1>4"
"1>4 (Down)",
"4>1 (Up)",
)
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,32 @@ class Structure_51_RoundaboutTest extends UnitTest {
setup.elementGroups().shouldMatchTo(
Seq(
Seq(
"1>1",
"1>1 (Down)",
"1>1 (Up)",
)
)
)
}

test("structure") {
pending
setup.structure()
val structure = setup.structure()
structure.shouldMatchTo(
TestStructure(
forwardPath = Some(
TestStructurePath(
startNodeId = 1,
endNodeId = 1,
nodeIds = Seq(1, 2, 3, 4, 1)
)
),
backwardPath = Some(
TestStructurePath(
startNodeId = 1,
endNodeId = 1,
nodeIds = Seq(1, 4, 3, 2, 1)
)
)
)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class Structure_52_RoundaboutRoundaboutTest extends UnitTest {

private def setup = new StructureTestSetupBuilder() {
memberWayWithTags(11, "", Tags.from("junction" -> "roundabout"), 1, 2, 3, 4, 1)
memberWayWithTags(12, "", Tags.from("junction" -> "roundabout"), 3, 4, 5, 6, 3)
memberWayWithTags(12, "", Tags.from("junction" -> "roundabout"), 3, 5, 6, 7, 3)
}.build

test("reference") {
Expand All @@ -20,21 +20,37 @@ class Structure_52_RoundaboutRoundaboutTest extends UnitTest {
}

test("elements") {
pending
setup.elementGroups().shouldMatchTo(
Seq(
Seq(
"1>1", // TODO
),
Seq(
"3>3",
"1>3 (Down)",
"3>1 (Up)",
"3>3 (Down)",
"3>3 (Up)",
),
)
)
}

test("structure") {
pending
setup.structure()
val structure = setup.structure()
structure.shouldMatchTo(
TestStructure(
forwardPath = Some(
TestStructurePath(
startNodeId = 1,
endNodeId = 3,
nodeIds = Seq(1, 2, 3, 5, 6, 7, 3)
)
),
backwardPath = Some(
TestStructurePath(
startNodeId = 3,
endNodeId = 1,
nodeIds = Seq(3, 7, 6, 5, 3, 4, 1)
)
)
)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,36 @@ class Structure_53_WayRoundaboutTest extends UnitTest {
}

test("elements") {
pending
setup.elementGroups().shouldMatchTo(
Seq(
Seq(
"1>3>3", // TODO
"1>3",
"3>3 (Down)",
"3>3 (Up)",
),
)
)
}

test("structure") {
pending
setup.structure()
val structure = setup.structure()
structure.shouldMatchTo(
TestStructure(
forwardPath = Some(
TestStructurePath(
startNodeId = 1,
endNodeId = 3,
nodeIds = Seq(1, 2, 3, 4, 5, 6, 3)
)
),
backwardPath = Some(
TestStructurePath(
startNodeId = 3,
endNodeId = 1,
nodeIds = Seq(3, 6, 5, 4, 3, 2, 1)
)
)
)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@ class Structure_55_DoubleRoundaboutTest extends UnitTest {
}

test("elements") {
pending
setup.elementGroups().shouldMatchTo(
Seq(
Seq(
"1>3>3", // TODO
),
Seq(
"5>7",
"1>3",
"3>5 (Down)",
"5>3 (Up)",
"5>9 (Down)",
"9>5 (Up)",
"9>11",
),
)
)
Expand All @@ -52,7 +53,7 @@ class Structure_55_DoubleRoundaboutTest extends UnitTest {
TestStructurePath(
startNodeId = 11,
endNodeId = 1,
nodeIds = Seq(11, 10, 9, 8, 5, 3, 2, 1)
nodeIds = Seq(11, 10, 9, 8, 5, 6, 3, 2, 1)
)
)
)
Expand Down

0 comments on commit b9b3736

Please sign in to comment.