blob: be13bc6c82ca6f66ed23447b4c506c2912a86ed9 [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"
"gonum.org/v1/gonum/floats/scalar"
"gonum.org/v1/gonum/num/dualcmplx"
)
// point is a 2-dimensional point/vector.
type point struct {
x, y float64
}
// raise raises the dimensionality of a point to a complex.
func raise(p point) complex128 {
return complex(p.x, p.y)
}
// 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 dual complex numbers.
// The transformations 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 := dualcmplx.Abs(by[i]); 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(dualcmplx.Mul(z, raiseDual(p)), dualcmplx.Conj(z))
// Extract the point.
return point{x: real(pp.Dual), y: imag(pp.Dual)}
}
func Example() {
// Translate a 1×1 square by [3, 4] and rotate it 90° around the
// origin.
fmt.Println("square:")
// Construct a displacement.
displace := dualcmplx.Number{
Real: 1,
Dual: 0.5 * raise(point{3, 4}),
}
// Construct a rotation.
alpha := math.Pi / 2
rotate := dualcmplx.Number{Real: complex(math.Cos(alpha/2), math.Sin(alpha/2))}
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, rotate,
)
// Clean up floating point error for clarity.
pp.x = scalar.Round(pp.x, 2)
pp.y = scalar.Round(pp.y, 2)
fmt.Printf(" %d %+v -> %+v\n", i, p, pp)
}
// Rotate a line segment 90° around its lower end [2, 2].
fmt.Println("\nline segment:")
// Construct a displacement to the origin from the lower end...
origin := dualcmplx.Number{
Real: 1,
Dual: 0.5 * raise(point{-2, -2}),
}
// ... and back from the origin to the lower end.
replace := dualcmplx.Number{
Real: 1,
Dual: -origin.Dual,
}
for i, p := range []point{
{x: 2, y: 2},
{x: 2, y: 3},
} {
pp := transform(p,
origin, // Displace to origin.
rotate, // Rotate around axis.
replace, // Displace back to original location.
)
// Clean up floating point error for clarity.
pp.x = scalar.Round(pp.x, 2)
pp.y = scalar.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}
}