surface/path.go

Functions Structs

Functions

func Arc

Arc adds a circular arc to the path.

The arc goes from angle1 to angle2 (in radians) around (cx, cy).

func (p *Path) Arc(cx, cy, r, angle1, angle2 float64) {
	const twoPi = 2 * math.Pi
	for angle2 < angle1 {
		angle2 += twoPi
	}

	const maxAngle = math.Pi / 2
	numSegments := int(math.Ceil((angle2 - angle1) / maxAngle))
	angleStep := (angle2 - angle1) / float64(numSegments)

	for i := 0; i < numSegments; i++ {
		a1 := angle1 + float64(i)*angleStep
		a2 := a1 + angleStep
		p.arcSegment(cx, cy, r, a1, a2)
	}
}

func Bounds

Bounds returns the axis-aligned bounding box of the path.

Returns an empty rectangle if the path is empty.

func (p *Path) Bounds() (minX, minY, maxX, maxY float64) {
	if len(p.points) == 0 {
		return 0, 0, 0, 0
	}

	minX = float64(p.points[0])
	maxX = minX
	minY = float64(p.points[1])
	maxY = minY

	for i := 2; i < len(p.points); i += 2 {
		x := float64(p.points[i])
		y := float64(p.points[i+1])
		if x < minX {
			minX = x
		}
		if x > maxX {
			maxX = x
		}
		if y < minY {
			minY = y
		}
		if y > maxY {
			maxY = y
		}
	}

	return minX, minY, maxX, maxY
}

func Circle

Circle adds a circle to the path.

func (p *Path) Circle(cx, cy, r float64) {
	const k = 0.5522847498307936
	offset := r * k

	p.MoveTo(cx+r, cy)
	p.CubicTo(cx+r, cy+offset, cx+offset, cy+r, cx, cy+r)
	p.CubicTo(cx-offset, cy+r, cx-r, cy+offset, cx-r, cy)
	p.CubicTo(cx-r, cy-offset, cx-offset, cy-r, cx, cy-r)
	p.CubicTo(cx+offset, cy-r, cx+r, cy-offset, cx+r, cy)
	p.Close()
}

func Clear

Clear removes all elements from the path.

func (p *Path) Clear() {
	p.verbs = p.verbs[:0]
	p.points = p.points[:0]
	p.startX, p.startY = 0, 0
	p.curX, p.curY = 0, 0
}

func Clone

Clone creates a deep copy of the path.

func (p *Path) Clone() *Path {
	clone := &Path{
		verbs:	make([]raster.PathVerb, len(p.verbs)),
		points:	make([]float32, len(p.points)),
		startX:	p.startX,
		startY:	p.startY,
		curX:	p.curX,
		curY:	p.curY,
	}
	copy(clone.verbs, p.verbs)
	copy(clone.points, p.points)
	return clone
}

func Close

Close closes the current subpath by connecting to the start point.

func (p *Path) Close() {
	if len(p.verbs) == 0 {
		return
	}
	p.verbs = append(p.verbs, raster.Close)
	p.curX, p.curY = p.startX, p.startY
}

func CubicTo

CubicTo adds a cubic Bezier curve from the current point.

(c1x, c1y) and (c2x, c2y) are control points, (x, y) is the endpoint.

func (p *Path) CubicTo(c1x, c1y, c2x, c2y, x, y float64) {
	if len(p.verbs) == 0 {
		p.MoveTo(c1x, c1y)
	}
	p.verbs = append(p.verbs, raster.CubicTo)
	p.points = append(p.points,
		float32(c1x), float32(c1y),
		float32(c2x), float32(c2y),
		float32(x), float32(y))
	p.curX, p.curY = float32(x), float32(y)
}

func CurrentPoint

CurrentPoint returns the current point.

func (p *Path) CurrentPoint() Point {
	return Point{X: float64(p.curX), Y: float64(p.curY)}
}

func Ellipse

Ellipse adds an ellipse to the path.

func (p *Path) Ellipse(cx, cy, rx, ry float64) {
	const k = 0.5522847498307936
	ox := rx * k
	oy := ry * k

	p.MoveTo(cx+rx, cy)
	p.CubicTo(cx+rx, cy+oy, cx+ox, cy+ry, cx, cy+ry)
	p.CubicTo(cx-ox, cy+ry, cx-rx, cy+oy, cx-rx, cy)
	p.CubicTo(cx-rx, cy-oy, cx-ox, cy-ry, cx, cy-ry)
	p.CubicTo(cx+ox, cy-ry, cx+rx, cy-oy, cx+rx, cy)
	p.Close()
}

func IsEmpty

IsEmpty returns true if the path has no elements.

func (p *Path) IsEmpty() bool {
	return len(p.verbs) == 0
}

func LineTo

LineTo adds a line from the current point to (x, y).

func (p *Path) LineTo(x, y float64) {
	if len(p.verbs) == 0 {
		p.MoveTo(x, y)
		return
	}
	p.verbs = append(p.verbs, raster.LineTo)
	p.points = append(p.points, float32(x), float32(y))
	p.curX, p.curY = float32(x), float32(y)
}

func MoveTo

MoveTo starts a new subpath at the given point.

func (p *Path) MoveTo(x, y float64) {
	p.verbs = append(p.verbs, raster.MoveTo)
	p.points = append(p.points, float32(x), float32(y))
	p.startX, p.startY = float32(x), float32(y)
	p.curX, p.curY = float32(x), float32(y)
}

func NewPath

NewPath creates a new empty path.

func NewPath() *Path {
	return &Path{
		verbs:	make([]raster.PathVerb, 0, 16),
		points:	make([]float32, 0, 64),
	}
}

func Points

Points returns the points slice for raster.PathLike interface.

func (p *Path) Points() []float32 {
	return p.points
}

func QuadTo

QuadTo adds a quadratic Bezier curve from the current point.

(cx, cy) is the control point, (x, y) is the endpoint.

func (p *Path) QuadTo(cx, cy, x, y float64) {
	if len(p.verbs) == 0 {
		p.MoveTo(cx, cy)
	}
	p.verbs = append(p.verbs, raster.QuadTo)
	p.points = append(p.points, float32(cx), float32(cy), float32(x), float32(y))
	p.curX, p.curY = float32(x), float32(y)
}

func Rectangle

Rectangle adds a rectangle to the path.

func (p *Path) Rectangle(x, y, w, h float64) {
	p.MoveTo(x, y)
	p.LineTo(x+w, y)
	p.LineTo(x+w, y+h)
	p.LineTo(x, y+h)
	p.Close()
}

func RoundedRectangle

RoundedRectangle adds a rectangle with rounded corners.

func (p *Path) RoundedRectangle(x, y, w, h, r float64) {
	maxR := math.Min(w, h) / 2
	if r > maxR {
		r = maxR
	}

	const k = 0.5522847498307936	// Bezier circle approximation constant
	ctl := r * k

	p.MoveTo(x+r, y)
	p.LineTo(x+w-r, y)
	p.CubicTo(x+w-r+ctl, y, x+w, y+r-ctl, x+w, y+r)
	p.LineTo(x+w, y+h-r)
	p.CubicTo(x+w, y+h-r+ctl, x+w-r+ctl, y+h, x+w-r, y+h)
	p.LineTo(x+r, y+h)
	p.CubicTo(x+r-ctl, y+h, x, y+h-r+ctl, x, y+h-r)
	p.LineTo(x, y+r)
	p.CubicTo(x, y+r-ctl, x+r-ctl, y, x+r, y)
	p.Close()
}

func Verbs

Verbs returns the verb slice for raster.PathLike interface.

func (p *Path) Verbs() []raster.PathVerb {
	return p.verbs
}

Structs

type Path struct

Path represents a vector path for drawing operations.

 

Path is the surface-level path type that wraps raster.PathLike.

It provides a convenient builder API for constructing paths.

 

Example:

 

p := surface.NewPath()

p.MoveTo(100, 100)

p.LineTo(200, 100)

p.LineTo(150, 200)

p.Close()

 

surface.Fill(p, style)

type Path struct {
	verbs	[]raster.PathVerb
	points	[]float32
	startX	float32
	startY	float32
	curX	float32
	curY	float32
}