Geojson“MultiLineString”到“LineString”

问题描述 投票:0回答:1

是否可以从

LineString
中的
MultiLineString
创建单个连续的
geojson
,而不弄乱线条的几何形状? (想想混乱的多线道路重叠和小间隙也会翻转方向)

这段 Node JS 代码表现不佳:

const fs = require('fs');

// Load the GeoJSON data
const geojson = JSON.parse(fs.readFileSync('Route20OK.geojson', 'utf8'));

// Helper function to calculate the distance between two coordinates
function calculateDistance(coord1, coord2) {
    const [lon1, lat1] = coord1;
    const [lon2, lat2] = coord2;
    const R = 6371000; // Earth radius in meters

    const dLat = (lat2 - lat1) * (Math.PI / 180);
    const dLon = (lon2 - lon1) * (Math.PI / 180);

    const a = Math.sin(dLat / 2) ** 2 + 
              Math.cos(lat1 * (Math.PI / 180)) * Math.cos(lat2 * (Math.PI / 180)) *
              Math.sin(dLon / 2) ** 2;

    return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
}

// Step 1: Find the two most "extreme" endpoints
function findExtremeEndpoints(segments) {
    const endpoints = [];

    // Collect all endpoints
    segments.forEach(segment => {
        endpoints.push(segment[0], segment[segment.length - 1]);
    });

    // Calculate a score for each endpoint by summing its distances to all other endpoints
    const scores = endpoints.map((endpoint, i) => {
        let score = 0;
        endpoints.forEach((other, j) => {
            if (i !== j) score += calculateDistance(endpoint, other);
        });
        return { point: endpoint, score };
    });

    // Sort by score and select the top two endpoints as the extreme endpoints
    scores.sort((a, b) => b.score - a.score);
    return [scores[0].point, scores[1].point];
}

// Step 2: Connect segments into a continuous path with orientation checks
function connectSegments(segments, extremeEndpoints) {
    const [extremeStart, extremeEnd] = extremeEndpoints;
    let path = [extremeStart];
    let currentPoint = extremeStart;
    const gapTolerance = 50; // meters

    while (segments.length > 0) {
        let closestIndex = -1;
        let closestSegment = null;
        let closestDistance = Infinity;
        let reverse = false;

        // Find the closest segment to connect to the current path end
        for (let i = 0; i < segments.length; i++) {
            const segment = segments[i];
            const start = segment[0];
            const end = segment[segment.length - 1];

            const distanceToStart = calculateDistance(currentPoint, start);
            const distanceToEnd = calculateDistance(currentPoint, end);

            if (distanceToStart < closestDistance) {
                closestDistance = distanceToStart;
                closestIndex = i;
                closestSegment = segment;
                reverse = false;
            }
            if (distanceToEnd < closestDistance) {
                closestDistance = distanceToEnd;
                closestIndex = i;
                closestSegment = segment;
                reverse = true;
            }
        }

        if (closestSegment) {
            // Reverse the segment if necessary
            if (reverse) closestSegment.reverse();

            // Add segment to the path, projecting midpoint for small gaps
            if (closestDistance <= gapTolerance) {
                const midPoint = [
                    (currentPoint[0] + closestSegment[0][0]) / 2,
                    (currentPoint[1] + closestSegment[0][1]) / 2
                ];
                path.push(midPoint);
            }

            path.push(...closestSegment);
            currentPoint = path[path.length - 1];
            segments.splice(closestIndex, 1); // Remove the segment from the list
        } else {
            break; // Exit if no more segments can connect
        }
    }

    return path;
}

// Process each feature in the GeoJSON
geojson.features = geojson.features.map(feature => {
    if (feature.geometry.type === 'MultiLineString') {
        const segments = feature.geometry.coordinates;

        // Step 1: Identify major endpoints using distance scoring
        const extremeEndpoints = findExtremeEndpoints(segments);

        // Step 2: Connect segments to form a continuous path
        const orderedCoordinates = connectSegments(segments, extremeEndpoints);

        // Update the geometry to a LineString with the ordered coordinates
        feature.geometry = {
            type: 'LineString',
            coordinates: orderedCoordinates
        };
    }
    return feature;
});

// Write the modified GeoJSON to a new file
fs.writeFileSync('Route20Final.geojson', JSON.stringify(geojson, null, 2));

console.log('GeoJSON has been processed and saved to output.geojson');

链接到下载 geojson

node.js geometry geojson multilinestring
1个回答
0
投票

我认为你需要将代码从单个巨型几何体分解为多个几何体。

From
enter image description here

To
enter image description here

demo.js

const fs = require('fs');

const geojson = JSON.parse(fs.readFileSync('Route20OK.geojson', 'utf8'));

// Function to split each segment into separate LineString features
function splitMultiLineString(feature) {
    const segments = feature.geometry.coordinates;
    return segments.map(segment => ({
        type: "Feature",
        properties: { ...feature.properties },
        geometry: {
            type: "LineString",
            coordinates: segment
        }
    }));
}

// Process each feature in the GeoJSON
let newFeatures = [];
geojson.features.forEach(feature => {
    if (feature.geometry.type === 'MultiLineString') {
        // Split the MultiLineString into multiple LineString features
        const lineStringFeatures = splitMultiLineString(feature);
        newFeatures.push(...lineStringFeatures);
    } else {
        newFeatures.push(feature);
    }
});

geojson.features = newFeatures;

fs.writeFileSync('Route20Final.geojson', JSON.stringify(geojson, null, 2));

console.log('GeoJSON has been processed and saved to Route20Final.geojson');

geojson.io 的结果

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.