代码之家  ›  专栏  ›  技术社区  ›  deblocker

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

  •  2
  • deblocker  · 技术社区  · 8 年前

    我有两个向量,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);
    

    从现在开始,我想 angleAlpha angleBeta 价值观 angleGamma 小于90度。

    约束段的大小:

    HG段和HE段必须满足以下条件:

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

    这将导致以下两种解决方案(如公认的答案-双迭代中所指出的):

    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>
    1 回复  |  直到 8 年前
        1
  •  3
  •   Nico Schertler    8 年前

    根据你的草图,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°
    

    您的值的微小差异可能是由舍入误差(在我的计算中或在您的计算中)引起的。