AS3:沿两个圆的公切线绘制一条直线

3

是舞台上的两个圆形,circ1和circ2。circ1半径为60,circ2半径为30。

在播放过程中,circ2可以被拖动到舞台周围。

我想要的是用它们共同的外切线将这两个圆连接起来。这是为了将旧海报变成一个交互式的盒子。这里是链接至海报,它可能会帮助你理解我的意思(虽然现在我只关注两个圆形)。

问题:我知道如何用笔纸找到公共切线,但一旦试图用Flash理解如何实现它,我的大脑就会崩溃。我不知道如何使用ActionScript来实现这一点。

我尝试过的方法:我四处寻找,这是我能找到的最接近的东西,它提供了我想要实现的功能(示例应用程序可在页面底部下载)。唯一的区别是这包括内部切线,而我不需要。

不幸的是,这个源代码是用Java编写的,尽管我已经尽力了,但我还不足以将它转换为AS3。

到目前为止,我自己所能做的只是定义每个圆的中心点,并意识到我无法让Flash解决变量方程。然后我花了几个小时在Google上搜索,试图弄清楚接下来该怎么做。

任何帮助将不胜感激,这是一个本周末截止的学校项目。我可能咬了比我更大的口,但现在太晚回头了。

提前致谢!


1
手动计算并不难,但如果你决定转换Java代码,至少发布你现在拥有的部分以及你卡住的地方。 - Blender
可能有4条不同的线可以连接您所描述的圆——2条在两侧(如海报所示),另外两条则从第一个圆的一侧到另一个圆的另一侧。您想要知道它们全部,还是只想要没有交叉的那些? - Rody Oldenhuis
这里有一个交互式图表,可以轻松转换为代码:http://www.cut-the-knot.org/Curriculum/Geometry/TangentTwoCirclesI.shtml - Markus Jarderot
2个回答

6
function DrawTangents(p1 : Point, r1 : Number, p2 : Point, r2 : Number) : void {
    var dx = p2.x - p1.x;
    var dy = p2.y - p1.y;
    var dist = Math.sqrt(dx*dx + dy*dy);

    this.graphics.drawCircle(p1.x, p1.y, r1);
    this.graphics.drawCircle(p2.x, p2.y, r2);

    if (dist <= Math.abs(r2 - r1)) {
        // The circles are coinciding. There are no valid tangents.
        return;
    }

    // Rotation from the x-axis.
    var angle1 = Math.atan2(dy, dx);

    // Relative angle of the normals. This is equal for both circles.
    var angle2 = Math.acos((r1 - r2)/dist);

    this.graphics.moveTo(p1.x + r1 * Math.cos(angle1 + angle2),
                         p1.y + r1 * Math.sin(angle1 + angle2));
    this.graphics.lineTo(p2.x + r2 * Math.cos(angle1 + angle2),
                         p2.y + r2 * Math.sin(angle1 + angle2));

    this.graphics.moveTo(p1.x + r1 * Math.cos(angle1 - angle2),
                         p1.y + r1 * Math.sin(angle1 - angle2));
    this.graphics.lineTo(p2.x + r2 * Math.cos(angle1 - angle2),
                         p2.y + r2 * Math.sin(angle1 - angle2));
}

谢谢,我在我的最终产品中使用了你的一些代码(例如重叠圆检测)。 - user1610980

3

这里有一份能够实现你描述的两个圆的工作代码 - 假设这两个圆是相同大小的。否则,这只是一个近似值,因为它假设切点将位于与连接圆心的线垂直的线上。

var point1 : Point = new Point(100, 100);
var point2 : Point = new Point(300, 50);
var radius1 : int = 60;
var radius2 : int = 30;

// if you draw a line from the first circle origo to
// the second origo, this is the angle of that line
var ang : Number = Math.atan2(point2.y - point1.y, point2.x - point1.x);

// find the first point on the circumference that is orthogonal
// to the line intersecting the two circle origos
var start1 : Point = new Point(point1.x + Math.cos(ang + Math.PI / 2) * radius1, 
                               point1.y + Math.sin(ang + Math.PI/2)* radius1);
var end1 : Point = new Point(point2.x + Math.cos(ang + Math.PI / 2) * radius2, 
                             point2.y + Math.sin(ang + Math.PI/2)* radius2);

// find the second point on the circumference that is orthogonal
// to the line intersecting the two circle origos
var start2 : Point = new Point(point1.x + Math.cos(ang - Math.PI / 2) * radius1, 
                               point1.y + Math.sin(ang - Math.PI/2)* radius1);
var end2 : Point = new Point(point2.x + Math.cos(ang - Math.PI / 2) * radius2,
                             point2.y + Math.sin(ang - Math.PI/2)* radius2);

// draw everything on the stage
this.graphics.lineStyle(1, 0x0);
this.graphics.drawCircle(point1.x, point1.y, radius1);
this.graphics.drawCircle(point2.x, point2.y, radius2);

this.graphics.moveTo(start1.x, start1.y);
this.graphics.lineTo(end1.x, end1.y);

this.graphics.moveTo(start2.x, start2.y);
this.graphics.lineTo(end2.x, end2.y);

这个完美地运作了,唯一我能够要求的就是将它放进一个函数里,但这对我来说很容易处理。谢谢! - user1610980

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