// Returns hash if they intersect, otherwise nil func Intersect(P1, Q1, P2, Q2 Vec) ([20]byte, bool) { // Vectors with same length and direction as line segments v1 := Q1.Sub(P1) v2 := Q2.Sub(P2) // Parallel vectors never intersect det := v2.X*v1.Y - v1.X*v2.Y if det == 0 { return sha1nil, false } // Intersection is calculated using linear algebra var k1, k2 big.Rat Pdx, Pdy := P2.X-P1.X, P2.Y-P1.Y invDet := big.NewRat(1, det) k1.Mul(invDet, big.NewRat(-v2.Y*Pdx+v2.X*Pdy, 1)) k2.Mul(invDet, big.NewRat(-v1.Y*Pdx+v1.X*Pdy, 1)) // Check if intersection is inside both segments zero := big.NewRat(0, 1) one := big.NewRat(1, 1) k1valid := k1.Cmp(zero) == 1 && k1.Cmp(one) == -1 k2valid := k2.Cmp(zero) == 1 && k2.Cmp(one) == -1 // Return hash of intersection coordinate if it was if k1valid && k2valid { var Ix, Iy big.Rat Ix.Mul(big.NewRat(v1.X, 1), &k1).Add(&Ix, big.NewRat(P1.X, 1)) Iy.Mul(big.NewRat(v1.Y, 1), &k1).Add(&Iy, big.NewRat(P1.Y, 1)) return sha1.Sum([]byte(fmt.Sprintf("%v,%v", Ix.String(), Iy.String()))), true } else { return sha1nil, false } }
func TestDecimal_Rat(t *testing.T) { tests := [...]struct { v, s int64 a string }{ {5, 0, "5/1"}, {5, -5, "500000/1"}, {1234, 3, "617/500"}, } for i, v := range tests { x := New(v.v, v.s) if xs := x.Rat(nil).String(); xs != v.a { t.Errorf("#%d: wanted %s, got %s", i, v.a, xs) } } // Test that the non-nil big.Rat is used. x := New(5, 0) r := new(big.Rat) if xs := x.Rat(r).String(); xs != r.String() { t.Errorf("wanted %s, got %s and %s", "5/1", xs, r.String()) } }
func num(x *big.Rat) string { if x.IsInt() { return x.Num().String() } return x.String() }
func align(b *big.Rat, w int) string { s := b.String() return strings.Repeat(" ", w-strings.Index(s, "/")) + s }