...

Source file src/github.com/golang/geo/r3/precisevector.go

Documentation: github.com/golang/geo/r3

     1  // Copyright 2016 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/big"
    20  )
    21  
    22  const (
    23  	// prec is the number of bits of precision to use for the Float values.
    24  	// To keep things simple, we use the maximum allowable precision on big
    25  	// values. This allows us to handle all values we expect in the s2 library.
    26  	prec = big.MaxPrec
    27  )
    28  
    29  // define some commonly referenced values.
    30  var (
    31  	precise0 = precInt(0)
    32  	precise1 = precInt(1)
    33  )
    34  
    35  // precStr wraps the conversion from a string into a big.Float. For results that
    36  // actually can be represented exactly, this should only be used on values that
    37  // are integer multiples of integer powers of 2.
    38  func precStr(s string) *big.Float {
    39  	// Explicitly ignoring the bool return for this usage.
    40  	f, _ := new(big.Float).SetPrec(prec).SetString(s)
    41  	return f
    42  }
    43  
    44  func precInt(i int64) *big.Float {
    45  	return new(big.Float).SetPrec(prec).SetInt64(i)
    46  }
    47  
    48  func precFloat(f float64) *big.Float {
    49  	return new(big.Float).SetPrec(prec).SetFloat64(f)
    50  }
    51  
    52  func precAdd(a, b *big.Float) *big.Float {
    53  	return new(big.Float).SetPrec(prec).Add(a, b)
    54  }
    55  
    56  func precSub(a, b *big.Float) *big.Float {
    57  	return new(big.Float).SetPrec(prec).Sub(a, b)
    58  }
    59  
    60  func precMul(a, b *big.Float) *big.Float {
    61  	return new(big.Float).SetPrec(prec).Mul(a, b)
    62  }
    63  
    64  // PreciseVector represents a point in ℝ³ using high-precision values.
    65  // Note that this is NOT a complete implementation because there are some
    66  // operations that Vector supports that are not feasible with arbitrary precision
    67  // math. (e.g., methods that need division like Normalize, or methods needing a
    68  // square root operation such as Norm)
    69  type PreciseVector struct {
    70  	X, Y, Z *big.Float
    71  }
    72  
    73  // PreciseVectorFromVector creates a high precision vector from the given Vector.
    74  func PreciseVectorFromVector(v Vector) PreciseVector {
    75  	return NewPreciseVector(v.X, v.Y, v.Z)
    76  }
    77  
    78  // NewPreciseVector creates a high precision vector from the given floating point values.
    79  func NewPreciseVector(x, y, z float64) PreciseVector {
    80  	return PreciseVector{
    81  		X: precFloat(x),
    82  		Y: precFloat(y),
    83  		Z: precFloat(z),
    84  	}
    85  }
    86  
    87  // Vector returns this precise vector converted to a Vector.
    88  func (v PreciseVector) Vector() Vector {
    89  	// The accuracy flag is ignored on these conversions back to float64.
    90  	x, _ := v.X.Float64()
    91  	y, _ := v.Y.Float64()
    92  	z, _ := v.Z.Float64()
    93  	return Vector{x, y, z}.Normalize()
    94  }
    95  
    96  // Equal reports whether v and ov are equal.
    97  func (v PreciseVector) Equal(ov PreciseVector) bool {
    98  	return v.X.Cmp(ov.X) == 0 && v.Y.Cmp(ov.Y) == 0 && v.Z.Cmp(ov.Z) == 0
    99  }
   100  
   101  func (v PreciseVector) String() string {
   102  	return fmt.Sprintf("(%10g, %10g, %10g)", v.X, v.Y, v.Z)
   103  }
   104  
   105  // Norm2 returns the square of the norm.
   106  func (v PreciseVector) Norm2() *big.Float { return v.Dot(v) }
   107  
   108  // IsUnit reports whether this vector is of unit length.
   109  func (v PreciseVector) IsUnit() bool {
   110  	return v.Norm2().Cmp(precise1) == 0
   111  }
   112  
   113  // Abs returns the vector with nonnegative components.
   114  func (v PreciseVector) Abs() PreciseVector {
   115  	return PreciseVector{
   116  		X: new(big.Float).Abs(v.X),
   117  		Y: new(big.Float).Abs(v.Y),
   118  		Z: new(big.Float).Abs(v.Z),
   119  	}
   120  }
   121  
   122  // Add returns the standard vector sum of v and ov.
   123  func (v PreciseVector) Add(ov PreciseVector) PreciseVector {
   124  	return PreciseVector{
   125  		X: precAdd(v.X, ov.X),
   126  		Y: precAdd(v.Y, ov.Y),
   127  		Z: precAdd(v.Z, ov.Z),
   128  	}
   129  }
   130  
   131  // Sub returns the standard vector difference of v and ov.
   132  func (v PreciseVector) Sub(ov PreciseVector) PreciseVector {
   133  	return PreciseVector{
   134  		X: precSub(v.X, ov.X),
   135  		Y: precSub(v.Y, ov.Y),
   136  		Z: precSub(v.Z, ov.Z),
   137  	}
   138  }
   139  
   140  // Mul returns the standard scalar product of v and f.
   141  func (v PreciseVector) Mul(f *big.Float) PreciseVector {
   142  	return PreciseVector{
   143  		X: precMul(v.X, f),
   144  		Y: precMul(v.Y, f),
   145  		Z: precMul(v.Z, f),
   146  	}
   147  }
   148  
   149  // MulByFloat64 returns the standard scalar product of v and f.
   150  func (v PreciseVector) MulByFloat64(f float64) PreciseVector {
   151  	return v.Mul(precFloat(f))
   152  }
   153  
   154  // Dot returns the standard dot product of v and ov.
   155  func (v PreciseVector) Dot(ov PreciseVector) *big.Float {
   156  	return precAdd(precMul(v.X, ov.X), precAdd(precMul(v.Y, ov.Y), precMul(v.Z, ov.Z)))
   157  }
   158  
   159  // Cross returns the standard cross product of v and ov.
   160  func (v PreciseVector) Cross(ov PreciseVector) PreciseVector {
   161  	return PreciseVector{
   162  		X: precSub(precMul(v.Y, ov.Z), precMul(v.Z, ov.Y)),
   163  		Y: precSub(precMul(v.Z, ov.X), precMul(v.X, ov.Z)),
   164  		Z: precSub(precMul(v.X, ov.Y), precMul(v.Y, ov.X)),
   165  	}
   166  }
   167  
   168  // LargestComponent returns the axis that represents the largest component in this vector.
   169  func (v PreciseVector) LargestComponent() Axis {
   170  	t := v.Abs()
   171  
   172  	if t.X.Cmp(t.Y) > 0 {
   173  		if t.X.Cmp(t.Z) > 0 {
   174  			return XAxis
   175  		}
   176  		return ZAxis
   177  	}
   178  	if t.Y.Cmp(t.Z) > 0 {
   179  		return YAxis
   180  	}
   181  	return ZAxis
   182  }
   183  
   184  // SmallestComponent returns the axis that represents the smallest component in this vector.
   185  func (v PreciseVector) SmallestComponent() Axis {
   186  	t := v.Abs()
   187  
   188  	if t.X.Cmp(t.Y) < 0 {
   189  		if t.X.Cmp(t.Z) < 0 {
   190  			return XAxis
   191  		}
   192  		return ZAxis
   193  	}
   194  	if t.Y.Cmp(t.Z) < 0 {
   195  		return YAxis
   196  	}
   197  	return ZAxis
   198  }
   199  
   200  // IsZero reports if this vector is exactly 0 efficiently.
   201  func (v PreciseVector) IsZero() bool {
   202  	return v.X.Sign() == 0 && v.Y.Sign() == 0 && v.Z.Sign() == 0
   203  }
   204  

View as plain text