Skip to content

Commit

Permalink
#368 improve RouteAnalysisContext report
Browse files Browse the repository at this point in the history
  • Loading branch information
vmarc committed Jun 24, 2024
1 parent 4a1e392 commit 9b7c710
Show file tree
Hide file tree
Showing 8 changed files with 331 additions and 199 deletions.
Original file line number Diff line number Diff line change
@@ -1,213 +1,76 @@
package kpn.server.analyzer.engine.analysis.route.analyzers

import kpn.core.analysis.RouteMember
import kpn.core.tools.config.Dirs
import kpn.server.analyzer.engine.analysis.route.RouteSegmentData
import kpn.server.analyzer.engine.analysis.route.domain.RouteAnalysisContext
import kpn.server.analyzer.engine.analysis.route.structure.Structure
import kpn.server.analyzer.engine.analysis.route.structure.StructureElementGroup
import kpn.server.analyzer.engine.analysis.route.structure.StructurePath
import kpn.server.analyzer.engine.analysis.route.report.RouteFactsReport
import kpn.server.analyzer.engine.analysis.route.report.RouteMembersReport
import kpn.server.analyzer.engine.analysis.route.report.RouteSegmentsReport
import kpn.server.analyzer.engine.analysis.route.report.RouteSummaryReport
import kpn.server.analyzer.engine.analysis.route.report.StructureElementGroupsReport
import kpn.server.analyzer.engine.analysis.route.report.StructureReport

import java.io.File
import java.io.PrintWriter

object RouteAnalysisContextReport {
def report(context: RouteAnalysisContext): Unit = {
new RouteAnalysisContextReport(context).report()
}
}

class RouteAnalysisContextReport(context: RouteAnalysisContext) {

private val out = {
val dir = new File(Dirs.root, "routes")
dir.mkdirs
new PrintWriter(new File(dir, s"/${context.relation.id}.html"))
}

def report(): Unit = {
reportStart()
printSummary()
printFacts()
reportRouteMembers()
context.segmentAnalysis.foreach { segmentAnalysis =>
printElementGroups(segmentAnalysis.elementGroups)
printRouteSegments(segmentAnalysis.routeSegments)
printStructure(segmentAnalysis.structure)
val out = {
val dir = new File(Dirs.root, "routes")
dir.mkdirs
new PrintWriter(new File(dir, s"/${context.relation.id}.html"))
}
reportEnd()
}

private def reportStart(): Unit = {
out.println("<html>")

out.println("<head>")
out.println(""" <meta http-equiv="content-type" content="text/html; charset=UTF-8">""")
out.println(""" <link href="styles.css" rel="stylesheet" type="text/css">""")
out.println(s" <title>${context.relation.id} route</title>")
out.println(" <style>")
out.println(" body {")
out.println(" font-family: monospace;")
out.println(" }")
out.println(" table {")
out.println(" margin: 30;")
out.println(" }")
out.println(" table, th, td {")
out.println(" border: 1px solid gray;")
out.println(" border-collapse: collapse;")
out.println(" }")
out.println(" td {")
out.println(" padding: .5em;")
out.println(" }")
out.println(" ")
out.println(" </style>")
out.println("</head>")

out.println("<body>")
}

private def reportEnd(): Unit = {
out.println("</body>")
out.println("</html>")
out.println(new RouteAnalysisContextReport(context).report())
out.close()
}
}

private def printSummary(): Unit = {
out.println("<table>")
row("name", context.routeNameAnalysis.flatMap(_.name).getOrElse("?"))
row("nodeNetwork", yes(context.nodeNetwork))
row("superRoute", yes(context.superRoute))
row("proposed", yes(context.proposed))
row("networkType", s"""${context.networkType.map(_.name).getOrElse("")}""")
row("scopedNetworkType", s"""${context.scopedNetworkTypeOption.map(_.key).getOrElse("")}""")
row("country", s"""${context.country.map(_.domain).getOrElse("")}""")
row("unexpectedNodeIds", context.unexpectedNodeIds.toSeq.flatten.mkString(", "))
row("unexpectedRelationIds", context.unexpectedRelationIds.toSeq.flatten.mkString(", "))
out.println("</table>")

context.routeNodeInfos.foreach { routeNodeInfo =>
/*
node: Node,
name: String,
longName: Option[String]
*/
}
}

private def row(key: String, value: String): Unit = {
out.println(s"<tr><td>$key</td><td>$value</td></tr>")
}

private def reportRouteMembers(): Unit = {
out.println("""<table>""")
reportRouteMembersHeader()
context.routeMembers.get.zipWithIndex.foreach { case (routeMember, index) =>
reportRouteMember(routeMember, index)
}
out.println("</table>")
}

private def reportRouteMembersHeader(): Unit = {
out.println("<tr>")
out.println("<td>nr</td>")
out.println("<td></td>")
out.println("<td>link</td>")
out.println("<td>id</td>")
out.println("<td>name</td>")
out.println("<td>role</td>")
out.println("<td>accessible</td>")
out.println("</tr>")
}

private def reportRouteMember(routeMember: RouteMember, index: Int): Unit = {
out.println("<tr>")
out.println("<td>")
out.println(s"""${index + 1}""")
out.println("</td>")
out.println("""<td style="padding:0">""")
out.println(s"""<img src="images/${routeMember.linkName}.png"/>""")
out.println("</td>")
out.println("<td>")
out.println("<pre>" + routeMember.link.map(_.reportString).getOrElse("") + "</pre>")
out.println("</td>")
out.println("<td>")
out.println(s"""<a href="https://www.openstreetmap.org/${routeMember.memberType}/${routeMember.id}">${routeMember.id}</a>""")
out.println("</td>")
out.println("<td>")
out.println(routeMember.name)
out.println("</td>")
out.println("<td>")
out.println(routeMember.role.getOrElse(""))
out.println("</td>")
out.println("<td>")
out.println(if (routeMember.accessible) "" else "no")
out.println("</td>")
out.println("</tr>")
}

private def printElementGroups(groups: Seq[StructureElementGroup]): Unit = {
out.println("<pre>")
out.println("elementGroups")
groups.foreach { group =>
out.println(" StructureElementGroup")
group.elements.foreach { element =>
out.println(" StructureElement")
element.fragments.foreach { fragment =>
out.println(s""" StructureFragment way=${fragment.way.id} bidirectional=${fragment.bidirectional}, nodeIds=${fragment.nodeIds.mkString(",")}""")
}
}
}
out.println("</pre>")
}

private def printRouteSegments(routeSegments: Seq[RouteSegmentData]): Unit = {
out.println("<pre>")
out.println("routeSegments")
routeSegments.foreach { routeSegment =>
out.println(s" id=${routeSegment.id}, id=${routeSegment.segment.id}, startNodeId=${routeSegment.segment.startNodeId}, endNodeId=${routeSegment.segment.endNodeId}")
}
out.println("</pre>")
}

private def printStructure(structure: Structure): Unit = {
out.println("<pre>")
out.println(s"Structure")
structure.forwardPath.foreach { path =>
printStructurePath("forwardPath", path)
}
structure.backwardPath.foreach { path =>
printStructurePath("backwardPath", path)
}
structure.otherPaths.foreach { path =>
printStructurePath("otherPath", path)
}
out.println("</pre>")
}

private def printStructurePath(name: String, path: StructurePath): Unit = {
out.println(s" StructurePath $name startNodeId=${path.startNodeId}, endNodeId=${path.endNodeId}")
path.elements.foreach { pathElement =>
out.println(s" StructurePathElement reversed=${pathElement.reversed}")
pathElement.element.fragments.foreach { fragment =>
out.println(s""" way=${fragment.way.id} bidirectional=${fragment.bidirectional}, nodeIds=${fragment.nodeIds.mkString(",")}""")
}
}
}

private def printFacts(): Unit = {
out.println("<pre>")
if (context.facts != context.oldFacts) {
out.println("FACTS DO NOT MATCH")
out.println(s" oldFacts=${context.oldFacts.map(_.name).mkString(", ")}")
out.println(s" newFacts=${context.facts.map(_.name).mkString(", ")}")
}
else {
out.println(s"facts=${context.facts.map(_.name).mkString(", ")}")
}
out.println("</pre>")
}
class RouteAnalysisContextReport(context: RouteAnalysisContext) {

private def yes(value: Boolean): String = {
if (value) "yes" else ""
def report(): String = {
s"""<html>
|${head()}
|<body>
|${RouteSummaryReport.report(context)}
|${RouteFactsReport.report(context)}
|${RouteMembersReport.report(context)}
|${RouteSegmentsReport.report(context)}
|${StructureElementGroupsReport.report(context.segmentAnalysis.get.elementGroups)}
|${StructureReport.report(context.segmentAnalysis.get.structure)}
|</body>
|</html>
|""".stripMargin
}

private def head(): String = {
s"""<head>
| <meta http-equiv="content-type" content="text/html; charset=UTF-8">
| <link href="styles.css" rel="stylesheet" type="text/css">
| <title>${context.relation.id} route</title>
| <style>
| body {
| font-family: monospace;
| }
| table {
| margin: 30;
| }
| table, th, td {
| border: 1px solid gray;
| border-collapse: collapse;
| }
| td {
| padding: .5em;
| }
| .header {
| background-color: #f8f8f8;
| }
| .spacer {
| min-width: 1em;
| border-left: none;
| border-right: none;
| }
|
| </style>
|</head>
|""".stripMargin
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ class RouteSegmentAnalyzer {

def analyze(wayMembers: Seq[WayMember]): RouteSegmentAnalysis = {

val nodes = wayMembers.flatMap(_.way.nodes).distinct
val nodeMap = nodes.map(node => node.id -> new Coordinate(node.lon, node.lat)).toMap

val elementGroups = try {
StructureElementAnalyzer.analyze(wayMembers)
}
Expand All @@ -49,6 +46,11 @@ class RouteSegmentAnalyzer {

val structure = new StructureAnalyzer().analyze(elementGroups)

val nodeMap = {
val nodes = wayMembers.flatMap(_.way.nodes).distinct
nodes.map(node => node.id -> new Coordinate(node.lon, node.lat)).toMap
}

val routeSegments = elementGroups.zipWithIndex.flatMap { case (elementGroup, index) =>
val lineStrings = elementGroup.elements.map { element =>
val coordinates = element.nodeIds.flatMap(nodeMap.get)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package kpn.server.analyzer.engine.analysis.route.report

import kpn.server.analyzer.engine.analysis.route.domain.RouteAnalysisContext

object RouteFactsReport {

def report(context: RouteAnalysisContext): String = {
if (context.facts != context.oldFacts) {
s"""<pre>
|FACTS DO NOT MATCH
| oldFacts=${context.oldFacts.map(_.name).mkString(", ")}
| newFacts=${context.facts.map(_.name).mkString(", ")}
|</pre>
|""".stripMargin
}
else {
s"""<pre>
|facts=${context.facts.map(_.name).mkString(", ")}
|</pre>
|""".stripMargin
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package kpn.server.analyzer.engine.analysis.route.report

import kpn.core.analysis.RouteMember
import kpn.server.analyzer.engine.analysis.route.domain.RouteAnalysisContext

object RouteMembersReport {
def report(context: RouteAnalysisContext): String = {
new RouteMembersReport(context).report()
}
}

class RouteMembersReport(context: RouteAnalysisContext) {
def report(): String = {
s"""<table>
| <tr class="header">
| <td>nr</td>
| <td></td>
| <td>link</td>
| <td>id</td>
| <td>name</td>
| <td>role</td>
| <td>accessible</td>
| </tr>
|${routeMemberRows()}
|</table>
|""".stripMargin
}

private def routeMemberRows(): String = {
context.routeMembers.get.zipWithIndex.map { case (routeMember, index) =>
routeMemberRow(routeMember, index)
}.mkString
}

private def routeMemberRow(routeMember: RouteMember, index: Int): String = {
s"""<tr>
| <td>
| ${index + 1}
| </td>
| <td style="padding:0">
| <img src="images/${routeMember.linkName}.png"/>
| </td>
| <td>
| <pre>${routeMember.link.map(_.reportString).getOrElse("")}</pre>
| </td>
| <td>
| <a href="https://www.openstreetmap.org/${routeMember.memberType}/${routeMember.id}">${routeMember.id}</a>
| </td>
| <td>
| ${routeMember.name}
| </td>
| <td>
| ${routeMember.role.getOrElse("")}
| </td>
| <td>
| ${if (routeMember.accessible) "" else "no"}
| </td>
|</tr>
|""".stripMargin
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package kpn.server.analyzer.engine.analysis.route.report

import kpn.server.analyzer.engine.analysis.route.RouteSegmentData
import kpn.server.analyzer.engine.analysis.route.domain.RouteAnalysisContext

object RouteSegmentsReport {
def report(context: RouteAnalysisContext): String = {
s"""<pre>
|routeSegments
|${context.segmentAnalysis.get.routeSegments.map(segmentReport).mkString("\n")}
|</pre>
|""".stripMargin
}

private def segmentReport(routeSegment: RouteSegmentData): String = {
s" id=${routeSegment.id}, id=${routeSegment.segment.id}, startNodeId=${routeSegment.segment.startNodeId}, endNodeId=${routeSegment.segment.endNodeId}"
}
}
Loading

0 comments on commit 9b7c710

Please sign in to comment.