UnitSquareToQuadrilateral:
PUBLIC PROC [p1, p2, p3, p4: Pair]
RETURNS [Matrix] ~ {
We wish to solve for N, the 3 by 3 perspective matrix that transforms a unit square,
{S0, S1, S2, S3}) to an arbitrary quadrilateral, {P0, P1, P2, P3}. Thus,
[Artwork node; type 'Artwork on' to command tool]
S is given by: {[0, 0, 1], [0, 1, 1], [1, 1, 1], [1, 0, 1]}; since the transform is homogeneous,
P is given by {[x1w, y1w, w], [x2w, y2w, w], [x3w, y3w, w], [x4w, y4w, w]}:
[Artwork node; type 'Artwork on' to command tool]
N is derived from the system of equations that result from the above.
Since N is homogeneous, it can be scaled arbitrarily; in particular, we can set N22 = 1.
For example, using P1, we obtain three equations:
(0, 0, 1) . (N00, N10, N20) = x1w, or N20 = x1w.
(0, 0, 1) . (N01, N11, N21) = y1w, or N21 = y1w.
(0, 0, 1) . (N02, N12, N22) = w, or N22 = w = 1.
These three simplify to:
N20 = x1 and N21 = y1.
The remaining six equations are obtained similarly. Cf. Heckbert, CG&A, Nov. 1986.
Det2:
PROC [a, b, c, d:
REAL]
RETURNS [
REAL] ~
INLINE {
RETURN[a*d-b*c]};
x0: REAL ¬ p1.x;
y0: REAL ¬ p1.y;
x1: REAL ¬ p2.x;
y1: REAL ¬ p2.y;
x2: REAL ¬ p3.x;
y2: REAL ¬ p3.y;
x3: REAL ¬ p4.x;
y3: REAL ¬ p4.y;
px: REAL ¬ x0-x1+x2-x3;
py: REAL ¬ y0-y1+y2-y3;
IF RealFns.AlmostZero[px, -21]
AND RealFns.AlmostZero[py, -21]
THEN RETURN[[[x2-x1, y2-y1, 0.0], [x1-x0, y1-y0, 0.0], [x0, y0, 1.0]]] -- affine
ELSE {
-- perspective
dx1: REAL ¬ x3-x2;
dx2: REAL ¬ x1-x2;
dy1: REAL ¬ y3-y2;
dy2: REAL ¬ y1-y2;
del: REAL ¬ Det2[dx1, dx2, dy1, dy2];
a, b, c, d, e, f, g, h: REAL;
IF del = 0.0 THEN ERROR; -- should be Error["Degenerate quadrilateral"]
Compute matrix: |a d g|
|b e h|
|c f 1|
g ¬ Det2[px, dx2, py, dy2]/del;
g ← Det2[px, dx2, dy1, dy2]/del;
h ¬ Det2[dx1, px, dy1, py]/del;
a ¬ x3-x0+g*x3;
b ¬ x1-x0+h*x1;
c ¬ x0;
d ¬ y3-y0+g*y3;
e ¬ y1-y0+h*y1;
f ¬ y0;
RETURN[[[a, d, g], [b, e, h], [c, f, 1.0]]];
};
};
QuadrilateralToRectangle:
PUBLIC PROC [p1, p2, p3, p4: Pair, rectangle: Rectangle]
RETURNS [transform: Matrix]
~ {
transform ¬ UnitSquareToQuadrilateral[p1, p2, p3, p4];
transform ¬ Invert[transform];
transform ¬ Scale[transform, [rectangle.w, rectangle.h]];
transform ¬ Translate[transform, [rectangle.x, rectangle.y]];
};