Skip to content

Commit

Permalink
[geom] Split shapes into individual files; includes a fix to Tri.Cont…
Browse files Browse the repository at this point in the history
…ains

Contains didn't properly account for collinearity.
  • Loading branch information
vibridi committed Sep 27, 2024
1 parent b58ebb9 commit 3e1cef5
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 80 deletions.
27 changes: 27 additions & 0 deletions internal/geom/rect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package geom

import "fmt"

// Rect represents a rectangle
type Rect struct {
TL P // top-left vertex of the rectangle
BR P // bottom-right vertex of the rectangle
}

func (r Rect) String() string {
return fmt.Sprintf("{geom.P{%.02f,%.02f},geom.P{%.02f,%.02f}}", r.TL.X, r.TL.Y, r.BR.X, r.BR.Y)
}

func (r Rect) SVG() string {
width := r.BR.X - r.TL.X
height := r.BR.Y - r.TL.Y
return fmt.Sprintf(`<rect class="rect" x="%f" y="%f" width="%f" height="%f" style="fill: lightgrey; stroke: black;" />`, r.TL.X, r.TL.Y, width, height)
}

func (r Rect) Width() float64 {
return r.BR.X - r.TL.X
}

func (r Rect) Height() float64 {
return r.BR.Y - r.TL.Y
}
18 changes: 18 additions & 0 deletions internal/geom/segment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package geom

import "fmt"

type Segment struct {
A, B P
}

func (seg Segment) SVG() string {
return fmt.Sprintf(`<path d="M %.2f,%.2f %.2f,%.2f" stroke="blue" />`, seg.A.X, seg.A.Y, seg.B.X, seg.B.Y)
}

func (seg Segment) Other(v P) P {
if seg.A == v {
return seg.B
}
return seg.A
}
79 changes: 0 additions & 79 deletions internal/geom/shapes.go

This file was deleted.

1 change: 0 additions & 1 deletion internal/geom/shortest.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ func Shortest(p1, p2 P, rects []Rect) []P {
// find start and end triangles
var start, end Tri
for _, t := range ts {
// fmt.Println(t.String())
if t.Contains(p1) {
start = t
}
Expand Down
52 changes: 52 additions & 0 deletions internal/geom/triangle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package geom

import "fmt"

// Tri represents a triangle
type Tri struct {
ID int
A, B, C P
}

func (t Tri) SVG() string {
return fmt.Sprintf(`<path d="M %.2f,%.2f %.2f,%.2f %.2f,%.2f Z" stroke="blue" fill="none"/>`, t.A.X, t.A.Y, t.B.X, t.B.Y, t.C.X, t.C.Y)
}

func (t Tri) Barycenter() P {
bx := (t.A.X + t.B.X + t.C.X) / 3
by := (t.A.Y + t.B.Y + t.C.Y) / 3
return P{bx, by}
}

func (t Tri) Contains(p P) bool {
s := 0
e := []P{t.A, t.B, t.C}
for i := range 3 {
or := orientation(e[i%3], e[(i+1)%3], p)
if or == cln {
q, r := e[i%3], e[(i+1)%3]
return p.X >= min(q.X, r.X) && p.X <= max(q.X, r.X) &&
p.Y >= min(q.Y, r.Y) && p.Y <= max(q.Y, r.Y)
}

if or != cw {
s++
}
}
return s == 3 || s == 0
}

func (t Tri) OrderedSide(i int) Segment {
e := []P{t.A, t.B, t.C}
a, b := e[i%3], e[(i+1)%3]
if a.X < b.X {
return Segment{a, b}
}
if b.X < a.X {
return Segment{b, a}
}
if a.Y < b.Y {
return Segment{a, b}
}
return Segment{b, a}
}
25 changes: 25 additions & 0 deletions internal/geom/triangle_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package geom

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestTri(t *testing.T) {
t.Run("contains", func(t *testing.T) {
cases := []struct {
t Tri
p P
}{
{Tri{0, P{0, 0}, P{20, 0}, P{20, 50}}, P{10, 5}},
{Tri{1, P{19.2, 44.7}, P{142.6, 16.5}, P{228, 212}}, P{28.6, 46.6}},
{Tri{2, P{20, 20}, P{200, 20}, P{300, 40}}, P{197.7, 27}},
{Tri{3, P{50, 10}, P{80, 10}, P{100, 50}}, P{65, 10}}, // collinear parallel x axis
{Tri{4, P{255, 210}, P{0, 60}, P{255, 60}}, P{185.615, 169.185}}, // collinear neg slope
}
for _, c := range cases {
assert.Truef(t, c.t.Contains(c.p), "triangle %d does not contain point", c.t.ID)
}
})
}

0 comments on commit 3e1cef5

Please sign in to comment.