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底图和红色贝塞尔曲线)

相关推荐
来恩100336 分钟前
jQuery选择器
前端·javascript·jquery
前端繁华如梦38 分钟前
树上挂苹果还是挂玻璃球?Three.js 程序化果实的完整实现指南
前端·javascript
CDwenhuohuo1 小时前
优惠券组件直接用 uview plus
前端·javascript·vue.js
川冰ICE2 小时前
TypeScript装饰器与元编程实战
前端·javascript·typescript
AI砖家2 小时前
Vue3组件传参大全,各种传参方式的对比
前端·javascript·vue.js
希望永不加班2 小时前
var局部变量类型推断的利弊
java·服务器·前端·javascript·html
threelab2 小时前
Three.js 3D 地图可视化 | 三维可视化 / AI 提示词
前端·javascript·人工智能·3d·着色器
失眠的咕噜3 小时前
PDA 安卓设备上传多张图片
android·前端·javascript
掰头战士3 小时前
深入了解JS原型及原型继承链机制
javascript
一只叁木Meow4 小时前
电商 SKU 选择器:用算法实现优雅的用户交互
前端·javascript·算法