Pictures

Pictures

Pictures are containers for grouping paths. They support clipping and can be combined.

Creating a Picture

local h = require("hobby")

local pic = h.picture()
    :add(path1)
    :add(path2)
    :add(path3)

Picture Methods

add(path)

Adds a path to the picture.

pic:add(circle)
pic:add(square)

addpicture(other)

Adds all paths from another picture.

local combined = h.picture()
    :addpicture(pic1)
    :addpicture(pic2)

clip(path)

Sets a clipping boundary. All paths in the picture will be clipped to this shape.

pic:clip(clipPath)

clippath()

Returns the current clipping path, or nil if none is set.

local cp = pic:clippath()

paths()

Returns all paths as a Lua table.

local all_paths = pic:paths()
for i, p in ipairs(all_paths) do
    print("Path " .. i)
end

Labels

Pictures support text labels similar to MetaPost’s label and dotlabel commands.

label(text, point, anchor)

Adds a text label at the given position with the specified anchor point.

pic:label("A", h.point(0, 0), "llft")    -- lower-left of point
pic:label("B", h.point(100, 0), "lrt")   -- lower-right of point
pic:label("C", h.point(50, 86), "top")   -- above point

Anchor values:

  • center or c - centered at point
  • left or lft - to the left of point
  • right or rt - to the right of point
  • top - above point
  • bottom or bot - below point
  • upperleft or ulft - upper-left of point
  • upperright or urt - upper-right of point
  • lowerleft or llft - lower-left of point
  • lowerright or lrt - lower-right of point

dotlabel(text, point, anchor, color)

Adds a label with a dot at the reference point.

pic:dotlabel("P", h.point(50, 50), "rt", h.color("blue"))

labels()

Returns all labels in the picture as a Lua table.

local all_labels = pic:labels()
for i, lbl in ipairs(all_labels) do
    print(lbl.text, lbl.fontsize)
end

Label Properties

Labels have the following properties and methods:

Property/Method Description
.text The label text
.fontsize Font size
:position() Returns position point
:setfontsize(size) Set font size
:color() Returns color
:setcolor(color) Set color

Adding Pictures to SVG

Use addpicture() on the SVG builder:

h.svg()
    :addpicture(pic)
    :write("output.svg")

Clipping Example

local h = require("hobby")

-- Create a circular clipping boundary
local clipCircle = h.fullcircle()
    :scaled(60)
    :shifted(50, 50)

-- Create paths to be clipped
local line1 = h.path()
    :moveto(h.point(0, 0))
    :lineto(h.point(100, 100))
    :stroke("red")
    :strokewidth(3)
    :build()

local line2 = h.path()
    :moveto(h.point(0, 100))
    :lineto(h.point(100, 0))
    :stroke("blue")
    :strokewidth(3)
    :build()

local square = h.unitsquare()
    :scaled(80)
    :shifted(10, 10)
    :stroke("green")
    :strokewidth(2)

-- Create picture with clipping
local pic = h.picture()
    :add(line1)
    :add(line2)
    :add(square)
    :clip(clipCircle)

-- Show clipping boundary (dashed)
local outline = h.fullcircle()
    :scaled(60)
    :shifted(50, 50)
    :evenly()
    :stroke("gray")

-- Output
h.svg()
    :padding(10)
    :addpicture(pic)
    :add(outline)
    :write("clip.svg")

Clipping example

Combining Pictures

local h = require("hobby")

-- First picture: circles
local circles = h.picture()
    :add(h.fullcircle():scaled(30):shifted(30, 30):stroke("red"))
    :add(h.fullcircle():scaled(20):shifted(30, 30):stroke("blue"))

-- Second picture: square
local squares = h.picture()
    :add(h.unitsquare():scaled(20):shifted(60, 20):stroke("green"))

-- Combine everything
local combined = h.picture()
    :addpicture(circles)
    :addpicture(squares)
    :add(h.fullcircle():scaled(10):shifted(80, 30):fill("purple"))

h.svg()
    :padding(10)
    :addpicture(combined)
    :write("combined.svg")