Advanced path operations, Bézier curves, and vector graphics.
// Start a new path
dc.NewPath()
// Move to a point without drawing
dc.MoveTo(x, y)
// Draw a line to a point
dc.LineTo(x, y)
// Close the current path
dc.ClosePath()
// Example: Triangle
dc.NewPath()
dc.MoveTo(100, 100)
dc.LineTo(200, 100)
dc.LineTo(150, 50)
dc.ClosePath()
dc.Fill()
// Draw arc (clockwise)
dc.Arc(centerX, centerY, radius, startAngle, endAngle)
// Draw arc (counter-clockwise)
dc.ArcNegative(centerX, centerY, radius, startAngle, endAngle)
// Example: Pac-Man shape
dc.MoveTo(200, 200)
dc.Arc(200, 200, 80, math.Pi/6, -math.Pi/6)
dc.ClosePath()
dc.Fill()
// Quadratic Bézier curve (one control point)
dc.QuadraticTo(controlX, controlY, endX, endY)
// Example: Smooth curve
dc.MoveTo(100, 300)
dc.QuadraticTo(200, 100, 300, 300)
dc.Stroke()
// Cubic Bézier curve (two control points)
dc.CubicTo(control1X, control1Y, control2X, control2Y, endX, endY)
// Example: S-curve
dc.MoveTo(100, 400)
dc.CubicTo(200, 300, 300, 500, 400, 400)
dc.Stroke()
// Create smooth curves through points
points := []Point{
{100, 200}, {200, 100}, {300, 250}, {400, 150}, {500, 200},
}
dc.MoveTo(points[0].X, points[0].Y)
for i := 1; i < len(points)-2; i++ {
// Calculate control points for smooth curve
cp1x := points[i].X + (points[i+1].X - points[i-1].X) / 6
cp1y := points[i].Y + (points[i+1].Y - points[i-1].Y) / 6
cp2x := points[i+1].X - (points[i+2].X - points[i].X) / 6
cp2y := points[i+1].Y - (points[i+2].Y - points[i].Y) / 6
dc.CubicTo(cp1x, cp1y, cp2x, cp2y, points[i+1].X, points[i+1].Y)
}
dc.Stroke()
// Create a new Path2D object
path := advancegg.NewPath2D()
// Build the path
path.MoveTo(100, 100)
path.LineTo(200, 100)
path.LineTo(200, 200)
path.LineTo(100, 200)
path.ClosePath()
// Use the path with context
dc.DrawPath(path)
dc.Fill()
// Get path bounds
bounds := path.GetBounds()
fmt.Printf("Bounds: %v\n", bounds)
// Check if point is inside path
contains := path.Contains(150, 150)
fmt.Printf("Contains point: %v\n", contains)
// Get path length
length := path.GetLength()
fmt.Printf("Path length: %f\n", length)
// Sample point at distance along path
point := path.GetPointAtDistance(length * 0.5) // Midpoint
// Transform path
matrix := advancegg.Identity()
matrix = matrix.Scale(2, 2)
matrix = matrix.Rotate(math.Pi / 4)
matrix = matrix.Translate(100, 100)
path.Transform(matrix)
// Or use individual transformations
path.Scale(2, 2)
path.Rotate(math.Pi / 4)
path.Translate(100, 100)
// Combine paths
path1 := advancegg.NewPath2D()
path1.MoveTo(100, 100)
path1.LineTo(200, 200)
path2 := advancegg.NewPath2D()
path2.MoveTo(300, 100)
path2.LineTo(400, 200)
// Add path2 to path1
path1.AddPath(path2)
// Clone a path
clonedPath := path1.Clone()
// Simplify path (reduce points while maintaining shape)
simplified := path.Simplify(tolerance)
// Smooth path (reduce sharp corners)
smoothed := path.Smooth(iterations)
// Create offset path (parallel path at distance)
offsetPath := path.Offset(distance)
// Inward offset (negative distance)
insetPath := path.Offset(-10)
// Union of two paths
union := path1.Union(path2)
// Intersection of two paths
intersection := path1.Intersection(path2)
// Difference (subtract path2 from path1)
difference := path1.Difference(path2)
// Exclusive or
xor := path1.XOR(path2)
// Convert stroke to filled path
strokePath := path.Stroke(width, lineCap, lineJoin)
// Stroke with dash pattern
dashedStroke := path.StrokeDashed(width, dashPattern, lineCap, lineJoin)
// Parse SVG path string
svgPath := "M 100 100 L 200 100 L 200 200 L 100 200 Z"
path := advancegg.ParseSVGPath(svgPath)
// Convert path to SVG string
svgString := path.ToSVG()
// Complex SVG path with curves
complexPath := "M 100 200 C 100 100 250 100 250 200 S 400 300 400 200"
path2 := advancegg.ParseSVGPath(complexPath)
Command | Description | Parameters |
---|---|---|
M x y |
Move to | x, y coordinates |
L x y |
Line to | x, y coordinates |
H x |
Horizontal line | x coordinate |
V y |
Vertical line | y coordinate |
C x1 y1 x2 y2 x y |
Cubic Bézier | control points and end point |
Q x1 y1 x y |
Quadratic Bézier | control point and end point |
A rx ry rotation large-arc sweep x y |
Arc | radii, rotation, flags, end point |
Z |
Close path | none |
package main
import (
"math"
"github.com/GrandpaEJ/advancegg"
)
func main() {
dc := advancegg.NewContext(800, 600)
// Background
dc.SetRGB(0.95, 0.95, 0.98)
dc.Clear()
// Draw a flower using paths
drawFlower(dc, 400, 300, 100)
// Draw a spiral
drawSpiral(dc, 200, 150, 80, 3)
// Draw a heart shape
drawHeart(dc, 600, 450, 60)
dc.SavePNG("complex-paths.png")
}
func drawFlower(dc *advancegg.Context, centerX, centerY, size float64) {
dc.SetRGB(1, 0.2, 0.4)
// Draw 8 petals
for i := 0; i < 8; i++ {
angle := float64(i) * math.Pi / 4
dc.Push()
dc.Translate(centerX, centerY)
dc.Rotate(angle)
// Petal shape using Bézier curves
dc.MoveTo(0, 0)
dc.CubicTo(0, -size*0.3, size*0.3, -size*0.8, 0, -size)
dc.CubicTo(-size*0.3, -size*0.8, 0, -size*0.3, 0, 0)
dc.Fill()
dc.Pop()
}
// Center
dc.SetRGB(1, 1, 0.2)
dc.DrawCircle(centerX, centerY, size*0.2)
dc.Fill()
}
func drawSpiral(dc *advancegg.Context, centerX, centerY, maxRadius float64, turns int) {
dc.SetRGB(0.2, 0.4, 0.8)
dc.SetLineWidth(3)
steps := turns * 100
dc.MoveTo(centerX, centerY)
for i := 1; i <= steps; i++ {
t := float64(i) / float64(steps)
angle := t * float64(turns) * 2 * math.Pi
radius := t * maxRadius
x := centerX + radius*math.Cos(angle)
y := centerY + radius*math.Sin(angle)
dc.LineTo(x, y)
}
dc.Stroke()
}
func drawHeart(dc *advancegg.Context, centerX, centerY, size float64) {
dc.SetRGB(0.8, 0.1, 0.2)
// Heart shape using two circles and a triangle
dc.MoveTo(centerX, centerY+size*0.3)
// Left curve
dc.CubicTo(centerX-size*0.8, centerY-size*0.3,
centerX-size*0.8, centerY-size*0.8,
centerX, centerY-size*0.2)
// Right curve
dc.CubicTo(centerX+size*0.8, centerY-size*0.8,
centerX+size*0.8, centerY-size*0.3,
centerX, centerY+size*0.3)
dc.Fill()
}