我怎样才能相对地缩放两点之间的东西?
How can I relatively scale something between two points?
这更像是一道数学题,我似乎无法在网上找到任何答案。
所以这就是我想要完成的事情:
假设我有一个圆圈,从 Ay
开始。现在随着这个圆圈向 By
移动,我希望它按比例缩放到一定大小。
因此,例如,如果圆的直径在 Ay
处为 5,那么当它达到 By
.
时,我如何将其缩放为 52.2
还有一个额外的问题:我可以用正方形实现同样的效果吗?
如果向量v=(By-Ay)
,Ay
和By
之间的直线可以定义为l(t)=Ay+vt
。因此 l(t)
上带有参数 t
的任何点的比例因子为 s=47.5t+5
。例如,在 t=0 时,直线上的点 Ay
具有比例因子 s=5
。如果你输入 t=1
,你会得到 By and scale s= 52.5
。对于您的奖励问题,比例因子是相同的,但您不能简单地将正方形的坐标乘以比例因子。您需要使用 l(t)
将正方形平移到原点并缩放坐标并将其平移回 l(t)
。
对于线性缩放 if
D[Ay]
是 circle/square 的 diameter/side 当它在 Ay
D[By]
是 circle/square 的 diameter/side 当它在 By
D[Cy]
是 circle/square 的 diameter/side 当它在 Cy
Ay <= Cy <= By
然后
D[Cy] = D[Ay] + (Cy - Ay) * (D[By] - D[Ay]) / (By - Ay)
根据位置补间。
键和关键帧
在动画中我们将已知的位置和状态定义为关键帧,通常我们根据时间对关键帧进行索引。
// 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 首先我们得到归一化时间
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
现在您有了标准化时间,您可以轻松计算任何状态
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
}
这就是关键帧的基础知识,您可以在此答案中找到更多相关信息
在space而不是时间
一切都很好,但对于您的问题这没有帮助,您没有使用时间而是使用位置来确定对象的当前状态。好吧,我们用什么来找到我们的当前状态并不重要,关键帧中的任何值都可以用来确定所有其他帧的状态。我们需要做的就是找到归一化差异,然后像对所有其他值进行归一化时间一样应用它。
归一化位置
所以让我们看看位置
考虑两个点 p1 和 p2,定义为
var p1 = {x : ?, y : ?}; // ? represent some number value
var p2 = {x : ?, y : ?}; // ? represent some number value
并代表你的仓位A,B
如果我们有第 3 个点 C
var c = {x : ?, y : ?}; // ? represent some number value
二维平面上的某处。我们想要一个公式,当 C 位于点 p1 时 return 为 0,当点 c 位于点 p2 时为 1。这将是我们用于获取当前状态的标准化位置。
由于position是2d,我们需要在计算中同时涉及x和y。我们得到从 p1 到点 c 的距离,并将它除以点 p1 和 p2 之间的距离。这会给我们想要的价值。为了找到距离,我们使用 pythag 解决方案。平方和的根
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 之间的线上,但情况并非总是如此,并且在严格检查下几乎从来没有,因为计算机存储数字信息,所以在任何需要非常精细细节的计算中都会有一点错误。此外,上述方法将为距 p2 远离 p1 的任何点的归一化距离 return 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 确实偏离了键之间的线,那么上面的函数也会 return 它应该在的位置。
如果需要更多
您可能希望对其进行扩展以适应许多关键帧。通常对于两个以上的关键帧和使用时间,通过找到时间大于第一个关键帧且小于下一个关键帧的位置,很容易找到我们想要的关键帧。但是,如果您使用位置来确定您所在的键,这就不是那么简单了。因此,为了帮助解决更复杂的问题,您会发现此功能很方便
// 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
}
然后,您可以通过找到距离它们之间的线 return 最小距离的键来找到您需要的两个键。你然后通过定义许多关键帧来定义一条复杂的线,无论你把一个对象放在哪里,你都可以计算它应该在哪里以及处于什么状态。
希望这对您有所帮助,不要过头了。如果任何阅读者不清楚,请在评论中说明,我会澄清。
这更像是一道数学题,我似乎无法在网上找到任何答案。
所以这就是我想要完成的事情:
假设我有一个圆圈,从 Ay
开始。现在随着这个圆圈向 By
移动,我希望它按比例缩放到一定大小。
因此,例如,如果圆的直径在 Ay
处为 5,那么当它达到 By
.
还有一个额外的问题:我可以用正方形实现同样的效果吗?
如果向量v=(By-Ay)
,Ay
和By
之间的直线可以定义为l(t)=Ay+vt
。因此 l(t)
上带有参数 t
的任何点的比例因子为 s=47.5t+5
。例如,在 t=0 时,直线上的点 Ay
具有比例因子 s=5
。如果你输入 t=1
,你会得到 By and scale s= 52.5
。对于您的奖励问题,比例因子是相同的,但您不能简单地将正方形的坐标乘以比例因子。您需要使用 l(t)
将正方形平移到原点并缩放坐标并将其平移回 l(t)
。
对于线性缩放 if
D[Ay]
是 circle/square 的 diameter/side 当它在Ay
D[By]
是 circle/square 的 diameter/side 当它在By
D[Cy]
是 circle/square 的 diameter/side 当它在Cy
Ay <= Cy <= By
然后
D[Cy] = D[Ay] + (Cy - Ay) * (D[By] - D[Ay]) / (By - Ay)
根据位置补间。
键和关键帧
在动画中我们将已知的位置和状态定义为关键帧,通常我们根据时间对关键帧进行索引。
// 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 首先我们得到归一化时间
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
现在您有了标准化时间,您可以轻松计算任何状态
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
}
这就是关键帧的基础知识,您可以在此答案中找到更多相关信息
在space而不是时间
一切都很好,但对于您的问题这没有帮助,您没有使用时间而是使用位置来确定对象的当前状态。好吧,我们用什么来找到我们的当前状态并不重要,关键帧中的任何值都可以用来确定所有其他帧的状态。我们需要做的就是找到归一化差异,然后像对所有其他值进行归一化时间一样应用它。
归一化位置
所以让我们看看位置
考虑两个点 p1 和 p2,定义为
var p1 = {x : ?, y : ?}; // ? represent some number value
var p2 = {x : ?, y : ?}; // ? represent some number value
并代表你的仓位A,B
如果我们有第 3 个点 C
var c = {x : ?, y : ?}; // ? represent some number value
二维平面上的某处。我们想要一个公式,当 C 位于点 p1 时 return 为 0,当点 c 位于点 p2 时为 1。这将是我们用于获取当前状态的标准化位置。
由于position是2d,我们需要在计算中同时涉及x和y。我们得到从 p1 到点 c 的距离,并将它除以点 p1 和 p2 之间的距离。这会给我们想要的价值。为了找到距离,我们使用 pythag 解决方案。平方和的根
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 之间的线上,但情况并非总是如此,并且在严格检查下几乎从来没有,因为计算机存储数字信息,所以在任何需要非常精细细节的计算中都会有一点错误。此外,上述方法将为距 p2 远离 p1 的任何点的归一化距离 return 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 确实偏离了键之间的线,那么上面的函数也会 return 它应该在的位置。
如果需要更多
您可能希望对其进行扩展以适应许多关键帧。通常对于两个以上的关键帧和使用时间,通过找到时间大于第一个关键帧且小于下一个关键帧的位置,很容易找到我们想要的关键帧。但是,如果您使用位置来确定您所在的键,这就不是那么简单了。因此,为了帮助解决更复杂的问题,您会发现此功能很方便
// 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
}
然后,您可以通过找到距离它们之间的线 return 最小距离的键来找到您需要的两个键。你然后通过定义许多关键帧来定义一条复杂的线,无论你把一个对象放在哪里,你都可以计算它应该在哪里以及处于什么状态。
希望这对您有所帮助,不要过头了。如果任何阅读者不清楚,请在评论中说明,我会澄清。