diff --git a/CHANGELOG.md b/CHANGELOG.md index ac82b66a..1d874a3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [v2.13.0] - forthcoming +## [v2.13.0] - 2021-07-06 ### Added diff --git a/docs/make.jl b/docs/make.jl index 35ab4184..d26f8245 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -12,7 +12,7 @@ makedocs( "Introduction to Luxor" => "index.md", "Tutorials" => [ "A first tutorial" => "tutorial/basictutorial.md", - "Design a logo" => "tutorial/design-a-logo.md", + "Quick start" => "tutorial/quickstart.md", "Simple animations" => "tutorial/simple-animation.md", ], "Examples" => [ diff --git a/docs/src/assets/figures/textrendering-linux-gnome-greyscale-aaa .png b/docs/src/assets/figures/textrendering-linux-gnome-greyscale-aaa .png new file mode 100644 index 00000000..64487b49 Binary files /dev/null and b/docs/src/assets/figures/textrendering-linux-gnome-greyscale-aaa .png differ diff --git a/docs/src/assets/figures/textrendering-linux-kde-rgb-subpixel-aa.png b/docs/src/assets/figures/textrendering-linux-kde-rgb-subpixel-aa.png new file mode 100644 index 00000000..8b74f214 Binary files /dev/null and b/docs/src/assets/figures/textrendering-linux-kde-rgb-subpixel-aa.png differ diff --git a/docs/src/assets/figures/textrendering-macos-alias-test.png b/docs/src/assets/figures/textrendering-macos-alias-test.png new file mode 100644 index 00000000..811eafe0 Binary files /dev/null and b/docs/src/assets/figures/textrendering-macos-alias-test.png differ diff --git a/docs/src/assets/figures/textrendering-windows-cleartype.png b/docs/src/assets/figures/textrendering-windows-cleartype.png new file mode 100644 index 00000000..1e30c385 Binary files /dev/null and b/docs/src/assets/figures/textrendering-windows-cleartype.png differ diff --git a/docs/src/assets/luxor-docs.css b/docs/src/assets/luxor-docs.css index 345bc364..58a42772 100644 --- a/docs/src/assets/luxor-docs.css +++ b/docs/src/assets/luxor-docs.css @@ -1,7 +1,8 @@ @font-face { font-family: JuliaMono-Regular; src: - url("https://github.com/cormullion/juliamono/raw/master/webfonts/JuliaMono-Regular.woff2"); + local('JuliaMono-Regular'), + url("https://cdn.jsdelivr.net/gh/cormullion/juliamono/webfonts/JuliaMono-Regular.woff2"); } pre, code { diff --git a/docs/src/explanation/imagematrix.md b/docs/src/explanation/imagematrix.md index ed1e3775..bdd1daa0 100644 --- a/docs/src/explanation/imagematrix.md +++ b/docs/src/explanation/imagematrix.md @@ -4,7 +4,7 @@ While drawing, you can copy the current graphics in a drawing as a matrix of pixels, using the [`image_as_matrix`](@ref) function. -With the `@imagematrix` macro, you can create your drawing with vector graphics in the usual way, but the result is returned as a matrix. This example processes an ampersand in Images.jl. +With the [`@imagematrix`](@ref) macro, you can create your drawing with vector graphics in the usual way, but the result is returned as a matrix. This example processes an ampersand in Images.jl. ``` using Luxor, Colors, Images, ImageFiltering diff --git a/docs/src/explanation/perfectpixels.md b/docs/src/explanation/perfectpixels.md index af6d7f1e..826bf5c5 100644 --- a/docs/src/explanation/perfectpixels.md +++ b/docs/src/explanation/perfectpixels.md @@ -2,9 +2,20 @@ ## Antialiasing -The process of converting smooth graphic shapes to a grid of pixels is automatically performed by Luxor/Cairo when you save the drawing as a PNG file. If you make an SVG or PDF drawing, this process is carried out by the application you use to view or display the file. It's usually better to defer the conversion as long as possible: eventually - unless you're using a pen plotter or laser cutter - your smooth outlines will have to be converted ("rasterized") to a grid of colored pixels. - -The smoothing process includes "anti-aliasing". You can - to some extent - adjust the amount of anti-aliasing used when you make drawings in Luxor. +The process of converting smooth graphic shapes to a grid of +pixels is automatically performed by Luxor/Cairo when you +save the drawing as a PNG file. If you make an SVG or PDF +drawing, this process is carried out by the application you +use to view or display the file. It's usually better to +defer the conversion as long as possible: eventually - +unless you're using a pen plotter or laser cutter - your +smooth outlines will have to be converted ("rasterized") to +a grid of colored pixels for their final journey to the +analogue world. + +The smoothing process includes "anti-aliasing". You can - to +some extent - adjust the amount of anti-aliasing used when +you make drawings in Luxor. ```@setup draw_matrix using Luxor, Colors @@ -45,19 +56,19 @@ function draw(antialias) end ``` -The [`setantialias`](@ref) function lets you set the antialiasing amount to a constant between 0 and 6. The Cairo documentation describes the different values as follows: +The [`setantialias`](@ref) function lets you set the anti-aliasing amount to a constant between 0 and 6. The Cairo documentation describes the different values as follows: | Value | Name | Description | |:----- |:---- |:---- | -|0 |`CAIRO_ANTIALIAS_DEFAULT` |Use the default antialiasing for the subsystem and target device| +|0 |`CAIRO_ANTIALIAS_DEFAULT` |Use the default anti-aliasing for the subsystem and target device| |1 |`CAIRO_ANTIALIAS_NONE` |Use a bilevel alpha mask| -|2 |`CAIRO_ANTIALIAS_GRAY` |Perform single-color antialiasing (using shades of gray for black text on a white background, for example)| -|3 |`CAIRO_ANTIALIAS_SUBPIXEL` |Perform antialiasing by taking advantage of the order of subpixel elements on devices such as LCD panels| -|4 |`CAIRO_ANTIALIAS_FAST` |Hint that the backend should perform some antialiasing but prefer speed over quality| +|2 |`CAIRO_ANTIALIAS_GRAY` |Perform single-color anti-aliasing (using shades of gray for black text on a white background, for example)| +|3 |`CAIRO_ANTIALIAS_SUBPIXEL` |Perform anti-aliasing by taking advantage of the order of subpixel elements on devices such as LCD panels| +|4 |`CAIRO_ANTIALIAS_FAST` |Hint that the backend should perform some anti-aliasing but prefer speed over quality| |5 |`CAIRO_ANTIALIAS_GOOD` |The backend should balance quality against performance| |6 |`CAIRO_ANTIALIAS_BEST` |Hint that the backend should render at the highest quality, sacrificing speed if necessary| -To show the antialiasing in action, the following code draws a red circle: +To show the anti-aliasing in action, the following code draws a red circle: ``` Drawing(20, 20, :image) @@ -69,15 +80,15 @@ mat = image_as_matrix() finish() ``` -Enlarging the matrix shows the default value of 0: +This drawing enlarges the matrix. Here's the default anti-aliasing value of 0: ```@example draw_matrix draw(0) # hide ``` -Luxor used 18 colors to render this red circle. +You can see that Luxor used 18 different colors to render this red circle. -Here's the bilevel mask (value 1 or "none"): +Here’s the result of the bilevel mask (value 1 or “none”) setting: ```@example draw_matrix draw(1) # hide @@ -99,58 +110,71 @@ The anti-aliasing process can vary according to the OS and device you're using. ## Text -The antialiasing described above does not apply to text. +The anti-aliasing described above does not apply to text. Text rendering is much more platform-dependent than graphics; Windows, MacOS, and Linux all have their own methods for rendering and rasterizing fonts, and currently Cairo.jl doesn't currently provide an interface to any font rendering APIs. -```@setup draw_text -using Luxor, Colors -function make_matrix(; - antialias=0) - d = Drawing(20, 20, :image) - setantialias(antialias) +Consider the following code: + +```julia +using Luxor + +function make_matrix() + Drawing(40, 40, :image) + background(1, 1, 1, 1) + setantialias(0) origin() - setcolor("red") - fontsize(20) + setcolor(0, 0, 0, 1) + fontsize(40) text("a", halign=:center, valign=:middle) - mat = image_as_matrix() + matrix = image_as_matrix() finish() - return mat -end - -function drawmatrix(A; - cellsize = (10, 10)) - table = Table(size(A)..., cellsize...) - for i in CartesianIndices(A) - r, c = Tuple(i) - sethue(A[r, c]) - box(table, r, c, :fill) - sethue("black") - box(table, r, c, :stroke) - end + return matrix end -function draw(antialias) - mat = make_matrix(antialias=antialias) - @drawsvg begin - background("black") - drawmatrix(mat, cellsize = 1 .* size(mat)) - c = length(unique(color.(mat))) - sethue("white") - fontsize(8) - text("number of colors used: $c", boxbottomcenter(BoundingBox() * 0.9), halign=:center) - end 300 300 +function draw() + matrix = make_matrix() + @png begin + background(0, 0, 0, 1) + table = Table(size(matrix)..., (15, 15)) + for i in CartesianIndices(matrix) + r, c = Tuple(i) + setcolor(matrix[r, c]) + box(table, r, c, :fillstroke) + end + end 400 400 "/tmp/alias-test.png" end ``` -On some platforms you'll see anti-aliased fonts rendered like this: +The output varies depending on the computer, OS, and rendering settings: -```@example draw_text -draw(1) # hide -``` +MacOS standard rendering: + +![macos alias text](../assets/figures/textrendering-macos-alias-test.png) + +Linux Gnome standard anti-aliasing: + +![linux gnome alias text](../assets/figures/textrendering-linux-gnome-greyscale-aaa .png) + +Linux KDE RGB anti-aliasing: + +![linux kde rgb alias text](../assets/figures/textrendering-linux-kde-rgb-subpixel-aa.png) + +Windows Cleartype anti-aliasing: + +![windows cleartype alias text](../assets/figures/textrendering-windows-cleartype.png) -On Windows systems, text might be displayed using Microsoft’s Cleartype subpixel rendering process, and variously colored pixels are drawn around the edges of text in order to provide a “smoother” appearance. +On Windows systems, and on some Linux desktops, text can be +displayed a subpixel rendering process, so that variously +colored pixels are drawn around the edges of text in an +attempt to provide a “smoother” appearance. -In addition, Windows uses font-hinting, a process in which the outlines of text glyphs are shifted so as to align better on the rectangular grid of pixels. +In addition, Windows and some Linux systems use +font-hinting, a process in which the outlines of text glyphs +are shifted so as to align better on the rectangular grid of +pixels. -If you want text to be aligned precisely on Windows, it might be worth investigating Luxor’s [`textoutlines`](@ref) function, which converts text to vector-based outlines. +If you want text to be aligned precisely, and in the +specified color, it might be worth investigating Luxor’s +[`textoutlines`](@ref) function, which converts text to +vector-based outlines. diff --git a/docs/src/explanation/transforms.md b/docs/src/explanation/transforms.md index 12dedb47..a13711a0 100644 --- a/docs/src/explanation/transforms.md +++ b/docs/src/explanation/transforms.md @@ -8,9 +8,9 @@ Graphics are placed on the current workspace according to the *current transform # Transformation functions -For basic transformations, use `translate(tx, ty)`, `scale(sx, sy)`, and `rotate(a)`. +For basic transformations, use [`translate(tx, ty)`](@ref), [`scale(sx, sy)`](@ref), and [`rotate(a)`](@ref). -`translate(pos)` (or `translate(x, y)`) shifts the current origin to `pos` (or by the specified amounts in x and y). It's relative and cumulative, rather than absolute: +[`translate(pos)`](@ref) (or `translate(x, y)`) shifts the current origin to `pos` (or by the specified amounts in x and y). It's relative and cumulative, rather than absolute: ```@example using Luxor, Colors, Random # hide @@ -117,7 +117,7 @@ julia> getmatrix() 0.0 ``` -`transform(a)` 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. +[`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 using Luxor # hide @@ -149,8 +149,8 @@ nothing # hide [`getmatrix`](@ref) gets the current matrix, `setmatrix(a)` sets the matrix to array `a`. -Other functions include [`getmatrix`](@ref) -[`setmatrix`](@ref) [`transform`](@ref) [`crossproduct`](@ref) [`blendmatrix`](@ref) [`rotationmatrix`](@ref) [`scalingmatrix`](@ref) [`translationmatrix`](@ref). +Other functions include [`getmatrix`](@ref), +[`setmatrix`](@ref), [`transform`](@ref), [`crossproduct`](@ref), [`blendmatrix`](@ref), [`rotationmatrix`](@ref), [`scalingmatrix`](@ref), and [`translationmatrix`](@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. diff --git a/docs/src/howto/animation.md b/docs/src/howto/animation.md index 18d77864..11fe76d1 100644 --- a/docs/src/howto/animation.md +++ b/docs/src/howto/animation.md @@ -90,6 +90,35 @@ animate(demo, [ Transitions for animations often use non-constant and non-linear motions, and these are usually provided by *easing* functions. Luxor defines some of the basic easing functions and they're listed in the (unexported) array `Luxor.easingfunctions`. Each scene can have one easing function. + +|List of easing functions| +|:--- | +|easingflat| +|lineartween| +|easeinquad| +|easeoutquad| +|easeinoutquad| +|easeincubic| +|easeoutcubic| +|easeinoutcubic| +|easeinquart| +|easeoutquart| +|easeinoutquart| +|easeinquint| +|easeoutquint| +|easeinoutquint| +|easeinsine| +|easeoutsine| +|easeinoutsine| +|easeinexpo| +|easeoutexpo| +|easeinoutexpo| +|easeincirc| +|easeoutcirc| +|easeinoutcirc| +|easeinoutinversequad| +|easeinoutbezier| + Most easing functions have names constructed like this: ``` @@ -115,13 +144,13 @@ function draweasingfunction(f, pos, w, h) end end -Drawing(650, 650, "../assets/figures/easingfunctions.png") # hide +Drawing(800, 650, "../assets/figures/easingfunctions.png") # hide background("white") # hide origin() # hide t = Tiler(650, 650, 5, 5) margin=5 fontsize(10) -fontface("Menlo") +fontface("JuliaMono-Regular") for (pos, n) in t n > length(Luxor.easingfunctions) && continue draweasingfunction(Luxor.easingfunctions[n], pos, @@ -201,31 +230,3 @@ Here: The [`easeinoutbezier`](@ref) function accepts two additional arguments, two normalized control points of a normalized Bezier curve from Point(0, 0) to Point(1, 1). You can use these to define the shape of a custom easing transition. The Bezier curve's `y` coordinate determines the acceleration. [?] ![animation of bezier easing](../assets/figures/animation-bezier-easing.gif) - -|List of easing functions| -|:--- | -|easingflat| -|lineartween| -|easeinquad| -|easeoutquad| -|easeinoutquad| -|easeincubic| -|easeoutcubic| -|easeinoutcubic| -|easeinquart| -|easeoutquart| -|easeinoutquart| -|easeinquint| -|easeoutquint| -|easeinoutquint| -|easeinsine| -|easeoutsine| -|easeinoutsine| -|easeinexpo| -|easeoutexpo| -|easeinoutexpo| -|easeincirc| -|easeoutcirc| -|easeinoutcirc| -|easeinoutinversequad| -|easeinoutbezier| diff --git a/docs/src/howto/createdrawings.md b/docs/src/howto/createdrawings.md index 2682f9fa..d9308bff 100644 --- a/docs/src/howto/createdrawings.md +++ b/docs/src/howto/createdrawings.md @@ -6,7 +6,7 @@ To create a drawing, and optionally specify the filename, type, and dimensions, 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). -The `@draw`, `@svg`, `@png`, and `@pdf` macros are designed to let you quickly create graphics without having to provide the usual boiler-plate functions. +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. !!! note @@ -67,9 +67,9 @@ or (less nicely): ) ``` -The `@draw` macro creates a PNG drawing in-memory (not saved in a file). You should see it displayed if you're working in a suitable environment (Juno, VSCode, Jupyter, Pluto). +The [`@draw`](@ref) macro creates a PNG drawing in-memory (not saved in a file). You should see it displayed if you're working in a suitable environment (Juno, VSCode, Jupyter, Pluto). -The SVG equivalent of `@draw` is `@drawsvg`. +The SVG equivalent of `@draw` is [`@drawsvg`](@ref). If you don't specify a size, the defaults are usually 600 by 600. If you don't specify a file name, files created with the macros are placed in your current working directory as `luxor-drawing-` followed by a time stamp. You don't even have to specify the suffix: @@ -102,7 +102,9 @@ You can choose to store the drawing in memory. The advantage is that in-memory d Drawing(width, height, surfacetype, [filename]) ``` -lets you supply `surfacetype` as a symbol (`:svg` or `:png`). This creates a new drawing of the given surface type and stores the image only in memory if no `filename` is supplied. The `@draw` macro creates PNG files in memory. +lets you supply `surfacetype` as a symbol (`:svg` or `:png`). This creates a new drawing of the given surface type and stores the image only in memory if no `filename` is supplied. + +The `@draw` and `@drawsvg` macros creates PNG/SVG files in memory. You can specify `:image` as the surface type. This allows you to copy the current drawing into a 2D matrix (using [`image_as_matrix`](@ref)). See the Images chapter for more information. diff --git a/docs/src/howto/polygons.md b/docs/src/howto/polygons.md index bff7ca60..2515af0d 100644 --- a/docs/src/howto/polygons.md +++ b/docs/src/howto/polygons.md @@ -8,32 +8,32 @@ A path is a sequence of one or more straight and curved (circular arc or Bézier Luxor also provides a BezierPath type, which is an array of four-point tuples, each of which is a Bézier cubic curve section. -|create |convert |draw |info |edit | -|:--- |:--- |:--- |:--- |:--- | -| *polygons* | | | | | -|[`ngon`](@ref) |[`polysmooth`](@ref) |[`poly`](@ref) |[`isinside`](@ref) |[`simplify`](@ref) | -|[`ngonside`](@ref) | |[`prettypoly`](@ref) |[`polyperimeter`](@ref) |[`polysplit`](@ref) | -|[`star`](@ref) | |[`polysmooth`](@ref) |[`polyarea`](@ref) |[`polyportion`](@ref) | -|[`polycross`](@ref) | | |[`polycentroid`](@ref) |[`polyremainder`](@ref) | -|[`offsetpoly`](@ref) | | |`boundingbox` |[`polysortbyangle`](@ref) | -|[`hypotrochoid`](@ref) | | |[`ispolyclockwise`](@ref) |[`polysortbydistance`](@ref) | -|[`epitrochoid`](@ref) | | |[`ispolyconvex`](@ref) |[`polyintersections`](@ref) | -|[`polyrotate!`](@ref) | | | |[`polymove!`](@ref) | -|[`polyfit`](@ref) | | | |[`polyscale!`](@ref) | -| | | | | | -| | | | |[`polyreflect!`](@ref) | -| | | | |[`polysample`](@ref) | -| | | | |[`polytriangulate`](@ref) | -| | | | |[`insertvertices!`](@ref) | -| *paths* | | | | | -|[`getpath`](@ref) |[`pathtopoly`](@ref) | | | | -|[`getpathflat`](@ref) | | | | | -| *Bezier paths* | | | | | -|[`makebezierpath`](@ref) |[`pathtobezierpaths`](@ref) |[`drawbezierpath`](@ref) | | | -|[`pathtobezierpaths`](@ref) |[`bezierpathtopoly`](@ref) |[`brush`](@ref) | | | -|`BezierPath` | | | | | -|`BezierPathSegment` | | | | | -|[`beziersegmentangles`](@ref) | | | | | +|create |convert |draw |info |edit | +|:--- |:--- |:--- |:--- |:--- | +| *polygons* | | | | | +|[`ngon`](@ref) |[`polysmooth`](@ref) |[`poly`](@ref) |[`isinside`](@ref) |[`simplify`](@ref) | +|[`ngonside`](@ref) | |[`prettypoly`](@ref) |[`polyperimeter`](@ref) |[`polysplit`](@ref) | +|[`star`](@ref) | |[`polysmooth`](@ref) |[`polyarea`](@ref) |[`polyportion`](@ref) | +|[`polycross`](@ref) | | |[`polycentroid`](@ref) |[`polyremainder`](@ref) | +|[`offsetpoly`](@ref) | | |[`BoundingBox`](@ref) |[`polysortbyangle`](@ref) | +|[`hypotrochoid`](@ref) | | |[`ispolyclockwise`](@ref) |[`polysortbydistance`](@ref) | +|[`epitrochoid`](@ref) | | |[`ispolyconvex`](@ref) |[`polyintersections`](@ref) | +|[`polyrotate!`](@ref) | | | |[`polymove!`](@ref) | +|[`polyfit`](@ref) | | | |[`polyscale!`](@ref) | +| | | | | | +| | | | |[`polyreflect!`](@ref) | +| | | | |[`polysample`](@ref) | +| | | | |[`polytriangulate`](@ref) | +| | | | |[`insertvertices!`](@ref) | +| *paths* | | | | | +|[`getpath`](@ref) |[`pathtopoly`](@ref) | | | | +|[`getpathflat`](@ref) | | | | | +| *Bezier paths* | | | | | +|[`makebezierpath`](@ref) |[`pathtobezierpaths`](@ref) |[`drawbezierpath`](@ref) | | | +|[`pathtobezierpaths`](@ref) |[`bezierpathtopoly`](@ref) |[`brush`](@ref) | | | +|[`BezierPath`](@ref) | | | | | +|[`BezierPathSegment`](@ref) | | | | | +|[`beziersegmentangles`](@ref) | | | | | ## Regular polygons ("ngons") @@ -41,7 +41,6 @@ A polygon is an array of points. The points can be joined with straight lines. You can make regular polygons — from triangles, pentagons, hexagons, septagons, heptagons, octagons, nonagons, decagons, and on-and-on-agons — with [`ngon`](@ref). - ```@example using Luxor, Colors # hide Drawing(700, 600, "../assets/figures/n-gon.png") # hide diff --git a/docs/src/howto/simplegraphics.md b/docs/src/howto/simplegraphics.md index bce9a7fc..5b24504c 100644 --- a/docs/src/howto/simplegraphics.md +++ b/docs/src/howto/simplegraphics.md @@ -14,7 +14,7 @@ The simple rectangle and box shapes can be made in different ways. ```@example using Luxor # hide Drawing(400, 220, "../assets/figures/basicrects.png") # hide -background("white") # hide +background("antiquewhite") # hide origin() # hide rulers() sethue("red") @@ -69,7 +69,7 @@ There are various ways to make circles, including by center and radius, or passi ```@example using Luxor # hide Drawing(400, 200, "../assets/figures/circles.png") # hide -background("white") # hide +background("antiquewhite") # hide origin() # hide setline(3) # hide @@ -99,7 +99,7 @@ The [`center3pts`](@ref) function returns the center position and radius of a ci ```@example using Luxor, Random # hide Drawing(400, 200, "../assets/figures/center3.png") # hide -background("white") # hide +background("antiquewhite") # hide origin() # hide setline(3) # hide sethue("black") @@ -120,7 +120,7 @@ With [`ellipse`](@ref) you can place ellipses and circles by defining the center ```@example using Luxor, Random # hide Drawing(500, 300, "../assets/figures/ellipses.png") # hide -background("white") # hide +background("antiquewhite") # hide fontsize(11) # hide Random.seed!(1) # hide origin() # hide @@ -148,7 +148,7 @@ nothing # hide using Luxor, Random # hide Drawing(400, 220, "../assets/figures/ellipses_1.png") # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide Random.seed!(42) # hide sethue("black") # hide @@ -187,7 +187,7 @@ The advantage of this method is that there's a `vertices=true` option, allowing using Luxor # hide Drawing(500, 450, "../assets/figures/ellipses_2.png") # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide sethue("gray30") # hide setline(1) # hide f1 = Point(-100, 0) @@ -211,7 +211,7 @@ The [`ellipseinquad`](@ref) function constructs an ellipse that fits in a four-s using Luxor # hide Drawing(600, 600, "../assets/figures/ellipseinquad.png") # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide sethue("gray30") # hide setline(1) # hide @@ -244,7 +244,7 @@ nothing # hide using Luxor # hide Drawing(600, 250, "../assets/figures/circle-path.png") # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide sethue("black") # hide setline(4) tiles = Tiler(600, 250, 1, 5) @@ -274,7 +274,7 @@ Functions to find tangents to circles include: using Luxor # hide Drawing(600, 250, "../assets/figures/point-circle-tangents.png") # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide setline(1) # hide sethue("black") # hide @@ -302,7 +302,7 @@ nothing # hide using Luxor # hide Drawing(600, 250, "../assets/figures/circle-circle-outer-tangents.png") # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide setline(1) # hide sethue("black") # hide @@ -335,7 +335,7 @@ Finding the inner tangents requires a separate function. using Luxor # hide Drawing(600, 250, "../assets/figures/circle-circle-inner-tangents.png") # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide setline(1) # hide sethue("black") # hide @@ -372,7 +372,7 @@ nothing # hide using Luxor # hide Drawing(600, 250, "../assets/figures/circle-tangents.png") # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide sethue("black") # hide setline(1) # hide @@ -419,7 +419,7 @@ nothing # hide using Luxor # hide Drawing(600, 250, "../assets/figures/circle-point-tangent.png") # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide sethue("black") # hide setline(1) # hide @@ -495,7 +495,7 @@ You can use [`rule`](@ref) to draw a line through a point, optionally at an angl ```@example using Luxor # hide Drawing(700, 200, "../assets/figures/rule.png") # hide -background("white") # hide +background("antiquewhite") # hide sethue("black") # hide setline(0.5) # hide y = 10 @@ -518,7 +518,7 @@ Use the `boundingbox` keyword argument to crop the ruled lines with a BoundingBo using Luxor # hide Drawing(700, 200, "../assets/figures/rulebbox.png") # hide origin() -background("white") # hide +background("antiquewhite") # hide sethue("black") # hide setline(0.75) # hide box(BoundingBox() * 0.9, :stroke) @@ -547,7 +547,7 @@ For straight arrows, supply the start and end points. For arrows as circular arc ```@example using Luxor # hide Drawing(400, 250, "../assets/figures/arrow.png") # hide -background("white") # hide +background("antiquewhite") # hide origin() # hide sethue("steelblue4") # hide setline(2) # hide @@ -564,7 +564,7 @@ If you provide four points, you can draw a Bézier curve with optional arrowhead ```@example using Luxor # hide Drawing(600, 400, "../assets/figures/arrowbezier.png") # hide -background("white") # hide +background("antiquewhite") # hide origin() # hide setline(2) # hide pts = ngon(Point(0, 0), 100, 8, vertices=true) @@ -611,8 +611,8 @@ shaft. ```@example using Luxor # hide -Drawing(600, 400, "../assets/figures/arrowbezierdecoration.png") # hide -background("white") # hide +Drawing(800, 400, "../assets/figures/arrowbezierdecoration.png") # hide +background("antiquewhite") # hide origin() # hide setline(2) # hide @@ -636,7 +636,10 @@ arrow(pts[1:4]..., decorate = () -> marker(10, 3)) sethue("olivedrab") # no arrow, just a graphic, at 0.75 -arrow(pts[1:4]..., decorate = () -> ngon(Point(0, 0), 20, 4, 0, :fill), decoration = 0.75, :none) +arrow(pts[1:4]..., + decorate = () -> + ngon(Point(0, 0), 20, 4, 0, :fill), + decoration = 0.75, :none) finish() # hide nothing # hide @@ -692,7 +695,7 @@ function redbluearrow(shaftendpoint, endpoint, shaftangle) end @drawsvg begin - background("white") + background("antiquewhite") arrow(O, O + (120, 120), linewidth=4, arrowheadlength=40, @@ -716,7 +719,7 @@ There are a few standard arc-drawing commands, such as [`curve`](@ref), [`arc`]( using Luxor # hide Drawing(600, 275, "../assets/figures/curve.png") # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide sethue("black") # hide @@ -756,7 +759,7 @@ using Luxor, Random # hide Drawing(700, 200, "../assets/figures/arc2r.png") # hide origin() # hide Random.seed!(42) # hide -background("white") # hide +background("antiquewhite") # hide tiles = Tiler(700, 200, 1, 6) for (pos, n) in tiles c1, pt2, pt3 = ngon(pos, rand(10:50), 3, rand(0:pi/12:2pi), vertices=true) @@ -779,7 +782,7 @@ nothing # hide using Luxor, Colors # hide Drawing(400, 250, "../assets/figures/arc2sagitta.svg") # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide setline(.5) # hide translate(0, 50) # hide pt1 = Point(-100, 0) @@ -807,7 +810,7 @@ A sector (technically an "annular sector") has an inner and outer radius, as wel ```@example using Luxor # hide Drawing(600, 200, "../assets/figures/sector.png") # hide -background("white") # hide +background("antiquewhite") # hide origin() # hide sethue("tomato") sector(50, 90, π/2, 0, :fill) @@ -824,7 +827,7 @@ You can also supply a value for a corner radius. The same sector is drawn but wi ```@example using Luxor # hide Drawing(600, 200, "../assets/figures/sectorrounded.png") # hide -background("white") # hide +background("antiquewhite") # hide origin() # hide sethue("tomato") sector(50, 90, π/2, 0, 15, :fill) @@ -841,7 +844,7 @@ A pie (or wedge) has start and end angles. ```@example using Luxor # hide Drawing(400, 300, "../assets/figures/pie.png") # hide -background("white") # hide +background("antiquewhite") # hide origin() # hide sethue("magenta") # hide pie(0, 0, 100, π/2, π, :fill) @@ -856,7 +859,7 @@ To construct spirals, use the [`spiral`](@ref) function. These can be drawn dire ```@example using Luxor # hide Drawing(600, 300, "../assets/figures/spiral.png") # hide -background("white") # hide +background("antiquewhite") # hide origin() # hide sethue("black") # hide setline(.5) # hide @@ -890,7 +893,7 @@ Use the `log=true` option to draw logarithmic (Bernoulli or Fibonacci) spirals. ```@example using Luxor # hide Drawing(600, 400, "../assets/figures/spiral-log.png") # hide -background("white") # hide +background("antiquewhite") # hide origin() # hide setline(.5) # hide sethue("black") # hide @@ -924,7 +927,7 @@ A *squircle* is a cross between a square and a circle. You can adjust the squari ```@example using Luxor # hide Drawing(600, 250, "../assets/figures/squircle.png") # hide -background("white") # hide +background("antiquewhite") # hide origin() # hide fontsize(20) # hide setline(2) @@ -948,7 +951,7 @@ To draw a simple rounded rectangle, supply a corner radius: using Luxor # hide Drawing(600, 250, "../assets/figures/round-rect-1.png") # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide sethue("black") # hide setline(4) box(O, 200, 150, 10, :stroke) @@ -964,7 +967,7 @@ Or you could smooth the corners of a box, like so: using Luxor # hide Drawing(600, 250, "../assets/figures/round-rect.png") # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide sethue("black") # hide setline(4) polysmooth(box(O, 200, 150, vertices=true), 10, :stroke) @@ -980,7 +983,7 @@ Use [`star`](@ref) to make a star. You can draw it immediately, or use the point ```@example using Luxor # hide Drawing(500, 300, "../assets/figures/stars.png") # hide -background("white") # hide +background("antiquewhite") # hide origin() # hide tiles = Tiler(400, 300, 4, 6, margin=5) for (pos, n) in tiles @@ -999,7 +1002,7 @@ The `ratio` determines the length of the inner radius compared with the outer. using Luxor # hide Drawing(500, 250, "../assets/figures/star-ratios.png") # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide sethue("black") # hide setline(2) # hide tiles = Tiler(500, 250, 1, 6, margin=10) @@ -1018,7 +1021,7 @@ Use [`polycross`](@ref) to draw a cross-shaped polygon. using Luxor # hide Drawing(600, 600, "../assets/figures/polycross.png") # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide sethue("black") # hide setline(2) # hide tiles = Tiler(600, 600, 4, 4, margin=10) @@ -1045,7 +1048,7 @@ using Luxor, Random # hide Drawing(750, 300, "../assets/figures/julia-logo.png") # hide Random.seed!(42) # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide cells = Table([300], [350, 350]) @@ -1110,7 +1113,7 @@ If you want cropmarks (aka trim marks), use the [`cropmarks`](@ref) function, su using Luxor # hide Drawing(700, 250, "../assets/figures/cropmarks.png") # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide sethue("red") box(O, 150, 150, :stroke) cropmarks(O, 150, 150) @@ -1130,7 +1133,7 @@ Simple dimensioning graphics can be generated with [`dimension`](@ref). To conve using Luxor # hide Drawing(700, 350, "../assets/figures/dimensioning.svg") # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide setline(0.75) sethue("purple") pentagon = ngonside(O, 120, 5, vertices=true) @@ -1198,7 +1201,7 @@ For simple barcharts, use the [`barchart`](@ref) function, supplying an array of using Luxor # hide Drawing(800, 420, "../assets/figures/bars.png") # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide fontsize(7) sethue("black") v = rand(-100:100, 25) @@ -1217,7 +1220,7 @@ Drawing(800, 450, "../assets/figures/bars1.png") # hide Random.seed!(2) # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide setopacity(0.8) # hide fontsize(8) # hide fontface("Helvetica-Bold") # hide @@ -1269,7 +1272,7 @@ using Luxor, Colors, Random # hide Drawing(800, 450, "../assets/figures/boxmap.png") # hide Random.seed!(13) # hide origin() # hide -background("white") # hide +background("antiquewhite") # hide fib = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144] diff --git a/docs/src/howto/turtle.md b/docs/src/howto/turtle.md index a02e3504..ff049914 100644 --- a/docs/src/howto/turtle.md +++ b/docs/src/howto/turtle.md @@ -5,7 +5,7 @@ DocTestSetup = quote ``` # Turtle graphics -Some simple "turtle graphics" functions are included. Functions to control the turtle begin with a capital letter: Forward, Turn, Circle, Orientation, Towards, Rectangle, Pendown, Penup, Pencolor, Penwidth, and Reposition, and so on, and angles are specified in degrees. +Luxor provides some basic "turtle graphics" functions. Functions to control the turtle begin (somewhat unusually) with a capital letter: Forward, Turn, Circle, Orientation, Towards, Rectangle, Pendown, Penup, Pencolor, Penwidth, and Reposition, and so on, and angles are specified in degrees rather than radians. ```@example using Luxor, Colors @@ -32,6 +32,26 @@ nothing # hide ![turtles](../assets/figures/turtles.png) +|List of words the turtle knows|Action | +|:--- |:--- | +|[`Forward`](@ref) | More forward by d units | +|[`Turn`](@ref) | Increase the turtle's rotation by n degrees | +|[`Circle`](@ref) | Draw filled circle centered at current pos | +|[`HueShift`](@ref) | Shift the Hue of the turtle's pen color by n | +|[`Message`](@ref) | Output text | +|[`Orientation`](@ref) | Set the turtle's orientation to n degrees | +|[`Pen_opacity_random`](@ref) | Set opacity to random value | +|[`Pencolor`](@ref) | Set the Red, Green, and Blue values | +|[`Pendown`](@ref) | Start drawing | +|[`Penup`](@ref) | Stop drawing | +|[`Penwidth`](@ref) | Set the width of the line to n | +|[`Pop `](@ref) | Move turtle to the value stored on the stack | +|[`Push`](@ref) | Save the turtle's position on the stack | +|[`Randomize_saturation`](@ref)| Randomize the saturation of the current color | +|[`Rectangle`](@ref) | Draw filled rectangle centered at current pos | +|[`Reposition`](@ref) | Place turtle at new position | +|[`Towards`](@ref) | Rotate turtle to face towards a point | + The turtle commands expect a reference to a turtle as the first argument (it doesn't have to be a turtle emoji!), and you can have any number of turtles active at a time. ```@example @@ -102,25 +122,3 @@ nothing # hide ``` ![hilbert turtle](../assets/figures/hilbertturtle.svg) - -|List of words the turtle knows| -|:---| -|Turtle| -|Forward| -|Turn| -|Circle| -|HueShift| -|Message| -|Orientation| -|Towards| -|Randomize_saturation| -|Rectangle| -|Pen_opacity_random| -|Pendown| -|Penup| -|Pencolor| -|Penwidth| -|Point| -|Pop| -|Push| -|Reposition| diff --git a/docs/src/tutorial/basictutorial.md b/docs/src/tutorial/basictutorial.md index 975aa984..a6fa59c9 100644 --- a/docs/src/tutorial/basictutorial.md +++ b/docs/src/tutorial/basictutorial.md @@ -3,9 +3,9 @@ DocTestSetup = quote using Luxor, Colors end ``` -# First tutorial +# A tutorial -Experienced Julia users and programmers fluent in other languages and graphics systems should have no problem using Luxor by referring to the rest of the documentation. For others, here is a short tutorial to help you get started. +Experienced Julia users and programmers fluent in other languages and graphics systems should have no problem using Luxor by referring to the rest of the documentation. For others, here is a tutorial to help you get started. ## What you need diff --git a/docs/src/tutorial/design-a-logo.md b/docs/src/tutorial/quickstart.md similarity index 98% rename from docs/src/tutorial/design-a-logo.md rename to docs/src/tutorial/quickstart.md index 30017e42..11087765 100644 --- a/docs/src/tutorial/design-a-logo.md +++ b/docs/src/tutorial/quickstart.md @@ -3,7 +3,15 @@ DocTestSetup = quote using Luxor, Colors end ``` -# Tutorial: design a logo +# Quick start: design a logo + +This section is a quick guide to getting started. Install the Luxor.jl package in the usual way: + +``` +julia> ] add Luxor +``` + +# A first drawing The new (and currently fictitious) organization JuliaFission has just asked you to design a new logo for them. They're @@ -14,8 +22,6 @@ suitably "atomic". Let's try out some ideas. -## A first drawing - ```@setup example_1 using Luxor svgimage = @drawsvg begin diff --git a/docs/src/tutorial/simple-animation.md b/docs/src/tutorial/simple-animation.md index b7959b45..f1c4c371 100644 --- a/docs/src/tutorial/simple-animation.md +++ b/docs/src/tutorial/simple-animation.md @@ -1,30 +1,29 @@ # Make simple animations Luxor.jl can help you build simple animations, by assembling -a series of PNG images. To make richer animations, you -should use [Javis.jl](https://github.com/Wikunia/Javis.jl) instead. +a series of PNG images into an animated GIF. + +!!! note + + To make richer or more complex animations, you should use [Javis.jl](https://github.com/Wikunia/Javis.jl). ## A Julia spinner -The first thing to do is to create a `Movie` object. This acts as a useful handle that we can pass from function to function. +The first thing to do is to create a `Movie` object. This acts as a useful object that we can pass from function to function. ```julia +using Luxor mymovie = Movie(400, 400, "mymovie") ``` -The resulting animation will be 400×400 pixels. +The resulting animation will be 400 × 400 pixels. -To make the graphics, use a function called `frame()` (it doesn't have to be called that, but it's a good name) which accepts two arguments, a Scene object, and a framenumber (integer). +To make the graphics, define a function called `frame()` (it doesn't have to be called that, but it's a good name) which accepts two arguments, a Scene object, and a framenumber (integer). -A movie consists of one or more scenes. A scene is an object which determines how many drawings should be made into a sequence. The framenumber lets you keep track of where you are in a scene. +A movie consists of one or more scenes. A scene is an object which determines how many drawings should be made into a sequence and what function should be used to make them. The framenumber lets you keep track of where you are in a scene. Here's a simple `frame` function which creates a drawing. -This function is responsible for drawing all the graphics for a single frame. -The incoming frame number is converted (normalized) to lie between 0 and 1 - ie. between the first frame and the last frame of the scene. It's multiplied by 2π and used as input to `rotate`. - -A sequence of drawings will be made, and as the framenumber goes from 1 to `n`, each drawing will be rotated by an increasing angle. For example, for a scene with 60 frames, framenumber 30 will set a rotation value of about `2π * 0.5`. - ```julia function frame(scene::Scene, framenumber::Int64) background("white") @@ -37,6 +36,17 @@ function frame(scene::Scene, framenumber::Int64) end ``` +This function is responsible for drawing all the graphics +for a single frame. The incoming frame number is converted +(normalized) to lie between 0 and 1 - ie. between the first +frame and the last frame of the scene. It's multiplied by 2π +and used as input to `rotate`. + +So as the framenumber goes from 1 to `n`, each drawing will +be rotated by an increasing angle from 0 to 2π. For example, +for a scene with 60 frames, framenumber 30 will set a +rotation value of about `2π * 0.5`. + The Scene object has details about the number of frames for this scene, the number of times the `frame` function is called. To actually build the animation, the [`animate`](@ref) function takes an array of one or more scenes and builds a GIF. @@ -54,7 +64,7 @@ animate(mymovie, Obviously, if you increase the range from 1:60 to, say, 1:300, you'll generate 300 drawings rather than 60, and the -rotation of the drawing will take longer and will be much +rotation will take longer and will be much smoother. Unless, of course, you change the framerate to be something other than the default `30`.