################################################################################ ### Determing Sections From imported OSM data (5 / 11) ################################################################################ ### Description: ### - This script determines Sections within Streets. ### Please, see tu_Osm_import.sh for further details. ### ### Preconditions: ### - activated necessary algebras ### - existing open database with successfully imported Osm data ### - ExtStreetsRel-relation ### ExtStreetsRel: rel{GeoData: sline, StreetId: int, Name: string, ### Ref: string, RoadClassRef: int, OneWay: int, ### Bridge: int, MaxSpeed: int, Tunnel: bool, ### Layer: int, GroupId: int} ### - RestrictionsRel-relation ### RestrictionsRel: rel{FromStreet: int, ToStreet: int, ViaPoint: point, ### Restriction: text} ### ### Postconditions: ### - already existing relations ### - ExtSectionsRel-relation ### ExtSectionsRel: rel{SectionId: int, Section: sline, StartNodeId: int, ### EndNodeId: int, StreetId: int, GroupId: int, ### SectionDist: real} ### - NodesRel-relation ### NodesRel: rel{Node: point, NodeId: int} ### - OnlyRestrictions ### OnlyRestrictions: rel{FromStreeRef: int, ToStreetRef: int, ### ViaNodeRef: int, ViaNode: point, ### Only: bool, Restriction: text} ### - NoUturnRestrictions ### NoUturnRestrictions: rel{FromStreeRef: int, ToStreetRef: int, ### ViaNodeRef: int, ViaNode: point, ### NoUturn: bool} ### - NoLeftTurnRestrictions ### NoLeftTurnRestrictions: rel{FromStreeRef: int, ToStreetRef: int, ### ViaNodeRef: int, ViaNode: point, ### NoLeftTurn: bool} ### - NoRightTurnRestrictions ### NoRightTurnRestrictions: rel{FromStreeRef: int, ToStreetRef: int, ### ViaNodeRef: int, ViaNode: point, ### NoRightTurn: bool} ### - NoStraightOnRestrictions ### NoStraightOnRestrictions: rel{FromStreeRef: int, ToStreetRef: int, ### ViaNodeRef: int, ViaNode: point, ### NoStraightOn: bool} ### ### Author: ### - Thomas Uchdorf, thomas.uchdorf(at)fernuni-hagen.de ################################################################################ # Computing all junctions and terminating points by finding the existing # crossings between Streets and adding terminating points #let juncTermPts = # (ExtStreetsRel feed # project [StreetId,GeoData,Layer] {s1} # ExtStreetsRel feed # project [StreetId,GeoData,Layer] {s2} # spatialjoin [GeoData_s1, GeoData_s2] # filter[(.StreetId_s1 < .StreetId_s2) and (.Layer_s1 = .Layer_s2)] # projectextend[; CrossRoads: crossings(.GeoData_s1, .GeoData_s2)] # filter[not(isempty(.CrossRoads))] # aggregateB[CrossRoads; # fun(P1: points, P2: points) P1 union P2; # [const points value ()]]) # union # (ExtStreetsRel feed # projectextend[; B : boundary(toline(.GeoData))] # aggregateB[B; # fun(P3 : points, P4 : points) P3 union P4; # [const points value ()]] # ); let SectionPtsTmp = (ExtStreetsRel feed project [StreetId,GeoData,Layer] {s1} ExtStreetsRel feed project [StreetId,GeoData,Layer] {s2} spatialjoin [GeoData_s1, GeoData_s2] filter[(.StreetId_s1 < .StreetId_s2) and (.Layer_s1 = .Layer_s2)] filter[.GeoData_s1 intersects .GeoData_s2] projectextend[; Road1: .StreetId_s1, Road2: .StreetId_s2, CrossRoads: crossings(.GeoData_s1, .GeoData_s2)] filter[(isdefined(.CrossRoads)) and (not(isempty(.CrossRoads)))] projectextendstream [Road1,Road2; Pt: components(.CrossRoads)]) (ExtStreetsRel feed projectextend [; Road1: .StreetId, Road2: .StreetId, B: boundary(toline(.GeoData))] projectextendstream [Road1,Road2; Pt: components(.B)] ) concat consume; let StSecPts = (SectionPtsTmp feed projectextend [Pt; Street: .Road1] SectionPtsTmp feed projectextend [Pt; Street: .Road2] concat sortby [Street,Pt] rdup sortby [Street] groupby [Street; SecPts: group feed projecttransformstream [Pt] collect_points [TRUE]] consume); #let SectionPtsRel = # (SectionPtsTmp feed # ExtStreetsRel feed # project [StreetId,GeoData] {s1} # hashjoin [Road1,StreetId_s1,99997]) # ExtStreetsRel feed # project [StreetId,GeoData] {s2} # hashjoin[Road2,StreetId_s2,99997] # filter [((.Road1=.Road2) and # (.Pt inside toline(.GeoData_s1)) and # (distance(.Pt,.GeoData_s1) = 0)) or # (not(.Road1=.Road2) and # (.Pt inside toline(.GeoData_s1)) and # (.Pt inside toline(.GeoData_s2)) and # (distance(.Pt,.GeoData_s1) = 0) and # (distance(.Pt,.GeoData_s2) = 0))] # extend [ # dist1: # ifthenelse(.Road1=.Road2, # 0.,atpoint(.GeoData_s1,.Pt,TRUE)), # dist2: # ifthenelse(.Road1=.Road2, # size(.GeoData_s1),atpoint(.GeoData_s2,.Pt,TRUE))] # sortby [Road1,dist1,dist2] # addcounter[SectionId,1] # consume; # Splitting up all Streets inTo Sections let StsPlusSecsTmp = StSecPts feed {a} ExtStreetsRel feed projectextend [; GroupId: .GroupId, StreetId: .StreetId, Street: .GeoData, UndirStreet: toline(.GeoData)] hashjoin [Street_a,StreetId,99997] projectextendstream [GroupId,StreetId,Street; Section: (.UndirStreet polylines [FALSE,.SecPts_a])] consume; # Creating a relation for the Sections by removing duplicates let SectionsTmp = StsPlusSecsTmp feed project [Section] sortby [Section] rdup addcounter[SectionId, 1] extend [Pts: boundary(.Section)] projectextend [SectionId, Section; Help: Fromline(.Section), Node1: get(.Pts,0), Node2: get(.Pts,1)] consume; # Removing the help points #delete juncTermPts; # Removing the help relations delete SectionPtsTmp; delete StSecPts; # Collecting all Nodes (junctions and end points) in one point array and # adding IDs To the Nodes To form a relation let NodesRel = components( SectionsTmp feed projectextend[; EndPoints: boundary(.Section)] aggregateB[EndPoints; fun(P1: points, P2: points) P1 union P2 ; [const points value ()]]) Namedtransformstream [Node] addcounter [NodeId,1] consume; # Adding indexes for faster access derive NodesRel_NodeId_btree = NodesRel createbtree[NodeId]; derive NodesRel_Node_rtree = NodesRel creatertree[Node]; # Combining source and destination points with Sections between them # (adding References To Nodes) # SectionsRel: rel{SectionId: int, Section: line, Node1: point, # Node2: point, Node1Id: int, Node2Id: int} let SectionsRel = (SectionsTmp feed NodesRel feed {a} hashjoin[Node1, Node_a, 99997]) NodesRel feed {b} hashjoin[Node2, Node_b, 99997] projectextend [SectionId, Section, Help, Node1, Node2; Node1Id: .NodeId_a, Node2Id: .NodeId_b] consume; # Removing the help relation delete SectionsTmp; # Adding indexes for faster access derive SectionsRel_SectionId_btree = SectionsRel createbtree[SectionId]; derive SectionsRel_Node1Id_btree = SectionsRel createbtree[Node1Id]; derive SectionsRel_Node2Id_btree = SectionsRel createbtree[Node2Id]; derive SectionsRel_Section_rtree = SectionsRel creatertree[Section]; # Creating a relation that enables linking Sections To additional Street # data like speed limits or Names and combining the order by group ID, # Street ID and distance on Street with the Section ID let ExtSectionsRel = (StsPlusSecsTmp feed projectextend [GroupId,StreetId,Street; Part: .Section] SectionsRel feed hashjoin [Part,Section,99997] remove [Part,Section] extend [ Node1Dist: atpoint(.Street,.Node1,TRUE), Node2Dist: atpoint(.Street,.Node2,TRUE)] extend [startNode: ifthenelse(.Node1Dist < .Node2Dist, .Node1, .Node2), endNode: ifthenelse(.Node1Dist < .Node2Dist, .Node2, .Node1), StartNodeId: ifthenelse(.Node1Dist < .Node2Dist, .Node1Id, .Node2Id), EndNodeId: ifthenelse(.Node1Dist < .Node2Dist, .Node2Id, .Node1Id)] extend [ LowerStreetDist: ifthenelse(.Node1Dist < .Node2Dist, .Node1Dist, .Node2Dist), HigherStreetDist: ifthenelse(.Node1Dist < .Node2Dist, .Node2Dist, .Node1Dist), SectionDist: size(.Help)] extend [Section: ifthenelse( .SectionDist = .HigherStreetDist, set_startsmaller(.Help, get_startsmaller(.Street)), set_startsmaller(.Help, get_startsmaller(create_sline(.StartNode,.EndNode))))] project[ GroupId, StreetId, SectionId, Section, StartNodeId, EndNodeId, LowerStreetDist,HigherStreetDist,SectionDist]) remove [SectionId] sortby [GroupId,StreetId,HigherStreetDist,LowerStreetDist] addcounter[SectionId, 1] # remove [StreetDist] consume; # Postprocessing Streets that start and end in the same point # (their Sections are computed in a wrong way, since their start and end # point as well as their positions on the Street can not be distinguished # separately) #... update ExtSectionsRel := (((((ExtStreetsRel feed extend [ StreetStartNode: atposition(.GeoData,0.0,TRUE), StreetEndNode: atposition(.GeoData,size(.GeoData),TRUE)] filter [.StreetStartNode = .StreetEndNode] ExtSectionsRel feed hashjoin [StreetId,StreetId,99997]) ExtSectionsRel feed {a} hashjoin [StreetId,StreetId_a,99997] filter [(.HigherStreetDist = .HigherStreetDist_a) and (.SectionId < .SectionId_a)]) NodesRel feed {e} hashjoin [StreetStartNode,Node_e,99997] remove [Node_e]) NodesRel feed {f} hashjoin [StreetEndNode,Node_f,99997] remove [Node_f] extend [StreetStartNodeId: .NodeId_e,StreetEndNodeId: .NodeId_f] projectextend [GroupId,StreetId,SectionId; NewSection: set_startsmaller(.Section,not(get_startsmaller(.Section))), NewStartNodeId: .StreetStartNodeId, NewEndNodeId: .StartNodeId, NewHigherStreetDist: .LowerStreetDist, NewLowerStreetDist: .HigherStreetDist, NewSectionDist: .SectionDist] {n}) ExtSectionsRel feed smouterjoin [SectionId_n,SectionId] projectextend [GroupId,StreetId; Section: ifthenelse(isdefined(.SectionId_n),.NewSection_n,.Section), StartNodeId: ifthenelse(isdefined(.SectionId_n),.NewStartNodeId_n,.StartNodeId), EndNodeId: ifthenelse(isdefined(.SectionId_n),.NewEndNodeId_n,.EndNodeId), LowerStreetDist: ifthenelse(isdefined(.SectionId_n), .NewLowerStreetDist_n,.LowerStreetDist), HigherStreetDist: ifthenelse(isdefined(.SectionId_n), .NewHigherStreetDist_n,.HigherStreetDist), SectionDist: ifthenelse(isdefined(.SectionId_n), .NewSectionDist_n,.SectionDist)] sortby [GroupId,StreetId,HigherStreetDist,LowerStreetDist] addcounter[SectionId, 1] consume); # Removing the help relations delete SectionsRel; delete StsPlusSecsTmp; # Adding indexes for faster access derive ExtSectionsRel_SectionId_btree = ExtSectionsRel createbtree[SectionId]; derive ExtSectionsRel_StartNodeId_btree = ExtSectionsRel createbtree[StartNodeId]; derive ExtSectionsRel_EndNodeId_btree = ExtSectionsRel createbtree[EndNodeId]; derive ExtSectionsRel_StreetId_btree = ExtSectionsRel createbtree[StreetId]; derive ExtSectionsRel_GroupId_btree = ExtSectionsRel createbtree[GroupId]; derive ExtSectionsRel_Section_rtree = ExtSectionsRel creatertree[Section]; #let StreetToNumSections = # ExtSectionsRel feed # sortby [StreetId] # groupby [StreetId; NumSections: group count] # consume; # Extending the Restrictions-relation by References To the junction points let ExtRestrictionsRel = RestrictionsRel feed NodesRel feed hashjoin [ViaPoint,Node,99997] extend [FromStreetRef: .FromStreet, ToStreetRef: .ToStreet, ViaNodeRef: .NodeId, ViaNode: .ViaPoint] remove [FromStreet, ToStreet, ViaPoint, NodeId, Node] consume; # Removing the help relation delete RestrictionsRel; # Splitting up the Restrictions relation and distributing the Restrictions To # different relations let OnlyRestrictions = ExtRestrictionsRel feed extend [Only: .Restriction starts "Only"] filter [.Only] remove [OsmId,RestrictionId] consume; # restrictive Restrictions have To be viewed separately since they otherwise # multiply tuples in conjunction with crossings let NoUturnRestrictions = ExtRestrictionsRel feed filter [.Restriction = "no_u_turn"] extend [NoUturn: TRUE] remove [OsmId,Restriction,RestrictionId] consume; let NoLeftTurnRestrictions = ExtRestrictionsRel feed filter [.Restriction = "no_left_turn"] extend [NoLeftTurn: TRUE] remove [OsmId,Restriction,RestrictionId] consume; let NoStraightOnRestrictions = ExtRestrictionsRel feed filter [.Restriction = "no_straight_on"] extend [NoStraightOn: TRUE] remove [OsmId,Restriction,RestrictionId] consume; let NoRightTurnRestrictions = ExtRestrictionsRel feed filter [.Restriction = "no_right_turn"] extend [NoRightTurn: TRUE] remove [OsmId,Restriction,RestrictionId] consume;