如何在两点之间相对缩放? [英] How can I relatively scale something between two points?

查看:108
本文介绍了如何在两点之间相对缩放?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这更多是一个数学问题,我似乎无法在线找到任何答案.

This is more of a math question, and I couldn't seem to find any answers online.

这就是我要完成的事情:

So here is what I am trying to accomplish:

让我说一个圈子,从Ay开始.现在,当这个圆朝着By方向移动时,我希望它按比例缩放到一定大小.

Lets say I have a circle, starting at Ay. Now as this circle moves towards By, I want it to scale proportionally to a certain size.

例如,如果圆的直径在Ay为5,我如何将其缩放到达到By时的52.2.

So for example, if the circle's diameter was 5 at Ay, how could I scale it to become 52.2 by the time it reaches By.

还有奖金问题:我能用正方形实现同样的目的吗?

And bonus question: could I achieve this same thing with a square?

推荐答案

根据位置进行补间.

键和关键帧

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

In animation we define known positions and states as key frames, normally we index the key frames in terms of time.

// 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之间的值),并将其乘以其他状态之间的差,然后将其添加到开始状态

To get the state of an object at any time t between the key frames we find the normalised time ( a value from 0 to 1) between the times and multiply that to the difference between other states then add that to the beginning state.

所以说时间是50,首先我们得到了归一化的时间

So say the time is 50 first we get the normalised time

var currentTime = 50;
var timeDif = currentTime - keys[0].time; // difference from start time to current
// to get the normalised time divid by the differance
var normTime = timeDif / (keys[1].time - keys[0].time); // divide by the differance in time between keys

现在您有了归一化的时间,您可以轻松计算任何状态

Now you have the normalised time you can easily calculate any of the states

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

这有点长,但这是为了使您轻松了解正在发生的事情.完整的抠像功能看起来像这样.

That is all a little long winded but that is to ease you into what is happening. the complete keying function would look like.

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
}

那是关键帧的基础,您可以在此答案中找到更多信息我该如何动画...?

Thats the basics of keyframing and you can find more on it in this answer How would I animate... ?

空间而不是时间

一切都很好,但是对于您的问题,这并没有帮助,您没有花时间使用位置来确定对象的当前状态.那么,使用什么来查找当前状态并不重要,关键帧中的任何值都可以用来确定所有其他状态.我们需要做的就是找到归一化的差异,然后像对待归一化的时间一样将其应用于所有其他值.

All good but for your problem this has not helped, you are not using time you are using position to determine the current state of the object. Well it does not matter what we use to find our current state, any of the values in the key frame can be used to determine that state of all the others. All we need to do is find the normalised difference and then apply that like we did normalised time to all the other values.

归一化职位

所以让我们看看位置

考虑两个点p1和p2,定义为

Consider two points p1 and p2, defined as

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

并代表您的位置A,B

And representing your positions A,B

如果我们有第三点C

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

在2D平面上的某个位置.我们想要一个公式,当C在点p1时将返回0,而当点c在点p2时将返回1.这将是我们用来获取当前状态的归一化位置.

somewhere on the 2D plane. We want a formula that will return a 0 when C is at point p1 and 1 when the point c is at point p2. This will be our normalised position used to get the current state.

位置为2d时,我们需要在计算中同时包含x和y.我们得到从p1到点c的距离,并将其除以点p1和p2之间的距离.那会给我们我们想要的价值.为了找到距离,我们使用了pythag解决方案.平方和的根

As position is 2d we need to involve both the x and y in the calculations. We get the distance from p1 to point c and the divide that by the distance between point p1 and p2. that will give us the value we want. To find the distance we use the pythag solution. root of the sum of the squares

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)应用于所有关键状态.

Then apply that (normDist) to all the key states.

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

定位问题

好吧,您说谢谢,对不起,但这不是解决方案,那就是如果您知道点c始终位于p1,p2之间的直线上,但并非总是如此,在严格的检查下几乎不会因为计算机存储数字信息,所以在任何需要非常详细的信息的计算中都会出现一点错误.同样,上述方法对于距离p1到p2的任何点的归一化距离将返回1,该点描述了围绕p1的圆.我们需要进一步限制该值.同样,如果c是在点p1之前或在点p2之后,则将很容易知道.因此,我们可以使用以下方法来做到这一点.

Ok you say thanks, sorry but that is not the solution, it would be if you knew that the point c is always on the line between p1, p2 but that is not always the case, and under a strict examination it is hardly ever because computers store digital information so there will be a little error in any calculation that requires very fine detail. Also the above method will return 1 for normalized distance for any point that is distance to p2 away from p1, that describes a circle around the point p1. We need to constrain this value a bit more. Also if c is befor the point p1 or after the point p2 it would be handy to know. Thus we can use the following to do so.

// 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);
}

现在我们可以进行补间并获得缩放比例

Now we can do the tweening and get your scale

// 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确实偏离了键之间的线,则上述函数还会返回其应有的位置.

That is the answer. As a side benefit if the point c does stray away from the line between the keys then the above function also return the position it should be.

需要的话更多

您可能需要扩展它以适应许多关键帧.通常,对于两个以上的关键帧并使用时间,可以通过找到时间大于第一个关键点且小于下一个关键点的位置来轻松找到我们想要的关键点.但这并不是那么简单,如果您要使用该位置来计算出您所处的位置.因此,为寻求更复杂的解决方案,您会发现此功能很方便

You may want to extend this to adapt to many key frames. Normally for more than two key frames and using time it is easy to find the keys that we want by finding where time is greater than the first key and less than the next key. But this is not as simple if you are using the position to work out at which key you are at. So to help a more complex solution you will find this function handy

// 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
}

然后,您可以找到两个键之间的距离最小的键,从而找到所需的两个键.然后,您可以通过定义许多关键帧来定义一条复杂的线,并且无论将对象放置在何处,都可以计算出对象应该在什么位置以及处于什么状态.

You can then find the two keys you need by finding the keys that return the smallest distance from the line between them. You and then define a complicated line by defining many key frames and where ever you put an object you can calculate where it should be and in what state.

希望这会有所帮助,并且不会超出顶部.如果有任何不清楚的地方,请在评论中注明,我将予以澄清.

Hope this helps and did not go over the top. If anything is unclear to anyone that reads please do say so in the comments and I will clarify.

这篇关于如何在两点之间相对缩放?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆