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 Jan 31, 2024
1 parent f441876 commit cdfb22b
Show file tree
Hide file tree
Showing 39 changed files with 270 additions and 153 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { PaginatorComponent } from '@app/components/shared/paginator';
[checked]="impact()"
(change)="onImpactChanged($event)"
i18n="@@changes.impact"
>Impact
>Impact
</mat-slide-toggle>
<kpn-paginator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,18 +97,14 @@ import { LocationNodeRoutesComponent } from './location-node-routes.component';
</ng-container>
<ng-container matColumnDef="last-survey">
<th mat-header-cell *matHeaderCellDef i18n="@@location-nodes.table.last-survey">
Survey
</th>
<th mat-header-cell *matHeaderCellDef i18n="@@location-nodes.table.last-survey">Survey</th>
<td mat-cell *matCellDef="let node">
{{ node.lastSurvey | day }}
</td>
</ng-container>
<ng-container matColumnDef="lastEdit">
<th mat-header-cell *matHeaderCellDef i18n="@@location-nodes.table.last-edit">
Last edit
</th>
<th mat-header-cell *matHeaderCellDef i18n="@@location-nodes.table.last-edit">Last edit</th>
<td mat-cell *matCellDef="let node" class="kpn-separated">
<kpn-day [timestamp]="node.lastUpdated" />
<kpn-josm-node [nodeId]="node.id" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package kpn.server.analyzer.engine.monitor.structure

case class StructurePathElement(
element: StructureElement,
reversed: Boolean
) {

def nodeIds: Seq[Long] = {
if (reversed) {
element.nodeIds.reverse
}
else {
element.nodeIds
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ class StructureAnalyzer(traceEnabled: Boolean = false) {
elementGroups.headOption.flatMap { firstElementGroup =>
val elements = firstElementGroup.elements.filter { element =>
element.direction match {
case None => true
case Some(ElementDirection.Down) => true
case Some(ElementDirection.Up) => false
case _ => true
}
}
elements.headOption match {
Expand All @@ -31,11 +31,14 @@ class StructureAnalyzer(traceEnabled: Boolean = false) {
elements.lastOption match {
case None => None
case Some(lastElement) =>
val structurePathElements = elements.map { element =>
StructurePathElement(element, reversed = false)
}
Some(
StructurePath(
firstElement.startNodeId,
lastElement.endNodeId,
elements
structurePathElements
)
)
}
Expand All @@ -47,25 +50,27 @@ class StructureAnalyzer(traceEnabled: Boolean = false) {
elementGroups.lastOption.flatMap { lastElementGroup =>
val elements = lastElementGroup.elements.reverse.filter { element =>
element.direction match {
case None => true
case Some(ElementDirection.Up) => true
case Some(ElementDirection.Down) => false
case _ => true
}
}
elements.lastOption match {
case None => None
case Some(firstElement) =>
elements.lastOption match {
case None => None
case Some(lastElement) =>
Some(
StructurePath(
firstElement.endNodeId,
lastElement.startNodeId,
elements.reverse
)
)
}
if (elements.isEmpty) {
None
}
else {
val structurePathElements = elements.map { element =>
StructurePathElement(element, reversed = true)
}
val startNodeId = structurePathElements.head.nodeIds.head
val endNodeId = structurePathElements.last.nodeIds.last
Some(
StructurePath(
startNodeId,
endNodeId,
structurePathElements
)
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package kpn.server.analyzer.engine.monitor.structure
import kpn.api.common.data.Node
import kpn.api.common.data.Way

case class StructureFragment(way: Way, /*direction: Option[Direction.Value] = None,*/ reversed: Boolean = false) {
case class StructureFragment(way: Way, reversed: Boolean = false) {

def startNode: Node = {
if (reversed) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,12 @@ package kpn.server.analyzer.engine.monitor.structure
case class StructurePath(
startNodeId: Long,
endNodeId: Long,
elements: Seq[StructureElement] = Seq.empty,
)
elements: Seq[StructurePathElement] = Seq.empty,
) {
def nodeIds: Seq[Long] = {
elements.headOption match {
case Some(firstElement) => firstElement.nodeIds.head +: elements.flatMap(_.nodeIds.tail)
case None => Seq.empty
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package kpn.server.analyzer.engine.monitor.structure

import kpn.core.util.UnitTest

class StructureElementTest extends UnitTest {

test("element") {
pending
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package kpn.server.analyzer.engine.monitor.structure

import kpn.api.common.data.Way
import kpn.core.util.UnitTest

class StructureFragmentTest extends UnitTest {

test("reversed false") {

val way = setupWay()
val fragment = StructureFragment(way, reversed = false)

fragment.nodeIds.shouldMatchTo(Seq(1, 2, 3))
fragment.startNode.id.shouldEqual(1)
fragment.endNode.id.shouldEqual(3)
fragment.string.shouldEqual("(11) 1>3")
}

test("reversed true") {

val way = setupWay()
val fragment = StructureFragment(way, reversed = true)

fragment.nodeIds.shouldMatchTo(Seq(3, 2, 1))
fragment.startNode.id.shouldEqual(3)
fragment.endNode.id.shouldEqual(1)
fragment.string.shouldEqual("(11) 3>1*")
}

private def setupWay(): Way = {
val setup = new StructureTestSetupBuilder() {
memberWay(11, "", 1, 2, 3)
}.build
setup.data.ways(11)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package kpn.server.analyzer.engine.monitor.structure

import kpn.core.util.UnitTest

class StructurePathTest extends UnitTest {

test("path") {

val setup = new StructureTestSetupBuilder() {
memberWay(11, "", 1, 2, 3)
}.build
val way = setup.data.ways(11)

val element = StructurePathElement(
element = StructureElement(
id = 1,
fragments = Seq(
StructureFragment(
way,
reversed = false
)
),
direction = None,
),
reversed = false
)

val path = StructurePath(
startNodeId = 1,
endNodeId = 3,
elements = Seq(element)
)

path.nodeIds.shouldMatchTo(Seq(1, 2, 3))
}
}
Original file line number Diff line number Diff line change
@@ -1,73 +1,9 @@
package kpn.server.analyzer.engine.monitor.structure

import kpn.api.common.SharedTestObjects
import kpn.api.common.data.raw.RawData
import kpn.api.common.data.raw.RawMember
import kpn.api.common.data.raw.RawNode
import kpn.api.common.data.raw.RawWay
import kpn.api.custom.Relation
import kpn.api.custom.Tags
import kpn.core.data.DataBuilder
import kpn.core.data.Data

import scala.collection.mutable.ListBuffer

class StructureTestSetup extends SharedTestObjects {

private val nodeBuffer = ListBuffer[RawNode]()
private val wayBuffer = ListBuffer[RawWay]()
private val memberBuffer = ListBuffer[RawMember]()

def memberWay(wayId: Long, role: String, nodeIds: Long*): RawMember = {
memberWayWithTags(wayId, role, Tags.from("highway" -> "road"), nodeIds: _*)
}

def memberWayWithTags(wayId: Long, role: String, tags: Tags, nodeIds: Long*): RawMember = {
addNodesIfMissing(nodeIds)
memberWay(wayId, tags, role, nodeIds: _*)
}

private def node(id: Long, name: String = "", lattitude: Double = 0, longitude: Double = 0): RawNode = {
rawNode(newRawNode(id, lattitude.toString, longitude.toString, tags = Tags.empty))
}

private def rawNode(rawNode: RawNode): RawNode = {
nodeBuffer += rawNode
rawNode
}

private def way(wayId: Long, nodeIds: Long*): RawWay = {
way(wayId, Tags.empty, nodeIds: _*)
}

private def way(wayId: Long, tags: Tags, nodeIds: Long*): RawWay = {
addNodesIfMissing(nodeIds)
val w = newRawWay(wayId, nodeIds = nodeIds.toVector, tags = tags)
wayBuffer += w
w
}

private def memberWay(wayId: Long, tags: Tags, role: String, nodeIds: Long*): RawMember = {
addNodesIfMissing(nodeIds)
way(wayId, tags, nodeIds: _*)
member("way", wayId, role)
}

private def member(memberType: String, ref: Long, role: String = ""): RawMember = {
val m = RawMember(memberType, ref, if (role.nonEmpty) Some(role) else None)
memberBuffer += m
m
}

private def addNodesIfMissing(nodeIds: Seq[Long]): Unit = {
val missingNodeIds = nodeIds.toSet -- nodeBuffer.map(_.id).toSet
missingNodeIds.foreach(id => node(id))
}

def relation: Relation = {
val relation = newRawRelation(1, members = memberBuffer.toSeq)
val rawData = RawData(None, nodeBuffer.toSeq, wayBuffer.toSeq, Seq(relation))
new DataBuilder(rawData).data.relations(1)
}
class StructureTestSetup(val data: Data) {

def elementGroups(traceEnabled: Boolean = false): Seq[Seq[String]] = {
val elementGroups = StructureElementAnalyzer.analyze(relation.members, traceEnabled)
Expand All @@ -85,4 +21,8 @@ class StructureTestSetup extends SharedTestObjects {
def structure(traceEnabled: Boolean = false): TestStructure = {
TestStructure.from(new StructureAnalyzer(traceEnabled).analyze(relation))
}

private def relation: Relation = {
data.relations(1)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package kpn.server.analyzer.engine.monitor.structure

import kpn.api.common.data.raw.RawData
import kpn.api.common.data.raw.RawMember
import kpn.api.common.data.raw.RawNode
import kpn.api.common.data.raw.RawWay
import kpn.api.common.SharedTestObjects
import kpn.api.custom.Relation
import kpn.api.custom.Tags
import kpn.core.data.Data
import kpn.core.data.DataBuilder

import scala.collection.mutable.ListBuffer

class StructureTestSetupBuilder extends SharedTestObjects {

private val nodeBuffer = ListBuffer[RawNode]()
private val wayBuffer = ListBuffer[RawWay]()
private val memberBuffer = ListBuffer[RawMember]()

def memberWay(wayId: Long, role: String, nodeIds: Long*): RawMember = {
memberWayWithTags(wayId, role, Tags.from("highway" -> "road"), nodeIds: _*)
}

def memberWayWithTags(wayId: Long, role: String, tags: Tags, nodeIds: Long*): RawMember = {
addNodesIfMissing(nodeIds)
memberWay(wayId, tags, role, nodeIds: _*)
}

private def node(id: Long, name: String = "", lattitude: Double = 0, longitude: Double = 0): RawNode = {
rawNode(newRawNode(id, lattitude.toString, longitude.toString, tags = Tags.empty))
}

private def rawNode(rawNode: RawNode): RawNode = {
nodeBuffer += rawNode
rawNode
}

private def way(wayId: Long, nodeIds: Long*): RawWay = {
way(wayId, Tags.empty, nodeIds: _*)
}

private def way(wayId: Long, tags: Tags, nodeIds: Long*): RawWay = {
addNodesIfMissing(nodeIds)
val w = newRawWay(wayId, nodeIds = nodeIds.toVector, tags = tags)
wayBuffer += w
w
}

private def memberWay(wayId: Long, tags: Tags, role: String, nodeIds: Long*): RawMember = {
addNodesIfMissing(nodeIds)
way(wayId, tags, nodeIds: _*)
member("way", wayId, role)
}

private def member(memberType: String, ref: Long, role: String = ""): RawMember = {
val m = RawMember(memberType, ref, if (role.nonEmpty) Some(role) else None)
memberBuffer += m
m
}

private def addNodesIfMissing(nodeIds: Seq[Long]): Unit = {
val missingNodeIds = nodeIds.toSet -- nodeBuffer.map(_.id).toSet
missingNodeIds.foreach(id => node(id))
}

def build: StructureTestSetup = {
val relation = newRawRelation(1, members = memberBuffer.toSeq)
val rawData = RawData(None, nodeBuffer.toSeq, wayBuffer.toSeq, Seq(relation))
new StructureTestSetup(new DataBuilder(rawData).data)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import kpn.core.util.UnitTest

class Structure_01_SingleWayBidirectionalTest extends UnitTest {

private def setup = new StructureTestSetup() {
private def setup = new StructureTestSetupBuilder() {
memberWay(11, "", 1, 2, 3)
}
}.build

test("reference") {
setup.reference().shouldMatchTo(
Expand Down

0 comments on commit cdfb22b

Please sign in to comment.