96 lines
3.0 KiB
Go
96 lines
3.0 KiB
Go
package common
|
|
|
|
type PerspectiveTransform struct {
|
|
a11, a21, a31 float64
|
|
a12, a22, a32 float64
|
|
a13, a23, a33 float64
|
|
}
|
|
|
|
func PerspectiveTransform_QuadrilateralToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3,
|
|
x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p float64) *PerspectiveTransform {
|
|
|
|
qToS := PerspectiveTransform_QuadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3)
|
|
sToQ := PerspectiveTransform_SquareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p)
|
|
return sToQ.times(qToS)
|
|
}
|
|
|
|
func (p *PerspectiveTransform) TransformPoints(points []float64) {
|
|
maxI := len(points) - 1 // points.length must be even
|
|
for i := 0; i < maxI; i += 2 {
|
|
x := points[i]
|
|
y := points[i+1]
|
|
denominator := p.a13*x + p.a23*y + p.a33
|
|
points[i] = (p.a11*x + p.a21*y + p.a31) / denominator
|
|
points[i+1] = (p.a12*x + p.a22*y + p.a32) / denominator
|
|
}
|
|
}
|
|
|
|
func (p *PerspectiveTransform) TransformPointsXY(xValues, yValues []float64) {
|
|
n := len(xValues)
|
|
for i := 0; i < n; i++ {
|
|
x := xValues[i]
|
|
y := yValues[i]
|
|
denominator := p.a13*x + p.a23*y + p.a33
|
|
xValues[i] = (p.a11*x + p.a21*y + p.a31) / denominator
|
|
yValues[i] = (p.a12*x + p.a22*y + p.a32) / denominator
|
|
}
|
|
}
|
|
|
|
func PerspectiveTransform_SquareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3 float64) *PerspectiveTransform {
|
|
dx3 := x0 - x1 + x2 - x3
|
|
dy3 := y0 - y1 + y2 - y3
|
|
if dx3 == 0.0 && dy3 == 0.0 {
|
|
// Affine
|
|
return &PerspectiveTransform{
|
|
x1 - x0, x2 - x1, x0,
|
|
y1 - y0, y2 - y1, y0,
|
|
0.0, 0.0, 1.0}
|
|
} else {
|
|
dx1 := x1 - x2
|
|
dx2 := x3 - x2
|
|
dy1 := y1 - y2
|
|
dy2 := y3 - y2
|
|
denominator := dx1*dy2 - dx2*dy1
|
|
a13 := (dx3*dy2 - dx2*dy3) / denominator
|
|
a23 := (dx1*dy3 - dx3*dy1) / denominator
|
|
return &PerspectiveTransform{
|
|
x1 - x0 + a13*x1, x3 - x0 + a23*x3, x0,
|
|
y1 - y0 + a13*y1, y3 - y0 + a23*y3, y0,
|
|
a13, a23, 1.0}
|
|
}
|
|
}
|
|
|
|
func PerspectiveTransform_QuadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3 float64) *PerspectiveTransform {
|
|
// Here, the adjoint serves as the inverse:
|
|
return PerspectiveTransform_SquareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3).buildAdjoint()
|
|
}
|
|
|
|
func (p *PerspectiveTransform) buildAdjoint() *PerspectiveTransform {
|
|
// Adjoint is the transpose of the cofactor matrix:
|
|
return &PerspectiveTransform{
|
|
p.a22*p.a33 - p.a23*p.a32,
|
|
p.a23*p.a31 - p.a21*p.a33,
|
|
p.a21*p.a32 - p.a22*p.a31,
|
|
p.a13*p.a32 - p.a12*p.a33,
|
|
p.a11*p.a33 - p.a13*p.a31,
|
|
p.a12*p.a31 - p.a11*p.a32,
|
|
p.a12*p.a23 - p.a13*p.a22,
|
|
p.a13*p.a21 - p.a11*p.a23,
|
|
p.a11*p.a22 - p.a12*p.a21,
|
|
}
|
|
}
|
|
|
|
func (p *PerspectiveTransform) times(other *PerspectiveTransform) *PerspectiveTransform {
|
|
return &PerspectiveTransform{
|
|
p.a11*other.a11 + p.a21*other.a12 + p.a31*other.a13,
|
|
p.a11*other.a21 + p.a21*other.a22 + p.a31*other.a23,
|
|
p.a11*other.a31 + p.a21*other.a32 + p.a31*other.a33,
|
|
p.a12*other.a11 + p.a22*other.a12 + p.a32*other.a13,
|
|
p.a12*other.a21 + p.a22*other.a22 + p.a32*other.a23,
|
|
p.a12*other.a31 + p.a22*other.a32 + p.a32*other.a33,
|
|
p.a13*other.a11 + p.a23*other.a12 + p.a33*other.a13,
|
|
p.a13*other.a21 + p.a23*other.a22 + p.a33*other.a23,
|
|
p.a13*other.a31 + p.a23*other.a32 + p.a33*other.a33,
|
|
}
|
|
}
|