From 5ca69d90e6849881a87bac110c5ba7ebb7be410d Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Sat, 1 Jul 2023 03:44:36 -0400 Subject: [PATCH] Fixed polygon filling --- examples/glaggle/main.go | 15 +++++++++++++-- polygon.go | 34 ++++++++++++++++++++-------------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/examples/glaggle/main.go b/examples/glaggle/main.go index a8816cd..fcd187a 100644 --- a/examples/glaggle/main.go +++ b/examples/glaggle/main.go @@ -6,14 +6,25 @@ import "image/png" import "git.tebibyte.media/tomo/ggfx" func main () { - img := image.NewRGBA(image.Rect(0, 0, 800, 600)) + img := image.NewRGBA(image.Rect(0, 0, 300, 300)) canvas := ggfx.Image[uint8] { Pix: img.Pix, Stride: img.Stride, Bounds: img.Rect, Width: 4, } - canvas.FillRectangle([]uint8 { 255, 0, 0, 255 }, image.Rect(7, 4, 34, 78)) + black := []uint8 { 0, 0, 0, 255 } + red := []uint8 { 255, 0, 0, 255 } + canvas.FillPolygon ( + black, + image.Pt(10, 10), + image.Pt(70, 50), + image.Pt(20, 70)) + canvas.StrokePolygon ( + red, 1, + image.Pt(10, 10), + image.Pt(70, 50), + image.Pt(20, 70)) file, err := os.Create("TEST.png") if err != nil { panic(err.Error()) } diff --git a/polygon.go b/polygon.go index 02e5f5e..2ddcf19 100644 --- a/polygon.go +++ b/polygon.go @@ -14,10 +14,11 @@ func (this Image[T]) FillPolygon (fill []T, points ...image.Point) { for _, point := range points[1:] { if point.X < area.Min.X { area.Min.X = point.X } if point.Y < area.Min.Y { area.Min.Y = point.Y } - if point.X < area.Max.X { area.Max.X = point.X } - if point.Y < area.Max.Y { area.Max.Y = point.Y } + if point.X > area.Max.X { area.Max.X = point.X } + if point.Y > area.Max.Y { area.Max.Y = point.Y } } area = this.Bounds.Intersect(area) + if area.Empty() { return } // this algorithm is adapted from: // https://www.alienryderflex.com/polygon_fill/ @@ -28,30 +29,35 @@ func (this Image[T]) FillPolygon (fill []T, points ...image.Point) { boundaryCount := 0 prevPoint := points[len(points) - 1] for _, point := range points { + fy := float64(y) + fPointX := float64(point.X) + fPointY := float64(point.Y) + fPrevX := float64(prevPoint.X) + fPrevY := float64(prevPoint.Y) addboundary := - point.Y < y && prevPoint.Y >= y || - prevPoint.Y < y && point.Y >= y + (fPointY < fy && fPrevY >= fy) || + (fPrevY < fy && fPointY >= fy) if addboundary { - boundaries[boundaryCount] = - point.X + - (y - point.Y) / - (prevPoint.Y - point.Y) * - (prevPoint.X - point.X) + boundaries[boundaryCount] = int ( + fPointX + + (fy - fPointY) / + (fPrevY - fPointY) * + (fPrevX - fPointX)) boundaryCount ++ } prevPoint = point } // sort boundary list - boundaries = boundaries[:boundaryCount] - sort.Ints(boundaries) + cutBoundaries := boundaries[:boundaryCount] + sort.Ints(cutBoundaries) // fill pixels between boundary pairs min := area.Min.X max := area.Max.X - for index := 0; index < len(boundaries); index ++ { - left := boundaries[index] - right := boundaries[index + 1] + for index := 0; index < len(cutBoundaries); index += 2 { + left := cutBoundaries[index] + right := cutBoundaries[index + 1] // stop if we have exited the polygon if left >= max { break }