Add intersection function

This commit is contained in:
pietervdvn 2021-12-19 02:11:22 +01:00
parent be9784e047
commit 99a38f2b10
5 changed files with 75 additions and 8 deletions

View file

@ -20,6 +20,7 @@
+ [sidewalk:left, sidewalk:right, generic_key:left:property, generic_key:right:property](#sidewalkleft,-sidewalk:right,-generic_key:left:property,-generic_key:right:property)
+ [distanceTo](#distanceto)
+ [overlapWith](#overlapwith)
+ [intersectionsWith](#intersectionswith)
+ [closest](#closest)
+ [closestn](#closestn)
+ [memberships](#memberships)
@ -200,6 +201,7 @@ Some advanced functions are available on **feat** as well:
- [distanceTo](#distanceTo)
- [overlapWith](#overlapWith)
- [intersectionsWith](#intersectionsWith)
- [closest](#closest)
- [closestn](#closestn)
- [memberships](#memberships)
@ -223,7 +225,19 @@ The resulting list is sorted in descending order by overlap. The feature with th
For example to get all objects which overlap or embed from a layer, use `_contained_climbing_routes_properties=feat.overlapWith('climbing_route')`
0. ...layerIds - one or more layer ids of the layer from which every feature is checked for overlap)
0. ...layerIds - one or more layer ids of the layer from which every feature is checked for overlap)
### intersectionsWith
Gives the intersection points with selected features. Only works with (Multi)Polygons and LineStrings.
Returns a `{feat: GeoJson, intersections: [number,number][]}` where `feat` is the full, original feature. This list is in random order.
If the current feature is a point, this function will return an empty list.
Points from other layers are ignored - even if the points are parts of the current linestring.
0. ...layerIds - one or more layer ids of the layer from which every feature is checked for intersection)
### closest

View file

@ -39,7 +39,7 @@ class OverlapFunc implements ExtraFunction {
"The resulting list is sorted in descending order by overlap. The feature with the most overlap will thus be the first in the list\n" +
"\n" +
"For example to get all objects which overlap or embed from a layer, use `_contained_climbing_routes_properties=feat.overlapWith('climbing_route')`"
_args = ["...layerIds - one or more layer ids of the layer from which every feature is checked for overlap)"]
_args = ["...layerIds - one or more layer ids of the layer from which every feature is checked for overlap)"]
_f(params, feat) {
return (...layerIds: string[]) => {
@ -67,6 +67,46 @@ class OverlapFunc implements ExtraFunction {
}
}
class IntersectionFunc implements ExtraFunction {
_name = "intersectionsWith";
_doc = "Gives the intersection points with selected features. Only works with (Multi)Polygons and LineStrings.\n\n" +
"Returns a `{feat: GeoJson, intersections: [number,number][]}` where `feat` is the full, original feature. This list is in random order.\n\n" +
"If the current feature is a point, this function will return an empty list.\n" +
"Points from other layers are ignored - even if the points are parts of the current linestring."
_args = ["...layerIds - one or more layer ids of the layer from which every feature is checked for intersection)"]
_f(params: ExtraFuncParams, feat) {
return (...layerIds: string[]) => {
const result: { feat: any, intersections: [number,number][] }[] = []
const bbox = BBox.get(feat)
for (const layerId of layerIds) {
const otherLayers = params.getFeaturesWithin(layerId, bbox)
if (otherLayers === undefined) {
continue;
}
if (otherLayers.length === 0) {
continue;
}
for (const tile of otherLayers) {
for (const otherFeature of tile) {
const intersections = GeoOperations.LineIntersections(feat, otherFeature)
result.push({feat, intersections})
}
}
}
return result;
}
}
}
class DistanceToFunc implements ExtraFunction {
_name = "distanceTo";
@ -351,6 +391,7 @@ export class ExtraFunctions {
private static readonly allFuncs: ExtraFunction[] = [
new DistanceToFunc(),
new OverlapFunc(),
new IntersectionFunc(),
new ClosestObjectFunc(),
new ClosestNObjectFunc(),
new Memberships(),

View file

@ -356,7 +356,7 @@ export class GeoOperations {
* Returns 0 if both are linestrings
* Returns null if the features are not intersecting
*/
static calculateInstersection(feature, otherFeature, featureBBox: BBox, otherFeatureBBox?: BBox): number {
private static calculateInstersection(feature, otherFeature, featureBBox: BBox, otherFeatureBBox?: BBox): number {
try {
if (feature.geometry.type === "LineString") {
@ -442,6 +442,13 @@ export class GeoOperations {
return undefined;
}
/**
* Calculates line intersection between two features.
*/
public static LineIntersections(feature, otherFeature): [number,number][]{
return turf.lineIntersect(feature, otherFeature).features.map(p =><[number,number]> p.geometry.coordinates)
}
public static AsGpx(feature, generatedWithLayer?: LayerConfig){
const metadata = {}

View file

@ -156,6 +156,9 @@ export default class LayoutConfig {
private static ExtractLayers(json: LayoutConfigJson, official: boolean, context: string): { layers: LayerConfig[], extractAllNodes: boolean } {
const result: LayerConfig[] = []
let exportAllNodes = false
if(json.layers === undefined){
throw "Got undefined layers for "+json.id+" at "+context
}
json.layers.forEach((layer, i) => {
if (typeof layer === "string") {
@ -193,12 +196,11 @@ export default class LayoutConfig {
if (typeof names === "string") {
names = [names]
}
// This is a very special layer which triggers special behaviour
exportAllNodes = names.some(name => name === "type_node");
names.forEach(name => {
if (name === "type_node") {
// This is a very special layer which triggers special behaviour
exportAllNodes = true;
}
const shared = AllKnownLayers.sharedLayersJson.get(name);
if (shared === undefined) {
throw `Unknown shared/builtin layer ${name} at ${context}.layers[${i}]. Available layers are ${Array.from(AllKnownLayers.sharedLayersJson.keys()).join(", ")}`;

View file

@ -88,6 +88,7 @@ class LayerOverviewUtils {
return errorCount
}
main(args: string[]) {
AllKnownLayers.runningGenerateScript = true;
@ -211,6 +212,8 @@ class LayerOverviewUtils {
// We load again from disc, as modifications were made above
const lt = this.loadThemesAndLayers();
this.writeFiles(lt);
} else {
const errors = layerErrorCount.concat(themeErrorCount).join("\n")