+
Skip to content

Parts of paths being filled even fill is transparent and only strokes are used #354

@aldernero

Description

@aldernero

One issue that has been preventing me from using Sketchy (my generative art framework) more often is frequent panics in the path intersection part of the code. This issue isn't about that specifically, but I'm guessing it might be related.

Even when there are no panics, I get unexpected behavior sometimes. Here is a simple example. This program animates a Lissajous figure, using ebitengine for the animation and canvas for drawing the curve. You can see from the animation that with some different phases of the curve, the empty areas between parts of the curve become filled. I would not expect this since I set the fill to transparent and only call Stroke().

The code is also below. Is this expected and if not is it related to path intersections?

Screencast_20251004_195642.webm
package main

import (
	"log"

	"github.com/aldernero/gaul"
	"github.com/hajimehoshi/ebiten/v2"
	"github.com/tdewolff/canvas"
	"github.com/tdewolff/canvas/renderers/rasterizer"
)

const (
	screenWidth     = 600
	screenHeight    = 600
	radiansPerTick  = 0.01
	curveResolution = 1000
	strokeWidth     = 1
	mmPerPx         = 0.26458333
)

type Game struct {
	lissa  gaul.Lissajous
	center gaul.Point
	scale  float64
	cnvs   *canvas.Canvas
}

func (g *Game) Update() error {
	g.lissa.Px += radiansPerTick
	return nil
}

func (g *Game) Draw(screen *ebiten.Image) {
	g.cnvs.Reset()
	ctx := canvas.NewContext(g.cnvs)

	// Draw background
	ctx.SetFillColor(canvas.Black)
	gaul.Rect{W: float64(screenWidth) * mmPerPx, H: float64(screenHeight) * mmPerPx}.Draw(ctx) // Background

	// Draw Lissajous curve
	ctx.SetStrokeWidth(strokeWidth)
	ctx.SetStrokeColor(canvas.White)
	ctx.SetFillColor(canvas.Transparent)
	curve := gaul.GenLissajous(g.lissa, curveResolution, g.center, g.scale)
	curve.Draw(ctx)
	ctx.Stroke()

	// Draw to ebiten screen
	img := rasterizer.Draw(g.cnvs, canvas.DefaultResolution, canvas.DefaultColorSpace)
	op := &ebiten.DrawImageOptions{}
	screen.DrawImage(ebiten.NewImageFromImage(img), op)
}

func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
	return screenWidth, screenHeight
}

func main() {

	game := Game{
		lissa: gaul.Lissajous{
			Nx: 3,
			Ny: 2,
			Px: 0,
			Py: 0,
		},
		center: gaul.Point{
			X: mmPerPx * screenWidth / 2,
			Y: mmPerPx * screenHeight / 2,
		},
		scale: float64(screenWidth) * mmPerPx * 0.4,
		cnvs:  canvas.New(screenWidth*mmPerPx, screenHeight*mmPerPx),
	}

	ebiten.SetWindowSize(screenWidth, screenHeight)
	ebiten.SetWindowTitle("Animated Lissajous Figure")
	if err := ebiten.RunGame(&game); err != nil {
		log.Fatal(err)
	}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载