Your implementation of the math is correct. The culprit in this case is the notorious mismatch between the "up" direction of the y-axis between mathematics and many graphics utilities; this affects the "clockwise" assumption of the mathematical formulation in the article.
In your implementation you define the quadrants like this:
const quadrants = [
[-1, -1], // TL
[1, -1], // TR
[1, 1], // BR
[-1, 1], // BL
]
This indeed renders the vertices in clockwise orientation, but results in counter-clockwise computation mathematically.
Replacing that with the following definition:
const quadrants = [
[-1, -1],
[-1, 1],
[1, 1],
[1, -1],
]
Results in proper solutions (albeit counter-clockwise rendering of the vertices and shifted correspondences between the "fitted" square and the original vertices).
(An alternative solution is to re-derive the math in a "down is y-positive" system but that's probably an overkill.)
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…