如何计算两个约束段的旋转角度?

问题描述 投票:2回答:1

我有两个向量,Y对齐是固定的,从而允许X对齐旋转。这些矢量通过两个固定长度的段连接在一起。给定两个矢量(82.74)之间的角度和所有段的长度,如何获得两个连接段(24.62和22.61)的角度?

enter image description here

给出的内容:向量的大小,以及X轴和OG之间的角度:

var magOG = 3,
    magOE = 4,
    magGH = 3,
    magEH = 2,
    angleGamma = 90;

这是我的出发点:angleGamma = 90 - 然后,我将有以下向量:

var vOG = new vec2(-3,0),
    vOE = new vec2(0,-4);

从这里开始,我试图让angleAlphaand angleBeta获得低于90度的angleGamma值。

受限制的部分的大小:

细分HG和HE必须符合以下条件:

/
|  OG*OG+ OE*OE = (HG + HE)*(HG + HE)
>
|  OG - HG = OE - HE
\

这将导致以下两个解决方案(如接受的答案中所指出的 - bilateration):

Solution 1:
========================================================
HG = 0.5*(-Math.sqrt(OG*OG + OE*OE) + OG - OE)
HE = 0.5*(-Math.sqrt(OG*OG + OE*OE) - OG + OE)

Solution 2:
========================================================
HG = 0.5*(Math.sqrt(OG*OG + OE*OE) + OG - OE)
HE = 0.5*(Math.sqrt(OG*OG + OE*OE) - OG + OE)

便笺:

这是一个完整解决方案的游乐场。这里使用的可视化库是伟大的JSXGraph。感谢拜罗伊特大学数字技术移动学习中心。

圆形交叉函数的积分:01AutoMonkey在这个问题的接受答案中:A JavaScript function that returns the x,y points of intersection between two circles?

function deg2rad(deg) {
  return deg * Math.PI / 180;
}

function rad2deg(rad) {
  return rad * 180 / Math.PI;
}

function lessThanEpsilon(x) {
  return (Math.abs(x) < 0.00000000001);
}

function angleBetween(point1, point2) {
  var x1 = point1.X(), y1 = point1.Y(), x2 = point2.X(), y2 = point2.Y();
  var dy = y2 - y1, dx = x2 - x1;
  var t = -Math.atan2(dx, dy); /* range (PI, -PI] */
  return rad2deg(t); /* range (180, -180] */
}

function circleIntersection(circle1, circle2) {
  var r1 = circle1.radius, cx1 = circle1.center.X(), cy1 = circle1.center.Y();
  var r2 = circle2.radius, cx2 = circle2.center.X(), cy2 = circle2.center.Y();

  var a, dx, dy, d, h, h2, rx, ry, x2, y2;

  /* dx and dy are the vertical and horizontal distances between the circle centers. */
  dx = cx2 - cx1;
  dy = cy2 - cy1;
  
  /* angle between circle centers */
  var theta = Math.atan2(dy,dx);

  /* vertical and horizontal components of the line connecting the circle centers */
  var xs1 = r1*Math.cos(theta), ys1 = r1*Math.sin(theta), xs2 = r2*Math.cos(theta), ys2 = r2*Math.sin(theta);
  
  /* intersection points of the line connecting the circle centers */
  var sxA = cx1 + xs1, syA = cy1 + ys1, sxL = cx2 - xs2, syL = cy2 - ys2;
  
  /* Determine the straight-line distance between the centers. */
  d = Math.sqrt((dy*dy) + (dx*dx));

  /* Check for solvability. */
  if (d > (r1 + r2)) {
    /* no solution. circles do not intersect. */
    return [[sxA,syA], [sxL,syL]];
  }

  thetaA = -Math.PI - Math.atan2(cx1,cy1); /* Swap X-Y and re-orient to -Y */
  xA = +r1*Math.sin(thetaA);
  yA = -r1*Math.cos(thetaA);
  ixA = cx1 - xA;
  iyA = cy1 - yA;

  thetaL = Math.atan(cx2/cy2);
  xL = -r2*Math.sin(thetaL);
  yL = -r2*Math.cos(thetaL);
  ixL = cx2 - xL;
  iyL = cy2 - yL;

  if(d === 0 && r1 === r2) {
    /* infinite solutions. circles are overlapping */
    return [[ixA,iyA], [ixL,iyL]];
  }
  
  if (d < Math.abs(r1 - r2)) {
    /* no solution. one circle is contained in the other */
   return [[ixA,iyA], [ixL,iyL]];
  }

  /* 'point 2' is the point where the line through the circle intersection points crosses the line between the circle centers. */

  /* Determine the distance from point 0 to point 2. */
  a = ((r1*r1) - (r2*r2) + (d*d)) / (2.0 * d);
  
  /* Determine the coordinates of point 2. */
  x2 = cx1 + (dx * a/d);
  y2 = cy1 + (dy * a/d);
  
  /* Determine the distance from point 2 to either of the intersection points. */
  h2 = r1*r1 - a*a;
  h = lessThanEpsilon(h2) ? 0 : Math.sqrt(h2);

  /* Now determine the offsets of the intersection points from point 2. */
  rx = -dy * (h/d);
  ry = +dx * (h/d);

  /* Determine the absolute intersection points. */
  var xi = x2 + rx, yi = y2 + ry;
  var xi_prime = x2 - rx, yi_prime = y2 - ry;

  return [[xi, yi], [xi_prime, yi_prime]];
}

function plot() {

  var cases = [
    {a: 1.1, l: 1.9, f: 0.3073},
    {a: 1.0, l: 1.7, f: 0.3229}
  ];

  var testCase = 1;
  
  var magA = cases[testCase].a, magL = cases[testCase].l;
  var maxS = Math.sqrt(magA*magA+magL*magL), magS1 = maxS * cases[testCase].f, magS2 = maxS - magS1;

  var origin = [0,0], board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox: [-5.0, 5.0, 5.0, -5.0], axis: true});
  var drawAs = {dashed: {dash: 3, strokeWidth: 0.5, strokeColor: '#888888'} };

  board.suspendUpdate();

  var leftArm = board.create('slider', [[-4.5, 3], [-1.5, 3], [0, -64, -180]]);
  var leftLeg = board.create('slider', [[-4.5, 2], [-1.5, 2], [0, -12, -30]]);

  var rightArm = board.create('slider', [[0.5, 3], [3.5, 3], [0, 64, 180]]);
  var rightLeg = board.create('slider', [[0.5, 2], [3.5, 2], [0, 12, 30]]);

  var lh = board.create('point', [
    function() { return +magA * Math.sin(deg2rad(leftArm.Value())); },
    function() { return -magA * Math.cos(deg2rad(leftArm.Value())); }
  ], {size: 3, name: 'lh'});
  var LA = board.create('line', [origin, lh], {straightFirst: false, straightLast: false, lastArrow: true});
  var cLS1 = board.create('circle', [function() { return [lh.X(), lh.Y()]; }, function() { return magS1; }], drawAs.dashed);
  
  var lf = board.create('point', [
    function() { return +magL * Math.sin(deg2rad(leftLeg.Value())); },
    function() { return -magL * Math.cos(deg2rad(leftLeg.Value())); }
  ], {size: 3, name: 'lf'});
  var LL = board.create('line', [origin, lf], {straightFirst: false, straightLast: false, lastArrow: true});
  var cLS2 = board.create('circle', [function() { return [lf.X(), lf.Y()]; }, function() { return magS2; }], drawAs.dashed);

  var lx1 = board.create('point', [
    function() { return circleIntersection(cLS1, cLS2)[0][0]; },
    function() { return circleIntersection(cLS1, cLS2)[0][1]; }
  ], {size: 3, face:'x', name: 'lx1'});

  var lx2 = board.create('point', [
    function() { return circleIntersection(cLS1, cLS2)[1][0]; },
    function() { return circleIntersection(cLS1, cLS2)[1][1]; }
  ], {size: 3, face:'x', name: 'lx2'});

  /* Angle between lh, lx1 shall be between 0 and -180 */
  var angleLAJ = board.create('text', [-3.7, 0.5, function(){ return angleBetween(lh, lx1).toFixed(2); }]);
  /* Angle between lf, lx1 shall be between 0 and 180 */
  var angleLLJ = board.create('text', [-2.7, 0.5, function(){ return angleBetween(lf, lx1).toFixed(2); }]);
  
  var rh = board.create('point', [
    function() { return +magA * Math.sin(deg2rad(rightArm.Value())); },
    function() { return -magA * Math.cos(deg2rad(rightArm.Value())); }
  ], {size: 3, name: 'rh'});
  var RA = board.create('line', [origin, rh], {straightFirst: false, straightLast: false, lastArrow: true});
  var cRS1 = board.create('circle', [function() { return [rh.X(), rh.Y()]; }, function() { return magS1; }], drawAs.dashed);
  
  var rf = board.create('point', [
    function() { return +magL * Math.sin(deg2rad(rightLeg.Value())); },
    function() { return -magL * Math.cos(deg2rad(rightLeg.Value())); }
  ], {size: 3, name: 'rf'});
  var RL = board.create('line', [origin, rf], {straightFirst: false, straightLast: false, lastArrow: true});
  var cRS2 = board.create('circle', [function() { return [rf.X(), rf.Y()]; }, function() { return magS2; }], drawAs.dashed);

  var rx1 = board.create('point', [
    function() { return circleIntersection(cRS1, cRS2)[1][0]; },
    function() { return circleIntersection(cRS1, cRS2)[1][1]; }
  ], {size: 3, face:'x', name: 'rx1'});

  var rx2 = board.create('point', [
    function() { return circleIntersection(cRS1, cRS2)[0][0]; },
    function() { return circleIntersection(cRS1, cRS2)[0][1]; }
  ], {size: 3, face:'x', name: 'rx2'});
  
  var angleRAJ = board.create('text', [+1.3, 0.5, function(){ return angleBetween(rh, rx1).toFixed(2); }]);
  var angleRLJ = board.create('text', [+2.3, 0.5, function(){ return angleBetween(rf, rx1).toFixed(2); }]);

  board.unsuspendUpdate();

}

plot();
<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/jsxgraph/0.99.7/jsxgraph.css" />
  <link rel="stylesheet" href="style.css">
  <script type="text/javascript" charset="UTF-8" src="//cdnjs.cloudflare.com/ajax/libs/jsxgraph/0.99.7/jsxgraphcore.js"></script>
</head>

<body>
  <div id="jxgbox" class="jxgbox" style="width:580px; height:580px;"></div>
</body>

</html>
javascript algorithm math trigonometry
1个回答
3
投票

根据你的草图,E和G的坐标是:

E = (0, -magOE)
G = magOG * ( -sin(gamma), -cos(gamma) )

然后,计算H的位置是trilateration问题。实际上,这只是双刃化,因为你错过了第三个距离。因此,你将获得两个可能的H位置。

首先,让我们定义一个新的坐标系,其中E位于原点,G位于x轴。我们原始坐标系中的x轴方向是:

x = (G - E) / ||G - E||

y轴是:

y = ( x.y, -x.x )

这个新坐标系中E和G的坐标是:

E* = (0, 0)
G* = (0, ||G - E||)

现在,我们可以很容易地在这个坐标系中找到H的坐标,直到前面提到的模糊度。我将在维基百科文章中使用的符号中缩写||G - E|| = d

H.x* = (magGH * magGH - magEH * magEH + d * d) / (2 * d)
H.y* = +- sqrt(magGH * magGH - H.x* * H.x*)

因此,我们有H.y的两个解决方案,一个正面和一个负面。

最后,我们只需要将H转换回原始坐标系:

H = x * H.x* + y * H.y* - (0, magOE)

给定H的坐标,计算角度非常简单:

alpha = arccos((H.x - G.x) / ||H - G||)
beta  = arccos((H.y - E.y) / ||H - E||)

从你的例子中取出值

magOG = 3
magOE = 4
magGH = 3
magEH = 2
angleGamma = 82.74°

我们先得到:

E = (0, -4)
G = 3 * ( -sin(82.74°), -cos(82.74°) )
  = (-2.976, -0.379)

我们的坐标系:

x =( - 0.635,0.773)y =(0.773,0.635)

在这个坐标系中:

E* = (0, 0)
G* = (0, 4.687)

然后,我们的辅助坐标系中的H的坐标是:

H* = (2.877, +- 0.851)

我只关注H * .y的正值,因为这是你在草图中标记的点。

转换回原始坐标系:

H = (-1.169, -1.237)

最后计算角度:

alpha = 25.41°
beta  = 22.94°

与您的值略有差异可能是由于舍入错误(无论是在我的计算中还是在您的计算中)。

© www.soinside.com 2019 - 2024. All rights reserved.