forked from MapComplete/MapComplete
		
	Add clipping to generateCache
This commit is contained in:
		
							parent
							
								
									f7f0ccdb7d
								
							
						
					
					
						commit
						509b237d02
					
				
					 3 changed files with 177 additions and 90 deletions
				
			
		| 
						 | 
					@ -15,6 +15,11 @@ import togpx from "togpx"
 | 
				
			||||||
import Constants from "../Models/Constants"
 | 
					import Constants from "../Models/Constants"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class GeoOperations {
 | 
					export class GeoOperations {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create a union between two features
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    static union = turf.union
 | 
				
			||||||
 | 
					    static intersect = turf.intersect
 | 
				
			||||||
    private static readonly _earthRadius = 6378137
 | 
					    private static readonly _earthRadius = 6378137
 | 
				
			||||||
    private static readonly _originShift = (2 * Math.PI * GeoOperations._earthRadius) / 2
 | 
					    private static readonly _originShift = (2 * Math.PI * GeoOperations._earthRadius) / 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -158,35 +163,6 @@ export class GeoOperations {
 | 
				
			||||||
        return result
 | 
					        return result
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Helper function which does the heavy lifting for 'inside'
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    private static pointInPolygonCoordinates(
 | 
					 | 
				
			||||||
        x: number,
 | 
					 | 
				
			||||||
        y: number,
 | 
					 | 
				
			||||||
        coordinates: [number, number][][]
 | 
					 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
        const inside = GeoOperations.pointWithinRing(
 | 
					 | 
				
			||||||
            x,
 | 
					 | 
				
			||||||
            y,
 | 
					 | 
				
			||||||
            /*This is the outer ring of the polygon */ coordinates[0]
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        if (!inside) {
 | 
					 | 
				
			||||||
            return false
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        for (let i = 1; i < coordinates.length; i++) {
 | 
					 | 
				
			||||||
            const inHole = GeoOperations.pointWithinRing(
 | 
					 | 
				
			||||||
                x,
 | 
					 | 
				
			||||||
                y,
 | 
					 | 
				
			||||||
                coordinates[i] /* These are inner rings, aka holes*/
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            if (inHole) {
 | 
					 | 
				
			||||||
                return false
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return true
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Detect wether or not the given point is located in the feature
 | 
					     * Detect wether or not the given point is located in the feature
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
| 
						 | 
					@ -620,6 +596,113 @@ export class GeoOperations {
 | 
				
			||||||
        return copy
 | 
					        return copy
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Takes two points and finds the geographic bearing between them, i.e. the angle measured in degrees from the north line (0 degrees)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static bearing(a: Coord, b: Coord): number {
 | 
				
			||||||
 | 
					        return turf.bearing(a, b)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Returns 'true' if one feature contains the other feature
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * const pond: Feature<Polygon, any> = {
 | 
				
			||||||
 | 
					     *       "type": "Feature",
 | 
				
			||||||
 | 
					     *       "properties": {"natural":"water","water":"pond"},
 | 
				
			||||||
 | 
					     *       "geometry": {
 | 
				
			||||||
 | 
					     *         "type": "Polygon",
 | 
				
			||||||
 | 
					     *         "coordinates": [[
 | 
				
			||||||
 | 
					     *             [4.362924098968506,50.8435422298544 ],
 | 
				
			||||||
 | 
					     *             [4.363272786140442,50.8435219059949 ],
 | 
				
			||||||
 | 
					     *             [4.363213777542114,50.8437420806679 ],
 | 
				
			||||||
 | 
					     *             [4.362924098968506,50.8435422298544 ]
 | 
				
			||||||
 | 
					     *           ]]}}
 | 
				
			||||||
 | 
					     * const park: Feature<Polygon, any> =   {
 | 
				
			||||||
 | 
					     *       "type": "Feature",
 | 
				
			||||||
 | 
					     *       "properties": {"leisure":"park"},
 | 
				
			||||||
 | 
					     *       "geometry": {
 | 
				
			||||||
 | 
					     *         "type": "Polygon",
 | 
				
			||||||
 | 
					     *         "coordinates": [[
 | 
				
			||||||
 | 
					     *            [ 4.36073541641235,50.84323737103244 ],
 | 
				
			||||||
 | 
					     *            [ 4.36469435691833, 50.8423905305197 ],
 | 
				
			||||||
 | 
					     *            [ 4.36659336090087, 50.8458997374786 ],
 | 
				
			||||||
 | 
					     *            [ 4.36254858970642, 50.8468007074916 ],
 | 
				
			||||||
 | 
					     *            [ 4.36073541641235, 50.8432373710324 ]
 | 
				
			||||||
 | 
					     *           ]]}}
 | 
				
			||||||
 | 
					     * GeoOperations.completelyWithin(pond, park) // => true
 | 
				
			||||||
 | 
					     * GeoOperations.completelyWithin(park, pond) // => false
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    static completelyWithin(
 | 
				
			||||||
 | 
					        feature: Feature<Geometry, any>,
 | 
				
			||||||
 | 
					        possiblyEncloingFeature: Feature<Polygon | MultiPolygon, any>
 | 
				
			||||||
 | 
					    ): boolean {
 | 
				
			||||||
 | 
					        return booleanWithin(feature, possiblyEncloingFeature)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create an intersection between two features.
 | 
				
			||||||
 | 
					     * A new feature is returned based on 'toSplit', which'll have a geometry that is completely withing boundary
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static clipWith(toSplit: Feature, boundary: Feature<Polygon>): Feature[] {
 | 
				
			||||||
 | 
					        if (toSplit.geometry.type === "Point") {
 | 
				
			||||||
 | 
					            const p = <Feature<Point>>toSplit
 | 
				
			||||||
 | 
					            if (GeoOperations.inside(p.geometry.coordinates, boundary)) {
 | 
				
			||||||
 | 
					                return [p]
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                return []
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (toSplit.geometry.type === "LineString") {
 | 
				
			||||||
 | 
					            const splitup = turf.lineSplit(<Feature<LineString>>toSplit, boundary)
 | 
				
			||||||
 | 
					            const kept = []
 | 
				
			||||||
 | 
					            for (const f of splitup.features) {
 | 
				
			||||||
 | 
					                const ls = <Feature<LineString>>f
 | 
				
			||||||
 | 
					                if (!GeoOperations.inside(GeoOperations.centerpointCoordinates(f), boundary)) {
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                f.properties = { ...toSplit.properties }
 | 
				
			||||||
 | 
					                kept.push(f)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return kept
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (toSplit.geometry.type === "Polygon" || toSplit.geometry.type == "MultiPolygon") {
 | 
				
			||||||
 | 
					            const splitup = turf.intersect(<Feature<Polygon>>toSplit, boundary)
 | 
				
			||||||
 | 
					            splitup.properties = { ...toSplit.properties }
 | 
				
			||||||
 | 
					            return [splitup]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        throw "Invalid geometry type with GeoOperations.clipWith: " + toSplit.geometry.type
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Helper function which does the heavy lifting for 'inside'
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private static pointInPolygonCoordinates(
 | 
				
			||||||
 | 
					        x: number,
 | 
				
			||||||
 | 
					        y: number,
 | 
				
			||||||
 | 
					        coordinates: [number, number][][]
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        const inside = GeoOperations.pointWithinRing(
 | 
				
			||||||
 | 
					            x,
 | 
				
			||||||
 | 
					            y,
 | 
				
			||||||
 | 
					            /*This is the outer ring of the polygon */ coordinates[0]
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        if (!inside) {
 | 
				
			||||||
 | 
					            return false
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for (let i = 1; i < coordinates.length; i++) {
 | 
				
			||||||
 | 
					            const inHole = GeoOperations.pointWithinRing(
 | 
				
			||||||
 | 
					                x,
 | 
				
			||||||
 | 
					                y,
 | 
				
			||||||
 | 
					                coordinates[i] /* These are inner rings, aka holes*/
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            if (inHole) {
 | 
				
			||||||
 | 
					                return false
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static pointWithinRing(x: number, y: number, ring: [number, number][]) {
 | 
					    private static pointWithinRing(x: number, y: number, ring: [number, number][]) {
 | 
				
			||||||
        let inside = false
 | 
					        let inside = false
 | 
				
			||||||
        for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
 | 
					        for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
 | 
				
			||||||
| 
						 | 
					@ -740,57 +823,4 @@ export class GeoOperations {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        throw "CalculateIntersection fallthrough: can not calculate an intersection between features"
 | 
					        throw "CalculateIntersection fallthrough: can not calculate an intersection between features"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Takes two points and finds the geographic bearing between them, i.e. the angle measured in degrees from the north line (0 degrees)
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static bearing(a: Coord, b: Coord): number {
 | 
					 | 
				
			||||||
        return turf.bearing(a, b)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Returns 'true' if one feature contains the other feature
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * const pond: Feature<Polygon, any> = {
 | 
					 | 
				
			||||||
     *       "type": "Feature",
 | 
					 | 
				
			||||||
     *       "properties": {"natural":"water","water":"pond"},
 | 
					 | 
				
			||||||
     *       "geometry": {
 | 
					 | 
				
			||||||
     *         "type": "Polygon",
 | 
					 | 
				
			||||||
     *         "coordinates": [[
 | 
					 | 
				
			||||||
     *             [4.362924098968506,50.8435422298544 ],
 | 
					 | 
				
			||||||
     *             [4.363272786140442,50.8435219059949 ],
 | 
					 | 
				
			||||||
     *             [4.363213777542114,50.8437420806679 ],
 | 
					 | 
				
			||||||
     *             [4.362924098968506,50.8435422298544 ]
 | 
					 | 
				
			||||||
     *           ]]}}
 | 
					 | 
				
			||||||
     * const park: Feature<Polygon, any> =   {
 | 
					 | 
				
			||||||
     *       "type": "Feature",
 | 
					 | 
				
			||||||
     *       "properties": {"leisure":"park"},
 | 
					 | 
				
			||||||
     *       "geometry": {
 | 
					 | 
				
			||||||
     *         "type": "Polygon",
 | 
					 | 
				
			||||||
     *         "coordinates": [[
 | 
					 | 
				
			||||||
     *            [ 4.36073541641235,50.84323737103244 ],
 | 
					 | 
				
			||||||
     *            [ 4.36469435691833, 50.8423905305197 ],
 | 
					 | 
				
			||||||
     *            [ 4.36659336090087, 50.8458997374786 ],
 | 
					 | 
				
			||||||
     *            [ 4.36254858970642, 50.8468007074916 ],
 | 
					 | 
				
			||||||
     *            [ 4.36073541641235, 50.8432373710324 ]
 | 
					 | 
				
			||||||
     *           ]]}}
 | 
					 | 
				
			||||||
     * GeoOperations.completelyWithin(pond, park) // => true
 | 
					 | 
				
			||||||
     * GeoOperations.completelyWithin(park, pond) // => false
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    static completelyWithin(
 | 
					 | 
				
			||||||
        feature: Feature<Geometry, any>,
 | 
					 | 
				
			||||||
        possiblyEncloingFeature: Feature<Polygon | MultiPolygon, any>
 | 
					 | 
				
			||||||
    ): boolean {
 | 
					 | 
				
			||||||
        return booleanWithin(feature, possiblyEncloingFeature)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Create a union between two features
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    static union = turf.union
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Create an intersection between two features
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    static intersect = turf.intersect
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,9 @@ import { GeoOperations } from "../Logic/GeoOperations"
 | 
				
			||||||
import SimpleMetaTaggers from "../Logic/SimpleMetaTagger"
 | 
					import SimpleMetaTaggers from "../Logic/SimpleMetaTagger"
 | 
				
			||||||
import FilteringFeatureSource from "../Logic/FeatureSource/Sources/FilteringFeatureSource"
 | 
					import FilteringFeatureSource from "../Logic/FeatureSource/Sources/FilteringFeatureSource"
 | 
				
			||||||
import Loc from "../Models/Loc"
 | 
					import Loc from "../Models/Loc"
 | 
				
			||||||
 | 
					import { Feature } from "geojson"
 | 
				
			||||||
 | 
					import { BBox } from "../Logic/BBox"
 | 
				
			||||||
 | 
					import { bboxClip } from "@turf/turf"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ScriptUtils.fixUtils()
 | 
					ScriptUtils.fixUtils()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -232,7 +235,8 @@ function sliceToTiles(
 | 
				
			||||||
    theme: LayoutConfig,
 | 
					    theme: LayoutConfig,
 | 
				
			||||||
    relationsTracker: RelationsTracker,
 | 
					    relationsTracker: RelationsTracker,
 | 
				
			||||||
    targetdir: string,
 | 
					    targetdir: string,
 | 
				
			||||||
    pointsOnlyLayers: string[]
 | 
					    pointsOnlyLayers: string[],
 | 
				
			||||||
 | 
					    clip: boolean
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    const skippedLayers = new Set<string>()
 | 
					    const skippedLayers = new Set<string>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -310,6 +314,7 @@ function sliceToTiles(
 | 
				
			||||||
            maxFeatureCount: undefined,
 | 
					            maxFeatureCount: undefined,
 | 
				
			||||||
            registerTile: (tile) => {
 | 
					            registerTile: (tile) => {
 | 
				
			||||||
                const tileIndex = tile.tileIndex
 | 
					                const tileIndex = tile.tileIndex
 | 
				
			||||||
 | 
					                const bbox = BBox.fromTileIndex(tileIndex).asGeoJson({})
 | 
				
			||||||
                console.log("Got tile:", tileIndex, tile.layer.layerDef.id)
 | 
					                console.log("Got tile:", tileIndex, tile.layer.layerDef.id)
 | 
				
			||||||
                if (tile.features.data.length === 0) {
 | 
					                if (tile.features.data.length === 0) {
 | 
				
			||||||
                    return
 | 
					                    return
 | 
				
			||||||
| 
						 | 
					@ -343,9 +348,9 @@ function sliceToTiles(
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                let strictlyCalculated = 0
 | 
					                let strictlyCalculated = 0
 | 
				
			||||||
                let featureCount = 0
 | 
					                let featureCount = 0
 | 
				
			||||||
                for (const feature of filteredTile.features.data) {
 | 
					                let features: Feature[] = filteredTile.features.data.map((f) => f.feature)
 | 
				
			||||||
 | 
					                for (const feature of features) {
 | 
				
			||||||
                    // Some cleanup
 | 
					                    // Some cleanup
 | 
				
			||||||
                    delete feature.feature["bbox"]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (tile.layer.layerDef.calculatedTags !== undefined) {
 | 
					                    if (tile.layer.layerDef.calculatedTags !== undefined) {
 | 
				
			||||||
                        // Evaluate all the calculated tags strictly
 | 
					                        // Evaluate all the calculated tags strictly
 | 
				
			||||||
| 
						 | 
					@ -353,7 +358,7 @@ function sliceToTiles(
 | 
				
			||||||
                            (ct) => ct[0]
 | 
					                            (ct) => ct[0]
 | 
				
			||||||
                        )
 | 
					                        )
 | 
				
			||||||
                        featureCount++
 | 
					                        featureCount++
 | 
				
			||||||
                        const props = feature.feature.properties
 | 
					                        const props = feature.properties
 | 
				
			||||||
                        for (const calculatedTagKey of calculatedTagKeys) {
 | 
					                        for (const calculatedTagKey of calculatedTagKeys) {
 | 
				
			||||||
                            const strict = props[calculatedTagKey]
 | 
					                            const strict = props[calculatedTagKey]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -379,7 +384,16 @@ function sliceToTiles(
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                    delete feature["bbox"]
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (clip) {
 | 
				
			||||||
 | 
					                    console.log("Clipping features")
 | 
				
			||||||
 | 
					                    features = [].concat(
 | 
				
			||||||
 | 
					                        ...features.map((f: Feature) => GeoOperations.clipWith(<any>f, bbox))
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Lets save this tile!
 | 
					                // Lets save this tile!
 | 
				
			||||||
                const [z, x, y] = Tiles.tile_from_index(tileIndex)
 | 
					                const [z, x, y] = Tiles.tile_from_index(tileIndex)
 | 
				
			||||||
                // console.log("Writing tile ", z, x, y, layerId)
 | 
					                // console.log("Writing tile ", z, x, y, layerId)
 | 
				
			||||||
| 
						 | 
					@ -391,7 +405,7 @@ function sliceToTiles(
 | 
				
			||||||
                    JSON.stringify(
 | 
					                    JSON.stringify(
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            type: "FeatureCollection",
 | 
					                            type: "FeatureCollection",
 | 
				
			||||||
                            features: filteredTile.features.data.map((f) => f.feature),
 | 
					                            features,
 | 
				
			||||||
                        },
 | 
					                        },
 | 
				
			||||||
                        null,
 | 
					                        null,
 | 
				
			||||||
                        " "
 | 
					                        " "
 | 
				
			||||||
| 
						 | 
					@ -476,8 +490,9 @@ export async function main(args: string[]) {
 | 
				
			||||||
    console.log("Cache builder started with args ", args.join(", "))
 | 
					    console.log("Cache builder started with args ", args.join(", "))
 | 
				
			||||||
    if (args.length < 6) {
 | 
					    if (args.length < 6) {
 | 
				
			||||||
        console.error(
 | 
					        console.error(
 | 
				
			||||||
            "Expected arguments are: theme zoomlevel targetdirectory lat0 lon0 lat1 lon1 [--generate-point-overview layer-name,layer-name,...] [--force-zoom-level z] \n" +
 | 
					            "Expected arguments are: theme zoomlevel targetdirectory lat0 lon0 lat1 lon1 [--generate-point-overview layer-name,layer-name,...] [--force-zoom-level z] [--clip]" +
 | 
				
			||||||
                "Note: a new directory named <theme> will be created in targetdirectory"
 | 
					                "--force-zoom-level causes non-cached-layers to be donwnloaded\n" +
 | 
				
			||||||
 | 
					                "--clip will erase parts of the feature falling outside of the bounding box"
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -494,6 +509,7 @@ export async function main(args: string[]) {
 | 
				
			||||||
    const lon0 = Number(args[4])
 | 
					    const lon0 = Number(args[4])
 | 
				
			||||||
    const lat1 = Number(args[5])
 | 
					    const lat1 = Number(args[5])
 | 
				
			||||||
    const lon1 = Number(args[6])
 | 
					    const lon1 = Number(args[6])
 | 
				
			||||||
 | 
					    const clip = args.indexOf("--clip") >= 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (isNaN(lat0)) {
 | 
					    if (isNaN(lat0)) {
 | 
				
			||||||
        throw "The first number (a latitude) is not a valid number"
 | 
					        throw "The first number (a latitude) is not a valid number"
 | 
				
			||||||
| 
						 | 
					@ -570,7 +586,7 @@ export async function main(args: string[]) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const extraFeatures = await downloadExtraData(theme)
 | 
					    const extraFeatures = await downloadExtraData(theme)
 | 
				
			||||||
    const allFeaturesSource = loadAllTiles(targetdir, tileRange, theme, extraFeatures)
 | 
					    const allFeaturesSource = loadAllTiles(targetdir, tileRange, theme, extraFeatures)
 | 
				
			||||||
    sliceToTiles(allFeaturesSource, theme, relationTracker, targetdir, generatePointLayersFor)
 | 
					    sliceToTiles(allFeaturesSource, theme, relationTracker, targetdir, generatePointLayersFor, clip)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let args = [...process.argv]
 | 
					let args = [...process.argv]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@ import { describe } from "mocha"
 | 
				
			||||||
import { expect } from "chai"
 | 
					import { expect } from "chai"
 | 
				
			||||||
import * as turf from "@turf/turf"
 | 
					import * as turf from "@turf/turf"
 | 
				
			||||||
import { GeoOperations } from "../../Logic/GeoOperations"
 | 
					import { GeoOperations } from "../../Logic/GeoOperations"
 | 
				
			||||||
 | 
					import { Feature, LineString, Polygon } from "geojson"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe("GeoOperations", () => {
 | 
					describe("GeoOperations", () => {
 | 
				
			||||||
    describe("calculateOverlap", () => {
 | 
					    describe("calculateOverlap", () => {
 | 
				
			||||||
| 
						 | 
					@ -133,4 +134,44 @@ describe("GeoOperations", () => {
 | 
				
			||||||
            expect(overlapsRev).empty
 | 
					            expect(overlapsRev).empty
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					    describe("clipWith", () => {
 | 
				
			||||||
 | 
					        it("clipWith should clip linestrings", () => {
 | 
				
			||||||
 | 
					            const bbox: Feature<Polygon> = {
 | 
				
			||||||
 | 
					                type: "Feature",
 | 
				
			||||||
 | 
					                properties: {},
 | 
				
			||||||
 | 
					                geometry: {
 | 
				
			||||||
 | 
					                    coordinates: [
 | 
				
			||||||
 | 
					                        [
 | 
				
			||||||
 | 
					                            [3.218560377159008, 51.21600586532159],
 | 
				
			||||||
 | 
					                            [3.218560377159008, 51.21499687768525],
 | 
				
			||||||
 | 
					                            [3.2207456783268356, 51.21499687768525],
 | 
				
			||||||
 | 
					                            [3.2207456783268356, 51.21600586532159],
 | 
				
			||||||
 | 
					                            [3.218560377159008, 51.21600586532159],
 | 
				
			||||||
 | 
					                        ],
 | 
				
			||||||
 | 
					                    ],
 | 
				
			||||||
 | 
					                    type: "Polygon",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            const line: Feature<LineString> = {
 | 
				
			||||||
 | 
					                type: "Feature",
 | 
				
			||||||
 | 
					                properties: {},
 | 
				
			||||||
 | 
					                geometry: {
 | 
				
			||||||
 | 
					                    coordinates: [
 | 
				
			||||||
 | 
					                        [3.218405371672816, 51.21499091846559],
 | 
				
			||||||
 | 
					                        [3.2208408127450525, 51.21560173433727],
 | 
				
			||||||
 | 
					                    ],
 | 
				
			||||||
 | 
					                    type: "LineString",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            const result = GeoOperations.clipWith(line, bbox)
 | 
				
			||||||
 | 
					            expect(result.length).to.equal(1)
 | 
				
			||||||
 | 
					            expect(result[0].geometry.type).to.eq("LineString")
 | 
				
			||||||
 | 
					            const clippedLine = (<Feature<LineString>>result[0]).geometry.coordinates
 | 
				
			||||||
 | 
					            const expCoordinates = [
 | 
				
			||||||
 | 
					                [3.2185480732975975, 51.21502965337126],
 | 
				
			||||||
 | 
					                [3.2207456783252724, 51.2155808773463],
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					            expect(clippedLine).to.deep.equal(expCoordinates)
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue