forked from MapComplete/MapComplete
Splitting of the actual intersection calculator, better handling of intersections
This commit is contained in:
parent
50827d38a8
commit
fbf0f278e1
1 changed files with 109 additions and 71 deletions
|
@ -44,7 +44,7 @@ export class GeoOperations {
|
||||||
const coor = feature.geometry.coordinates;
|
const coor = feature.geometry.coordinates;
|
||||||
for (const otherFeature of otherFeatures) {
|
for (const otherFeature of otherFeatures) {
|
||||||
|
|
||||||
if(feature.id === otherFeature.id){
|
if (feature.id !== undefined && feature.id === otherFeature.id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,59 +64,15 @@ export class GeoOperations {
|
||||||
|
|
||||||
for (const otherFeature of otherFeatures) {
|
for (const otherFeature of otherFeatures) {
|
||||||
|
|
||||||
if(feature.id === otherFeature.id){
|
if (feature.id !== undefined && feature.id === otherFeature.id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const otherFeatureBBox = BBox.get(otherFeature);
|
const intersection = this.calculateInstersection(feature, otherFeature, featureBBox)
|
||||||
const overlaps = featureBBox.overlapsWith(otherFeatureBBox)
|
if (intersection === null) {
|
||||||
if (!overlaps) {
|
continue
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the length of the intersection
|
|
||||||
try {
|
|
||||||
|
|
||||||
let intersectionPoints = turf.lineIntersect(feature, otherFeature);
|
|
||||||
if (intersectionPoints.features.length == 0) {
|
|
||||||
// No intersections.
|
|
||||||
// If one point is inside of the polygon, all points are
|
|
||||||
|
|
||||||
|
|
||||||
const coors = feature.geometry.coordinates;
|
|
||||||
const startCoor = coors[0]
|
|
||||||
if (this.inside(startCoor, otherFeature)) {
|
|
||||||
result.push({feat: otherFeature, overlap: this.lengthInMeters(feature)})
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let intersectionPointsArray = intersectionPoints.features.map(d => {
|
|
||||||
return d.geometry.coordinates
|
|
||||||
});
|
|
||||||
|
|
||||||
if (intersectionPointsArray.length == 1) {
|
|
||||||
// We need to add the start- or endpoint of the current feature, depending on which one is embedded
|
|
||||||
const coors = feature.geometry.coordinates;
|
|
||||||
const startCoor = coors[0]
|
|
||||||
if (this.inside(startCoor, otherFeature)) {
|
|
||||||
// The startpoint is embedded
|
|
||||||
intersectionPointsArray.push(startCoor)
|
|
||||||
} else {
|
|
||||||
intersectionPointsArray.push(coors[coors.length - 1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let intersection = turf.lineSlice(turf.point(intersectionPointsArray[0]), turf.point(intersectionPointsArray[1]), feature);
|
|
||||||
|
|
||||||
if (intersection == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const intersectionSize = turf.length(intersection); // in km
|
|
||||||
result.push({feat: otherFeature, overlap: intersectionSize * 1000})
|
|
||||||
} catch (exception) {
|
|
||||||
console.warn("EXCEPTION CAUGHT WHILE INTERSECTING: ", exception);
|
|
||||||
}
|
}
|
||||||
|
result.push({feat: otherFeature, overlap: intersection})
|
||||||
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -126,35 +82,25 @@ export class GeoOperations {
|
||||||
|
|
||||||
for (const otherFeature of otherFeatures) {
|
for (const otherFeature of otherFeatures) {
|
||||||
|
|
||||||
if(feature.id === otherFeature.id){
|
if (feature.id === otherFeature.id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(otherFeature.geometry.type === "Point"){
|
if (otherFeature.geometry.type === "Point") {
|
||||||
if (this.inside(otherFeature, feature)) {
|
if (this.inside(otherFeature, feature)) {
|
||||||
result.push({feat: otherFeature, overlap: undefined})
|
result.push({feat: otherFeature, overlap: undefined})
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const otherFeatureBBox = BBox.get(otherFeature);
|
|
||||||
const overlaps = featureBBox.overlapsWith(otherFeatureBBox)
|
|
||||||
if (!overlaps) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the surface area of the intersection
|
// Calculate the surface area of the intersection
|
||||||
try {
|
|
||||||
|
|
||||||
const intersection = turf.intersect(feature, otherFeature);
|
const intersection = this.calculateInstersection(feature, otherFeature, featureBBox)
|
||||||
if (intersection == null) {
|
if (intersection === null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
const intersectionSize = turf.area(intersection); // in m²
|
|
||||||
result.push({feat: otherFeature, overlap: intersectionSize})
|
|
||||||
} catch (exception) {
|
|
||||||
console.warn("EXCEPTION CAUGHT WHILE INTERSECTING: ", exception);
|
|
||||||
}
|
}
|
||||||
|
result.push({feat: otherFeature, overlap: intersection})
|
||||||
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -171,7 +117,7 @@ export class GeoOperations {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pointCoordinate.geometry !== undefined){
|
if (pointCoordinate.geometry !== undefined) {
|
||||||
pointCoordinate = pointCoordinate.geometry.coordinates
|
pointCoordinate = pointCoordinate.geometry.coordinates
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,6 +177,98 @@ export class GeoOperations {
|
||||||
static lengthInMeters(feature: any) {
|
static lengthInMeters(feature: any) {
|
||||||
return turf.length(feature) * 1000
|
return turf.length(feature) * 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the intersection between two features.
|
||||||
|
* Returns the length if intersecting a linestring and a (multi)polygon (in meters), returns a surface area (in m²) if intersecting two (multi)polygons
|
||||||
|
* Returns 0 if both are linestrings
|
||||||
|
* Returns null if the features are not intersecting
|
||||||
|
*/
|
||||||
|
private static calculateInstersection(feature, otherFeature, featureBBox: BBox, otherFeatureBBox?: BBox): number {
|
||||||
|
try {
|
||||||
|
if (feature.geometry.type === "LineString") {
|
||||||
|
|
||||||
|
|
||||||
|
otherFeatureBBox = otherFeatureBBox ?? BBox.get(otherFeature);
|
||||||
|
const overlaps = featureBBox.overlapsWith(otherFeatureBBox)
|
||||||
|
if (!overlaps) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the length of the intersection
|
||||||
|
|
||||||
|
|
||||||
|
let intersectionPoints = turf.lineIntersect(feature, otherFeature);
|
||||||
|
if (intersectionPoints.features.length == 0) {
|
||||||
|
// No intersections.
|
||||||
|
// If one point is inside of the polygon, all points are
|
||||||
|
|
||||||
|
|
||||||
|
const coors = feature.geometry.coordinates;
|
||||||
|
const startCoor = coors[0]
|
||||||
|
if (this.inside(startCoor, otherFeature)) {
|
||||||
|
return this.lengthInMeters(feature)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
let intersectionPointsArray = intersectionPoints.features.map(d => {
|
||||||
|
return d.geometry.coordinates
|
||||||
|
});
|
||||||
|
|
||||||
|
if (otherFeature.geometry.type === "LineString") {
|
||||||
|
if (intersectionPointsArray.length > 0) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (intersectionPointsArray.length == 1) {
|
||||||
|
// We need to add the start- or endpoint of the current feature, depending on which one is embedded
|
||||||
|
const coors = feature.geometry.coordinates;
|
||||||
|
const startCoor = coors[0]
|
||||||
|
if (this.inside(startCoor, otherFeature)) {
|
||||||
|
// The startpoint is embedded
|
||||||
|
intersectionPointsArray.push(startCoor)
|
||||||
|
} else {
|
||||||
|
intersectionPointsArray.push(coors[coors.length - 1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let intersection = turf.lineSlice(turf.point(intersectionPointsArray[0]), turf.point(intersectionPointsArray[1]), feature);
|
||||||
|
|
||||||
|
if (intersection == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const intersectionSize = turf.length(intersection); // in km
|
||||||
|
return intersectionSize * 1000
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (feature.geometry.type === "Polygon" || feature.geometry.type === "MultiPolygon") {
|
||||||
|
const otherFeatureBBox = BBox.get(otherFeature);
|
||||||
|
const overlaps = featureBBox.overlapsWith(otherFeatureBBox)
|
||||||
|
if (!overlaps) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (otherFeature.geometry.type === "LineString") {
|
||||||
|
return this.calculateInstersection(otherFeature, feature, otherFeatureBBox, featureBBox)
|
||||||
|
}
|
||||||
|
|
||||||
|
const intersection = turf.intersect(feature, otherFeature);
|
||||||
|
if (intersection == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return turf.area(intersection); // in m²
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (exception) {
|
||||||
|
console.warn("EXCEPTION CAUGHT WHILE INTERSECTING: ", exception);
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue