使用JavaScript查找三角形中的第三个点

3

好的,我需要在JavaScript中弄清楚如何在三角形上绘制第三个点。请参见下面的图示。

A和B将是随机点(可能是正数或负数,取决于它们相对于0,0原点的位置)。

因此,A和B是已知点(x和y)。

我已经弄清楚了如何基于A和B绘制C。

我想控制C和D之间的距离。例如,我想说“C和D之间的距离现在是20px…… D在哪里?”

因此,为了举例,我们可以说C和D之间的距离将是20px。这意味着我拥有CD和CB,但没有DB。我还知道C(x,y)和B(x,y)。

现在我需要找到D……我不是一个数学天才,所以请像我五岁那样给我解释一下。我已经多次搜索过谷歌,尝试使用多个示例,但仍然迷失方向……例如:我看到一些涉及phi的方程式……phi是什么?我如何在JavaScript术语中使用phi等等......

总结:

A(x,y) is known (randomized)
B(x,y) is known (randomized)
C(x,y) is known (midpoint of AB)
CB is known (using distance formula)
CD = 20 pixels (or whatever I set it to).
DB = ???
D(x,y) = ???

以下是我目前的翻译,但可能不正确...

var Aeh = {x:50, y:75};
    var Bee = {x:300, y:175};
    var Cee = {x:0, y:0};
    var Dee = {x:0, y:0};

    window.onload = function(){ 
         refreshPoints();
         solveForC();
    } 
    function refreshPoints(){
        TweenLite.set("#pointA", {x:Aeh.x, y:Aeh.y});
        TweenLite.set("#pointB", {x:Bee.x, y:Bee.y});
        TweenLite.set("#pointC", {x:Cee.x, y:Cee.y});
        TweenLite.set("#pointD", {x:Dee.x, y:Dee.y});
    }
    function solveForC() {
        Cee.x = (Bee.x + Aeh.x)/2;
        Cee.y = (Bee.y + Aeh.y)/2;
        refreshPoints();
        solveForD();
    }
    function solveForD() {
        // Dee.x = AB * Cos(Φ) + x_1
        // Dee.y = AB * Sin(Φ) + y_1

        Dee.x = (Cee.x+Bee.x/2) * Math.cos((1 + Math.sqrt(5)) / 2) + Cee.x;
        Dee.y = (Cee.y+Bee.y/2) * Math.sin((1 + Math.sqrt(5)) / 2) + Cee.y;

        refreshPoints();
    }

diagram


你尝试过任何代码吗? - J Shubham
我根据其他人在网上发布的一些方程式尝试了我上面发布的代码。但我并不理解其中的数学原理,所以有点盲目。 - Cmaxster
除非C是AB的中点,否则您需要知道C与A或B之间的距离?此外,我们还需要知道D在AB的哪一侧,否则会有两个解决方案。 - meowgoesthedog
C是中点,所以我可以很容易地找到C和B之间的距离。我想随机将D翻转到任一侧,但我不确定如何操作... 我想我需要两种解决方案...总结:A已知(随机化)B已知(随机化)C = 已知(AB的中点)CB已知CD = 20像素(或我设置的其他值)。DB = ??? - Cmaxster
2个回答

2
你有点A、点B和点C(中点),你知道从点C到点D的距离已经确定(比如设为20),且从点A到点B的直线与从点C到点D的直线垂直。使用这个条件,你可以找到两个满足要求的点D。最简单的方法是计算出从点A到点B的直线的角度,并利用它来帮助计算点D。
var angleAB = Math.atan2(B.y - A.y, B.x - A.x);
// to get the angle of the line from C to D, add 90 degrees
// in radians, that is Math.PI / 2
var angleCD = angleAB + Math.PI / 2;

// now you can calculate one of D's solutions
// the 20 represents your distance from C to D, and can be changed if desired.
DeeOne.x = C.x + 20 * Math.cos(angleCD);
DeeOne.y = C.y + 20 * Math.sin(angleCD);

// a second solution can be found by going in the other direction from C
DeeTwo.x = C.x - 20 * Math.cos(angleCD);
DeeTwo.y = C.x - 20 * Math.sin(angleCD);

如果您只需要从图表中得出某个特定距离等信息,可能有一些方法可以减少计算量。希望这能帮到您。


哇,太感谢了!!!它起作用了...不过我应该注意到Math.atan2返回了“NaN”,但是Math.tan似乎可以工作...这两者之间有重要的区别吗?还是“tan”对我来说可以同样地工作? - Cmaxster
atanatan2基本上是等价的...我认为可能有一些情况(当A和B具有相同的x坐标时),atan2会起作用,但atan会出错。但如果它能工作,那就太好了!如果你想要非常小心,确保在A和B具有相同的x坐标时也能正常工作。 - arbuthnott
3
哦,我刚才发现为什么 atan2 会出问题了。atan 接受一个参数 num / denom,但是 atan2 要求将它们分开输入。所以我应该写成 Math.atan2((B.y - A.y), (B.x - A.x)) 而不是 Math.atan2((B.y - A.y) / (B.x - A.x))。如果可以的话,我会进行编辑... - arbuthnott

0

稍微快一些且更准确的替代方案。

该函数从线段 AB 的中点找到点 dist

如果 left = 1(默认),则 D 在线段 AB 左侧,否则 D 在右侧。

function findD(A, B, dist, left = 1){ // if left = 1 the D is left of the line AB 
    const nx = B.x - A.x;
    const ny = B.y - A.y;
    dist /= Math.sqrt(nx * nx + ny * ny) * left;
    return {
        x : A.x + nx / 2 - ny * dist, 
        y : A.y + ny / 2 + nx * dist
    }
}

你可能会想用Math.hypot(nx,ny)替换掉Math.sqrt(nx * nx + ny * ny)来节省2次乘法和1次加法,但是hypot的速度非常慢,使用sqrt函数的计算速度为每秒1000万次,而使用hypot后,计算速度降至200万次。我还测试了另一个答案(优化过的),其峰值解决方案速度为每秒340万个。
对于JavaScript来说,使用atan2sincos并不是很大的问题,因为64位双精度浮点数使得这些函数引入的误差在范围内大约为±1e-14*最长边长。但是如果避免使用这些函数,误差可以减小一点。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接