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/[email protected]/dist/ol.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/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底图和红色贝塞尔曲线)

相关推荐
运维@小兵1 小时前
vue访问后端接口,实现用户注册
前端·javascript·vue.js
雨汨1 小时前
web:InfiniteScroll 无限滚动
前端·javascript·vue.js
小盐巴小严2 小时前
正则表达式
javascript·正则表达式
天天打码2 小时前
Rspack:字节跳动自研 Web 构建工具-基于 Rust打造高性能前端工具链
开发语言·前端·javascript·rust·开源
AA-代码批发V哥2 小时前
正则表达式: 从基础到进阶的语法指南
java·开发语言·javascript·python·正则表达式
字节高级特工2 小时前
【C++】”如虎添翼“:模板初阶
java·c语言·前端·javascript·c++·学习·算法
小冻梨!!!3 小时前
Spark,在shell中运行RDD程序
大数据·javascript·spark
大猫会长3 小时前
lenis滑动插件的笔记
javascript
db_lnn_20213 小时前
【vue】全局组件及组件模块抽离
前端·javascript·vue.js
Qin_jiangshan3 小时前
vue实现进度条带指针
前端·javascript·vue.js