openlayers利用已知的三个经纬度的坐标点 , 绘制一个贝塞尔曲线

以下是使用OpenLayers根据三个经纬度点绘制贝塞尔曲线的完整实现方案。贝塞尔曲线通过控制点生成平滑曲线,特别适合绘制地图上的弧线、路径等。

实现思路

  1. 贝塞尔曲线原理:使用三个点(起点、控制点、终点)生成二阶贝塞尔曲线。
  2. 坐标转换:将WGS 84经纬度点转换为Web Mercator投影(EPSG:3857)以在地图上正确显示。
  3. 曲线计算:通过贝塞尔公式计算曲线上的多个点,形成近似曲线。
  4. 地图渲染 :使用OpenLayers的LineString几何对象绘制曲线。

代码实现

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>OpenLayers贝塞尔曲线绘制</title>
    <script src="https://cdn.jsdelivr.net/npm/ol@7.3.0/dist/ol.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/ol@7.3.0/ol.css" rel="stylesheet">
    <style>
        .map {
            width: 100%;
            height: 400px;
        }
    </style>
</head>
<body>
    <div id="map" class="map"></div>

    <script>
        // 1. 定义三个经纬度点(起点、控制点、终点)
      const startPoint = [116.3, 39.9]; // 北京(起点)
      const controlPoint = [110.0, 30.5]; // 控制点(黄海海域)
      const endPoint = [121.4, 31.2]; // 上海(终点)

        // 2. 经纬度转Web Mercator投影
        const transformPoints = (points) => {
            return points.map(point => 
                ol.proj.transform(point, 'EPSG:4326', 'EPSG:3857')
            );
        };

        // 3. 计算二阶贝塞尔曲线上的点
        function calculateBezierPoints(start, control, end, segments = 50) {
            const points = [];
            for (let t = 0; t <= 1; t += 1 / segments) {
                // 二阶贝塞尔公式: B(t) = (1-t)²P0 + 2(1-t)tP1 + t²P2
                const x = Math.pow(1 - t, 2) * start[0] + 
                          2 * (1 - t) * t * control[0] + 
                          Math.pow(t, 2) * end[0];
                const y = Math.pow(1 - t, 2) * start[1] + 
                          2 * (1 - t) * t * control[1] + 
                          Math.pow(t, 2) * end[1];
                points.push([x, y]);
            }
            return points;
        }

        // 4. 转换坐标并计算贝塞尔曲线
        const [startMerc, controlMerc, endMerc] = transformPoints([
            startPoint, controlPoint, endPoint
        ]);
        
        const bezierPoints = calculateBezierPoints(
            startMerc, controlMerc, endMerc, 100
        );

        // 5. 创建地图
        const map = new ol.Map({
            target: 'map',
            layers: [
                new ol.layer.Tile({
                    source: new ol.source.OSM()  // 使用OpenStreetMap作为底图
                })
            ],
            view: new ol.View({
                center: ol.proj.transform([118, 35], 'EPSG:4326', 'EPSG:3857'),
                zoom: 5
            })
        });

        // 6. 创建贝塞尔曲线要素
        const bezierCurve = new ol.geom.LineString(bezierPoints);
        
        const feature = new ol.Feature({
            geometry: bezierCurve,
            name: '贝塞尔曲线'
        });

        // 7. 设置曲线样式
        feature.setStyle(new ol.style.Style({
            stroke: new ol.style.Stroke({
                color: 'rgba(255, 0, 0, 0.8)',  // 红色半透明
                width: 3,
                lineDash: [10, 5]  // 虚线样式
            })
        }));

        // 8. 添加曲线到地图
        const vectorSource = new ol.source.Vector({
            features: [feature]
        });
        
        const vectorLayer = new ol.layer.Vector({
            source: vectorSource
        });
        
        map.addLayer(vectorLayer);

        // 9. 添加起点、控制点和终点标记
        const addMarker = (coord, label) => {
            const marker = new ol.Feature({
                geometry: new ol.geom.Point(coord),
                name: label
            });
            
            marker.setStyle(new ol.style.Style({
                image: new ol.style.Circle({
                    radius: 6,
                    fill: new ol.style.Fill({ color: 'blue' }),
                    stroke: new ol.style.Stroke({ color: 'white', width: 2 })
                }),
                text: new ol.style.Text({
                    text: label,
                    font: '14px Arial',
                    fill: new ol.style.Fill({ color: 'black' }),
                    stroke: new ol.style.Stroke({ color: 'white', width: 2 }),
                    offsetY: -10
                })
            }));
            
            vectorSource.addFeature(marker);
        };
        
        addMarker(startMerc, '起点');
        addMarker(controlMerc, '控制点');
        addMarker(endMerc, '终点');
    </script>
</body>
</html>

核心代码解析

  1. 贝塞尔曲线计算

    • 使用二阶贝塞尔公式:( B(t) = (1-t)^2P_0 + 2(1-t)tP_1 + t^2P_2 )
    • 通过参数t从0到1的变化,计算曲线上的多个点,segments参数控制精度
  2. 坐标转换

    • 使用ol.proj.transform()将WGS 84经纬度转换为Web Mercator坐标
    • 确保所有点在同一投影系统下计算
  3. 地图渲染

    • 使用LineString几何对象表示曲线
    • 通过Style设置曲线样式(颜色、宽度、虚线等)
    • 添加标记点显示起点、控制点和终点

效果展示

(注:实际运行时会显示OpenStreetMap底图和红色贝塞尔曲线)

相关推荐
烟话618 分钟前
Vue3响应式原理【通俗理解】
前端·javascript·vue.js
下北沢美食家20 分钟前
JavaScript面试题2
开发语言·javascript·ecmascript
浩星28 分钟前
electron系列5:深入理解Electron打包
前端·javascript·electron
英俊潇洒美少年34 分钟前
React 实现 AI 流式打字机对话:SSE 分包粘包处理 + 并发优化
前端·javascript·react.js
叫我一声阿雷吧1 小时前
JS 入门通关手册(44):宏任务 / 微任务 / Event Loop(前端最难核心,面试必考
javascript·宏任务·event loop· 前端面试· 微任务· 事件循环·js单线程
We་ct1 小时前
LeetCode 172. 阶乘后的零:从暴力到最优,拆解解题核心
开发语言·前端·javascript·算法·leetcode·typescript
军军君011 小时前
数字孪生监控大屏实战模板:可视化数字统计展示
前端·javascript·vue.js·typescript·echarts·数字孪生·前端大屏
吴声子夜歌1 小时前
ES6——Iterator和for...of循环详解
前端·javascript·es6
小李子呢02112 小时前
前端八股3---ref和reactive
开发语言·前端·javascript
web_小码农2 小时前
CSS 3D动画 旋转木马示例(带弧度支持手动拖动)
javascript·css·3d