Parse routes not indexed by the root SIT element

master
Araozu 2024-09-10 22:33:40 -05:00
parent ddda0706e4
commit 3b2c7da296
1 changed files with 124 additions and 39 deletions

145
main.go
View File

@ -7,6 +7,7 @@ import (
"log"
"os"
"regexp"
"sort"
"strconv"
)
@ -72,6 +73,11 @@ type OsmDocument struct {
Ways []OsmWay `xml:"way"`
}
type CombiPair struct {
Departure *OsmRelation
Return *OsmRelation
}
type CombiData struct {
// Number that succeedes the Company name.
// E.g.: 7
@ -86,6 +92,7 @@ type CombiData struct {
Ref string
Color string
Members *[]OsmMember
ReturnMembers *[]OsmMember
}
// Type to be consumed by the client
@ -128,36 +135,13 @@ func main() {
nodesMap[node.Id] = &node
}
// Get the relation with id 17642638,
// that relation hosts the SIT data
var sitId int64 = 17642638
var sitRelation *OsmRelation
for _, relation := range osmDocument.Relations {
if relation.Id == sitId {
sitRelation = &relation
}
}
if sitRelation == nil {
panic("SIT relation with id 17642638 not found!")
}
// (naively) get all the submembers
sitMembers := make([]OsmRelation, 0)
for _, member := range sitRelation.Members {
// search the member
// TODO: determine if this is a performance bottleneck,
// and requires optimization (insertion sort & binary search)
for _, relation := range osmDocument.Relations {
if relation.Id == member.Ref {
sitMembers = append(sitMembers, relation)
}
}
}
// Contains a list of pairs of relations
sitMembers := getSITRelations(&osmDocument)
// transform sitMembers into CombiData
combis := make([]CombiData, 0)
for _, member := range sitMembers {
combis = append(combis, parseCombiData(member))
for _, memberPair := range sitMembers {
combis = append(combis, parseCombiData(memberPair))
}
// Create a map from string to CombiLine
@ -188,11 +172,10 @@ func main() {
// Convert each CombiData into a CombiRoute and store it
for _, combi := range combis {
log.Printf("Processing %s %s", combi.Company, combi.Ref)
returnCoord := make([][]float64, 0)
combiRoute := CombiRoute{
Name: combi.Ref,
Departure: getCoordinates(&osmDocument.Ways, nodesMap, combi.Members),
Return: &returnCoord,
Return: getCoordinates(&osmDocument.Ways, nodesMap, combi.ReturnMembers),
}
combiLineSlice := combiRoutesMap[combi.Id]
combiLineSlice.Routes = append(combiLineSlice.Routes, combiRoute)
@ -348,6 +331,10 @@ func writeOutput(lines map[string]*CombiLine, routes map[int]*CombiRouteContaine
for _, combiLine := range lines {
combiLineSlice = append(combiLineSlice, combiLine)
}
// sort the map
sort.Slice(combiLineSlice, func(i, j int) bool {
return combiLineSlice[i].Id < combiLineSlice[j].Id
})
// print JSON
jsonBytes, err := json.Marshal(combiLineSlice)
@ -361,6 +348,9 @@ func writeOutput(lines map[string]*CombiLine, routes map[int]*CombiRouteContaine
//
for lineId, routeContainer := range routes {
outFilename := fmt.Sprintf("output/routes_%d.json", lineId)
sort.Slice(routeContainer.Routes, func(i, j int) bool {
return routeContainer.Routes[i].Name < routeContainer.Routes[j].Name
})
jsonBytes, err := json.Marshal(routeContainer.Routes)
if err != nil {
panic(nil)
@ -375,7 +365,10 @@ func writeOutput(lines map[string]*CombiLine, routes map[int]*CombiRouteContaine
log.Print("JSON files written to output/")
}
func parseCombiData(member OsmRelation) CombiData {
func parseCombiData(combiPair *CombiPair) CombiData {
member := combiPair.Departure
returnMember := combiPair.Return
var operatorTag *OsmTag
var nameTag *OsmTag
var refTag *OsmTag
@ -420,9 +413,101 @@ func parseCombiData(member OsmRelation) CombiData {
Ref: refTag.V,
Color: colorTag.V,
Members: &member.Members,
ReturnMembers: &returnMember.Members,
}
}
// Finds all the relations that are related to the SIT
func getSITRelations(osmDocument *OsmDocument) []*CombiPair {
// a route is identified by the pair operator,ref
// how to know which route is the departure,
// and which is the return?
// each district (route, color) is assigned to a district/area
// in arequipa,
// so to know which way is each route, we compare the first
// coordinate against a coordinate located at that district
// TODO: implement that
// map of maps
// map of `operator` to (map of `ref` to OsmRelation)
operators := make(map[string]*(map[string]*[]*OsmRelation))
// search, filter and store
for _, r := range osmDocument.Relations {
if r.Tag("type", "route") && r.Tag("route", "bus") && r.Tag("network", "SIT") {
operator := r.GetTag("operator")
ref := r.GetTag("ref")
// check if operator map exists, create if not
operatorMap := operators[operator]
if operatorMap == nil {
newMap := make(map[string]*[]*OsmRelation)
operatorMap = &newMap
operators[operator] = &newMap
}
// check if ref exists, create if not
refs := (*operatorMap)[ref]
if refs == nil {
refsArr := make([]*OsmRelation, 0)
refs = &refsArr
(*operatorMap)[ref] = &refsArr
}
// insert
*refs = append(*refs, &r)
}
}
// map and filter
pairs := make([]*CombiPair, 0)
for operatorKey, operator := range operators {
for refKey, relationSlice := range *operator {
if len(*relationSlice) != 2 {
log.Printf("operator(%s) ref(%s): expected 2 ref elements, found %d", operatorKey, refKey, len(*relationSlice))
continue
}
// AYAYA!
newPair := CombiPair{
Departure: (*relationSlice)[0],
Return: (*relationSlice)[1],
}
pairs = append(pairs, &newPair)
}
}
return pairs
}
func (r *OsmRelation) HasTag(tagName string) bool {
for _, tag := range r.Tags {
if tag.K == tagName {
return true
}
}
return false
}
func (r *OsmRelation) Tag(tagName string, tagValue string) bool {
for _, tag := range r.Tags {
if tag.K == tagName && tag.V == tagValue {
return true
}
}
return false
}
func (r *OsmRelation) GetTag(tagName string) string {
for _, tag := range r.Tags {
if tag.K == tagName {
return tag.V
}
}
panic(fmt.Sprintf("Tried to get, from relation(%d), tag %s, but it was not found", r.Id, tagName))
}
// Extracts the id from a line name.
// E.g.: "C11 - Cotum" -> 11
func parseLineId(lineName string) int {