Various small fixes
This commit is contained in:
parent
261cde3e28
commit
1af5e44ad4
6 changed files with 176 additions and 20 deletions
|
@ -7,7 +7,6 @@ import FeatureSource from "../FeatureSource";
|
||||||
import PointRenderingConfig from "../../../Models/ThemeConfig/PointRenderingConfig";
|
import PointRenderingConfig from "../../../Models/ThemeConfig/PointRenderingConfig";
|
||||||
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig";
|
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig";
|
||||||
|
|
||||||
|
|
||||||
export default class RenderingMultiPlexerFeatureSource {
|
export default class RenderingMultiPlexerFeatureSource {
|
||||||
public readonly features: UIEventSource<(any & { pointRenderingIndex: number | undefined, lineRenderingIndex: number | undefined })[]>;
|
public readonly features: UIEventSource<(any & { pointRenderingIndex: number | undefined, lineRenderingIndex: number | undefined })[]>;
|
||||||
|
|
||||||
|
@ -29,7 +28,7 @@ export default class RenderingMultiPlexerFeatureSource {
|
||||||
|
|
||||||
const lineRenderObjects = layer.lineRendering
|
const lineRenderObjects = layer.lineRendering
|
||||||
|
|
||||||
const withIndex: (any & { pointRenderingIndex: number | undefined, lineRenderingIndex: number | undefined })[] = [];
|
const withIndex: (any & { pointRenderingIndex: number | undefined, lineRenderingIndex: number | undefined, multiLineStringIndex: number | undefined })[] = [];
|
||||||
|
|
||||||
|
|
||||||
function addAsPoint(feat, rendering, coordinate) {
|
function addAsPoint(feat, rendering, coordinate) {
|
||||||
|
@ -69,11 +68,18 @@ export default class RenderingMultiPlexerFeatureSource {
|
||||||
const coordinate = coordinates[coordinates.length - 1]
|
const coordinate = coordinates[coordinates.length - 1]
|
||||||
addAsPoint(feat, rendering, coordinate)
|
addAsPoint(feat, rendering, coordinate)
|
||||||
}
|
}
|
||||||
|
for (let i = 0; i < lineRenderObjects.length; i++) {
|
||||||
|
withIndex.push({
|
||||||
|
...feat,
|
||||||
|
lineRenderingIndex: i
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (feat.geometry.type === "MultiLineString") {
|
if (feat.geometry.type === "MultiLineString") {
|
||||||
const lineList = feat.geometry.coordinates
|
const lineList: [number, number][][] = feat.geometry.coordinates
|
||||||
for (const coordinates of lineList) {
|
for (let i1 = 0; i1 < lineList.length; i1++) {
|
||||||
|
const coordinates = lineList[i1];
|
||||||
|
|
||||||
for (const rendering of startRenderings) {
|
for (const rendering of startRenderings) {
|
||||||
const coordinate = coordinates[0]
|
const coordinate = coordinates[0]
|
||||||
|
@ -83,19 +89,25 @@ export default class RenderingMultiPlexerFeatureSource {
|
||||||
const coordinate = coordinates[coordinates.length - 1]
|
const coordinate = coordinates[coordinates.length - 1]
|
||||||
addAsPoint(feat, rendering, coordinate)
|
addAsPoint(feat, rendering, coordinate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (let i = 0; i < lineRenderObjects.length; i++) {
|
||||||
|
const orig = {
|
||||||
|
...feat,
|
||||||
|
lineRenderingIndex: i,
|
||||||
|
multiLineStringIndex: i1
|
||||||
|
}
|
||||||
|
orig.geometry.coordinates = coordinates
|
||||||
|
orig.geometry.type = "LineString"
|
||||||
|
withIndex.push(orig)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (let i = 0; i < lineRenderObjects.length; i++) {
|
|
||||||
withIndex.push({
|
|
||||||
...feat,
|
|
||||||
lineRenderingIndex: i
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return withIndex;
|
return withIndex;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,7 +3,6 @@ import {BBox} from "./BBox";
|
||||||
import togpx from "togpx"
|
import togpx from "togpx"
|
||||||
import Constants from "../Models/Constants";
|
import Constants from "../Models/Constants";
|
||||||
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
|
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
|
||||||
import {meta} from "@turf/turf";
|
|
||||||
|
|
||||||
export class GeoOperations {
|
export class GeoOperations {
|
||||||
|
|
||||||
|
@ -465,6 +464,151 @@ export class GeoOperations {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IdentifieCommonSegments(coordinatess: [number,number][][] ): {
|
||||||
|
originalIndex: number,
|
||||||
|
segmentShardWith: number[],
|
||||||
|
coordinates: []
|
||||||
|
}[]{
|
||||||
|
|
||||||
|
// An edge. Note that the edge might be reversed to fix the sorting condition: start[0] < end[0] && (start[0] != end[0] || start[0] < end[1])
|
||||||
|
type edge = {start: [number, number], end: [number, number], intermediate: [number,number][], members: {index:number, isReversed: boolean}[]}
|
||||||
|
|
||||||
|
// The strategy:
|
||||||
|
// 1. Index _all_ edges from _every_ linestring. Index them by starting key, gather which relations run over them
|
||||||
|
// 2. Join these edges back together - as long as their membership groups are the same
|
||||||
|
// 3. Convert to results
|
||||||
|
|
||||||
|
const allEdgesByKey = new Map<string, edge>()
|
||||||
|
|
||||||
|
for (let index = 0; index < coordinatess.length; index++){
|
||||||
|
const coordinates = coordinatess[index];
|
||||||
|
for (let i = 0; i < coordinates.length - 1; i++){
|
||||||
|
|
||||||
|
const c0 = coordinates[i];
|
||||||
|
const c1 = coordinates[i + 1]
|
||||||
|
const isReversed = (c0[0] > c1[0]) || (c0[0] == c1[0] && c0[1] > c1[1])
|
||||||
|
|
||||||
|
let key : string
|
||||||
|
if(isReversed){
|
||||||
|
key = ""+c1+";"+c0
|
||||||
|
}else{
|
||||||
|
key = ""+c0+";"+c1
|
||||||
|
}
|
||||||
|
const member = {index, isReversed}
|
||||||
|
if(allEdgesByKey.has(key)){
|
||||||
|
allEdgesByKey.get(key).members.push(member)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
let edge : edge;
|
||||||
|
if(!isReversed){
|
||||||
|
edge = {
|
||||||
|
start : c0,
|
||||||
|
end: c1,
|
||||||
|
members: [member],
|
||||||
|
intermediate: []
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
edge = {
|
||||||
|
start : c1,
|
||||||
|
end: c0,
|
||||||
|
members: [member],
|
||||||
|
intermediate: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
allEdgesByKey.set(key, edge)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lets merge them back together!
|
||||||
|
|
||||||
|
let didMergeSomething = false;
|
||||||
|
let allMergedEdges = Array.from(allEdgesByKey.values())
|
||||||
|
const allEdgesByStartPoint = new Map<string, edge[]>()
|
||||||
|
for (const edge of allMergedEdges) {
|
||||||
|
|
||||||
|
edge.members.sort((m0, m1) => m0.index - m1.index)
|
||||||
|
|
||||||
|
const kstart = edge.start+""
|
||||||
|
if(!allEdgesByStartPoint.has(kstart)){
|
||||||
|
allEdgesByStartPoint.set(kstart, [])
|
||||||
|
}
|
||||||
|
allEdgesByStartPoint.get(kstart).push(edge)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function membersAreCompatible(first:edge, second:edge): boolean{
|
||||||
|
// There must be an exact match between the members
|
||||||
|
if(first.members === second.members){
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if(first.members.length !== second.members.length){
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Members are sorted and have the same length, so we can check quickly
|
||||||
|
for (let i = 0; i < first.members.length; i++) {
|
||||||
|
const m0 = first.members[i]
|
||||||
|
const m1 = second.members[i]
|
||||||
|
if(m0.index !== m1.index || m0.isReversed !== m1.isReversed){
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allrigth, they are the same, lets mark this permanently
|
||||||
|
second.members = first.members
|
||||||
|
return true
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
do{
|
||||||
|
didMergeSomething = false
|
||||||
|
// We use 'allMergedEdges' as our running list
|
||||||
|
const consumed = new Set<edge>()
|
||||||
|
for (const edge of allMergedEdges) {
|
||||||
|
// Can we make this edge longer at the end?
|
||||||
|
if(consumed.has(edge)){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Considering edge", edge)
|
||||||
|
const matchingEndEdges = allEdgesByStartPoint.get(edge.end+"")
|
||||||
|
console.log("Matchign endpoints:", matchingEndEdges)
|
||||||
|
if(matchingEndEdges === undefined){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (let i = 0; i < matchingEndEdges.length; i++){
|
||||||
|
const endEdge = matchingEndEdges[i];
|
||||||
|
|
||||||
|
if(consumed.has(endEdge)){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!membersAreCompatible(edge, endEdge)){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can make the segment longer!
|
||||||
|
didMergeSomething = true
|
||||||
|
console.log("Merging ", edge, "with ", endEdge)
|
||||||
|
edge.intermediate.push(edge.end)
|
||||||
|
edge.end = endEdge.end
|
||||||
|
consumed.add(endEdge)
|
||||||
|
matchingEndEdges.splice(i, 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allMergedEdges = allMergedEdges.filter(edge => !consumed.has(edge));
|
||||||
|
|
||||||
|
}while(didMergeSomething)
|
||||||
|
|
||||||
|
return []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ export default class ScrollableFullScreen extends UIElement {
|
||||||
if (!isShown.data) {
|
if (!isShown.data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (hash === undefined || hash === "") {
|
if (hash === undefined || hash === "" || hash !== hashToShow) {
|
||||||
isShown.setData(false)
|
isShown.setData(false)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -24,7 +24,7 @@ export default class LocationInput extends InputElement<Loc> implements MinimapO
|
||||||
osmTags: {and: []}
|
osmTags: {and: []}
|
||||||
},
|
},
|
||||||
mapRendering: [{
|
mapRendering: [{
|
||||||
location: ["point"],
|
location: ["point","centroid"],
|
||||||
icon: "./assets/svg/crosshair-empty.svg"
|
icon: "./assets/svg/crosshair-empty.svg"
|
||||||
}]
|
}]
|
||||||
}, "matchpoint icon", true
|
}, "matchpoint icon", true
|
||||||
|
|
|
@ -152,7 +152,7 @@ export default class ShowDataLayer {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if ((feat.geometry.type === "LineString" || feat.geometry.type === "MultiLineString")) {
|
if (feat.geometry.type === "LineString") {
|
||||||
const self = this;
|
const self = this;
|
||||||
const coords = L.GeoJSON.coordsToLatLngs(feat.geometry.coordinates)
|
const coords = L.GeoJSON.coordsToLatLngs(feat.geometry.coordinates)
|
||||||
const tagsSource = this.allElements?.addOrGetElement(feat) ?? new UIEventSource<any>(feat.properties);
|
const tagsSource = this.allElements?.addOrGetElement(feat) ?? new UIEventSource<any>(feat.properties);
|
||||||
|
@ -270,7 +270,7 @@ export default class ShowDataLayer {
|
||||||
|
|
||||||
let infobox: FeatureInfoBox = undefined;
|
let infobox: FeatureInfoBox = undefined;
|
||||||
|
|
||||||
const id = `popup-${feature.properties.id}-${feature.geometry.type}-${this.showDataLayerid}-${this._cleanCount}-${feature.pointRenderingIndex ?? feature.lineRenderingIndex}`
|
const id = `popup-${feature.properties.id}-${feature.geometry.type}-${this.showDataLayerid}-${this._cleanCount}-${feature.pointRenderingIndex ?? feature.lineRenderingIndex}-${feature.multiLineStringIndex ?? ""}`
|
||||||
popup.setContent(`<div style='height: 65vh' id='${id}'>Popup for ${feature.properties.id} ${feature.geometry.type} ${id} is loading</div>`)
|
popup.setContent(`<div style='height: 65vh' id='${id}'>Popup for ${feature.properties.id} ${feature.geometry.type} ${id} is loading</div>`)
|
||||||
leafletLayer.on("popupopen", () => {
|
leafletLayer.on("popupopen", () => {
|
||||||
if (infobox === undefined) {
|
if (infobox === undefined) {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
"osmTags": "user:location=yes",
|
"osmTags": "user:location=yes",
|
||||||
"maxCacheAge": 0
|
"maxCacheAge": 0
|
||||||
},
|
},
|
||||||
"title": {
|
"#title": {
|
||||||
"render": "Your travelled path"
|
"render": "Your travelled path"
|
||||||
},
|
},
|
||||||
"tagRenderings": [
|
"tagRenderings": [
|
||||||
|
@ -18,10 +18,10 @@
|
||||||
},
|
},
|
||||||
"export_as_gpx"
|
"export_as_gpx"
|
||||||
],
|
],
|
||||||
"name": "Your track",
|
"#name": "Your track",
|
||||||
"mapRendering": [
|
"mapRendering": [
|
||||||
{
|
{
|
||||||
"width": 3,
|
"width": 0,
|
||||||
"color": "#bb000077"
|
"color": "#bb000077"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in a new issue