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"
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()) }

View File

@ -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 }