diff --git a/src/cmd/math/main.go b/src/cmd/math/main.go index 9651117..3982487 100644 --- a/src/cmd/math/main.go +++ b/src/cmd/math/main.go @@ -32,7 +32,7 @@ func main() { gx.Point{0, 1}, gx.Point{1, 0}, }.Line() - fmt.Println(l1.Crosses(l2)) + fmt.Println(gx.LinersCross(l1, l2)) fmt.Println(l1.ContainsPoint(gx.Point{1, 4})) t := gx.Rectangle{ diff --git a/src/gx/line.go b/src/gx/line.go index 8c7c2c1..f3c048e 100644 --- a/src/gx/line.go +++ b/src/gx/line.go @@ -13,76 +13,48 @@ type Liner interface { Line() Line } +type LinerPointContainer interface { + Liner + PointContainer +} + // The type represents a line segment. type LineSegment [2]Point // The type represents multiple line segments. type LineSegments []LineSegment -// Check whether the liner is parallel to the line. -func (l Line) Parallel(liner Liner) bool { - buf := liner.Line() +type Edge = LineSegment +type Edges []Vertex + + +// Check if two LinerPointContainers do cross and return the +// crossing point. +func LinersCross(lp1, lp2 LinerPointContainer) (Point, bool) { + l1 := lp1.Line() + l2 := lp2.Line() - if buf.K == l.K { - return true - } - - return false -} - -func (l Line) Line() Line { - return l -} - -func (l Line) ContainsPoint(p Point) bool { - buf := Line{0, p.Y} - pc, ok := l.crossesLine(buf) - if !ok { - return false - } - - return pc == p -} - -func (l Line) Crosses(with Liner) (Point, bool) { - switch with.(type) { - case Line : - return l.crossesLine(with.(Line)) - case LineSegment : - return with.(LineSegment).crossesLine(l) - default: - panic("unhandled type") - } -} - -func (l1 Line) crossesLine(l2 Line) (Point, bool) { - if l1.Parallel(l2) { + p, crosses := l1.crossesLine(l2) + if !crosses || + !lp1.ContainsPoint(p) || + !lp2.ContainsPoint(p) { return Point{}, false } - x := (l1.C - l2.C) / (l2.K - l1.K) - y := l1.K*x + l1.C - return Point{x, y}, true + return p, true } -func (l LineSegment) ContainsPoint(p Point) bool { - line := l.Line() - if !line.ContainsPoint(p) { - return false - } +// Check whether the liner is parallel to the other liner. +func LinersParallel(first, second Liner) bool { + l1 := first.Line() + l2 := second.Line() - return false + return l1.K == l2.K } -// Get square of length of line segment. -func (ls LineSegment) LenSqr() Float { - return Sqr(ls[0].X - ls[1].X) + - Sqr(ls[0].Y - ls[1].Y) -} - -// Get length of the line segment. -func (ls LineSegment) Len() Float { - return math.Sqrt(ls.LenSqr()) +// Returns the line itself. Made to implement the Liner interface. +func (l Line) Line() Line { + return l } // Returns corresponding to the segment line line. @@ -96,35 +68,55 @@ func (l LineSegment) Line() Line { return Line{k, c} } -func (l LineSegment) Crosses(with Liner) (Point, bool) { - switch with.(type) { - case Line : - return l.crossesLine(with.(Line)) - case LineSegment : - return l.crossesLineSegment(with.(LineSegment)) - default: - panic("The type that is not defined to be crossed") +func (l Line) ContainsPoint(p Point) bool { + buf := Line{0, p.Y} + pc, ok := l.crossesLine(buf) + if !ok { + return false } + + return pc == p } -func (l LineSegment) Contains(what any) bool { - switch what.(type) { - case Point : - return l.containsPoint(what.(Point)) - default : - panic("Unexpected type") +func (l LineSegment) ContainsPoint(p Point) bool { + line := l.Line() + if !line.ContainsPoint(p) { + return false } + + xMax := Max(l[0].X, l[1].X) + xMin := Min(l[0].X, l[1].X) + + yMax := Max(l[0].Y, l[1].Y) + yMin := Min(l[0].Y, l[1].Y) + + if !(xMin < p.X && p.X < xMax) || + !(yMin < p.Y && p.Y < yMax) { + return false + } + + return true } -func (l LineSegment) containsPoint(p Point) bool { - return false +func (l1 Line) crossesLine(l2 Line) (Point, bool) { + if LinersParallel(l1, l2) { + return Point{}, false + } + + x := (l1.C - l2.C) / (l2.K - l1.K) + y := l1.K*x + l1.C + return Point{x, y}, true } -func (l LineSegment) crossesLineSegment(with LineSegment) (Point, bool) { - return Point{}, false + +// Get square of length of line segment. +func (ls LineSegment) LenSqr() Float { + return Sqr(ls[0].X - ls[1].X) + + Sqr(ls[0].Y - ls[1].Y) } -func (l LineSegment) crossesLine(with Line) (Point, bool) { - return Point{}, false +// Get length of the line segment. +func (ls LineSegment) Len() Float { + return math.Sqrt(ls.LenSqr()) } diff --git a/src/gx/math.go b/src/gx/math.go index 0b4dec3..ce7945b 100644 --- a/src/gx/math.go +++ b/src/gx/math.go @@ -30,6 +30,22 @@ func Sgn(v Float) Float { return 0 } +func Max(v1, v2 Float) Float { + if v1 > v2 { + return v1 + } + + return v2 +} + +func Min(v1, v2 Float) Float { + if v1 < v2 { + return v1 + } + + return v2 +} + func RadiansToDegrees(v Float) Float { return v } diff --git a/src/gx/rect.go b/src/gx/rect.go index d29d7af..d99bb14 100644 --- a/src/gx/rect.go +++ b/src/gx/rect.go @@ -39,7 +39,13 @@ func (r Rectangle) Vertices() Points { } func (r Rectangle) Edges() LineSegments { - return LineSegments{} + vs := r.Vertices() + return LineSegments{ + LineSegment{vs[0], vs[1]}, + LineSegment{vs[1], vs[2]}, + LineSegment{vs[2], vs[3]}, + LineSegment{vs[4], vs[0]}, + } } // Get 2 triangles that the rectangle consists of. diff --git a/src/gx/vector.go b/src/gx/vector.go index e9c9a41..3c658bc 100644 --- a/src/gx/vector.go +++ b/src/gx/vector.go @@ -9,6 +9,7 @@ type Vector struct { X, Y Float } type Point = Vector +type Vertex = Vector type Vectors []Vector type Points []Point