二阶贝塞尔曲线生成弧线

概述

本文分享一个二阶贝塞尔曲线曲线生成弧线的算法。

效果

image.png

实现

1. 封装方法

class ArcLine {
   
  constructor(from, to, num = 100) {
   
    this.from = from;
    this.to = to;
    this.num = num;
    return this.getPointList();
  }
  getPointList() {
   
    const {
    from, to } = this
    const ctrlPoint = this.getOffsetPoint(from, to);
    const points = this.create2PBezier(from, ctrlPoint, to)
    return points
  }
  getOffsetPoint(start, end) {
   
    const distance = this.getDistance(start, end) / 2; //除以3?
    let angle, dX, dY;
    const mp = [start[0], start[1]];
    const deltaAngle = - Math.PI / 8; //偏移0.2弧度
    if (start[0] != end[0] && start[1] != end[1]) {
    //斜率存在
      const k = (end[1] - start[1]) / (end[0] - start[0]);
      angle = Math.atan(k);
    } else if (start[0] == end[0]) {
    //垂直线
      angle = (start[1] <= end[1] ? 1 : -1) * Math.PI / 2;
    } else {
    //水平线
      angle = 0;
    }
    if (start[0] <= end[0]) {
   
      angle -= deltaAngle;
      dX = Math.round(Math.cos(angle) * distance);
      dY = Math.round(Math.sin(angle) * distance);
      mp[0] += dX;
      mp[1] += dY;
    } else {
   
      angle += deltaAngle;
      dX = Math.round(Math.cos(angle) * distance);
      dY = Math.round(Math.sin(angle) * distance);
      mp[0] -= dX;
      mp[1] -= dY;
    }
    return mp;
  }

  getDistance(p1, p2) {
   
    return Math.sqrt((p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]));
  }

  bezier2P(p0, p1, p2, t) {
   
    const P0 = p0 * Math.pow(1 - t, 2);
    const P1 = p1 * 2 * t * (1 - t);
    const P2 = p2 * t * t;
    return P0 + P1 + P2;
  }

  getBezierNowPoint2P(p0, p1, p2, num, tick) {
   
    return {
   
      x: this.bezier2P(p0[0], p1[0], p2[0], num * tick),
      y: this.bezier2P(p0[1], p1[1], p2[1], num * tick),
    };
  }
  create2PBezier(p0, p1, p2) {
   
    const num = this.num
    const t = 1 / (num - 1);
    const points = [];
    for (let i = 0; i < num; i++) {
   
      const point = this.getBezierNowPoint2P(p0, p1, p2, i, t);
      points.push([point.x, point.y]);
    }
    return points;
  }
}

2. 前端调用

示例使用openlayers实现。

let vetSource = new ol.source.Vector({
   
  features: [],
});
let vectorLayer = new ol.layer.Vector({
   
  source: vetSource,
  style: new ol.style.Style({
   
    stroke: new ol.style.Stroke({
   
      color: "#f00",
      width: 2,
    }),
  }),
});
map.addLayer(vectorLayer)

function addAllLines() {
   
  let features = [];
  for (let i = 0; i < pointData.length; i++) {
   
    const after = pointData[i];
    const from = [101.797439042302, 36.5937248286007];
    const to = [after.lon, after.lat].map(Number);
    let points = new ArcLine(from, to);
    points = points.map((p) => ol.proj.fromLonLat(p));
    lineData.push(points);

    features.push(
      new ol.Feature({
   
        geometry: new ol.geom.LineString(points),
      })
    );
  }
  vetSource.addFeatures(features);
  map.getView().animate({
   
    center: [12474607.173951693, 4278483.982819865],
    zoom: 3.8,
  });
}

相关推荐

  1. 计算机图形学作业:三阶曲面

    2024-01-16 10:38:01       37 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-16 10:38:01       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-16 10:38:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-16 10:38:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-16 10:38:01       18 阅读

热门阅读

  1. WordPiece和SentencePiece区别

    2024-01-16 10:38:01       35 阅读
  2. 用使用pandas拆分excel单元格

    2024-01-16 10:38:01       31 阅读
  3. ChatGPT和文心一言哪个更好用?

    2024-01-16 10:38:01       38 阅读
  4. 前端笔试题(二)

    2024-01-16 10:38:01       37 阅读
  5. 【C++练级之路】【Lv.6】【STL】string类的模拟实现

    2024-01-16 10:38:01       31 阅读
  6. linux centos7 django uwsgi 部署

    2024-01-16 10:38:01       32 阅读