forked from MapComplete/MapComplete
		
	More work on splitting roads, WIP; refactoring tests
This commit is contained in:
		
							parent
							
								
									e374bb355c
								
							
						
					
					
						commit
						1f93923820
					
				
					 62 changed files with 1163 additions and 823 deletions
				
			
		
							
								
								
									
										142
									
								
								Logic/Osm/Actions/RelationSplitHandler.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								Logic/Osm/Actions/RelationSplitHandler.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,142 @@ | |||
| import OsmChangeAction from "./OsmChangeAction"; | ||||
| import {Changes} from "../Changes"; | ||||
| import {ChangeDescription} from "./ChangeDescription"; | ||||
| import {OsmObject, OsmRelation, OsmWay} from "../OsmObject"; | ||||
| 
 | ||||
| export interface RelationSplitInput { | ||||
|     relation: OsmRelation, | ||||
|     originalWayId: number, | ||||
|     allWayIdsInOrder: number[], | ||||
|     originalNodes: number[], | ||||
|     allWaysNodesInOrder: number[][] | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * When a way is split and this way is part of a relation, the relation should be updated too to have the new segment if relevant. | ||||
|  */ | ||||
| export default class RelationSplitHandler extends OsmChangeAction { | ||||
| 
 | ||||
|     constructor(input: RelationSplitInput) { | ||||
|         super() | ||||
|     } | ||||
| 
 | ||||
|     async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> { | ||||
|         return []; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * A simple strategy to split relations: | ||||
|  * -> Download the way members just before and just after the original way | ||||
|  * -> Make sure they are still aligned | ||||
|  * | ||||
|  * Note that the feature might appear multiple times. | ||||
|  */ | ||||
| export class InPlaceReplacedmentRTSH extends OsmChangeAction { | ||||
|     private readonly _input: RelationSplitInput; | ||||
| 
 | ||||
|     constructor(input: RelationSplitInput) { | ||||
|         super(); | ||||
|         this._input = input; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns which node should border the member at the given index | ||||
|      */ | ||||
|     private async targetNodeAt(i: number, first: boolean) { | ||||
|         const member = this._input.relation.members[i] | ||||
|         if (member === undefined) { | ||||
|             return undefined | ||||
|         } | ||||
|         if (member.type === "node") { | ||||
|             return member.ref | ||||
|         } | ||||
|         if (member.type === "way") { | ||||
|             const osmWay = <OsmWay>await OsmObject.DownloadObjectAsync("way/" + member.ref) | ||||
|             const nodes = osmWay.nodes | ||||
|             if (first) { | ||||
|                 return nodes[0] | ||||
|             } else { | ||||
|                 return nodes[nodes.length - 1] | ||||
|             } | ||||
|         } | ||||
|         if (member.type === "relation") { | ||||
|             return undefined | ||||
|         } | ||||
|         return undefined; | ||||
|     } | ||||
| 
 | ||||
|     async CreateChangeDescriptions(changes: Changes): Promise<ChangeDescription[]> { | ||||
| 
 | ||||
|         const wayId = this._input.originalWayId | ||||
|         const relation = this._input.relation | ||||
|         const members = relation.members | ||||
|         const originalNodes = this._input.originalNodes; | ||||
|         const firstNode = originalNodes[0] | ||||
|         const lastNode = originalNodes[originalNodes.length - 1] | ||||
|         const newMembers: { type: "node" | "way" | "relation", ref: number, role: string }[] = [] | ||||
| 
 | ||||
|         for (let i = 0; i < members.length; i++) { | ||||
|             const member = members[i]; | ||||
|             if (member.type !== "way" || member.ref !== wayId) { | ||||
|                 newMembers.push(member) | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             const nodeIdBefore = await this.targetNodeAt(i - 1, false) | ||||
|             const nodeIdAfter = await this.targetNodeAt(i + 1, true) | ||||
| 
 | ||||
|             const firstNodeMatches = nodeIdBefore === undefined ||  nodeIdBefore === firstNode | ||||
|             const lastNodeMatches =nodeIdAfter === undefined ||  nodeIdAfter === lastNode | ||||
| 
 | ||||
|             if (firstNodeMatches && lastNodeMatches) { | ||||
|                 // We have a classic situation, forward situation
 | ||||
|                 for (const wId of this._input.allWayIdsInOrder) { | ||||
|                     newMembers.push({ | ||||
|                         ref: wId, | ||||
|                         type: "way", | ||||
|                         role: member.role | ||||
|                     }) | ||||
|                 } | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             const firstNodeMatchesRev = nodeIdBefore === undefined || nodeIdBefore === lastNode | ||||
|             const lastNodeMatchesRev =nodeIdAfter === undefined || nodeIdAfter === firstNode | ||||
|             if (firstNodeMatchesRev || lastNodeMatchesRev) { | ||||
|                 // We (probably) have a reversed situation, backward situation
 | ||||
|                 for (let i1 =  this._input.allWayIdsInOrder.length - 1; i1 >= 0; i1--){ | ||||
|                     // Iterate BACKWARDS
 | ||||
|                     const wId = this._input.allWayIdsInOrder[i1]; | ||||
|                     newMembers.push({ | ||||
|                         ref: wId, | ||||
|                         type: "way", | ||||
|                         role: member.role | ||||
|                     }) | ||||
|                 } | ||||
|                 continue; | ||||
|             } | ||||
|              | ||||
|             // Euhm, allright... Something weird is going on, but let's not care too much
 | ||||
|             // Lets pretend this is forward going
 | ||||
|             for (const wId of this._input.allWayIdsInOrder) { | ||||
|                 newMembers.push({ | ||||
|                     ref: wId, | ||||
|                     type: "way", | ||||
|                     role: member.role | ||||
|                 }) | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         return [{ | ||||
|             id: relation.id, | ||||
|             type: "relation", | ||||
|             changes: {members: newMembers} | ||||
|         }]; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue