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)
|
+ [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)
|
+ [distanceTo](#distanceto)
|
||||||
+ [overlapWith](#overlapwith)
|
+ [overlapWith](#overlapwith)
|
||||||
|
+ [intersectionsWith](#intersectionswith)
|
||||||
+ [closest](#closest)
|
+ [closest](#closest)
|
||||||
+ [closestn](#closestn)
|
+ [closestn](#closestn)
|
||||||
+ [memberships](#memberships)
|
+ [memberships](#memberships)
|
||||||
|
@ -200,6 +201,7 @@ Some advanced functions are available on **feat** as well:
|
||||||
|
|
||||||
- [distanceTo](#distanceTo)
|
- [distanceTo](#distanceTo)
|
||||||
- [overlapWith](#overlapWith)
|
- [overlapWith](#overlapWith)
|
||||||
|
- [intersectionsWith](#intersectionsWith)
|
||||||
- [closest](#closest)
|
- [closest](#closest)
|
||||||
- [closestn](#closestn)
|
- [closestn](#closestn)
|
||||||
- [memberships](#memberships)
|
- [memberships](#memberships)
|
||||||
|
@ -226,6 +228,18 @@ For example to get all objects which overlap or embed from a layer, use `_contai
|
||||||
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
|
### closest
|
||||||
|
|
||||||
Given either a list of geojson features or a single layer name, gives the single object which is nearest to the feature. In the case of ways/polygons, only the centerpoint is considered. Returns a single geojson feature or undefined if nothing is found (or not yet laoded)
|
Given either a list of geojson features or a single layer name, gives the single object which is nearest to the feature. In the case of ways/polygons, only the centerpoint is considered. Returns a single geojson feature or undefined if nothing is found (or not yet laoded)
|
||||||
|
|
|
@ -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 {
|
class DistanceToFunc implements ExtraFunction {
|
||||||
|
|
||||||
_name = "distanceTo";
|
_name = "distanceTo";
|
||||||
|
@ -351,6 +391,7 @@ export class ExtraFunctions {
|
||||||
private static readonly allFuncs: ExtraFunction[] = [
|
private static readonly allFuncs: ExtraFunction[] = [
|
||||||
new DistanceToFunc(),
|
new DistanceToFunc(),
|
||||||
new OverlapFunc(),
|
new OverlapFunc(),
|
||||||
|
new IntersectionFunc(),
|
||||||
new ClosestObjectFunc(),
|
new ClosestObjectFunc(),
|
||||||
new ClosestNObjectFunc(),
|
new ClosestNObjectFunc(),
|
||||||
new Memberships(),
|
new Memberships(),
|
||||||
|
|
|
@ -356,7 +356,7 @@ export class GeoOperations {
|
||||||
* Returns 0 if both are linestrings
|
* Returns 0 if both are linestrings
|
||||||
* Returns null if the features are not intersecting
|
* 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 {
|
try {
|
||||||
if (feature.geometry.type === "LineString") {
|
if (feature.geometry.type === "LineString") {
|
||||||
|
|
||||||
|
@ -442,6 +442,13 @@ export class GeoOperations {
|
||||||
return undefined;
|
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){
|
public static AsGpx(feature, generatedWithLayer?: LayerConfig){
|
||||||
|
|
||||||
const metadata = {}
|
const metadata = {}
|
||||||
|
|
|
@ -156,6 +156,9 @@ export default class LayoutConfig {
|
||||||
private static ExtractLayers(json: LayoutConfigJson, official: boolean, context: string): { layers: LayerConfig[], extractAllNodes: boolean } {
|
private static ExtractLayers(json: LayoutConfigJson, official: boolean, context: string): { layers: LayerConfig[], extractAllNodes: boolean } {
|
||||||
const result: LayerConfig[] = []
|
const result: LayerConfig[] = []
|
||||||
let exportAllNodes = false
|
let exportAllNodes = false
|
||||||
|
if(json.layers === undefined){
|
||||||
|
throw "Got undefined layers for "+json.id+" at "+context
|
||||||
|
}
|
||||||
json.layers.forEach((layer, i) => {
|
json.layers.forEach((layer, i) => {
|
||||||
|
|
||||||
if (typeof layer === "string") {
|
if (typeof layer === "string") {
|
||||||
|
@ -193,12 +196,11 @@ export default class LayoutConfig {
|
||||||
if (typeof names === "string") {
|
if (typeof names === "string") {
|
||||||
names = [names]
|
names = [names]
|
||||||
}
|
}
|
||||||
names.forEach(name => {
|
|
||||||
if (name === "type_node") {
|
|
||||||
// This is a very special layer which triggers special behaviour
|
|
||||||
exportAllNodes = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// This is a very special layer which triggers special behaviour
|
||||||
|
exportAllNodes = names.some(name => name === "type_node");
|
||||||
|
|
||||||
|
names.forEach(name => {
|
||||||
const shared = AllKnownLayers.sharedLayersJson.get(name);
|
const shared = AllKnownLayers.sharedLayersJson.get(name);
|
||||||
if (shared === undefined) {
|
if (shared === undefined) {
|
||||||
throw `Unknown shared/builtin layer ${name} at ${context}.layers[${i}]. Available layers are ${Array.from(AllKnownLayers.sharedLayersJson.keys()).join(", ")}`;
|
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
|
return errorCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
main(args: string[]) {
|
main(args: string[]) {
|
||||||
|
|
||||||
AllKnownLayers.runningGenerateScript = true;
|
AllKnownLayers.runningGenerateScript = true;
|
||||||
|
@ -211,6 +212,8 @@ class LayerOverviewUtils {
|
||||||
|
|
||||||
// We load again from disc, as modifications were made above
|
// We load again from disc, as modifications were made above
|
||||||
const lt = this.loadThemesAndLayers();
|
const lt = this.loadThemesAndLayers();
|
||||||
|
|
||||||
|
|
||||||
this.writeFiles(lt);
|
this.writeFiles(lt);
|
||||||
} else {
|
} else {
|
||||||
const errors = layerErrorCount.concat(themeErrorCount).join("\n")
|
const errors = layerErrorCount.concat(themeErrorCount).join("\n")
|
||||||
|
|
Loading…
Reference in a new issue