找到一個很好的方法來做到這一點已經困擾了我一段時間:假設我有一個包含一組點的選擇框。通過拖動角可以縮放框中點之間的距離(距離)。現在對於一個軸對齊的框,這很容易。以一個角點作爲定位點(從每個點減去這個角點,對其進行縮放,然後再將其添加到該點),並將每個點x和y乘以框變大的因子。非軸對齊縮放
但現在拿一個不與x和y軸對齊的盒子。當您拖動角落時,如何縮放此框內的點?
找到一個很好的方法來做到這一點已經困擾了我一段時間:假設我有一個包含一組點的選擇框。通過拖動角可以縮放框中點之間的距離(距離)。現在對於一個軸對齊的框,這很容易。以一個角點作爲定位點(從每個點減去這個角點,對其進行縮放,然後再將其添加到該點),並將每個點x和y乘以框變大的因子。非軸對齊縮放
但現在拿一個不與x和y軸對齊的盒子。當您拖動角落時,如何縮放此框內的點?
您選取矩形的一個角落作爲原點。連接到它的兩條邊將作爲基礎(u
和v
,它們應該相互垂直)。您需要先對它們進行標準化。
從座標中減去原點,然後用縮放矢量(u
)和另一個矢量(v
)計算點積。這會給你多少u
和v
貢獻的座標。
然後你縮放你想要的組件。要獲得最終的座標,只需將(現縮放後的)分量與它們各自的向量相乘,然後將它們相加即可。
例如:
Points: p1 = (3,5) and p2 = (6,4)
Selection corners: (0,2),(8,0),(9,4),(1,6)
selected origin = (8,0)
u = ((0,2)-(8,0))/|(0,2)-(8,0)| = <-0.970, 0.242>
v = <-0.242, -0.970>
(v
是u
,但翻轉座標,其中一人否定)
p1´ = p1 - origin = (-5, 5)
p2´ = p2 - origin = (-2, 4)
p1_u = p1´ . u = -0.970 * (-5) + 0.242 * 5 = 6.063
p1_v = p1´ . v = -0.242 * (-5) - 0.970 * 5 = -3.638
Scale p1_u by 0.5: 3.038
p1_u * u + p1_v * v + origin = <5.941, 4.265>
Same for p2: <7.412, 3.647>
正如你或許可以看到,他們已經走向線(8,0)
- (9,4)
,因爲我們縮放了0.5,以(0,8)
作爲原點。
編輯:結果比我預料的有點難以解釋。
在Python代碼,它可能是這個樣子:
def scale(points, origin, u, scale):
# normalize
len_u = (u[0]**2 + u[1]**2) ** 0.5
u = (u[0]/len_u, u[1]/len_u)
# create v
v = (-u[1],u[0])
ret = []
for x,y in points:
# subtract origin
x, y = x - origin[0], y - origin[1]
# calculate dot product
pu = x * u[0] + y * u[1]
pv = x * v[0] + y * v[1]
# scale
pu = pu * scale
# transform back to normal space
x = pu * u[0] + pv * v[0] + origin[0]
y = pu * u[1] + pv * v[1] + origin[1]
ret.append((x,y))
return ret
>>> scale([(3,5),(6,4)],(8,0),(-8,2),0.5)
[(5.9411764705882355, 4.2647058823529411), (7.4117647058823533, 3.6470588235294117)]
任何框都包含在一個圓圈內。
您可以找到綁定框的圓,找到它的中心,並且與軸對齊的框完全相同。
比方說,盒子被定義爲一組的四點(P1,P2,P3和P4)。 爲簡單起見,我們會說你拖着P1,而P3是對面的角落(你用作錨點的那個角落)。我們將鼠標位置標記爲M,並將希望計算的新點標記爲N1,N2和N4。 P3當然會保持不變。
你的縮放因子可以通過矢量減法和矢量點積簡單地計算:
N1 = scale*P1 + (1 - scale)*P3
N2 = scale*P2 + (1 - scale)*P3
N4 = scale*P4 + (1 - scale)*P3
:
scale = ((M - P3) dot (P1 - P3))/((P1 - P3) dot (P1 - P3))
和三個新的點可以用標量乘法和向量加法被發現編輯:我看到MizardX已經回答了這個問題,所以我的答案是在這裏幫助解決這個困難的問題。我希望它有幫助!
編輯:這裏是非比例縮放的算法。在這種情況下,N1是等於M(點被拖動跟隨鼠標),所以感興趣的唯一的點是N2和N4:
N2 = ((M - P3) dot (P2 - P3))/((P2 - P3) dot (P2 - P3)) * (P2 - P3) + P3
N4 = ((M - P3) dot (P4 - P3))/((P4 - P3) dot (P4 - P3)) * (P4 - P3) + P3
其中*代表標量乘法
編輯:這裏有一些C++代碼可以回答這個問題。我相信這個問題現在已經很長時間了,但這是一個有趣的問題,編寫代碼我有一些樂趣。
#include <vector>
class Point
{
public:
float x;
float y;
Point() { x = y = 0; }
Point(float nx, float ny) { x = nx; y = ny; }
};
Point& operator-(Point& A, Point& B) { return Point(A.x-B.x, A.y-B.y); }
Point& operator+(Point& A, Point& B) { return Point(A.x+B.x, A.y+B.y); }
Point& operator*(float sc, Point& P) { return Point(sc*P.x, sc*P.y); }
float dot_product(Point A, Point B) { return A.x*B.x + A.y*B.y; }
struct Rect { Point point[4]; };
void scale_points(Rect box, int anchor, Point mouse, vector<Point> points)
{
Point& P3 = box.point[anchor];
Point& P2 = box.point[(anchor + 1)%4];
Point& P1 = box.point[(anchor + 2)%4];
Point& P4 = box.point[(anchor + 3)%4];
Point A = P4 - P3;
Point aFactor = dot_product(mouse - P3, A)/dot_product(A, A) * A;
Point B = P2 - P3;
Point bFactor = dot_product(mouse - P3, B)/dot_product(B, B) * B;
for (int i = 0; i < points.size(); i++)
{
Point P = points[i] - P3;
points[i] = P3 + dot_product(P, aFactor) + dot_product(P, bFactor);
}
}
優雅和正確 – 2008-12-02 22:25:32
您剛剛用另一個問題替換了一個問題。你如何得到綁定盒子的圓圈? – 2008-12-02 22:28:55