blob: d56b301feb7b44eb1f42ae96ad3cc174147f1587 [file] [log] [blame]
// Copyright ©2018 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package dualcmplx_test
import (
"fmt"
"math"
"math/cmplx"
"gonum.org/v1/gonum/floats"
"gonum.org/v1/gonum/num/dualcmplx"
)
// point is a 2-dimensional point/vector.
type point struct {
x, y float64
}
// raiseDual raises the dimensionality of a point to a dual complex number.
func raiseDual(p point) dualcmplx.Number {
return dualcmplx.Number{
Real: 1,
Dual: complex(p.x, p.y),
}
}
// transform performs the transformation of p by the given set of dual
// complex transforms in order. The rotations are normalized to unit
// vectors.
func transform(p point, by ...dualcmplx.Number) point {
if len(by) == 0 {
return p
}
// Ensure the modulus of by is correctly scaled.
for i := range by {
if len := cmplx.Abs(by[i].Real); len != 1 {
by[i].Real *= complex(1/len, 0)
}
}
// Perform the transformations.
z := by[0]
for _, o := range by[1:] {
z = dualcmplx.Mul(o, z)
}
pp := dualcmplx.Mul(z, raiseDual(p))
// Extract the point.
return point{x: real(pp.Dual), y: imag(pp.Dual)}
}
func Example() {
// Translate a 1×1 square [3, 4] and rotate it 90° around the
// origin.
fmt.Println("square:")
for i, p := range []point{
{x: 0, y: 0},
{x: 0, y: 1},
{x: 1, y: 0},
{x: 1, y: 1},
} {
pp := transform(p,
// Displace.
raiseDual(point{3, 4}),
// Rotate.
dualcmplx.Number{Real: complex(math.Cos(math.Pi/2), math.Sin(math.Pi/2))},
)
// Clean up floating point error for clarity.
pp.x = floats.Round(pp.x, 2)
pp.y = floats.Round(pp.y, 2)
fmt.Printf(" %d %+v -> %+v\n", i, p, pp)
}
// Rotate a line segment 90° around its lower end.
fmt.Println("\nline segment:")
// Offset to origin from lower end.
off := raiseDual(point{-2, -2})
for i, p := range []point{
{x: 2, y: 2},
{x: 2, y: 3},
} {
pp := transform(p,
// Shift origin.
//
// Complex number multiplication is commutative,
// so the offset can be constructed as a single
// dual complex number.
dualcmplx.Mul(off, dualcmplx.ConjDual(dualcmplx.ConjCmplx(off))),
// Rotate.
dualcmplx.Number{Real: complex(math.Cos(math.Pi/2), math.Sin(math.Pi/2))},
)
// Clean up floating point error for clarity.
pp.x = floats.Round(pp.x, 2)
pp.y = floats.Round(pp.y, 2)
fmt.Printf(" %d %+v -> %+v\n", i, p, pp)
}
// Output:
//
// square:
// 0 {x:0 y:0} -> {x:-4 y:3}
// 1 {x:0 y:1} -> {x:-5 y:3}
// 2 {x:1 y:0} -> {x:-4 y:4}
// 3 {x:1 y:1} -> {x:-5 y:4}
//
// line segment:
// 0 {x:2 y:2} -> {x:2 y:2}
// 1 {x:2 y:3} -> {x:1 y:2}
}