Fixed polygon filling

This commit is contained in:
Sasha Koshka 2023-07-01 03:44:36 -04:00
parent 85b71a91a3
commit 5ca69d90e6
2 changed files with 33 additions and 16 deletions

View File

@ -6,14 +6,25 @@ import "image/png"
import "git.tebibyte.media/tomo/ggfx" import "git.tebibyte.media/tomo/ggfx"
func main () { func main () {
img := image.NewRGBA(image.Rect(0, 0, 800, 600)) img := image.NewRGBA(image.Rect(0, 0, 300, 300))
canvas := ggfx.Image[uint8] { canvas := ggfx.Image[uint8] {
Pix: img.Pix, Pix: img.Pix,
Stride: img.Stride, Stride: img.Stride,
Bounds: img.Rect, Bounds: img.Rect,
Width: 4, 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") file, err := os.Create("TEST.png")
if err != nil { panic(err.Error()) } if err != nil { panic(err.Error()) }

View File

@ -14,10 +14,11 @@ func (this Image[T]) FillPolygon (fill []T, points ...image.Point) {
for _, point := range points[1:] { for _, point := range points[1:] {
if point.X < area.Min.X { area.Min.X = point.X } if point.X < area.Min.X { area.Min.X = point.X }
if point.Y < area.Min.Y { area.Min.Y = point.Y } if point.Y < area.Min.Y { area.Min.Y = point.Y }
if point.X < area.Max.X { area.Max.X = point.X } if point.X > area.Max.X { area.Max.X = point.X }
if point.Y < area.Max.Y { area.Max.Y = point.Y } if point.Y > area.Max.Y { area.Max.Y = point.Y }
} }
area = this.Bounds.Intersect(area) area = this.Bounds.Intersect(area)
if area.Empty() { return }
// this algorithm is adapted from: // this algorithm is adapted from:
// https://www.alienryderflex.com/polygon_fill/ // https://www.alienryderflex.com/polygon_fill/
@ -28,30 +29,35 @@ func (this Image[T]) FillPolygon (fill []T, points ...image.Point) {
boundaryCount := 0 boundaryCount := 0
prevPoint := points[len(points) - 1] prevPoint := points[len(points) - 1]
for _, point := range points { for _, point := range points {
fy := float64(y)
fPointX := float64(point.X)
fPointY := float64(point.Y)
fPrevX := float64(prevPoint.X)
fPrevY := float64(prevPoint.Y)
addboundary := addboundary :=
point.Y < y && prevPoint.Y >= y || (fPointY < fy && fPrevY >= fy) ||
prevPoint.Y < y && point.Y >= y (fPrevY < fy && fPointY >= fy)
if addboundary { if addboundary {
boundaries[boundaryCount] = boundaries[boundaryCount] = int (
point.X + fPointX +
(y - point.Y) / (fy - fPointY) /
(prevPoint.Y - point.Y) * (fPrevY - fPointY) *
(prevPoint.X - point.X) (fPrevX - fPointX))
boundaryCount ++ boundaryCount ++
} }
prevPoint = point prevPoint = point
} }
// sort boundary list // sort boundary list
boundaries = boundaries[:boundaryCount] cutBoundaries := boundaries[:boundaryCount]
sort.Ints(boundaries) sort.Ints(cutBoundaries)
// fill pixels between boundary pairs // fill pixels between boundary pairs
min := area.Min.X min := area.Min.X
max := area.Max.X max := area.Max.X
for index := 0; index < len(boundaries); index ++ { for index := 0; index < len(cutBoundaries); index += 2 {
left := boundaries[index] left := cutBoundaries[index]
right := boundaries[index + 1] right := cutBoundaries[index + 1]
// stop if we have exited the polygon // stop if we have exited the polygon
if left >= max { break } if left >= max { break }