You pick one corner of the rectangle as the origin. The two edges connected to it will be the basis (u
and v
, which should be perpendicular to each other). You would need to normalize them first.
Subtract the origin from the coordinates and calculate the dot-product with the scaling vector (u
), and with the other vector (v
). This would give you how much u
and v
contributes to the coordinate.
Then you scale the component you want. To get the final coordinate, you just multiply the the (now scaled) components with their respective vector, and add them together.
For example:
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
is u
, but with flipped coordinates, and one of them negated)
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>
As you maybe can see, they have moved towards the line (8,0)
-(9,4)
, since we scaled by 0.5, with (0,8)
as the origin.
Edit: This turned out to be a little harder to explain than I anticipated.
In python code, it could look something like this:
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)]