func (p Place) Azimuth(point Place) float64 { if (p.Latitude == point.Latitude) && (p.Longitude == point.Longitude) { return 0.0 } esq := (1.0 - 1.0/298.25) * (1.0 - 1.0/298.25) alat3 := math.Atan(math.Tan(p.Latitude/RadiansToDegrees)*esq) * RadiansToDegrees alat4 := math.Atan(math.Tan(point.Latitude/RadiansToDegrees)*esq) * RadiansToDegrees rlat1 := alat3 / RadiansToDegrees rlat2 := alat4 / RadiansToDegrees rdlon := (point.Longitude - p.Longitude) / RadiansToDegrees clat1 := math.Cos(rlat1) clat2 := math.Cos(rlat2) slat1 := math.Sin(rlat1) slat2 := math.Sin(rlat2) cdlon := math.Cos(rdlon) sdlon := math.Sin(rdlon) yazi := sdlon * clat2 xazi := clat1*slat2 - slat1*clat2*cdlon azi := RadiansToDegrees * math.Atan2(yazi, xazi) if azi < 0.0 { azi += 360.0 } return azi }
func (p Place) Distance(point Place) float64 { if (p.Latitude == point.Latitude) && (p.Longitude == point.Longitude) { return 0.0 } esq := (1.0 - 1.0/298.25) * (1.0 - 1.0/298.25) alat3 := math.Atan(math.Tan(p.Latitude/RadiansToDegrees)*esq) * RadiansToDegrees alat4 := math.Atan(math.Tan(point.Latitude/RadiansToDegrees)*esq) * RadiansToDegrees rlat1 := alat3 / RadiansToDegrees rlat2 := alat4 / RadiansToDegrees rdlon := (point.Longitude - p.Longitude) / RadiansToDegrees clat1 := math.Cos(rlat1) clat2 := math.Cos(rlat2) slat1 := math.Sin(rlat1) slat2 := math.Sin(rlat2) cdlon := math.Cos(rdlon) cdel := slat1*slat2 + clat1*clat2*cdlon switch { case cdel > 1.0: cdel = 1.0 case cdel < -1.0: cdel = -1.0 } return RadiansToKm * math.Acos(cdel) }
func (p Place) BackAzimuth(point Place) float64 { if (p.Latitude == point.Latitude) && (p.Longitude == point.Longitude) { return 0.0 } esq := (1.0 - 1.0/298.25) * (1.0 - 1.0/298.25) alat3 := math.Atan(math.Tan(p.Latitude/RadiansToDegrees)*esq) * RadiansToDegrees alat4 := math.Atan(math.Tan(point.Latitude/RadiansToDegrees)*esq) * RadiansToDegrees rlat1 := alat3 / RadiansToDegrees rlat2 := alat4 / RadiansToDegrees rdlon := (point.Longitude - p.Longitude) / RadiansToDegrees clat1 := math.Cos(rlat1) clat2 := math.Cos(rlat2) slat1 := math.Sin(rlat1) slat2 := math.Sin(rlat2) cdlon := math.Cos(rdlon) sdlon := math.Sin(rdlon) ybaz := -sdlon * clat1 xbaz := clat2*slat1 - slat2*clat1*cdlon baz := RadiansToDegrees * math.Atan2(ybaz, xbaz) if baz < 0.0 { baz += 360.0 } return baz }
// Generates sample from general Levy-stable distibution. func Sample(alpha float64, beta float64, mu float64, sigma float64) float64 { if beta == 0.0 { return symmetric(alpha, mu, sigma) } v := math.Pi * (rand.Float64() - 0.5) w := 0.0 for w == 0.0 { w = rand.ExpFloat64() } if alpha == 1.0 { x := ((0.5*math.Pi+beta*v)*math.Tan(v) - beta*math.Log(0.5*math.Pi*w*math.Cos(v)/(0.5*math.Pi+beta*v))) / (0.5 * math.Pi) return sigma*x + beta*sigma*math.Log(sigma)/(0.5*math.Pi) + mu } t := beta * math.Tan(0.5*math.Pi*alpha) s := math.Pow(1.0+t*t, 1.0/(2.0*alpha)) b := math.Atan(t) / alpha x := s * math.Sin(alpha*(v+b)) * math.Pow(math.Cos(v-alpha*(v+b))/w, (1.0-alpha)/alpha) / math.Pow(math.Cos(v), 1.0/alpha) return sigma*x + mu }
// Project finds radon projections of N lines running through the image // center for lines angled 0 to 180 degrees from horizontal. // Totally not working // // /param img - img.Image src image // /param N - int number of angled lines to consider. // /return sinogram - Projections // /return nbPerLine - number of pixel per line in sinogram // /return error - if failed func Project(img image.Image, N int) (*image.Gray, []uint8, error) { if N == 0 { N = 180 } var err error size := img.Bounds().Size() D := max(size.X, size.Y) xCenter, yCenter := float64(size.X)/2.0, float64(size.Y)/2.0 xOff := int(math.Floor(xCenter + roundingFactor(xCenter))) yOff := int(math.Floor(yCenter + roundingFactor(yCenter))) radonMap := image.NewGray(image.Rect(0, 0, N, D)) if err != nil { return nil, nil, err } nbPerLine := make([]uint8, N) for k := 0; k < (N/4)+1; k++ { θ := float64(k) * math.Pi / float64(N) α := math.Tan(θ) for x := 0; x < D; x++ { y := α * float64(x-xOff) yd := int(math.Floor(y + roundingFactor(y))) if (yd+yOff >= 0) && (yd+yOff < size.Y) && (x < size.X) { addPixelsToGray(img, x, yd+yOff, *radonMap, k, x) nbPerLine[k]++ } if (yd+xOff >= 0) && (yd+xOff < size.X) && (k != N/4) && (x < size.Y) { addPixelsToGray(img, yd+xOff, x, *radonMap, N/2-k, x) nbPerLine[N/2-k]++ } } } for j, k := 0, 3*N/4; k < N; k++ { θ := float64(k) * math.Pi / float64(N) α := math.Tan(θ) for x := 0; x < D; x++ { y := α * float64(x-xOff) yd := int(math.Floor(y + roundingFactor(y))) if (yd+yOff >= 0) && (yd+yOff < size.Y) && (x < size.X) { addPixelsToGray(img, x, yd+yOff, *radonMap, k, x) nbPerLine[k]++ } if (yOff-yd >= 0) && (yOff-yd < size.X) && (2*yOff-x >= 0) && (2*yOff-x < size.Y) && (k != 3*N/4) { addPixelsToGray(img, -yd+yOff, -(x-yOff)+yOff, *radonMap, k-j, x) nbPerLine[k-j]++ } } j += 2 } return radonMap, nbPerLine, nil }
func (p *PerspectiveCamera) UpdateProjectionMatrix() { var fov = math3d.RadToDeg(2 * math.Atan(math.Tan(math3d.DegToRad(p.Fov)*0.5)/p.Zoom)) if p.FullWidth > 0 { var aspect = p.FullWidth / p.FullHeight var top = math.Tan(math3d.DegToRad(fov*0.5)) * p.Near var bottom = -top var left = aspect * bottom var right = aspect * top var width = math.Abs(right - left) var height = math.Abs(top - bottom) p.ProjectionMatrix.MakeFrustum( left+p.X*width/p.FullWidth, left+(p.X+p.Width)*width/p.FullWidth, top-(p.Y+p.Height)*height/p.FullHeight, top-p.Y*height/p.FullHeight, p.Near, p.Far, ) } else { p.ProjectionMatrix.MakePerspective(fov, p.Aspect, p.Near, p.Far) } }
func (self *Calc) CalculateFunction(funcName string, arg32 float32) float32 { if len(self.errors) > 0 { return 1 } var result float64 arg := float64(arg32) switch funcName { case "sin": result = math.Sin(self.DegToRad(arg)) case "cos": result = math.Cos(self.DegToRad(arg)) case "tg": result = math.Tan(self.DegToRad(arg)) case "ctg": result = 1.0 / math.Tan(self.DegToRad(arg)) case "arcsin": result = self.RadToDeg(math.Asin(arg)) case "arccos": result = self.RadToDeg(math.Acos(arg)) case "arctg": result = self.RadToDeg(math.Atan(arg)) case "arcctg": result = self.RadToDeg(math.Atan(1 / arg)) case "sqrt": result = math.Sqrt(arg) default: self.errors = append(self.errors, "Unknown identifier "+funcName) return 1 } return float32(result) }
func (m *Context) determineZoom(bounds s2.Rect, center s2.LatLng) int { b := bounds.AddPoint(center) if b.IsEmpty() || b.IsPoint() { return 15 } tileSize := m.tileProvider.TileSize margin := 4.0 + m.determineExtraMarginPixels() w := (float64(m.width) - 2.0*margin) / float64(tileSize) h := (float64(m.height) - 2.0*margin) / float64(tileSize) minX := (b.Lo().Lng.Degrees() + 180.0) / 360.0 maxX := (b.Hi().Lng.Degrees() + 180.0) / 360.0 minY := (1.0 - math.Log(math.Tan(b.Lo().Lat.Radians())+(1.0/math.Cos(b.Lo().Lat.Radians())))/math.Pi) / 2.0 maxY := (1.0 - math.Log(math.Tan(b.Hi().Lat.Radians())+(1.0/math.Cos(b.Hi().Lat.Radians())))/math.Pi) / 2.0 dx := math.Abs(maxX - minX) dy := math.Abs(maxY - minY) zoom := 1 for zoom < 30 { tiles := float64(uint(1) << uint(zoom)) if dx*tiles > w || dy*tiles > h { return zoom - 1 } zoom = zoom + 1 } return 15 }
// AnomalyDistance returns true anomaly and distance for near-parabolic orbits. // // Distance r returned in AU. // An error is returned if the algorithm fails to converge. func (e *Elements) AnomalyDistance(jde float64) (ν unit.Angle, r float64, err error) { // fairly literal translation of code on p. 246 q1 := base.K * math.Sqrt((1+e.Ecc)/e.PDis) / (2 * e.PDis) // line 20 g := (1 - e.Ecc) / (1 + e.Ecc) // line 20 t := jde - e.TimeP // line 22 if t == 0 { // line 24 return 0, e.PDis, nil } d1, d := 10000., 1e-9 // line 14 q2 := q1 * t // line 28 s := 2. / (3 * math.Abs(q2)) // line 30 s = 2 / math.Tan(2*math.Atan(math.Cbrt(math.Tan(math.Atan(s)/2)))) if t < 0 { // line 34 s = -s } if e.Ecc != 1 { // line 36 l := 0 // line 38 for { s0 := s // line 40 z := 1. y := s * s g1 := -y * s q3 := q2 + 2*g*s*y/3 // line 42 for { z += 1 // line 44 g1 = -g1 * g * y // line 46 z1 := (z - (z+1)*g) / (2*z + 1) // line 48 f := z1 * g1 // line 50 q3 += f // line 52 if z > 50 || math.Abs(f) > d1 { // line 54 return 0, 0, errors.New("No convergence") } if math.Abs(f) <= d { // line 56 break } } l++ // line 58 if l > 50 { return 0, 0, errors.New("No convergence") } for { s1 := s // line 60 s = (2*s*s*s/3 + q3) / (s*s + 1) if math.Abs(s-s1) <= d { // line 62 break } } if math.Abs(s-s0) <= d { // line 64 break } } } ν = unit.Angle(2 * math.Atan(s)) // line 66 r = e.PDis * (1 + e.Ecc) / (1 + e.Ecc*ν.Cos()) // line 68 if ν < 0 { // line 70 ν += 2 * math.Pi } return }
// Equatorial computes data for a sundial level with the equator. // // Argument φ is geographic latitude at which the sundial will be located; // a is the length of a straight stylus perpendicular to the plane of the // sundial. // // The sundial will have two sides, north and south. Results n and s define // lines on the north and south sides of the sundial. Result coordinates // are in units of a, the stylus length. func Equatorial(φ, a float64) (n, s []Line) { tφ := math.Tan(φ) for i := 0; i < 24; i++ { nl := Line{Hour: i} sl := Line{Hour: i} H := float64(i-12) * 15 * math.Pi / 180 aH := math.Abs(H) sH, cH := math.Sincos(H) for _, d := range m { tδ := math.Tan(d * math.Pi / 180) H0 := math.Acos(-tφ * tδ) if aH > H0 { continue } x := -a * sH / tδ yy := a * cH / tδ if tδ < 0 { sl.Points = append(sl.Points, Point{x, yy}) } else { nl.Points = append(nl.Points, Point{x, -yy}) } } if len(nl.Points) > 0 { n = append(n, nl) } if len(sl.Points) > 0 { s = append(s, sl) } } return }
func argsCheckAndAddColor(org float32, index int, anivalue float32) float32 { if len(os.Args) < index*2+1 { return org } targ, err := strconv.ParseFloat(os.Args[index*2], 32) if err != nil { return org } anivalue += 1 switch os.Args[index*2-1] { case "+": return org + float32(targ)*anivalue case "*": return org * float32(targ) * anivalue case "/": return org / (float32(targ) * anivalue) case "^": return float32(math.Pow(float64(org), targ*float64(anivalue))) case "sin+": return 255 * float32(math.Sin((float64(org)+targ*float64(anivalue))/255*math.Pi*2)) case "sin*": return 255 * float32(math.Sin((float64(org)*targ*float64(anivalue))/255*math.Pi*2)) case "cos+": return 255 * float32(math.Cos((float64(org)+targ*float64(anivalue))/255*math.Pi*2)) case "cos*": return 255 * float32(math.Cos((float64(org)*targ*float64(anivalue))/255*math.Pi*2)) case "tan+": return 255 * float32(math.Tan((float64(org)+targ*float64(anivalue))/255*math.Pi*2)) case "tan*": return 255 * float32(math.Tan((float64(org)*targ*float64(anivalue))/255*math.Pi*2)) } return org }
// PointArea returns the area on the unit sphere for the triangle defined by the // given points. // // This method is based on l'Huilier's theorem, // // tan(E/4) = sqrt(tan(s/2) tan((s-a)/2) tan((s-b)/2) tan((s-c)/2)) // // where E is the spherical excess of the triangle (i.e. its area), // a, b, c are the side lengths, and // s is the semiperimeter (a + b + c) / 2. // // The only significant source of error using l'Huilier's method is the // cancellation error of the terms (s-a), (s-b), (s-c). This leads to a // *relative* error of about 1e-16 * s / min(s-a, s-b, s-c). This compares // to a relative error of about 1e-15 / E using Girard's formula, where E is // the true area of the triangle. Girard's formula can be even worse than // this for very small triangles, e.g. a triangle with a true area of 1e-30 // might evaluate to 1e-5. // // So, we prefer l'Huilier's formula unless dmin < s * (0.1 * E), where // dmin = min(s-a, s-b, s-c). This basically includes all triangles // except for extremely long and skinny ones. // // Since we don't know E, we would like a conservative upper bound on // the triangle area in terms of s and dmin. It's possible to show that // E <= k1 * s * sqrt(s * dmin), where k1 = 2*sqrt(3)/Pi (about 1). // Using this, it's easy to show that we should always use l'Huilier's // method if dmin >= k2 * s^5, where k2 is about 1e-2. Furthermore, // if dmin < k2 * s^5, the triangle area is at most k3 * s^4, where // k3 is about 0.1. Since the best case error using Girard's formula // is about 1e-15, this means that we shouldn't even consider it unless // s >= 3e-4 or so. func PointArea(a, b, c Point) float64 { sa := float64(b.Angle(c.Vector)) sb := float64(c.Angle(a.Vector)) sc := float64(a.Angle(b.Vector)) s := 0.5 * (sa + sb + sc) if s >= 3e-4 { // Consider whether Girard's formula might be more accurate. dmin := s - math.Max(sa, math.Max(sb, sc)) if dmin < 1e-2*s*s*s*s*s { // This triangle is skinny enough to use Girard's formula. ab := a.PointCross(b) bc := b.PointCross(c) ac := a.PointCross(c) area := math.Max(0.0, float64(ab.Angle(ac.Vector)-ab.Angle(bc.Vector)+bc.Angle(ac.Vector))) if dmin < s*0.1*area { return area } } } // Use l'Huilier's formula. return 4 * math.Atan(math.Sqrt(math.Max(0.0, math.Tan(0.5*s)*math.Tan(0.5*(s-sa))* math.Tan(0.5*(s-sb))*math.Tan(0.5*(s-sc))))) }
// Angle returns the angle between great circles defined by three points. // // Coordinates may be right ascensions and declinations or longitudes and // latitudes. If r1, d1, r2, d2 defines one line and r2, d2, r3, d3 defines // another, the result is the angle between the two lines. // // Algorithm by Meeus. func Angle(r1, d1, r2, d2, r3, d3 float64) float64 { sd2, cd2 := math.Sincos(d2) sr21, cr21 := math.Sincos(r2 - r1) sr32, cr32 := math.Sincos(r3 - r2) C1 := math.Atan2(sr21, cd2*math.Tan(d1)-sd2*cr21) C2 := math.Atan2(sr32, cd2*math.Tan(d3)-sd2*cr32) return C1 + C2 }
// ConvertToNorthingEasting converts latitude and longitude to // Ordnance Survey grid reference northing and easting. // It returns a struct containing easting and northing coordinates as float64 type // or an error if the arguments passed in are out of bounds func ConvertToNorthingEasting(lat, lon float64) (*OsGrid, error) { o := OsGrid{} // validate input if lat < -90 || lat > 90 { return &o, ErrInvalidLat } if lon < -180 || lon > 180 { return &o, ErrInvalidLon } φ := toRadians(lat) λ := toRadians(lon) cosφ := math.Cos(φ) sinφ := math.Sin(φ) ν := a * f0 / math.Sqrt(1-e2*sinφ*sinφ) ρ := a * f0 * (1 - e2) / math.Pow(1-e2*sinφ*sinφ, 1.5) η2 := ν/ρ - 1 Ma := (1 + n + (5/4)*n2 + (5/4)*n3) * (φ - φ0) Mb := (3*n + 3*n*n + (21/8)*n3) * math.Sin(φ-φ0) * math.Cos(φ+φ0) Mc := ((15/8)*n2 + (15/8)*n3) * math.Sin(2*(φ-φ0)) * math.Cos(2*(φ+φ0)) Md := (35 / 24) * n3 * math.Sin(3*(φ-φ0)) * math.Cos(3*(φ+φ0)) M := b * f0 * (Ma - Mb + Mc - Md) cos3φ := cosφ * cosφ * cosφ cos5φ := cos3φ * cosφ * cosφ tan2φ := math.Tan(φ) * math.Tan(φ) tan4φ := tan2φ * tan2φ I := M + n0 II := (ν / 2) * sinφ * cosφ III := (ν / 24) * sinφ * cos3φ * (5 - tan2φ + 9*η2) IIIA := (ν / 720) * sinφ * cos5φ * (61 - 58*tan2φ + tan4φ) IV := ν * cosφ V := (ν / 6) * cos3φ * (ν/ρ - tan2φ) VI := (ν / 120) * cos5φ * (5 - 18*tan2φ + tan4φ + 14*η2 - 58*tan2φ*η2) Δλ := λ - λ0 Δλ2 := Δλ * Δλ Δλ3 := Δλ2 * Δλ Δλ4 := Δλ3 * Δλ Δλ5 := Δλ4 * Δλ Δλ6 := Δλ5 * Δλ northingVal := I + II*Δλ2 + III*Δλ4 + IIIA*Δλ6 northingVal, _ = strconv.ParseFloat(fmt.Sprintf("%.3f", northingVal), 64) // truncate after 3 decimal positions o.Northing = northingVal eastingVal := e0 + IV*Δλ + V*Δλ3 + VI*Δλ5 eastingVal, _ = strconv.ParseFloat(fmt.Sprintf("%.3f", eastingVal), 64) // truncate after 3 decimal positions o.Easting = eastingVal return &o, nil }
func TestAreaAndCentroid(t *testing.T) { if got := north_hemi.Area(); math.Abs(got-2*math.Pi) > 1e-15 { t.Errorf("%v.Area() == %v, want %v", north_hemi, got, 2*math.Pi) } if got := east_hemi.Area(); got > 2*math.Pi+1e-12 { t.Errorf("%v.Area() > %v, want <= %v", east_hemi, got, 2*math.Pi+1e-12) } if got := east_hemi.Area(); got < 2*math.Pi-1e-12 { t.Errorf("%v.Area() > %v, want >= %v", east_hemi, got, 2*math.Pi-1e-12) } // Construct spherical caps of random height, and approximate their // boundary with closely spaced vertices. Then check that the area and // centroid are correct. const kMaxDist = 1e-6 for i := 0; i < 100; i++ { // Choose a coordinate frame for the spherical cap. x, y, z := randomFrame() // Given two points at latitude phi and whose longitudes differ // by dtheta, the geodesic between the two points has a maximum // latitude of atan(tan(phi) / cos(dtheta/2)). This can be // derived by positioning the two points at (-dtheta/2, phi) // and (dtheta/2, phi). // // We want to position the vertices close enough together so // that their maximum distance from the boundary of the // spherical cap is kMaxDist. Thus we want // fabs(atan(tan(phi) / cos(dtheta/2)) - phi) <= kMaxDist. height := 2 * rand.Float64() phi := math.Asin(1 - height) max_dtheta := 2 * math.Acos(math.Tan(math.Abs(phi))/math.Tan(math.Abs(phi)+kMaxDist)) max_dtheta = math.Min(math.Pi, max_dtheta) var vertices []Point for theta := 0.0; theta < 2*math.Pi; theta += rand.Float64() * max_dtheta { a := x.Mul(math.Cos(theta) * math.Cos(phi)) b := y.Mul(math.Sin(theta) * math.Cos(phi)) c := z.Mul(math.Sin(phi)) vertices = append(vertices, Point{a.Add(b).Add(c)}) } loop := NewLoopFromPath(vertices) area := loop.Area() centroid := loop.Centroid() expectedArea := 2 * math.Pi * height if got := math.Abs(area - expectedArea); got > 2*math.Pi*kMaxDist { t.Errorf("%v > %v", got, 2*math.Pi*kMaxDist) } if got := math.Abs(area - expectedArea); got < 0.01*kMaxDist { t.Errorf("%v < %v", got, 0.01*kMaxDist) } expectedCentroid := z.Mul(expectedArea * (1 - 0.5*height)) if got := centroid.Sub(expectedCentroid).Norm(); got > 2*kMaxDist { t.Errorf("(%v - %v).Norm() == %v, want <= %v", centroid, expectedCentroid, got, 2*kMaxDist) } } }
/** * Return the area of triangle ABC. The method used is about twice as * expensive as Girard's formula, but it is numerically stable for both large * and very small triangles. The points do not need to be normalized. The area * is always positive. * * The triangle area is undefined if it contains two antipodal points, and * becomes numerically unstable as the length of any edge approaches 180 * degrees. */ func Area(a, b, c Point) float64 { // This method is based on l'Huilier's theorem, // // tan(E/4) = sqrt(tan(s/2) tan((s-a)/2) tan((s-b)/2) tan((s-c)/2)) // // where E is the spherical excess of the triangle (i.e. its area), // a, b, c, are the side lengths, and // s is the semiperimeter (a + b + c) / 2 . // // The only significant source of error using l'Huilier's method is the // cancellation error of the terms (s-a), (s-b), (s-c). This leads to a // *relative* error of about 1e-16 * s / min(s-a, s-b, s-c). This compares // to a relative error of about 1e-15 / E using Girard's formula, where E is // the true area of the triangle. Girard's formula can be even worse than // this for very small triangles, e.g. a triangle with a true area of 1e-30 // might evaluate to 1e-5. // // So, we prefer l'Huilier's formula unless dmin < s * (0.1 * E), where // dmin = min(s-a, s-b, s-c). This basically includes all triangles // except for extremely long and skinny ones. // // Since we don't know E, we would like a conservative upper bound on // the triangle area in terms of s and dmin. It's possible to show that // E <= k1 * s * sqrt(s * dmin), where k1 = 2*sqrt(3)/Pi (about 1). // Using this, it's easy to show that we should always use l'Huilier's // method if dmin >= k2 * s^5, where k2 is about 1e-2. Furthermore, // if dmin < k2 * s^5, the triangle area is at most k3 * s^4, where // k3 is about 0.1. Since the best case error using Girard's formula // is about 1e-15, this means that we shouldn't even consider it unless // s >= 3e-4 or so. // We use volatile doubles to force the compiler to truncate all of these // quantities to 64 bits. Otherwise it may compute a value of dmin > 0 // simply because it chose to spill one of the intermediate values to // memory but not one of the others. sa := b.Angle(c.Vector).Radians() sb := c.Angle(a.Vector).Radians() sc := a.Angle(b.Vector).Radians() s := 0.5 * (sa + sb + sc) if s >= 3e-4 { // Consider whether Girard's formula might be more accurate. s2 := s * s dmin := s - math.Max(sa, math.Max(sb, sc)) if dmin < 1e-2*s*s2*s2 { // This triangle is skinny enough to consider Girard's formula. area := GirardArea(a, b, c) if dmin < s*(0.1*area) { return area } } } // Use l'Huilier's formula. return 4 * math.Atan( math.Sqrt( math.Max(0.0, math.Tan(0.5*s)*math.Tan(0.5*(s-sa))*math.Tan(0.5*(s-sb))*math.Tan(0.5*(s-sc))))) }
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)) }
// MinSepRect returns the minimum separation between two moving objects. // // Like MinSep, but using a method of rectangular coordinates that gives // accurate results even for close approaches. func MinSepRect(jd1, jd3 float64, r1, d1, r2, d2 []float64) (float64, error) { if len(r1) != 3 || len(d1) != 3 || len(r2) != 3 || len(d2) != 3 { return 0, interp.ErrorNot3 } uv := func(r1, d1, r2, d2 float64) (u, v float64) { sd1, cd1 := math.Sincos(d1) Δr := r2 - r1 tΔr := math.Tan(Δr) thΔr := math.Tan(Δr / 2) K := 1 / (1 + sd1*sd1*tΔr*thΔr) sΔd := math.Sin(d2 - d1) u = -K * (1 - (sd1/cd1)*sΔd) * cd1 * tΔr v = K * (sΔd + sd1*cd1*tΔr*thΔr) return } us := make([]float64, 3, 6) vs := us[3:6] for x, r := range r1 { us[x], vs[x] = uv(r, d1[x], r2[x], d2[x]) } u3, err := interp.NewLen3(-1, 1, us) if err != nil { panic(err) // bug not caller's fault. } v3, err := interp.NewLen3(-1, 1, vs) if err != nil { panic(err) // bug not caller's fault. } up0 := (us[2] - us[0]) / 2 vp0 := (vs[2] - vs[0]) / 2 up1 := us[0] + us[2] - 2*us[1] vp1 := vs[0] + vs[2] - 2*vs[1] up := up0 vp := vp0 dn := -(us[1]*up + vs[1]*vp) / (up*up + vp*vp) n := dn var u, v float64 for limit := 0; limit < 10; limit++ { u = u3.InterpolateN(n) v = v3.InterpolateN(n) if math.Abs(dn) < 1e-5 { return math.Hypot(u, v), nil // success } up := up0 + n*up1 vp := vp0 + n*vp1 dn = -(u*up + v*vp) / (up*up + vp*vp) n += dn } return 0, errors.New("MinSepRect: failure to converge") }
func Deg2num(lng, lat float64, zoom int) (x, y int) { n := math.Exp2(float64(zoom)) x = int(math.Floor((lng + 180.0) / 360.0 * n)) lat_rad := lat * math.Pi / 180 y = int(math.Floor((1.0 - math.Log(math.Tan(lat_rad)+1.0/math.Cos(lat_rad))/math.Pi) / 2.0 * n)) return }
func plot_cone(α float64, preservePrev bool) { nu, nv := 11, 21 l := 1.2 r := math.Tan(α) * l S, T := utl.MeshGrid2D(0, l, 0, 2.0*PI, nu, nv) X := la.MatAlloc(nv, nu) Y := la.MatAlloc(nv, nu) Z := la.MatAlloc(nv, nu) u := make([]float64, 3) v := make([]float64, 3) L := rot_matrix() for j := 0; j < nu; j++ { for i := 0; i < nv; i++ { u[0] = S[i][j] * r * math.Cos(T[i][j]) u[1] = S[i][j] * r * math.Sin(T[i][j]) u[2] = S[i][j] la.MatVecMul(v, 1, L, u) X[i][j], Y[i][j], Z[i][j] = v[0], v[1], v[2] } } pp := 0 if preservePrev { pp = 1 } plt.Wireframe(X, Y, Z, io.Sf("color='b', lw=0.5, preservePrev=%d", pp)) }
// reset our viewport after a window resize func resizeWindow(width, height int) { // protect against a divide by zero if height == 0 { height = 1 } // Setup our viewport gl.Viewport(0, 0, int(width), int(height)) // change to the projection matrix and set our viewing volume. gl.MatrixMode(gl.PROJECTION) gl.LoadIdentity() // aspect ratio aspect := gl.GLdouble(gl.GLfloat(width) / gl.GLfloat(height)) // Set our perspective. // This code is equivalent to using gluPerspective as in the original tutorial. var fov, near, far gl.GLdouble fov = 45.0 near = 0.1 far = 100.0 top := gl.GLdouble(math.Tan(float64(fov*math.Pi/360.0))) * near bottom := -top left := aspect * bottom right := aspect * top gl.Frustum(float64(left), float64(right), float64(bottom), float64(top), float64(near), float64(far)) // Make sure we're changing the model view and not the projection gl.MatrixMode(gl.MODELVIEW) // Reset the view gl.LoadIdentity() }
// Horizontal computes data for a horizontal sundial. // // Argument φ is geographic latitude at which the sundial will be located, // a is the length of a straight stylus perpendicular to the plane of the // sundial. // // Results consist of a set of lines, a center point, and u, the length of a // polar stylus. They are in units of a, the stylus length. func Horizontal(φ, a float64) (lines []Line, center Point, u float64) { sφ, cφ := math.Sincos(φ) tφ := sφ / cφ for i := 0; i < 24; i++ { l := Line{Hour: i} H := float64(i-12) * 15 * math.Pi / 180 aH := math.Abs(H) sH, cH := math.Sincos(H) for _, d := range m { tδ := math.Tan(d * math.Pi / 180) H0 := math.Acos(-tφ * tδ) if aH > H0 { continue // sun below horizon } Q := cφ*cH + sφ*tδ x := a * sH / Q y := a * (sφ*cH - cφ*tδ) / Q l.Points = append(l.Points, Point{x, y}) } if len(l.Points) > 0 { lines = append(lines, l) } } center.Y = -a / tφ u = a / math.Abs(sφ) return }
// Vertical computes data for a vertical sundial. // // Argument φ is geographic latitude at which the sundial will be located. // D is gnomonic declination, the azimuth of the perpendicular to the plane // of the sundial, measured from the southern meridian towards the west. // Argument a is the length of a straight stylus perpendicular to the plane // of the sundial. // // Results consist of a set of lines, a center point, and u, the length of a // polar stylus. They are in units of a, the stylus length. func Vertical(φ, D, a float64) (lines []Line, center Point, u float64) { sφ, cφ := math.Sincos(φ) tφ := sφ / cφ sD, cD := math.Sincos(D) for i := 0; i < 24; i++ { l := Line{Hour: i} H := float64(i-12) * 15 * math.Pi / 180 aH := math.Abs(H) sH, cH := math.Sincos(H) for _, d := range m { tδ := math.Tan(d * math.Pi / 180) H0 := math.Acos(-tφ * tδ) if aH > H0 { continue // sun below horizon } Q := sD*sH + sφ*cD*cH - cφ*cD*tδ if Q < 0 { continue // sun below plane of sundial } x := a * (cD*sH - sφ*sD*cH + cφ*sD*tδ) / Q y := -a * (cφ*cH + sφ*tδ) / Q l.Points = append(l.Points, Point{x, y}) } if len(l.Points) > 0 { lines = append(lines, l) } } center.X = -a * sD / cD center.Y = a * tφ / cD u = a / math.Abs(cφ*cD) return }
func (scn *Scene) Init() { scn.StartLine = 0 // Start rendering line scn.EndLine = scn.ImgHeight - 1 scn.Image = image.NewRGBA(image.Rect(0, 0, scn.ImgWidth, scn.ImgHeight)) scn.GridWidth = scn.ImgWidth * scn.OverSampling scn.GridHeight = scn.ImgHeight * scn.OverSampling scn.Look = scn.CameraLook.Sub(scn.CameraPos) scn.Vhor = scn.Look.Cross(scn.CameraUp) scn.Vhor = scn.Vhor.Normalize() scn.Vver = scn.Look.Cross(scn.Vhor) scn.Vver = scn.Vver.Normalize() fl := float64(scn.GridWidth) / (2 * math.Tan((0.5*scn.VisionField)*PI_180)) Vp := scn.Look.Normalize() Vp.X = Vp.X*fl - 0.5*(float64(scn.GridWidth)*scn.Vhor.X+float64(scn.GridHeight)*scn.Vver.X) Vp.Y = Vp.Y*fl - 0.5*(float64(scn.GridWidth)*scn.Vhor.Y+float64(scn.GridHeight)*scn.Vver.Y) Vp.Z = Vp.Z*fl - 0.5*(float64(scn.GridWidth)*scn.Vhor.Z+float64(scn.GridHeight)*scn.Vver.Z) scn.Vp = Vp }
// Approximate a circular arc of fewer than π/2 // radians with cubic Bézier curve. func partialArc(p *pdf.Path, x, y, r vg.Length, a1, a2 float64) { a := (a2 - a1) / 2 x4 := r * vg.Length(math.Cos(a)) y4 := r * vg.Length(math.Sin(a)) x1 := x4 y1 := -y4 const k = 0.5522847498 // some magic constant f := k * vg.Length(math.Tan(a)) x2 := x1 + f*y4 y2 := y1 + f*x4 x3 := x2 y3 := -y2 // Rotate and translate points into position. ar := a + a1 sinar := vg.Length(math.Sin(ar)) cosar := vg.Length(math.Cos(ar)) x2r := x2*cosar - y2*sinar + x y2r := x2*sinar + y2*cosar + y x3r := x3*cosar - y3*sinar + x y3r := x3*sinar + y3*cosar + y x4 = r*vg.Length(math.Cos(a2)) + x y4 = r*vg.Length(math.Sin(a2)) + y p.Curve(pdfPoint(x2r, y2r), pdfPoint(x3r, y3r), pdfPoint(x4, y4)) }
// Frustum returns a projection matrix similar to gluPerspective. The arguments are field of view angle in degrees, aspect ratio and near and far z clipping plane distance. func Frustum(fov, aspect, zNear, zFar float64) Mat4 { f := 1 / math.Tan(fov*deg/2) return Mat4{[4]float64{f / aspect, 0, 0, 0}, [4]float64{0, f, 0, 0}, [4]float64{0, 0, (zNear + zFar) / (zNear - zFar), (2 * zNear * zFar) / (zNear - zFar)}, [4]float64{0, 0, -1, 0}} }
func fwd(q state, u control) state { var qd state qd.x = u.s * math.Cos(q.th) qd.y = u.s * math.Sin(q.th) qd.th = u.s * math.Tan(u.ph) / AXLEDIST return qd }
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 }
func (m *Matrix4) Perspective(fov, aspect, near, far float32) { xymax := near * float32(internalMath.Tan(float64(fov*(internalMath.Pi/90.0)))) ymin := -xymax xmin := -xymax width := xymax - xmin height := xymax - ymin depth := far - near q := -(far + near) / depth qn := -2.0 * (far * near) / depth w := 2.0 * near / width w = w / aspect h := 2.0 * near / height m[0] = w m[4] = 0 m[8] = 0 m[12] = 0 m[1] = 0 m[5] = h m[9] = 0 m[13] = 0 m[2] = 0 m[6] = 0 m[10] = q m[14] = qn m[3] = 0 m[7] = 0 m[11] = -1 m[15] = 0 }
// TransformSkew generally skews the following text, drawings and images // keeping the point (x, y) stationary. angleX ranges from -90 degrees (skew to // the left) to 90 degrees (skew to the right). angleY ranges from -90 degrees // (skew to the bottom) to 90 degrees (skew to the top). // // The TransformBegin() example demonstrates this method. func (f *Fpdf) TransformSkew(angleX, angleY, x, y float64) { if angleX <= -90 || angleX >= 90 || angleY <= -90 || angleY >= 90 { f.err = fmt.Errorf("skew values must be between -90° and 90°") return } x *= f.k y = (f.h - y) * f.k var tm TransformMatrix tm.A = 1 tm.B = math.Tan(angleY * math.Pi / 180) tm.C = math.Tan(angleX * math.Pi / 180) tm.D = 1 tm.E = -tm.C * y tm.F = -tm.B * x f.Transform(tm) }