计算 45 度捕捉的坐标

Calculate coordinates for 45 degree snap

我有一个 SVG 在原点和鼠标指针之间画一条线,我想做的是当按下 shift 时(event.shiftKey === true)使线 "snap" 到最近的 45 度坐标,基本上与您在 photoshop 中获得的行为相同。

我已经设法计算出两点之间的角度(因此我也可以决定捕捉哪个角度,如果需要的话可能会使用 IF/ELSE 树)但是我不知道我如何根据新度数重新计算 "end" 坐标。

我在这里建立了一个简化的例子:https://jsbin.com/sohafekije/2/edit?html,js,output

我还拍了一张我正在尝试重现的 Photoshop 行为的照片(质量很差,因为我不得不使用相机,因为我无法截屏 - 抱歉)只是为了 100% 清晰:http://i.imgur.com/Yo04uxY.jpg

本质上,我正在尝试重现您在按住 Shift 键时在 photoshop 中获得的行为,但我猜想您需要非常擅长数学才能找到解决方案,而我不是!

非常感谢任何帮助:)

var app = document.getElementById('app'),
    svg = SVG(app),
    line = svg.polyline([]).fill('none').stroke({ width: 1 }),
    start = [250,250],
    end = null,
    angleTxt = document.getElementById('angle'),
    lineLengthTxt = document.getElementById('linelength');

line.marker('start', 10, 10, function(add) {
  add.circle(10).fill('#f06')
})

// On mouse move, redraw the line
svg.on('mousemove', function(e){
  end = [e.layerX, e.layerY];
  line.plot([start, end]);
  calcAngle();
});

function calcAngle() {
  var deltaX = end[0] - start[0],
      deltaY = end[1] - start[1],
      rad = Math.atan2(deltaY, deltaX),
      deg = rad * (180/Math.PI),
      linelen = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
  

  
  angleTxt.textContent = deg;
  lineLengthTxt.textContent = linelen;
  
}
#app { border: 1px solid blue; width:100%; height:600px}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
  <script type="text/javascript" src="https://rawgit.com/svgdotjs/svg.js/master/dist/svg.js"></script>
</head>
<body>
  <div id="app"></div>
  Angle: <span id="angle">-</span><br>
  Line Length: <span id="linelength">-</span>
</body>
</html>

我做到了!

How use it

您计算新角度并使用余弦作为 x 值并使用正弦作为 y 值来应用它。这里的角度从 -PI 到 PI,步长为 PI/4;如果要更改步骤,请将 'var newAngle = ...' 行中的 4 替换为其他数字。

How it's works

首先我在考虑你需要 8 个角度位置,4 个 PI 弧度(一个圆是 2PI 弧度)。所以你需要简化你的角度。

newAngle / Math.PI // value is between -1 and 1 (it's a double)
newAngle / Math.PI * 4 // value is between -4 and 4 (it's a double)
Math.round(newAngle / Math.PI * 4) // value is between -4 and 4 (but it's a integer now)
Math.round(newAngle / Math.PI * 4) / 4 // value is between -1 and 1 (with step of 0.25)
Math.round(newAngle / Math.PI * 4) / 4 * Math.PI // value is between -PI and PI with step of 0.25 * PI (PI/4)

现在你的新角度是正确的。 Cosinus return 角度的 x 值(查看维基百科的图形解释)和 Sinus 角度的 y 值。 将 COSINUS/SINUS 乘以长度即可找到下一个点。

function applyNewAngle() {
  var deltaX = end[0] - start[0],
      deltaY = end[1] - start[1],
      dist = Math.sqrt(Math.pow(deltaX,2) + Math.pow(deltaY,2));
  var newAngle = Math.atan2(deltaY, deltaX);
  var shiftedAngle = Math.round(newAngle / Math.PI * 4) / 4 * Math.PI;
  end = [start[0]+dist*Math.cos(shiftedAngle), start[1]+dist*Math.sin(shiftedAngle)];
}