Beispiel #1
0
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
}
Beispiel #2
0
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)
}
Beispiel #3
0
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
}
Beispiel #4
0
// 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
}
Beispiel #5
0
// 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
}
Beispiel #6
0
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)
	}
}
Beispiel #7
0
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)
}
Beispiel #8
0
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
}
Beispiel #9
0
// 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
}
Beispiel #10
0
// 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
}
Beispiel #11
0
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
}
Beispiel #12
0
// 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)))))
}
Beispiel #13
0
// 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
}
Beispiel #15
0
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)
		}
	}
}
Beispiel #16
0
/**
 * 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))
}
Beispiel #18
0
// 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")
}
Beispiel #19
0
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
}
Beispiel #20
0
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()
}
Beispiel #22
0
// 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
}
Beispiel #23
0
// 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
}
Beispiel #24
0
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

}
Beispiel #25
0
// 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))
}
Beispiel #26
0
Datei: matrix.go Projekt: aiju/gl
// 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}}
}
Beispiel #27
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
}
Beispiel #28
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
}
Beispiel #29
0
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
}
Beispiel #30
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)
}