Add intersection function
This commit is contained in:
parent
be9784e047
commit
99a38f2b10
5 changed files with 75 additions and 8 deletions
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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 = {}
|
||||
|
|
|
@ -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(", ")}`;
|
||||
|
|
|
@ -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")
|
||||
|
|
Loading…
Reference in a new issue