gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

vector.go (4603B)


      1 // Copyright 2014 Google Inc. All rights reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package r3
     16 
     17 import (
     18 	"fmt"
     19 	"math"
     20 
     21 	"github.com/golang/geo/s1"
     22 )
     23 
     24 // Vector represents a point in ℝ³.
     25 type Vector struct {
     26 	X, Y, Z float64
     27 }
     28 
     29 // ApproxEqual reports whether v and ov are equal within a small epsilon.
     30 func (v Vector) ApproxEqual(ov Vector) bool {
     31 	const epsilon = 1e-16
     32 	return math.Abs(v.X-ov.X) < epsilon && math.Abs(v.Y-ov.Y) < epsilon && math.Abs(v.Z-ov.Z) < epsilon
     33 }
     34 
     35 func (v Vector) String() string { return fmt.Sprintf("(%0.24f, %0.24f, %0.24f)", v.X, v.Y, v.Z) }
     36 
     37 // Norm returns the vector's norm.
     38 func (v Vector) Norm() float64 { return math.Sqrt(v.Dot(v)) }
     39 
     40 // Norm2 returns the square of the norm.
     41 func (v Vector) Norm2() float64 { return v.Dot(v) }
     42 
     43 // Normalize returns a unit vector in the same direction as v.
     44 func (v Vector) Normalize() Vector {
     45 	n2 := v.Norm2()
     46 	if n2 == 0 {
     47 		return Vector{0, 0, 0}
     48 	}
     49 	return v.Mul(1 / math.Sqrt(n2))
     50 }
     51 
     52 // IsUnit returns whether this vector is of approximately unit length.
     53 func (v Vector) IsUnit() bool {
     54 	const epsilon = 5e-14
     55 	return math.Abs(v.Norm2()-1) <= epsilon
     56 }
     57 
     58 // Abs returns the vector with nonnegative components.
     59 func (v Vector) Abs() Vector { return Vector{math.Abs(v.X), math.Abs(v.Y), math.Abs(v.Z)} }
     60 
     61 // Add returns the standard vector sum of v and ov.
     62 func (v Vector) Add(ov Vector) Vector { return Vector{v.X + ov.X, v.Y + ov.Y, v.Z + ov.Z} }
     63 
     64 // Sub returns the standard vector difference of v and ov.
     65 func (v Vector) Sub(ov Vector) Vector { return Vector{v.X - ov.X, v.Y - ov.Y, v.Z - ov.Z} }
     66 
     67 // Mul returns the standard scalar product of v and m.
     68 func (v Vector) Mul(m float64) Vector { return Vector{m * v.X, m * v.Y, m * v.Z} }
     69 
     70 // Dot returns the standard dot product of v and ov.
     71 func (v Vector) Dot(ov Vector) float64 { return v.X*ov.X + v.Y*ov.Y + v.Z*ov.Z }
     72 
     73 // Cross returns the standard cross product of v and ov.
     74 func (v Vector) Cross(ov Vector) Vector {
     75 	return Vector{
     76 		v.Y*ov.Z - v.Z*ov.Y,
     77 		v.Z*ov.X - v.X*ov.Z,
     78 		v.X*ov.Y - v.Y*ov.X,
     79 	}
     80 }
     81 
     82 // Distance returns the Euclidean distance between v and ov.
     83 func (v Vector) Distance(ov Vector) float64 { return v.Sub(ov).Norm() }
     84 
     85 // Angle returns the angle between v and ov.
     86 func (v Vector) Angle(ov Vector) s1.Angle {
     87 	return s1.Angle(math.Atan2(v.Cross(ov).Norm(), v.Dot(ov))) * s1.Radian
     88 }
     89 
     90 // Axis enumerates the 3 axes of ℝ³.
     91 type Axis int
     92 
     93 // The three axes of ℝ³.
     94 const (
     95 	XAxis Axis = iota
     96 	YAxis
     97 	ZAxis
     98 )
     99 
    100 // Ortho returns a unit vector that is orthogonal to v.
    101 // Ortho(-v) = -Ortho(v) for all v.
    102 func (v Vector) Ortho() Vector {
    103 	ov := Vector{0.012, 0.0053, 0.00457}
    104 	switch v.LargestComponent() {
    105 	case XAxis:
    106 		ov.Z = 1
    107 	case YAxis:
    108 		ov.X = 1
    109 	default:
    110 		ov.Y = 1
    111 	}
    112 	return v.Cross(ov).Normalize()
    113 }
    114 
    115 // LargestComponent returns the axis that represents the largest component in this vector.
    116 func (v Vector) LargestComponent() Axis {
    117 	t := v.Abs()
    118 
    119 	if t.X > t.Y {
    120 		if t.X > t.Z {
    121 			return XAxis
    122 		}
    123 		return ZAxis
    124 	}
    125 	if t.Y > t.Z {
    126 		return YAxis
    127 	}
    128 	return ZAxis
    129 }
    130 
    131 // SmallestComponent returns the axis that represents the smallest component in this vector.
    132 func (v Vector) SmallestComponent() Axis {
    133 	t := v.Abs()
    134 
    135 	if t.X < t.Y {
    136 		if t.X < t.Z {
    137 			return XAxis
    138 		}
    139 		return ZAxis
    140 	}
    141 	if t.Y < t.Z {
    142 		return YAxis
    143 	}
    144 	return ZAxis
    145 }
    146 
    147 // Cmp compares v and ov lexicographically and returns:
    148 //
    149 //   -1 if v <  ov
    150 //    0 if v == ov
    151 //   +1 if v >  ov
    152 //
    153 // This method is based on C++'s std::lexicographical_compare. Two entities
    154 // are compared element by element with the given operator. The first mismatch
    155 // defines which is less (or greater) than the other. If both have equivalent
    156 // values they are lexicographically equal.
    157 func (v Vector) Cmp(ov Vector) int {
    158 	if v.X < ov.X {
    159 		return -1
    160 	}
    161 	if v.X > ov.X {
    162 		return 1
    163 	}
    164 
    165 	// First elements were the same, try the next.
    166 	if v.Y < ov.Y {
    167 		return -1
    168 	}
    169 	if v.Y > ov.Y {
    170 		return 1
    171 	}
    172 
    173 	// Second elements were the same return the final compare.
    174 	if v.Z < ov.Z {
    175 		return -1
    176 	}
    177 	if v.Z > ov.Z {
    178 		return 1
    179 	}
    180 
    181 	// Both are equal
    182 	return 0
    183 }