gonum.org/v1/gonum@v0.14.0/spatial/r2/vector.go (about)

     1  // Copyright ©2019 The Gonum Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package r2
     6  
     7  import "math"
     8  
     9  // Vec is a 2D vector.
    10  type Vec struct {
    11  	X, Y float64
    12  }
    13  
    14  // Add returns the vector sum of p and q.
    15  func Add(p, q Vec) Vec {
    16  	return Vec{
    17  		X: p.X + q.X,
    18  		Y: p.Y + q.Y,
    19  	}
    20  }
    21  
    22  // Sub returns the vector sum of p and -q.
    23  func Sub(p, q Vec) Vec {
    24  	return Vec{
    25  		X: p.X - q.X,
    26  		Y: p.Y - q.Y,
    27  	}
    28  }
    29  
    30  // Scale returns the vector p scaled by f.
    31  func Scale(f float64, p Vec) Vec {
    32  	return Vec{
    33  		X: f * p.X,
    34  		Y: f * p.Y,
    35  	}
    36  }
    37  
    38  // Dot returns the dot product p·q.
    39  func Dot(p, q Vec) float64 {
    40  	return p.X*q.X + p.Y*q.Y
    41  }
    42  
    43  // Cross returns the cross product p×q.
    44  func Cross(p, q Vec) float64 {
    45  	return p.X*q.Y - p.Y*q.X
    46  }
    47  
    48  // Rotate returns a new vector, rotated by alpha around the provided point, q.
    49  func Rotate(p Vec, alpha float64, q Vec) Vec {
    50  	return NewRotation(alpha, q).Rotate(p)
    51  }
    52  
    53  // Norm returns the Euclidean norm of p
    54  //
    55  //	|p| = sqrt(p_x^2 + p_y^2).
    56  func Norm(p Vec) float64 {
    57  	return math.Hypot(p.X, p.Y)
    58  }
    59  
    60  // Norm2 returns the Euclidean squared norm of p
    61  //
    62  //	|p|^2 = p_x^2 + p_y^2.
    63  func Norm2(p Vec) float64 {
    64  	return p.X*p.X + p.Y*p.Y
    65  }
    66  
    67  // Unit returns the unit vector colinear to p.
    68  // Unit returns {NaN,NaN} for the zero vector.
    69  func Unit(p Vec) Vec {
    70  	if p.X == 0 && p.Y == 0 {
    71  		return Vec{X: math.NaN(), Y: math.NaN()}
    72  	}
    73  	return Scale(1/Norm(p), p)
    74  }
    75  
    76  // Cos returns the cosine of the opening angle between p and q.
    77  func Cos(p, q Vec) float64 {
    78  	return Dot(p, q) / (Norm(p) * Norm(q))
    79  }
    80  
    81  // Rotation describes a rotation in 2D.
    82  type Rotation struct {
    83  	sin, cos float64
    84  	p        Vec
    85  }
    86  
    87  // NewRotation creates a rotation by alpha, around p.
    88  func NewRotation(alpha float64, p Vec) Rotation {
    89  	if alpha == 0 {
    90  		return Rotation{sin: 0, cos: 1, p: p}
    91  	}
    92  	sin, cos := math.Sincos(alpha)
    93  	return Rotation{sin: sin, cos: cos, p: p}
    94  }
    95  
    96  // Rotate returns p rotated according to the parameters used to construct
    97  // the receiver.
    98  func (r Rotation) Rotate(p Vec) Vec {
    99  	if r.isIdentity() {
   100  		return p
   101  	}
   102  	o := Sub(p, r.p)
   103  	return Add(Vec{
   104  		X: (o.X*r.cos - o.Y*r.sin),
   105  		Y: (o.X*r.sin + o.Y*r.cos),
   106  	}, r.p)
   107  }
   108  
   109  func (r Rotation) isIdentity() bool {
   110  	return r.sin == 0 && r.cos == 1
   111  }
   112  
   113  // minElem returns a vector with the element-wise
   114  // minimum components of vectors a and b.
   115  func minElem(a, b Vec) Vec {
   116  	return Vec{
   117  		X: math.Min(a.X, b.X),
   118  		Y: math.Min(a.Y, b.Y),
   119  	}
   120  }
   121  
   122  // maxElem returns a vector with the element-wise
   123  // maximum components of vectors a and b.
   124  func maxElem(a, b Vec) Vec {
   125  	return Vec{
   126  		X: math.Max(a.X, b.X),
   127  		Y: math.Max(a.Y, b.Y),
   128  	}
   129  }
   130  
   131  // absElem returns the vector with components set to their absolute value.
   132  func absElem(a Vec) Vec {
   133  	return Vec{
   134  		X: math.Abs(a.X),
   135  		Y: math.Abs(a.Y),
   136  	}
   137  }
   138  
   139  // mulElem returns the Hadamard product between vectors a and b.
   140  //
   141  //	v = {a.X*b.X, a.Y*b.Y, a.Z*b.Z}
   142  func mulElem(a, b Vec) Vec {
   143  	return Vec{
   144  		X: a.X * b.X,
   145  		Y: a.Y * b.Y,
   146  	}
   147  }
   148  
   149  // divElem returns the Hadamard product between vector a
   150  // and the inverse components of vector b.
   151  //
   152  //	v = {a.X/b.X, a.Y/b.Y, a.Z/b.Z}
   153  func divElem(a, b Vec) Vec {
   154  	return Vec{
   155  		X: a.X / b.X,
   156  		Y: a.Y / b.Y,
   157  	}
   158  }