Skip to content

Commit

Permalink
update doc strings
Browse files Browse the repository at this point in the history
  • Loading branch information
cormullion committed Feb 3, 2023
1 parent 6683e41 commit e8bc5b7
Show file tree
Hide file tree
Showing 10 changed files with 712 additions and 471 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ See https://github.com/JuliaGraphics/Cairo.jl/pull/357.

- `getcolor()` gets current color

- multiply Point by 3×3 matrix using `*`
- multiply Point by 3×3 matrix using `*`

### Changed

- added more information to doc strings

### Removed

### Deprecated
Expand Down
14 changes: 13 additions & 1 deletion docs/src/explanation/basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,19 @@ nothing # hide

[`gsave`](@ref) saves a copy of the current graphics settings (current axis rotation, position, scale, line and text settings, color, and so on). When the next [`grestore`](@ref) is called, all changes you've made to the graphics settings will be discarded, and the previous settings are restored, so things return to how they were when you last used [`gsave`](@ref). [`gsave`](@ref) and [`grestore`](@ref) should always be balanced in pairs, enclosing the functions.

The `@layer` macro is a synonym for a [`gsave`](@ref)...[`grestore`](@ref) pair.
```julia
@svg begin
circle(Point(0, 0), 100, action = :stroke)
gsave()
sethue("red")
rule(Point(0, 0))
rule(Point(0, 0), pi/2)
grestore()
circle(Point(0, 0), 200, action = :stroke)
end
```

The `@layer` macro is a shorter synonym for a [`gsave`](@ref)...[`grestore`](@ref) pair.

```julia
@svg begin
Expand Down
10 changes: 6 additions & 4 deletions docs/src/explanation/transforms.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ Line thicknesses are not scaled by default. For example, with a current line thi

## Matrices

In Luxor, there's always a *current matrix* that determines how coordinates are interpreted in the current workspace. It's a six element array:
In Luxor, there's always a *current matrix* that determines how coordinates are interpreted in the current workspace. In Cairo, it's a six element array:

```math
\begin{bmatrix}
Expand All @@ -174,7 +174,7 @@ In Luxor, there's always a *current matrix* that determines how coordinates are
\end{bmatrix}
```

which is usually handled in Julia/Cairo/Luxor as a simple vector (array):
and Luxor/Cairo matrix functions accept and return simple 6-element vectors:

```julia
julia> getmatrix()
Expand All @@ -187,6 +187,10 @@ julia> getmatrix()
0.0
```

!!! note

You can convert between the 6-element and 3x3 versions of a transformation matrix using the functions [`cairotojuliamatrix`](@ref) and [`juliatocairomatrix`](@ref).

[`transform(a)`](@ref) transforms the current workspace by ‘multiplying’ the current matrix with matrix `a`. For example, `transform([1, 0, xskew, 1, 50, 0])` skews the current matrix by `xskew` radians and moves it 50 in x and 0 in y.

```@example
Expand Down Expand Up @@ -224,8 +228,6 @@ Other functions include [`getmatrix`](@ref),

Use the [`getscale`](@ref), [`gettranslation`](@ref), and [`getrotation`](@ref) functions to find the current values of the current matrix. These can also find the values of arbitrary 3x3 matrices.

You can convert between the 6-element and 3x3 versions of a transformation matrix using the functions [`cairotojuliamatrix`](@ref)
and [`juliatocairomatrix`](@ref).

## World position

Expand Down
24 changes: 12 additions & 12 deletions docs/src/howto/createdrawings.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ In Luxor you always work with a current drawing, so the first thing to do is to

To create a drawing, and optionally specify the filename, type, and dimensions, use the [`Drawing`](@ref) constructor function.

To finish a drawing and close the file, use [`finish`](@ref), and, if the drawing doesn't appear in your notebook, you can launch an external application to view it using [`preview`](@ref).
To finish a drawing and close the file, use [`finish`](@ref).

To finish a drawing and close the file, use [`finish`](@ref), and, to launch an external application to view it, use [`preview`](@ref).
Ff the drawing doesn't appear automatically in your notebook or editing environment, you can type [`preview`](@ref) to see it.

![jupyter](../assets/figures/jupyter.png)

If you're using VS Code, then PNG and SVG drawings should appear in the Plots pane, if it's enabled. In a Pluto notebook, output appears above the cell. In a notebook environment, output appears in the next notebook cell.
If you're using VS Code, then PNG and SVG drawings should automatically appear in the Plots pane, if it's enabled. In a Pluto notebook, output appears above the cell. In a notebook environment, output appears in the next notebook cell.

![juno](../assets/figures/juno.png)

Expand All @@ -20,19 +20,19 @@ If you're using VS Code, then PNG and SVG drawings should appear in the Plots pa

## Quick drawings with macros

The [`@draw`](@ref), [`@svg`](@ref), [`@png`](@ref), and [`@pdf`](@ref) macros are designed to let you quickly create graphics without having to provide the usual boiler-plate functions.
The [`@draw`](@ref), [`@svg`](@ref), [`@drawsvg`](@ref), [`@png`](@ref), and [`@pdf`](@ref) macros are designed to let you quickly create graphics without having to provide the usual boiler-plate functions.

!!! note

The macros are shortcuts, designed to make it quick and easy to get started. You can save a few keystrokes and some time, but, for full control over all parameters, use [`Drawing`](@ref).
The macros are shortcuts, designed to make it quick and easy to get started. You can save keystrokes and time, but, for full control over all parameters, use [`Drawing`](@ref).

For example, the Julia code:
For example, this:

```julia
@svg circle(Point(0, 0), 20, action = :stroke) 50 50
```

expands to
is equivalent to this:

```julia
Drawing(50, 50, "luxor-drawing-(timestamp).svg")
Expand All @@ -44,7 +44,7 @@ finish()
preview()
```

They're just short-cuts. You can omit the width and height (thus defaulting to 600 by 600, except for `@imagematrix`), and you don't have to specify a filename (you'll get time-stamped files in the current working directory). For multiple lines, use either:
You can omit the width and height (thus defaulting to 600 by 600, except for `@imagematrix`), and you don't have to specify a filename (you'll get time-stamped files in the current working directory). For multiple lines, use either:

```julia
@svg begin
Expand Down Expand Up @@ -86,7 +86,7 @@ preview()

### In-memory drawings

You can choose to store drawings in memory. The advantage is that in-memory drawings are quicker, and the results can be passed as Julia data. Also, it's useful in some environments to not have to worry about writing files.
You can choose to store drawings in memory rather than use files. The advantage is that in-memory drawings are quicker, and the results can be passed as Julia data. Also, it's useful in some restricted environments to not have to worry about writing files.

This syntax for the [`Drawing`](@ref) function:

Expand All @@ -100,9 +100,9 @@ The [`@draw`](@ref) macro (equivalent to `Drawing(..., :png)` creates a PNG draw

The SVG equivalent of `@draw` is [`@drawsvg`](@ref).

Use [`svgstring()`](@ref) to extract the SVG source for a finished SVG drawing.
Use [`svgstring()`](@ref) to extract the SVG drawing's source as text.

If you want to generate SVG without making a drawing, use `@savesvg` instead of `@drawsvg`.
If you want to generate SVG code without making a drawing, use `@savesvg` instead of `@drawsvg`.

### Concatenating SVG drawings

Expand Down Expand Up @@ -246,4 +246,4 @@ See the [Drawings as image matrices](@ref) section for more information.

## Recordings

The `:rec` option for `Drawing()` creates a recording surface in memory. You can then use `snapshot(filename, ...)` to copy the drawing into a file.
The `:rec` option for `Drawing()` creates a recording surface in memory. You can then use `snapshot(filename, ...)` to copy the drawing into a file. See [Snapshots](@ref).
116 changes: 111 additions & 5 deletions docs/src/tutorial/basicpath.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ So, we've constructed a path. The final job is to decide what to do with it, unl

At this point, the current path is empty again, and there is no current point.

And that's how you draw paths in Luxor. However, you'd be right if you think it will be a bit tedious to construct all shapes like this. This is why there are so many other functions in Luxor, such as `circle()`, `ngon()`, `star()`, `rect()`, `box()`, to name just a few!
And that's how you draw paths in Luxor. However, you'd be right if you think it will be a bit tedious to construct every single shape like this. This is why there are so many other functions in Luxor, such as `circle()`, `ngon()`, `star()`, `rect()`, `box()`, to name just a few.

## Arcs

Expand Down Expand Up @@ -167,11 +167,115 @@ strokepath()
end
```

## Translate, scale, rotate

Suppose you want to repeat a path in various places on the drawing. Obviously you don't want to repeat the steps in the path over and over again.

```@example
using Luxor
function t()
move(Point(100, 0))
line(Point(0, -100))
line(Point(-100, 0))
closepath()
strokepath()
end
@drawsvg begin
background("black")
sethue("white")
t()
end
```

The triangle is drawn when you call the `t()` function. The coordinates are interpreted relative to the current (0, 0) position, scale, and orientation.

To draw the triangle in another location, you can use `translate()` to move the (0, 0) to another location.

```@example
using Luxor
function t()
move(Point(100, 0))
line(Point(0, -100))
line(Point(-100, 0))
closepath()
strokepath()
end
@drawsvg begin
background("black")
sethue("white")
t()
translate(Point(150, 150))
t()
end
```

Similarly, you could use `scale()` and `rotate()` which further modify the current state.

```@example
using Luxor
function t()
move(Point(100, 0))
line(Point(0, -100))
line(Point(-100, 0))
closepath()
strokepath()
end
@drawsvg begin
background("black")
sethue("white")
t()
translate(Point(150, 150))
t()
translate(Point(30, 30))
scale(0.5)
t()
translate(Point(120, 120))
rotate(π/3)
t()
end
```

But, if you experiment with these three functions, you'll notice that the changes are always relative to the previous state. How do you return to a default initial state? You could undo every transformation (in the right order). But a better way is to enclose a set of changes of position, scale, and orientation in a pair of functions (`gsave()` and `grestore()`) that isolate the modifications.

The following code generates a grid of points in a nested loop. At each iteration, `gsave()` saves the current position, scale, and orientation, the graphics are drawn, and then `grestore()` restores the previously saved state.

```@example
using Luxor
function t()
move(Point(100, 0))
line(Point(0, -100))
line(Point(-100, 0))
closepath()
strokepath()
end
@drawsvg begin
background("black")
sethue("white")
for x in -250:20:250, y in -250:20:250
gsave()
translate(Point(x, y))
scale(0.1)
rotate(rand() * 2π)
t()
grestore()
end
end
```

!!! note

As an alternative to `gsave()` and `grestore()` you can use the `@layer begin ... end` macro, which does the same thing.

## Useful tools

You can use `currentpoint()` to get the current point.

`rulers()` is useful for displaying the current x and y axes.
`rulers()` is useful for drawing the current x and y axes before you start a path.

`storepath()` grabs the current path and saves it as a Path object. You can draw a stored path using `drawpath()`.

Expand All @@ -189,9 +293,9 @@ line(Point(100, 100))
strokepath()
```

## The straight line alternative
## Polygonal thinking

If you just want to draw straight lines, you might also like to know about Luxor polygons. A polygon is just an array (a Julia Vector) of points, and you can draw it (as many times as you like) using functions such as `poly()`.
In Luxor, a polygon is an array (a Julia Vector) of Points. You can treat it like any standard array, and then eventually draw it using the `poly()` function. It's all straight lines, no curves, so you might have to draw a lot of them to get shapes that look like curves.

```@example
using Luxor
Expand All @@ -207,4 +311,6 @@ using Luxor
end
```

Curves are nice, but eventually they'll have to be converted to line segments...
It's probably easier to generate polygons using Julia code than it is to generate paths. But, no curves. If you need arcs and Bezier curves, stick to paths.

The `poly()` function simply builds a path with straight lines, and then does the `:fill` or `:stroke` action, depending on which you provide.
18 changes: 9 additions & 9 deletions docs/src/tutorial/basictutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ Notice that this function doesn't define anything about what color it is, or whe
@png begin
setopacity(0.7)
for θ in range(0, step=π/6, length=12)
@layer begin
gsave()
rotate(θ)
translate(0, -150)
egg(50, :path)
Expand All @@ -486,7 +486,7 @@ Notice that this function doesn't define anything about what color it is, or whe

randomhue()
strokepath()
end
grestore()
end
end 800 800 "eggstravaganza.png"
```
Expand Down Expand Up @@ -527,7 +527,7 @@ background("white")
origin()
setopacity(0.7)
for θ in range(0, step=π/6, length=12)
@layer begin
gsave()
rotate(θ)
translate(0, -150)
egg(50, :path)
Expand All @@ -537,15 +537,15 @@ for θ in range(0, step=π/6, length=12)
randomhue()
strokepath()
end
grestore()
end
finish()
```
![point example](../assets/figures/tutorial-egg-7.png)

The loop runs 12 times, with `theta` increasing from 0 upwards in steps of π/6. But before each egg is drawn, the entire drawing environment is rotated by `theta` radians and then shifted along the y-axis away from the origin by -150 units (the y-axis values usually increase downwards, so, before any rotation takes place, a shift of -150 looks like an upwards shift). The [`randomhue`](@ref) function does what you expect, and the `egg` function is passed the `:fill` action and the radius.

Notice that the four drawing instructions are encased in a `@layer begin...end` shell. Any change made to the drawing environment inside this shell is discarded after the `end`. This allows us to make temporary changes to the scale and rotation, etc. and discard them easily once the shapes have been drawn.
Notice that the four drawing instructions are encased in a `gsave()`/`grestore()` pair. Any change made to the drawing environment inside this pair is discarded after the `grestore()`. This allows us to make temporary changes to the scale and rotation, etc. and discard them easily once the shapes have been drawn.

Rotations and angles are typically specified in radians. The positive x-axis (a line from the origin increasing in x) starts off heading due east from the origin, and the y-axis due south, and positive angles are clockwise (ie from the positive x-axis towards the positive y-axis). So the second egg in the previous example was drawn after the axes were rotated by π/6 radians clockwise.

Expand Down Expand Up @@ -736,13 +736,13 @@ using Luxor, Colors
sethue("gold")
eg(:fill)
eg(:clip)
@layer begin
gsave()
for i in 360:-4:1
sethue(Colors.HSV(i, 1.0, 0.8))
rotate/30)
ngon(O, i, 5, 0, action = :stroke)
end
end
grestore()
clipreset()
sethue("red")
eg(:stroke)
Expand Down Expand Up @@ -787,13 +787,13 @@ eg(a) = egg(150, a)
sethue("gold")
eg(:fill)
eg(:clip)
@layer begin
gsave()
for i in 360:-4:1
sethue(Colors.HSV(i, 1.0, 0.8))
rotate(π/30)
ngon(O, i, 5, 0, action = :stroke)
end
end
grestore()
clipreset()
sethue("red")
eg(:stroke)
Expand Down
Loading

0 comments on commit e8bc5b7

Please sign in to comment.