首页 > 解决方案 > 沿圆弧移动一个点到另一个点的距离

问题描述

我有一个180°的弧。我有两个点(V3 和 V4)被弧长沿弧线绘制。如何将 V4 的位置设置为相对于它与 V3 而不是 V1 的距离?我不想使用角距离,而是 x & y 中的距离。我仍然希望 V4 沿着相同的弧线移动,但我希望能够拖动一个滑块,其正值向 V2 移动,负值向 V1 移动,具体取决于 V3 的位置。

任何帮助都会很棒。谢谢!

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var percentSlider = document.getElementById("percentSlider");
var distanceSlider = document.getElementById("distanceSlider");
var pReadout = document.querySelector(".readout.percent");
var dReadout = document.querySelector(".readout.distance");
var distance = document.getElementById("distance");

class Vector {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

function drawDot(v, txt, color) {
  ctx.beginPath();
  r = 4;
  ctx.arc(v.x, v.y, r, 0, Math.PI * 2, false);
  ctx.closePath();
  ctx.fillStyle = color;
  ctx.fill();
  ctx.font = '10px sans-serif';
  ctx.fillText(txt, v.x - 6, v.y - 12);
}

function clamp(n, minn, maxn) {
  return Math.max(Math.min(maxn, n), minn);
}

function PosByPercent(cx, cy, d, radius, perc) {
  angle = perc * Math.PI;
  let newX = cx + radius * Math.cos(angle);
  let newY = cy - radius * Math.sin(angle);
  return new Vector(newX, newY)
}

function PosByDistance(cx, cy, d, radius) {
  a = 1 - Math.pow(d / radius, 2) / 2;
  a = clamp(a, -1, 1);
  angle = Math.acos(a);
  let newX = cx + radius * Math.cos(angle);
  let newY = cy - radius * Math.sin(angle);
  return new Vector(newX, newY)
}

function drawAll() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  let angle = 0;
  let d = distanceSlider.value;
  let p = percentSlider.value;
  let cx = canvas.width / 2;
  let cy = canvas.height / 2;
  let radius = 70;
  v1 = new Vector(cx + radius, cy);
  v2 = new Vector(cx - radius, cy);
  v3 = PosByPercent(cx, cy, d, radius, p);
  v4 = PosByDistance(cx, cy, d, radius, p);

  ctx.beginPath();
  ctx.arc(cx, cy, radius, Math.PI, 0, false);
  ctx.lineWidth = 3;
  ctx.strokeStyle = "#3f3f3f";
  ctx.stroke();

  drawDot(v1, "V1", "#40e4ff");
  drawDot(v2, "V2", "#40e4ff");
  drawDot(v3, "V3", "#FF0000");
  drawDot(v4, "V4", "#00ff48");
}

function getDistances() {
  let a = v4.x - v3.x;
  let b = v4.y - v3.y;
  let c = Math.sqrt(a * a + b * b);
  distance.innerHTML = "<div><span>dist - v3 & v4: </span>" + parseFloat(c).toFixed(1) + "</div>";
}

var v1, v2, v3, v4;
drawAll();
getDistances();
dReadout.innerHTML = distanceSlider.value;
pReadout.innerHTML = percentSlider.value;

percentSlider.oninput = function() {
  pReadout.innerHTML = percentSlider.value;
  drawAll();
  getDistances();
}

distanceSlider.oninput = function() {
  dReadout.innerHTML = distanceSlider.value;
  drawAll();
  getDistances();
}
body {
  margin: 0px;
  font-family: sans-serif;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

#canvas {
  background-color: #2b2b2b;
  border: 1px solid rgba(0, 0, 0, 0.2);
  width: 200px;
  height: 200px;
  margin-bottom: 4px;
}

#controls {
  background-color: white;
  position: fixed;
  top: 0;
  right: 0;
  padding: 10px;
  width: 200px;
  box-sizing: border-box;
}

.row {
  display: block;
}

label {
  display: block;
  text-align: left;
}

label span {
  font-size: 10px;
}

.readout {
  width: 80px;
  font-size: 12px;
  text-align: left;
  padding-left: 2px;
  box-sizing: border-box;
}

#myRange {
  width: 130px;
}

#distance {
  font-size: 13px;
  position: fixed;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  text-align: left;
  top: 0;
  left: 0;
  background: #333;
  color: white;
  padding: 10px;
}

#distance span {
  color: rgba(255, 255, 255, 0.6);
}
<canvas id="canvas" width=200 height=200></canvas>
<div id="controls">
  <div class="row" id="perc">
    <label for="percentSlider">V3 <span>(%)</span></label>
    <input type="range" step="0.01" min="0" max="1" value="0.75" class="slider" id="percentSlider">
    <span class="readout percent"></span>
  </div>
  <div class="row" id="dist">
    <label for="distanceSlider">V4 <span>(dist from V1)</span></label>
    <input type="range" step="0.1" min="0" max="360" value="0" class="slider" id="distanceSlider">
    <span class="readout distance"></span>
  </div>
</div>
<div id="distance"></div>

*** 编辑 *** 我最初是用 Math.PI 的百分比设置 V3(如上面的片段),但通过使用 arc_length/radius 设置两个点的位置来获得所需的结果。

标签: javascriptmathcanvastrigonometry

解决方案


当你计算v3位置时,你知道它angle是中间结果。

记住这个角度并将其用于计算v4位置,如下所示:

function PosByDistanceFromV3(cx, cy, d, radius, v3angle) {
  a = 1 - Math.pow(d / radius, 2) / 2;
  a = clamp(a, -1, 1);
  angle = Math.acos(a) + v3angle;
  angle = clamp(angle, 0, Math.PI);
  let newX = cx + radius * Math.cos(angle);
  let newY = cy - radius * Math.sin(angle);
  return new Vector(newX, newY)
}

推荐阅读