diff --git a/generate/template/astronomy.go b/generate/template/astronomy.go
index 7f056549..2ab6f104 100644
--- a/generate/template/astronomy.go
+++ b/generate/template/astronomy.go
@@ -240,7 +240,7 @@ func TimeFromTerrestrialDays(tt float64) AstroTime {
return makeTime(universalTime(tt), tt)
}
-func (time *AstroTime) AddDays(days float64) AstroTime {
+func (time AstroTime) AddDays(days float64) AstroTime {
return TimeFromUniversalDays(time.Ut + days)
}
@@ -260,6 +260,11 @@ type AstroVector struct {
T AstroTime
}
+// Returns the length of vec expressed in the same distance units as vec's components.
+func (vec AstroVector) Length() float64 {
+ return math.Sqrt(vec.X*vec.X + vec.Y*vec.Y + vec.Z*vec.Z)
+}
+
type StateVector struct {
X float64
Y float64
@@ -270,6 +275,16 @@ type StateVector struct {
T AstroTime
}
+// Position returns the position vector inside a state vector.
+func (state StateVector) Position() AstroVector {
+ return AstroVector{state.X, state.Y, state.Z, state.T}
+}
+
+// Position returns the velocity vector inside a state vector.
+func (state StateVector) Velocity() AstroVector {
+ return AstroVector{state.Vx, state.Vy, state.Vz, state.T}
+}
+
type Spherical struct {
Lat float64
Lon float64
@@ -433,4 +448,34 @@ type constelBoundary struct {
decLo float64
}
+// DegreesFromRadians converts an angle expressed in radians to an angle expressed in degrees.
+func DegreesFromRadians(radians float64) float64 {
+ return radians * (180.0 / math.Pi)
+}
+
+// RadiansFromDegrees converts an angle expressed in degrees to an angle expressed in radians.
+func RadiansFromDegrees(degrees float64) float64 {
+ return degrees * (math.Pi / 180.0)
+}
+
+// AngleBetween calculates the angle in degrees between two vectors.
+// Given a pair of vectors avec and bvec, this function returns the
+// angle in degrees between the vectors in 3D space.
+// The angle is measured in the plane that contains both vectors.
+// The returned value is in the closed range [0, 180].
+func AngleBetween(avec AstroVector, bvec AstroVector) float64 {
+ r := avec.Length() * bvec.Length()
+ if r < 1.0e-8 {
+ panic("Cannot find angle between vectors because they are too short.")
+ }
+ dot := (avec.X*bvec.X + avec.Y*bvec.Y + avec.Z*bvec.Z) / r
+ if dot <= -1.0 {
+ return 180.0
+ }
+ if dot >= +1.0 {
+ return 0.0
+ }
+ return DegreesFromRadians(math.Acos(dot))
+}
+
//$ASTRO_CONSTEL()
diff --git a/generate/unit_test_golang b/generate/unit_test_golang
index 1a26e183..285f094c 100755
--- a/generate/unit_test_golang
+++ b/generate/unit_test_golang
@@ -10,7 +10,7 @@ Fail()
go version || Fail "Cannot find Go compiler."
cd ../source/golang
-go test || Fail "Failure in Go unit tests."
+go test -v || Fail "Failure in Go unit tests."
cd ../../generate
echo "unit_test_golang: success"
exit 0
diff --git a/source/golang/README.md b/source/golang/README.md
index 638d126c..e37f7449 100644
--- a/source/golang/README.md
+++ b/source/golang/README.md
@@ -13,13 +13,17 @@ It provides a suite of well\-tested functions for calculating positions of the S
## Index
- [Constants](<#constants>)
+- [func AngleBetween\(avec AstroVector, bvec AstroVector\) float64](<#AngleBetween>)
+- [func DegreesFromRadians\(radians float64\) float64](<#DegreesFromRadians>)
+- [func RadiansFromDegrees\(degrees float64\) float64](<#RadiansFromDegrees>)
- [type AstroMoonQuarter](<#AstroMoonQuarter>)
- [type AstroSearchFunc](<#AstroSearchFunc>)
- [type AstroTime](<#AstroTime>)
- [func TimeFromTerrestrialDays\(tt float64\) AstroTime](<#TimeFromTerrestrialDays>)
- [func TimeFromUniversalDays\(ut float64\) AstroTime](<#TimeFromUniversalDays>)
- - [func \(time \*AstroTime\) AddDays\(days float64\) AstroTime](<#AstroTime.AddDays>)
+ - [func \(time AstroTime\) AddDays\(days float64\) AstroTime](<#AstroTime.AddDays>)
- [type AstroVector](<#AstroVector>)
+ - [func \(vec AstroVector\) Length\(\) float64](<#AstroVector.Length>)
- [type AtmosphereInfo](<#AtmosphereInfo>)
- [type AxisInfo](<#AxisInfo>)
- [type Body](<#Body>)
@@ -37,6 +41,8 @@ It provides a suite of well\-tested functions for calculating positions of the S
- [type SeasonsInfo](<#SeasonsInfo>)
- [type Spherical](<#Spherical>)
- [type StateVector](<#StateVector>)
+ - [func \(state StateVector\) Position\(\) AstroVector](<#StateVector.Position>)
+ - [func \(state StateVector\) Velocity\(\) AstroVector](<#StateVector.Velocity>)
- [type TimeFormat](<#TimeFormat>)
- [type Topocentric](<#Topocentric>)
@@ -118,8 +124,35 @@ const (
)
```
+
+## func [AngleBetween]()
+
+```go
+func AngleBetween(avec AstroVector, bvec AstroVector) float64
+```
+
+AngleBetween calculates the angle in degrees between two vectors. Given a pair of vectors avec and bvec, this function returns the angle in degrees between the vectors in 3D space. The angle is measured in the plane that contains both vectors. The returned value is in the closed range \[0, 180\].
+
+
+## func [DegreesFromRadians]()
+
+```go
+func DegreesFromRadians(radians float64) float64
+```
+
+DegreesFromRadians converts an angle expressed in radians to an angle expressed in degrees.
+
+
+## func [RadiansFromDegrees]()
+
+```go
+func RadiansFromDegrees(degrees float64) float64
+```
+
+RadiansFromDegrees converts an angle expressed in degrees to an angle expressed in radians.
+
-## type [AstroMoonQuarter]()
+## type [AstroMoonQuarter]()
@@ -131,7 +164,7 @@ type AstroMoonQuarter struct {
```
-## type [AstroSearchFunc]()
+## type [AstroSearchFunc]()
@@ -206,10 +239,10 @@ func TimeFromUniversalDays(ut float64) AstroTime
-### func \(\*AstroTime\) [AddDays]()
+### func \(AstroTime\) [AddDays]()
```go
-func (time *AstroTime) AddDays(days float64) AstroTime
+func (time AstroTime) AddDays(days float64) AstroTime
```
@@ -228,8 +261,17 @@ type AstroVector struct {
}
```
+
+### func \(AstroVector\) [Length]()
+
+```go
+func (vec AstroVector) Length() float64
+```
+
+Returns the length of vec expressed in the same distance units as vec's components.
+
-## type [AtmosphereInfo]()
+## type [AtmosphereInfo]()
@@ -242,7 +284,7 @@ type AtmosphereInfo struct {
```
-## type [AxisInfo]()
+## type [AxisInfo]()
@@ -256,7 +298,7 @@ type AxisInfo struct {
```
-## type [Body]()
+## type [Body]()
@@ -281,7 +323,7 @@ type CalendarDateTime struct {
```
-## type [DeltaTimeFunc]()
+## type [DeltaTimeFunc]()
@@ -290,7 +332,7 @@ type DeltaTimeFunc func(ut float64) float64
```
-## type [Ecliptic]()
+## type [Ecliptic]()
@@ -303,7 +345,7 @@ type Ecliptic struct {
```
-## type [Equatorial]()
+## type [Equatorial]()
@@ -317,7 +359,7 @@ type Equatorial struct {
```
-## type [JupiterMoonsInfo]()
+## type [JupiterMoonsInfo]()
@@ -331,7 +373,7 @@ type JupiterMoonsInfo struct {
```
-## type [LibrationInfo]()
+## type [LibrationInfo]()
@@ -347,7 +389,7 @@ type LibrationInfo struct {
```
-## type [NodeEventInfo]()
+## type [NodeEventInfo]()
@@ -359,7 +401,7 @@ type NodeEventInfo struct {
```
-## type [NodeEventKind]()
+## type [NodeEventKind]()
@@ -368,7 +410,7 @@ type NodeEventKind int
```
-## type [Observer]()
+## type [Observer]()
@@ -381,7 +423,7 @@ type Observer struct {
```
-## type [Refraction]()
+## type [Refraction]()
@@ -400,7 +442,7 @@ const (
```
-## type [RotationMatrix]()
+## type [RotationMatrix]()
@@ -411,7 +453,7 @@ type RotationMatrix struct {
```
-## type [SeasonsInfo]()
+## type [SeasonsInfo]()
@@ -425,7 +467,7 @@ type SeasonsInfo struct {
```
-## type [Spherical]()
+## type [Spherical]()
@@ -438,7 +480,7 @@ type Spherical struct {
```
-## type [StateVector]()
+## type [StateVector]()
@@ -454,8 +496,26 @@ type StateVector struct {
}
```
+
+### func \(StateVector\) [Position]()
+
+```go
+func (state StateVector) Position() AstroVector
+```
+
+Position returns the position vector inside a state vector.
+
+
+### func \(StateVector\) [Velocity]()
+
+```go
+func (state StateVector) Velocity() AstroVector
+```
+
+Position returns the velocity vector inside a state vector.
+
-## type [TimeFormat]()
+## type [TimeFormat]()
@@ -475,7 +535,7 @@ const (
```
-## type [Topocentric]()
+## type [Topocentric]()
diff --git a/source/golang/astronomy.go b/source/golang/astronomy.go
index d1d06a6e..8ff3e299 100644
--- a/source/golang/astronomy.go
+++ b/source/golang/astronomy.go
@@ -240,7 +240,7 @@ func TimeFromTerrestrialDays(tt float64) AstroTime {
return makeTime(universalTime(tt), tt)
}
-func (time *AstroTime) AddDays(days float64) AstroTime {
+func (time AstroTime) AddDays(days float64) AstroTime {
return TimeFromUniversalDays(time.Ut + days)
}
@@ -260,6 +260,11 @@ type AstroVector struct {
T AstroTime
}
+// Returns the length of vec expressed in the same distance units as vec's components.
+func (vec AstroVector) Length() float64 {
+ return math.Sqrt(vec.X*vec.X + vec.Y*vec.Y + vec.Z*vec.Z)
+}
+
type StateVector struct {
X float64
Y float64
@@ -270,6 +275,16 @@ type StateVector struct {
T AstroTime
}
+// Position returns the position vector inside a state vector.
+func (state StateVector) Position() AstroVector {
+ return AstroVector{state.X, state.Y, state.Z, state.T}
+}
+
+// Position returns the velocity vector inside a state vector.
+func (state StateVector) Velocity() AstroVector {
+ return AstroVector{state.Vx, state.Vy, state.Vz, state.T}
+}
+
type Spherical struct {
Lat float64
Lon float64
@@ -433,6 +448,36 @@ type constelBoundary struct {
decLo float64
}
+// DegreesFromRadians converts an angle expressed in radians to an angle expressed in degrees.
+func DegreesFromRadians(radians float64) float64 {
+ return radians * (180.0 / math.Pi)
+}
+
+// RadiansFromDegrees converts an angle expressed in degrees to an angle expressed in radians.
+func RadiansFromDegrees(degrees float64) float64 {
+ return degrees * (math.Pi / 180.0)
+}
+
+// AngleBetween calculates the angle in degrees between two vectors.
+// Given a pair of vectors avec and bvec, this function returns the
+// angle in degrees between the vectors in 3D space.
+// The angle is measured in the plane that contains both vectors.
+// The returned value is in the closed range [0, 180].
+func AngleBetween(avec AstroVector, bvec AstroVector) float64 {
+ r := avec.Length() * bvec.Length()
+ if r < 1.0e-8 {
+ panic("Cannot find angle between vectors because they are too short.")
+ }
+ dot := (avec.X*bvec.X + avec.Y*bvec.Y + avec.Z*bvec.Z) / r
+ if dot <= -1.0 {
+ return 180.0
+ }
+ if dot >= +1.0 {
+ return 0.0
+ }
+ return DegreesFromRadians(math.Acos(dot))
+}
+
var constelNames = [...]constelInfo{
{"And", "Andromeda"},
{"Ant", "Antila"},
diff --git a/source/golang/astronomy_test.go b/source/golang/astronomy_test.go
index 18119cb9..498d0595 100644
--- a/source/golang/astronomy_test.go
+++ b/source/golang/astronomy_test.go
@@ -27,3 +27,14 @@ func TestTerrestrialTime(t *testing.T) {
t.Errorf("Excessive Universal Time Error = %g for time2", utdiff2)
}
}
+
+func TestAngleBetween(t *testing.T) {
+ time := TimeFromUniversalDays(0.0)
+ a := AstroVector{1.0, 0.0, 0.0, time}
+ b := AstroVector{1.0, 1.0, 0.0, time}
+ angle := AngleBetween(a, b)
+ diff := math.Abs(angle - 45.0)
+ if diff > 1.0e-14 {
+ t.Errorf("Excessive angle error = %g", diff)
+ }
+}