如何在两点之间相对地缩放某个对象?

2024-04-28 06:58:59 发布

您现在位置:Python中文网/ 问答频道 /正文

这更像是一道数学题,我似乎在网上找不到答案。在

所以我要做的是:

假设我有一个圆,从Ay开始。现在,当这个圆朝By移动时,我希望它按一定的比例缩放。在

例如,如果圆在Ay处的直径是5,那么我如何在它到达By时将其缩放到52.2。在

enter image description here

还有另外一个问题:我能用正方形来达到同样的效果吗?在


Tags: 答案by比例效果直径正方形ay数学题
3条回答

在位置上有点小

关键帧和关键帧

在动画中,我们将已知的位置和状态定义为关键帧,通常我们根据时间索引关键帧。在

// an array of keys. The ? represents the applicable number value
var keys = [{ 
         time : 0, // the state of an object at time 0
         pos : {x : ? , y : ? }, // position
         scale : ?,
         rotation : ?,
         colour : [?,?,?],       // rgb colour, just for the hell of it
         // and whatever else you may want to animate
     },{
         time : 100, // the state of the object at time 100
         pos : {x : ? , y : ? },
         scale : ?,
         rotation : ?,
         colour : [?,?,?],
         // and whatever else you may want to animate
     }
]

标准化时间

为了在关键帧之间的任何时间t获得对象的状态,我们找到时间之间的标准化时间(从0到1的值),然后乘以其他状态之间的差,然后将其添加到开始状态。在

假设时间是50,首先我们得到标准化时间

^{pr2}$

现在你有了标准化的时间,你可以很容易地计算出任何状态

var scaleDif =  keys[1].scale - keys[0].scale; // get diff in scale
var scaleChange = scaleDif * normTime;  // multiply by the normalised time
var currentScale = keys[0].scale + scaleChange; // add to the starting scale

这是有点冗长,但这是为了让你进入正在发生的事情。完整的键控功能看起来像。在

function tweenKeys(time,key1,key2){
    var nt = (time - key1.time) / (key2.time - key1.time); // get normalised time
    // because you can not divide by zero we need a little check. Javascript return infinity if we div by zero but we want the value 0 
    nt = nt < Infinity ? nt : 0; // zero if there was a divide by zero
    var ck = {}; // ck for current key. the key represents the state at time
    ck.scale = key1.scale + (key2.scale - key1.scale) * nt;
    ck.rotation = key1.rotation + (key2.rotation - key1.rotation ) * nt;
    ck.pos.x = key1.pos.x + (key2.pos.x- key1.pos.x) * nt;
    ck.pos.y = key1.pos.y + (key2.pos.y- key1.pos.y) * nt;
    ck.colour[0] = key1.colour[0] + (key2.colour[0] - key1.colour[0]) * nt;
    ck.colour[1] = key1.colour[1] + (key2.colour[1] - key1.colour[1]) * nt;
    ck.colour[2] = key1.colour[2] + (key2.colour[2] - key1.colour[2]) * nt;
    return ck; // return the newly create state
}

这是关键帧的基础,您可以在这个答案中找到更多关于它的内容How would I animate... ?

在空间而不是时间上

一切都好,但对你的问题这没有帮助,你没有使用时间你正在使用位置来确定对象的当前状态。不管我们用什么来找到我们的当前状态,关键帧中的任何一个值都可以用来确定其他所有的状态。我们所要做的就是找到标准化的差异,然后像我们对所有其他值进行归一化处理一样,将其应用于所有其他值。在

标准化位置

我们来看看位置

考虑两点p1和p2,定义为

var p1 = {x : ?, y : ?}; // ? represent some number value
var p2 = {x : ?, y : ?}; // ? represent some number value

代表你的A,B位置

如果我们有第三个C点

var c = {x : ?, y : ?}; // ? represent some number value

在二维平面上的某个地方。我们需要一个公式,当C在p1点时返回0,当C点在p2点时返回1。这将是我们用来获得当前状态的标准化位置。在

因为x和y都需要计算。我们得到从p1到点c的距离,然后除以p1和p2之间的距离。这会给我们想要的价值。我们用毕达格解来求距离。平方根和

var dist = Math.sqrt( Math.pow( p2.x - p1.x, 2) + Math.pow( p2.y - p1.y, 2)); // for the twisted world of IE users and
var dist = Math.hypot(p2.x - p1.x, p2.y - p1.y); // for all good browsers

所以标准化的距离是

var normDist = Math.hypot(c.x - p1.x, c.y - p1.y) / Math.hypot(p2.x - p1.x, p2.y - p1.y); 
// because you can not divide by zero we need a little check. Javascript returns infinity if we div by zero but we want the value 0 
normDist = normDist < Infinity ? normDist : 0; // zero if there was a divide by zero

然后将它(normDist)应用于所有的键状态。在

var currentScale = (keys[1].scale - keys[0].scale) * normDist + keys[0].scale;

定位问题

好吧,你说谢谢,对不起,但这不是解决办法,如果你知道c点总是在p1,p2之间的直线上,那就不一定了,在严格的检查下,它几乎永远不会是因为计算机存储数字信息,所以在任何需要非常精细的细节的计算中都会有一点误差。同样,对于距离p1的p2的任何点,上面的方法将返回1作为标准化距离,它描述了一个围绕点p1的圆。我们需要进一步限制这个值。另外,如果c在点p1之前或者在点p2之后,就很容易知道了。因此,我们可以使用下面的方法。在

// get the unit distance on the line p1,p2 of point c representing 
// the distance along the line that is closest to c
function unitDistOfPoint(p1,p2,c){
    var v1 = {}; // working vectors
    var v2 = {}; 
    v1.x = p2.x - p1.x; // vector between p1,p2
    v1.y = p2.y - p1.y;
    v2.x = c.x - p1.x;  // vector to c from p1
    v2.y = c.y - p1.y;
    // a little math magic. Divide the dot product of the vectors v2, v1
    // by the square of line length
    return (v2.x * v1.x + v2.y * v1.y) / (v1.y * v1.y + v1.x * v1.x);
}

现在我们可以做吐温,得到你的秤

// return the state for a object at point c in terms of key1, to key2
function tweenKeysViaPos(c,key1,key2){
    // get the normalised distance of the point c between keys 1 and 2
    var nd = unitDistOfPoint(c, key1.pos, key2.pos); // nd for normalised distance
    // you may want to constrain the position to only between the points 
    // do that by clamping the value nd between 0 and 1 inclusive
    nd = Math.max(0, Math.min(1, nd)); // clamp the normalise distance
    var ck = {}; // ck for current key. the key represents the state at time
    ck.scale = key1.scale + (key2.scale - key1.scale) * nt;
    ck.rotation = key1.rotation + (key2.rotation - key1.rotation ) * nt;
    ck.pos.x = key1.pos.x + (key2.pos.x- key1.pos.x) * nt;
    ck.pos.y = key1.pos.y + (key2.pos.y- key1.pos.y) * nt;
    ck.colour[0] = key1.colour[0] + (key2.colour[0] - key1.colour[0]) * nt;
    ck.colour[1] = key1.colour[1] + (key2.colour[1] - key1.colour[1]) * nt;
    ck.colour[2] = key1.colour[2] + (key2.colour[2] - key1.colour[2]) * nt;
    return ck; // return the newly create state
}

这就是答案。如果偏离了c键的位置,那么它也应该远离c键的位置。在

如有需要,可获取更多信息

您可能需要扩展此选项以适应许多关键帧。在比第一帧更容易找到关键帧的地方。但是如果你用这个位置来计算你在哪一个键,这就不那么简单了。一个复杂的函数可以帮助你找到更方便的解决方案

// returns the distance point c is from the line p1,p2. If on the line
// the the return value is 0. If befor point p1 or after p2 then the distance
// is the distance to p1, or p2 respectively
function distFromLine(p1,p2,c){
    var v1 = {}; // working vectors
    var v2 = {}; 
    v1.x = p2.x - p1.x; // vector between p1,p2
    v1.y = p2.y - p1.y;
    v2.x = c.x - p1.x;  // vector to c from p1
    v2.y = c.y - p1.y;
    // a little math magic. Divide the dot product of the vectors v2, v1
    // by the square of line length
    var u = (v2.x * v1.x + v2.y * v1.y) / (v1.y * v1.y + v1.x * v1.x);
    var v3 = {};
    if(u < 0){ // befor the start
        return Math.hypot(v2.x,v2.y); // distance to p1
    }
    if(u > 1){ // after end
        return Math.hypot(c.x - p2.x,c.y p2.y); // distance to p2
    }
    // get the point on the line that is closest
    v3.x = p1.x + v1.x * u;
    v3.y = p1.y + v1.y * u;
    // return the distance from that point to c
    return Math.hypot(c.x - v3.x,c.y - v3.y); // distance from line of c
}

然后,您可以通过查找从它们之间的直线返回最小距离的键来找到所需的两个键。然后通过定义许多关键帧来定义一条复杂的线,并且无论你把一个对象放在哪里,你都可以计算出它应该在哪里,处于什么状态。在

希望这对你有帮助,不要太过分。如果任何人不清楚,请在评论中说出来,我会澄清的。在

对于线性缩放,如果

  • D[Ay]是圆/正方形在Ay处的直径/边
  • D[By]是圆/正方形在By处的直径/边
  • D[Cy]是圆/正方形在Cy处的直径/边
  • Ay <= Cy <= By

那么

D[Cy] = D[Ay] + (Cy - Ay) * (D[By] - D[Ay]) / (By - Ay)

如果向量v=(By-Ay),那么Ay和{}之间的线可以定义为l(t)=Ay+vt。因此,l(t)上带有参数t的任何点都具有s=47.5t+5的缩放因子。例如,在t=0处,这条直线上的点Ay具有缩放因子s=5。如果你把t=1放进去,你就可以通过并缩放s= 52.5。对于你的附加问题,比例因子是相同的,但你不能简单地乘以比例因子中的正方形坐标。您需要使用l(t)将正方形平移到原点,并缩放坐标并将其转换回l(t)。在

相关问题 更多 >