/** * Returns the true centroid of the spherical triangle ABC multiplied by the * signed area of spherical triangle ABC. The reasons for multiplying by the * signed area are (1) this is the quantity that needs to be summed to compute * the centroid of a union or difference of triangles, and (2) it's actually * easier to calculate this way. */ func TrueCentroid(a, b, c Point) Point { // I couldn't find any references for computing the true centroid of a // spherical triangle... I have a truly marvellous demonstration of this // formula which this margin is too narrow to contain :) // assert (isUnitLength(a) && isUnitLength(b) && isUnitLength(c)); sina := b.Cross(c.Vector).Norm() sinb := c.Cross(a.Vector).Norm() sinc := a.Cross(b.Vector).Norm() var ra float64 = 1 var rb float64 = 1 var rc float64 = 1 if sina != 0 { ra = math.Asin(sina) / sina } if sinb != 0 { rb = math.Asin(sinb) / sinb } if sinc != 0 { rc = math.Asin(sinc) / sinc } // Now compute a point M such that M.X = rX * det(ABC) / 2 for X in A,B,C. x := PointFromCoordsRaw(a.X, b.X, c.X) y := PointFromCoordsRaw(a.Y, b.Y, c.Y) z := PointFromCoordsRaw(a.Z, b.Z, c.Z) r := PointFromCoordsRaw(ra, rb, rc) return PointFromCoordsRaw( 0.5*y.Cross(z.Vector).Dot(r.Vector), 0.5*z.Cross(x.Vector).Dot(r.Vector), 0.5*x.Cross(y.Vector).Dot(r.Vector), ) }
// This is named GetDistance() in the C++ API. func (x Point) DistanceToEdgeWithNormal(a, b, a_cross_b Point) s1.Angle { // There are three cases. If X is located in the spherical wedge // defined by A, B, and the axis A x B, then the closest point is on // the segment AB. Otherwise the closest point is either A or B; the // dividing line between these two cases is the great circle passing // through (A x B) and the midpoint of AB. if CCW(a_cross_b, a, x) && CCW(x, b, a_cross_b) { // The closest point to X lies on the segment AB. We compute // the distance to the corresponding great circle. The result // is accurate for small distances but not necessarily for // large distances (approaching Pi/2). // // TODO: sanity check a != b sin_dist := math.Abs(x.Dot(a_cross_b.Vector)) / a_cross_b.Norm() return s1.Angle(math.Asin(math.Min(1.0, sin_dist))) } // Otherwise, the closest point is either A or B. The cheapest method is // just to compute the minimum of the two linear (as opposed to spherical) // distances and convert the result to an angle. Again, this method is // accurate for small but not large distances (approaching Pi). xa := x.Sub(a.Vector).Norm2() xb := x.Sub(b.Vector).Norm2() linear_dist2 := math.Min(xa, xb) return s1.Angle(2 * math.Asin(math.Min(1.0, 0.5*math.Sqrt(linear_dist2)))) }
/** * A slightly more efficient version of getDistance() where the cross product * of the two endpoints has been precomputed. The cross product does not need * to be normalized, but should be computed using S2.robustCrossProd() for the * most accurate results. */ func getDistanceWithCross(x, a, b, aCrossB Point) s1.Angle { if !x.IsUnit() || !a.IsUnit() || !b.IsUnit() { panic("x, a and b need to be unit length") } // There are three cases. If X is located in the spherical wedge defined by // A, B, and the axis A x B, then the closest point is on the segment AB. // Otherwise the closest point is either A or B; the dividing line between // these two cases is the great circle passing through (A x B) and the // midpoint of AB. if simpleCCW(aCrossB, a, x) && simpleCCW(x, b, aCrossB) { // The closest point to X lies on the segment AB. We compute the distance // to the corresponding great circle. The result is accurate for small // distances but not necessarily for large distances (approaching Pi/2). sinDist := math.Abs(x.Dot(aCrossB.Vector)) / aCrossB.Norm() return s1.Angle(math.Asin(math.Min(1.0, sinDist))) } // Otherwise, the closest point is either A or B. The cheapest method is // just to compute the minimum of the two linear (as opposed to spherical) // distances and convert the result to an angle. Again, this method is // accurate for small but not large distances (approaching Pi). linearDist2 := math.Min(x.Sub(a.Vector).Norm2(), x.Sub(b.Vector).Norm2()) return s1.Angle(2 * math.Asin(math.Min(1.0, 0.5*math.Sqrt(linearDist2)))) }
func getBoundingBox(rf Radiusfence) (x1, x2, y1, y2 float64) { var lat1, lat2, lon1, lon2 float64 //Convert long,lat to rad latRad := rf.p.Latitude * DegToRad longRad := rf.p.Longitude * DegToRad northMost := math.Asin(math.Sin(latRad)*math.Cos(rf.r/Radius) + math.Cos(latRad)*math.Sin(rf.r/Radius)*math.Cos(North)) southMost := math.Asin(math.Sin(latRad)*math.Cos(rf.r/Radius) + math.Cos(latRad)*math.Sin(rf.r/Radius)*math.Cos(South)) eastMost := longRad + math.Atan2(math.Sin(East)*math.Sin(rf.r/Radius)*math.Cos(latRad), math.Cos(rf.r/Radius)-math.Sin(latRad)*math.Sin(latRad)) westMost := longRad + math.Atan2(math.Sin(West)*math.Sin(rf.r/Radius)*math.Cos(latRad), math.Cos(rf.r/Radius)-math.Sin(latRad)*math.Sin(latRad)) if northMost > southMost { lat1 = southMost lat2 = northMost } else { lat1 = northMost lat2 = southMost } if eastMost > westMost { lon1 = westMost lon2 = eastMost } else { lon1 = eastMost lon2 = westMost } return lat1, lat2, lon1, lon2 }
// Grena3 calculates topocentric solar position following algorithm number 3 // described in Grena, 'Five new algorithms for the computation of sun position // from 2010 to 2110', Solar Energy 86 (2012) pp. 1323-1337. func Grena3(date time.Time, latitudeDegrees float64, longitudeDegrees float64, deltaTSeconds float64, pressureHPa float64, temperatureCelsius float64) (azimuthDegrees, zenithDegrees float64) { t := calcT(date) tE := t + 1.1574e-5*deltaTSeconds omegaAtE := 0.0172019715 * tE lambda := -1.388803 + 1.720279216e-2*tE + 3.3366e-2*math.Sin(omegaAtE-0.06172) + 3.53e-4*math.Sin(2.0*omegaAtE-0.1163) epsilon := 4.089567e-1 - 6.19e-9*tE sLambda := math.Sin(lambda) cLambda := math.Cos(lambda) sEpsilon := math.Sin(epsilon) cEpsilon := math.Sqrt(1.0 - sEpsilon*sEpsilon) alpha := math.Atan2(sLambda*cEpsilon, cLambda) if alpha < 0 { alpha = alpha + 2*math.Pi } delta := math.Asin(sLambda * sEpsilon) h := 1.7528311 + 6.300388099*t + toRad(longitudeDegrees) - alpha h = math.Mod((h+math.Pi), (2*math.Pi)) - math.Pi if h < -math.Pi { h = h + 2*math.Pi } sPhi := math.Sin(toRad(latitudeDegrees)) cPhi := math.Sqrt((1 - sPhi*sPhi)) sDelta := math.Sin(delta) cDelta := math.Sqrt(1 - sDelta*sDelta) sH := math.Sin(h) cH := math.Cos(h) sEpsilon0 := sPhi*sDelta + cPhi*cDelta*cH eP := math.Asin(sEpsilon0) - 4.26e-5*math.Sqrt(1.0-sEpsilon0*sEpsilon0) gamma := math.Atan2(sH, cH*sPhi-sDelta*cPhi/cDelta) deltaRe := 0.0 if eP > 0 && pressureHPa > 0.0 && pressureHPa < 3000.0 && temperatureCelsius > -273 && temperatureCelsius < 273 { deltaRe = (0.08422 * (pressureHPa / 1000)) / ((273.0 + temperatureCelsius) * math.Tan(eP+0.003138/(eP+0.08919))) } z := math.Pi/2 - eP - deltaRe azimuthDegrees = convertAzimuth(gamma) zenithDegrees = toDeg(z) return }
func main() { fmt.Println("cos(pi/2):", math.Cos(math.Pi/2)) fmt.Println("cos(0):", math.Cos(0)) fmt.Println("sen(pi/2):", math.Sin(math.Pi/2)) fmt.Println("sen(0):", math.Sin(0)) fmt.Println("arccos(1):", math.Acos(1)) fmt.Println("arccos(0):", math.Acos(0)) fmt.Println("arcsen(1):", math.Asin(1)) fmt.Println("arcsen(0):", math.Asin(0)) }
// Given a point X and an edge AB, check that the distance from X to AB is // "distance_radians" and the closest point on AB is "expected_closest" func TestDistanceToEdge(t *testing.T) { tests := []struct { x Point a Point b Point distance_radians float64 expected_closest Point }{ {pc(1, 0, 0), pc(1, 0, 0), pc(0, 1, 0), 0, pc(1, 0, 0)}, {pc(0, 1, 0), pc(1, 0, 0), pc(0, 1, 0), 0, pc(0, 1, 0)}, {pc(1, 3, 0), pc(1, 0, 0), pc(0, 1, 0), 0, pc(1, 3, 0)}, {pc(0, 0, 1), pc(1, 0, 0), pc(0, 1, 0), math.Pi / 2, pc(1, 0, 0)}, {pc(0, 0, -1), pc(1, 0, 0), pc(0, 1, 0), math.Pi / 2, pc(1, 0, 0)}, {pc(-1, -1, 0), pc(1, 0, 0), pc(0, 1, 0), 0.75 * math.Pi, pc(0, 0, 0)}, {pc(0, 1, 0), pc(1, 0, 0), pc(1, 1, 0), math.Pi / 4, pc(1, 1, 0)}, {pc(0, -1, 0), pc(1, 0, 0), pc(1, 1, 0), math.Pi / 2, pc(1, 0, 0)}, {pc(0, -1, 0), pc(1, 0, 0), pc(-1, 1, 0), math.Pi / 2, pc(1, 0, 0)}, {pc(-1, -1, 0), pc(1, 0, 0), pc(-1, 1, 0), math.Pi / 2, pc(-1, 1, 0)}, {pc(1, 1, 1), pc(1, 0, 0), pc(0, 1, 0), math.Asin(math.Sqrt(1. / 3)), pc(1, 1, 0)}, {pc(1, 1, -1), pc(1, 0, 0), pc(0, 1, 0), math.Asin(math.Sqrt(1. / 3)), pc(1, 1, 0)}, {pc(-1, 0, 0), pc(1, 1, 0), pc(1, 1, 0), 0.75 * math.Pi, pc(1, 1, 0)}, {pc(0, 0, -1), pc(1, 1, 0), pc(1, 1, 0), math.Pi / 2, pc(1, 1, 0)}, {pc(-1, 0, 0), pc(1, 0, 0), pc(1, 0, 0), math.Pi, pc(1, 0, 0)}, } for _, test := range tests { test.x = Point{test.x.Normalize()} test.a = Point{test.a.Normalize()} test.b = Point{test.b.Normalize()} test.expected_closest = Point{test.expected_closest.Normalize()} got := test.x.DistanceToEdge(test.a, test.b).Radians() if math.Abs(got-test.distance_radians) > 1e-14 { t.Errorf("%v.DistanceToEdge(%v, %v) = %v, want %v", test.x, test.a, test.b, got, test.distance_radians) } closest := test.x.ClosestPoint(test.a, test.b) if test.expected_closest == pc(0, 0, 0) { if closest != test.a && closest != test.b { t.Errorf("NOT: %v == %v || %v == %v", closest, test.a, closest, test.b) } } else { if !closest.ApproxEqual(test.expected_closest) { t.Errorf("%v != %v", closest, test.expected_closest) } } } }
func Test_Mw02(tst *testing.T) { //verbose() chk.PrintTitle("Mw02") prms := []string{"φ", "Mfix"} vals := []float64{32, 0} var o NcteM o.Init(prms, vals) if SAVE_FIG { // rosette full, ref := false, true r := 1.1 * SQ2 * o.M(1) / 3.0 PlotRosette(r, full, ref, true, 7) // NcteM npts := 201 X := make([]float64, npts) Y := make([]float64, npts) W := utl.LinSpace(-1, 1, npts) for i, w := range W { θ := math.Asin(w) / 3.0 r := SQ2 * o.M(w) / 3.0 X[i] = -r * math.Sin(math.Pi/6.0-θ) Y[i] = r * math.Cos(math.Pi/6.0-θ) //plt.Text(X[i], Y[i], io.Sf("$\\\\theta=%.2f$", θ*180.0/math.Pi), "size=8, ha='center', color='red'") //plt.Text(X[i], Y[i], io.Sf("$w=%.2f$", w), "size=8, ha='center', color='red'") } plt.Plot(X, Y, "'b-'") // MC g := func(θ float64) float64 { return SQ2 * o.Sinφ / (SQ3*math.Cos(θ) - o.Sinφ*math.Sin(θ)) } io.Pforan("M( 1) = %v\n", SQ2*o.M(1)/3.0) io.Pforan("g(30) = %v\n", g(math.Pi/6.0)) for i, w := range W { θ := math.Asin(w) / 3.0 r := g(θ) X[i] = -r * math.Sin(math.Pi/6.0-θ) Y[i] = r * math.Cos(math.Pi/6.0-θ) } plt.Plot(X, Y, "'k-'") // save plt.Equal() plt.SaveD("/tmp/gosl", "mw02.eps") } }
func main() { fmt.Printf("sin(%9.6f deg) = %f\n", d, math.Sin(d*math.Pi/180)) fmt.Printf("sin(%9.6f rad) = %f\n", r, math.Sin(r)) fmt.Printf("cos(%9.6f deg) = %f\n", d, math.Cos(d*math.Pi/180)) fmt.Printf("cos(%9.6f rad) = %f\n", r, math.Cos(r)) fmt.Printf("tan(%9.6f deg) = %f\n", d, math.Tan(d*math.Pi/180)) fmt.Printf("tan(%9.6f rad) = %f\n", r, math.Tan(r)) fmt.Printf("asin(%f) = %9.6f deg\n", s, math.Asin(s)*180/math.Pi) fmt.Printf("asin(%f) = %9.6f rad\n", s, math.Asin(s)) fmt.Printf("acos(%f) = %9.6f deg\n", c, math.Acos(c)*180/math.Pi) fmt.Printf("acos(%f) = %9.6f rad\n", c, math.Acos(c)) fmt.Printf("atan(%f) = %9.6f deg\n", t, math.Atan(t)*180/math.Pi) fmt.Printf("atan(%f) = %9.6f rad\n", t, math.Atan(t)) }
// Dist computes the spherical distance between two points on the unit sphere S². func (p Geo) Dist(q Geo) float64 { u1 := p.c() v1 := q.c() dot := u1.dot(v1) if dot > 0 { t := u1.sub(v1) return 2 * math.Asin(0.5*t.abs()) } if dot < 0 { t := u1.add(v1) return math.Pi - 2*math.Asin(0.5*t.abs()) } return math.Pi / 2 }
func geoBoundAroundPoint(center *Point, distance float64) *Bound { radDist := distance / EarthRadius radLat := deg2rad(center.Lat()) radLon := deg2rad(center.Lng()) minLat := radLat - radDist maxLat := radLat + radDist var minLon, maxLon float64 if minLat > minLatitude && maxLat < maxLatitude { deltaLon := math.Asin(math.Sin(radDist) / math.Cos(radLat)) minLon = radLon - deltaLon if minLon < minLongitude { minLon += 2 * math.Pi } maxLon = radLon + deltaLon if maxLon > maxLongitude { maxLon -= 2 * math.Pi } } else { minLat = math.Max(minLat, minLatitude) maxLat = math.Min(maxLat, maxLatitude) minLon = minLongitude maxLon = maxLongitude } return &Bound{ sw: &Point{rad2deg(minLon), rad2deg(minLat)}, ne: &Point{rad2deg(maxLon), rad2deg(maxLat)}, } }
// u.sep(v) returns ∠(u,v) (angular separation). func (u vec) sep(v vec) float64 { u1, v1 := u.hat(), v.hat() dot := u1.dot(v1) if dot > 0 { t := u1.sub(v1) return 2 * math.Asin(0.5*t.abs()) } if dot < 0 { t := u1.add(v1) return math.Pi - 2*math.Asin(0.5*t.abs()) } if u1.maxabs() == 0 || v1.maxabs() == 0 { return 0 } return math.Pi / 2 }
// ElasticInOut Acceleration until halfway, then deceleration func ElasticInOut(t, b, c, d float64) float64 { if t > d { return c } s := math.SqrtPi p := d * (0.3 * 1.5) a := c if t == 0 { return b } t /= d / 2 if t == 2 { return b + c } if a < math.Abs(c) { s = p / 4 } else { s = p / DoublePi * math.Asin(c/a) } t-- if t < 0 { return -0.5*(a*math.Pow(2, 10*t)*math.Sin((t*d-s)*DoublePi/p)) + b } return a*math.Pow(2, -10*t)*math.Sin((t*d-s)*DoublePi/p)*0.5 + c + b }
// ElasticOut Decelerating to zero velocity func ElasticOut(t, b, c, d float64) float64 { if t > d { return c } s := math.SqrtPi p := d * 0.3 a := c if t == 0 { return b } t /= d if t == 1 { return b + c } if a < math.Abs(c) { s = p / 4 } else { s = p / DoublePi * math.Asin(c/a) } return a*math.Pow(2, -10*t)*math.Sin((t*d-s)*DoublePi/p) + c + b }
func (c *OutlineCone) Paths() Paths { center := Vector{0, 0, 0} hyp := center.Sub(c.Eye).Length() opp := c.Radius theta := math.Asin(opp / hyp) adj := opp / math.Tan(theta) d := math.Cos(theta) * adj // r := math.Sin(theta) * adj w := center.Sub(c.Eye).Normalize() u := w.Cross(c.Up).Normalize() c0 := c.Eye.Add(w.MulScalar(d)) a0 := c0.Add(u.MulScalar(c.Radius * 1.01)) b0 := c0.Add(u.MulScalar(-c.Radius * 1.01)) var p0 Path for a := 0; a < 360; a++ { x := c.Radius * math.Cos(Radians(float64(a))) y := c.Radius * math.Sin(Radians(float64(a))) p0 = append(p0, Vector{x, y, 0}) } return Paths{ p0, {{a0.X, a0.Y, 0}, {0, 0, c.Height}}, {{b0.X, b0.Y, 0}, {0, 0, c.Height}}, } }
// AstrometricJ2000 is a utility function for computing astrometric coordinates. // // It is used internally and only exported so that it can be used from // multiple packages. It is not otherwise expected to be used. // // Argument f is a function that returns J2000 equatorial rectangular // coodinates of a body. // // Results are J2000 right ascention, declination, and elongation. func AstrometricJ2000(f func(float64) (x, y, z float64), jde float64, e *pp.V87Planet) (α, δ, ψ float64) { X, Y, Z := solarxyz.PositionJ2000(e, jde) x, y, z := f(jde) // (33.10) p. 229 ξ := X + x η := Y + y ζ := Z + z Δ := math.Sqrt(ξ*ξ + η*η + ζ*ζ) { τ := base.LightTime(Δ) x, y, z = f(jde - τ) ξ = X + x η = Y + y ζ = Z + z Δ = math.Sqrt(ξ*ξ + η*η + ζ*ζ) } α = math.Atan2(η, ξ) if α < 0 { α += 2 * math.Pi } δ = math.Asin(ζ / Δ) R0 := math.Sqrt(X*X + Y*Y + Z*Z) ψ = math.Acos((ξ*X + η*Y + ζ*Z) / R0 / Δ) return }
// Returns a Point populated with the lat and lng coordinates of transposing the origin point the distance (in meters) supplied by the compass bearing (in degrees) supplied. // Original Implementation from: http://www.movable-type.co.uk/scripts/latlong.html func (p *Point) PointAtDistanceAndBearing(dist float64, bearing float64) *Point { dr := dist / EARTH_RADIUS bearing = (bearing * (math.Pi / 180.0)) lat1 := (p.lat * (math.Pi / 180.0)) lng1 := (p.lng * (math.Pi / 180.0)) lat2_part1 := math.Sin(lat1) * math.Cos(dr) lat2_part2 := math.Cos(lat1) * math.Sin(dr) * math.Cos(bearing) lat2 := math.Asin(lat2_part1 + lat2_part2) lng2_part1 := math.Sin(bearing) * math.Sin(dr) * math.Cos(lat1) lng2_part2 := math.Cos(dr) - (math.Sin(lat1) * math.Sin(lat2)) lng2 := lng1 + math.Atan2(lng2_part1, lng2_part2) lng2 = math.Mod((lng2+3*math.Pi), (2*math.Pi)) - math.Pi lat2 = lat2 * (180.0 / math.Pi) lng2 = lng2 * (180.0 / math.Pi) return &Point{lat: lat2, lng: lng2} }
// EqToEcl converts equatorial coordinates to ecliptic coordinates. func (ecl *Ecliptic) EqToEcl(eq *Equatorial, ε *Obliquity) *Ecliptic { sα, cα := eq.RA.Sincos() sδ, cδ := eq.Dec.Sincos() ecl.Lon = unit.Angle(math.Atan2(sα*ε.C+(sδ/cδ)*ε.S, cα)) // (13.1) p. 93 ecl.Lat = unit.Angle(math.Asin(sδ*ε.C - cδ*ε.S*sα)) // (13.2) p. 93 return ecl }
// EclToEq converts ecliptic coordinates to equatorial coordinates. // // λ: ecliptic longitude coordinate to transform // β: ecliptic latitude coordinate to transform // sε: sine of obliquity of the ecliptic // cε: cosine of obliquity of the ecliptic // // Results: // α: right ascension // δ: declination func EclToEq(λ, β unit.Angle, sε, cε float64) (α unit.RA, δ unit.Angle) { sλ, cλ := λ.Sincos() sβ, cβ := β.Sincos() α = unit.RAFromRad(math.Atan2(sλ*cε-(sβ/cβ)*sε, cλ)) // (13.3) p. 93 δ = unit.Angle(math.Asin(sβ*cε + cβ*sε*sλ)) // (13.4) p. 93 return }
// EqToEcl converts equatorial coordinates to ecliptic coordinates. // // α: right ascension coordinate to transform, in radians // δ: declination coordinate to transform, in radians // sε: sine of obliquity of the ecliptic // cε: cosine of obliquity of the ecliptic // // Results: // // λ: ecliptic longitude in radians // β: ecliptic latitude in radians func EqToEcl(α, δ, sε, cε float64) (λ, β float64) { sα, cα := math.Sincos(α) sδ, cδ := math.Sincos(δ) λ = math.Atan2(sα*cε+(sδ/cδ)*sε, cα) // (13.1) p. 93 β = math.Asin(sδ*cε - cδ*sε*sα) // (13.2) p. 93 return }
func (f *Filter) madgwick(timestamp int64, values []float32) { C.madgwick_update_array( f.orientation, C.float(sampleFreq), C.float(beta), (*_Ctype_float)(&values[0])) // quaternion slice o := f.orientation q := []float32{ float32(o.q0), float32(o.q1), float32(o.q2), float32(o.q3), } q1 := float64(o.q0) q2 := float64(o.q1) q3 := float64(o.q2) q4 := float64(o.q3) // euler angles in radians (madgwick 2010) z := math.Atan2(2*q2*q3-2*q1*q4, 2*q1*q1+2*q2*q2-1) * rad2deg y := -math.Asin(2*q2*q4+2*q1*q3) * rad2deg x := math.Atan2(2*q3*q4-2*q1*q2, 2*q1*q1+2*q4*q4-1) * rad2deg e := []float64{z, y, x} if false { log.Println("qtn", timestamp, q) log.Println("eul", timestamp, e) } broadcast(timestamp, "qtn", q) }
// Generate a spiral func GenerateSpiral(setup Spiral, plotCoords chan<- Coordinate) { defer close(plotCoords) // MM that will be moved in a single step, used to calc what the new position along spiral will be after one time slice moveDist := 4.0 * Settings.MaxSpeed_MM_S * TimeSlice_US / 1000000.0 theta := 0.0 for radius := setup.RadiusBegin; radius >= setup.RadiusEnd; { plotCoords <- Coordinate{X: radius * math.Cos(theta), Y: radius * math.Sin(theta)} // use right triangle to approximate arc distance along spiral, ignores radiusDelta for this calculation thetaDelta := 2.0 * math.Asin(moveDist/(2.0*radius)) theta += thetaDelta if theta >= 2.0*math.Pi { theta -= 2.0 * math.Pi } radiusDelta := setup.RadiusDeltaPerRev * thetaDelta / (2.0 * math.Pi) radius -= radiusDelta //fmt.Println("Radius", radius, "Radius delta", radiusDelta, "Theta", theta, "Theta delta", thetaDelta) } plotCoords <- Coordinate{X: 0, Y: 0} }
// Generate a circle that slides along a given axis func GenerateSlidingCircle(setup SlidingCircle, plotCoords chan<- Coordinate) { defer close(plotCoords) // MM that will be moved in a single step, used to calc what the new position along spiral will be after one time slice moveDist := 4.0 * Settings.MaxSpeed_MM_S * TimeSlice_US / 1000000.0 displacement := Coordinate{X: setup.CircleDisplacement, Y: 0} theta := 0.0 thetaDelta := 2.8 * math.Asin(moveDist/(2.0*setup.Radius)) origin := Coordinate{X: 0.0, Y: 0.0} for drawnCircles := 0; drawnCircles < setup.NumbCircles; { circlePos := Coordinate{X: setup.Radius * math.Cos(theta), Y: setup.Radius * math.Sin(theta)} origin = origin.Add(displacement.Scaled(thetaDelta / (2.0 * math.Pi))) plotCoords <- circlePos.Add(origin) theta += thetaDelta if theta > 2.0*math.Pi { theta -= 2.0 * math.Pi drawnCircles++ } } plotCoords <- Coordinate{X: 0, Y: 0} }
func TestTofloat(t *testing.T) { oldval := cfg.UseRadians cfg.UseRadians = true type test struct { in string out float64 } var tests []test = []test{ {"2.5+2.5", 2.5 + 2.5}, {"2.5*2.5", 2.5 * 2.5}, {"3/2", 3. / 2.}, {"2^10", math.Pow(2, 10)}, {"sqrt(2)", math.Sqrt(2)}, {"sin(2)", math.Sin(2)}, {"cos(2)", math.Cos(2)}, {"tan(2)", math.Tan(2)}, {"arcsin(0.3)", math.Asin(0.3)}, {"arccos(0.3)", math.Acos(0.3)}, {"arctan(0.3)", math.Atan(0.3)}, {"ln(2)", math.Log(2)}, {"log(2)", math.Log10(2)}, } for _, k := range tests { result := TextToCas(k.in).Tofloat() if result != k.out { t.Errorf("Tofloat: In:%v Out:%v Result:%v", k.in, k.out, result) } } cfg.UseRadians = oldval }
// EqToEcl converts equatorial coordinates to ecliptic coordinates. // // α: right ascension coordinate to transform // δ: declination coordinate to transform // sε: sine of obliquity of the ecliptic // cε: cosine of obliquity of the ecliptic // // Results: // // λ: ecliptic longitude // β: ecliptic latitude func EqToEcl(α unit.RA, δ unit.Angle, sε, cε float64) (λ, β unit.Angle) { sα, cα := α.Sincos() sδ, cδ := δ.Sincos() λ = unit.Angle(math.Atan2(sα*cε+(sδ/cδ)*sε, cα)) // (13.1) p. 93 β = unit.Angle(math.Asin(sδ*cε - cδ*sε*sα)) // (13.2) p. 93 return }
// AngleError returns both an angle as in the function Angle, and an error // as in the function Error. // // The algorithm is by B. Pessens. func AngleError(r1, d1, r2, d2, r3, d3 float64) (ψ, ω float64) { sr1, cr1 := math.Sincos(r1) sd1, cd1 := math.Sincos(d1) sr2, cr2 := math.Sincos(r2) sd2, cd2 := math.Sincos(d2) sr3, cr3 := math.Sincos(r3) sd3, cd3 := math.Sincos(d3) a1 := cd1 * cr1 a2 := cd2 * cr2 a3 := cd3 * cr3 b1 := cd1 * sr1 b2 := cd2 * sr2 b3 := cd3 * sr3 c1 := sd1 c2 := sd2 c3 := sd3 l1 := b1*c2 - b2*c1 l2 := b2*c3 - b3*c2 l3 := b1*c3 - b3*c1 m1 := c1*a2 - c2*a1 m2 := c2*a3 - c3*a2 m3 := c1*a3 - c3*a1 n1 := a1*b2 - a2*b1 n2 := a2*b3 - a3*b2 n3 := a1*b3 - a3*b1 ψ = math.Acos((l1*l2 + m1*m2 + n1*n2) / (math.Sqrt(l1*l1+m1*m1+n1*n1) * math.Sqrt(l2*l2+m2*m2+n2*n2))) ω = math.Asin((a2*l3 + b2*m3 + c2*n3) / (math.Sqrt(a2*a2+b2*b2+c2*c2) * math.Sqrt(l3*l3+m3*m3+n3*n3))) return }
func TestRectBounderMaxLatitudeSimple(t *testing.T) { cubeLat := math.Asin(1 / math.Sqrt(3)) // 35.26 degrees cubeLatRect := Rect{r1.IntervalFromPoint(-cubeLat).AddPoint(cubeLat), s1.IntervalFromEndpoints(-math.Pi/4, math.Pi/4)} tests := []struct { a, b Point want Rect }{ // Check cases where the min/max latitude is attained at a vertex. { a: PointFromCoords(1, 1, 1), b: PointFromCoords(1, -1, -1), want: cubeLatRect, }, { a: PointFromCoords(1, -1, 1), b: PointFromCoords(1, 1, -1), want: cubeLatRect, }, } for _, test := range tests { if got := rectBoundForPoints(test.a, test.b); !rectsApproxEqual(got, test.want, rectErrorLat, rectErrorLng) { t.Errorf("RectBounder for points (%v, %v) near max lat failed: got %v, want %v", test.a, test.b, got, test.want) } } }
// EclToEq converts ecliptic coordinates to equatorial coordinates. func (eq *Equatorial) EclToEq(ecl *Ecliptic, ε *Obliquity) *Equatorial { sβ, cβ := ecl.Lat.Sincos() sλ, cλ := ecl.Lon.Sincos() eq.RA = unit.RAFromRad(math.Atan2(sλ*ε.C-(sβ/cβ)*ε.S, cλ)) // (13.3) p. 93 eq.Dec = unit.Angle(math.Asin(sβ*ε.C + cβ*ε.S*sλ)) // (13.4) p. 93 return eq }
// Sep returns the separation angle in radians between x and y. // If any of x or y is zero-vector, it returns zero. func (x Vec) Sep(y Vec) float64 { xhat, yhat := x.Hat(), y.Hat() dot := xhat.Dot(yhat) if dot > 0.0 { tmp := xhat.Sub(yhat) return 2.0 * math.Asin(bracket(tmp.Abs()/2.0, 0.0, 1.0)) } if dot < 0.0 { tmp := xhat.Add(yhat) return math.Pi - 2.0*math.Asin(bracket(tmp.Abs()/2.0, 0.0, 1.0)) } if xhat.Zero() || yhat.Zero() { return 0.0 } return math.Pi / 2.0 }
func EaseInOutElastic(start, end, value float32) float32 { end -= start var d float32 = 1.0 var p float32 = d * 0.3 var s float32 = 0.0 var a float32 = 0.0 if value == 0 { return start } value /= d if value == 1 { return start + end } if a == 0 || a < float32(math.Abs(float64(end))) { a = end s = p / 4 } else { s = p / (2 * float32(math.Pi)) * float32(math.Asin(float64(end/a))) } if value < 1 { return -0.5*(a*float32(math.Pow(2, 10*(float64(value)-1)))*float32(math.Sin(float64((value*d-s)*(2*math.Pi)/p)))) + start } return a*float32(math.Pow(2, -10*(float64(value)-1)))*float32(math.Sin(float64((value*d-s)*(2*math.Pi)/p)))*0.5 + end + start }