diff --git a/CHANGELOG.md b/CHANGELOG.md index c62a13fd..03aece22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [v3.3.0] - forthcoming +## [v3.3.0] - 2022-06-01 11:28:44 ### Added @@ -8,9 +8,10 @@ - `textfit()` algorithm revisited; it's quicker, at least.... - `polymorph()` keywords changed -- `polymorph()` can now morph between open polygons +- `polymorph()` can now also morph between open polygons - minimum Julia version is now 1.6 - there are still bugs/edgecases in `polyhull()` which I can't find/fix +- docs now built on Linux (for LaTeX purposes) ### Removed diff --git a/docs/src/assets/figures/pro-text-example.png b/docs/src/assets/figures/pro-text-example.png index 407b5d87..9aac3311 100644 Binary files a/docs/src/assets/figures/pro-text-example.png and b/docs/src/assets/figures/pro-text-example.png differ diff --git a/docs/src/assets/figures/pro-text-placement.png b/docs/src/assets/figures/pro-text-placement.png index d66a7b1b..5e9aa13a 100644 Binary files a/docs/src/assets/figures/pro-text-placement.png and b/docs/src/assets/figures/pro-text-placement.png differ diff --git a/docs/src/assets/figures/texttrack.svg b/docs/src/assets/figures/texttrack.svg new file mode 100644 index 00000000..67f0400e --- /dev/null +++ b/docs/src/assets/figures/texttrack.svg @@ -0,0 +1,1065 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/src/example/examples.md b/docs/src/example/examples.md index 2152a187..fce1e7b3 100644 --- a/docs/src/example/examples.md +++ b/docs/src/example/examples.md @@ -43,7 +43,7 @@ graphics without you having to provide the usual set-up and finish instructions: ```julia -# using Luxor +using Luxor @png begin fontsize(50) @@ -54,26 +54,36 @@ finish instructions: ![background](../assets/figures/hello-world-macro.png) -```julia -@svg begin +```@example +using Luxor + +@drawsvg begin + background("black") sethue("red") - randpoint = Point(rand(-200:200), rand(-200:200)) - circle(randpoint, 2, :fill) - sethue("black") + randpoint = Point(rand(-300:300), rand(-300:300)) + circle(randpoint, 5, :fill) + sethue("white") foreach(f -> arrow(f, between(f, randpoint, .1), arrowheadlength=6), - first.(collect(Table(fill(20, 15), fill(20, 15))))) + first.(collect(Table(fill(30, 20), fill(30, 20))))) end ``` -![background](../assets/figures/circle-dots.png) The `@draw` and `drawsvg` macros are useful if you work in Juno/VS Code IDEs or a notebook environment such as Jupyter or Pluto and don't need to always save your work in files. They create a PNG or SVG format drawing in memory, rather -than saved in a file. It's displayed in the plot pane or in -an adjacent cell. +than saved in a file. + +In this document, which was generated by Documenter.jl, the result +of executing the code is included and displayed as a +graphic. + +For Juno and VS Code, the graphic is usually displayed in +the plot pane. In Pluto, it appears above the cell. ```julia +using Luxor + @draw begin setopacity(0.85) steps = 20 @@ -137,10 +147,10 @@ Here's a version of the Sierpinski recursive triangle, clipped to a circle. ![Sierpinski](../assets/figures/sierpinski.png) ```julia -# using Luxor, Colors -# Drawing() -# background("white") -# origin() +using Luxor, Colors +Drawing() +background("white") +origin() function triangle(points, degree) sethue(cols[degree]) @@ -170,8 +180,8 @@ depth = 8 # 12 is ok, 20 is right out (on my computer, at least) cols = distinguishable_colors(depth) # from Colors.jl draw(depth) -# finish() -# preview() +finish() +preview() ``` The Point type is an immutable composite type containing `x` and `y` fields that specify a 2D point. @@ -181,7 +191,7 @@ The Point type is an immutable composite type containing `x` and `y` fields that [`tickline()`](@ref) is useful for generating spaced points along a line: ```@example -using Luxor # hide +using Luxor @drawsvg begin background("black") fontsize(12) @@ -196,7 +206,7 @@ end 800 150 The [`arrow`](@ref) functions let you add decoration to the arrow shafts, so it's possible to use this function to create more complicated spacings. Here's how a curved number line could be made: ```@example -using Luxor # hide +using Luxor @drawsvg begin background("antiquewhite") _counter() = (a = -1; () -> a += 1) @@ -268,10 +278,10 @@ If you have the right fonts installed, you can easily draw simple ``\LaTeX`` equ ```@example # drawing with 800×300 canvas -using Luxor # hide +using Luxor using MathTeXEngine -d = Drawing(800, 300, :svg) # hide -origin() # hide +d = Drawing(800, 300, :svg) +origin() background("khaki") f(t) = Point(4cos(t) + 2cos(5t), 4sin(t) + 2sin(5t)) setline(15) @@ -283,8 +293,8 @@ fontsize(35) end sethue("grey5") text(L"f(t) = [4\cos(t) + 2\cos(5t), 4\sin(t) + 2\sin(5t)]", halign=:center) -finish() # hide -d # hide +finish() +d ``` ## Triangulations @@ -294,12 +304,12 @@ random points can be used to derive a set of Voronoi cells. ```@example # Inspired by @TheCedarPrince! -using Luxor, Colors, Random # hide -Random.seed!(42) # hide +using Luxor, Colors, Random +Random.seed!(42) -d = @drawsvg begin # hide -background("black") # hide -setlinejoin("bevel") # hide +d = @drawsvg begin +background("black") +setlinejoin("bevel") verts = randompointarray(BoundingBox(), 40) triangles = polytriangulate(verts) # create Delaunay @@ -340,6 +350,6 @@ for v in verts strokepath() end end -end 800 500 # hide -d # hide +end 800 500 +d ``` diff --git a/docs/src/howto/polygons.md b/docs/src/howto/polygons.md index 59602bca..1d3efca1 100644 --- a/docs/src/howto/polygons.md +++ b/docs/src/howto/polygons.md @@ -1227,6 +1227,16 @@ nothing # hide ![polysampling 2](../assets/figures/polysample2.png) +!!! note + + In Luxor, you'll meet `close` and `closed` options. + `close` is an instruction to path-drawing functions, + that says "join the most recent point to the first + point". Whereas, `closed` is an indication that the + polygons or paths should be treated as being closed + rather than open, ie whether that last segment joining + the end point to the first is used for calculations. + ### Polygon side lengths `polydistances` returns an array of the accumulated side lengths of a polygon. diff --git a/docs/src/howto/text.md b/docs/src/howto/text.md index e9dd7908..ab0c34b5 100644 --- a/docs/src/howto/text.md +++ b/docs/src/howto/text.md @@ -16,17 +16,10 @@ Use: - `fontface(fontname)` to specify the fontname - `fontsize(fontsize)` to specify the fontsize -```@example -using Luxor # hide -Drawing(600, 100, "../assets/figures/toy-text-example.png") # hide -origin() # hide -background("azure") # hide -sethue("black") # hide +```julia fontsize(16) fontface("Georgia-Bold") text("Georgia: a serif typeface designed in 1993 by Matthew Carter.", halign=:center) -finish() # hide -nothing # hide ``` ![text placement](../assets/figures/toy-text-example.png) @@ -42,16 +35,9 @@ Use: - `setfont(fontname, fontsize)` to specify the fontname and size - `settext(text, [position])` to place the text at a position, and optionally specify horizontal and vertical alignment, rotation (in degrees counterclockwise!), and the presence of any pseudo-Pango-flavored markup. -```@example -using Luxor # hide -Drawing(600, 100, "../assets/figures/pro-text-example.png") # hide -origin() # hide -background("azure") # hide -sethue("black") # hide +```julia setfont("Georgia Bold", 16) settext("Georgia: a serif typeface designed in 1993 by Matthew Carter.", halign="center") -finish() # hide -nothing # hide ``` ![text placement](../assets/figures/pro-text-example.png) @@ -68,11 +54,7 @@ To select a font in the Pro text API, use [`setfont`](@ref) and supply both the Use [`text`](@ref) to place text. -```@example -using Luxor # hide -Drawing(400, 150, "../assets/figures/text-placement.png") # hide -origin() # hide -background("white") # hide +```julia fontsize(80) # hide sethue("black") # hide pt1 = Point(-100, 0) @@ -87,23 +69,15 @@ text("5", pt2, halign=:center, valign = :top) text("6", pt3, halign=:right, valign = :top) sethue("red") map(p -> circle(p, 4, :fill), [pt1, pt2, pt3]) -finish() # hide -nothing # hide ``` ![text placement](../assets/figures/text-placement.png) -```@example -using Luxor # hide -Drawing(400, 300, "../assets/figures/text-rotation.png") # hide -origin() # hide -background("white") # hide +```julia sethue("black") # hide fontsize(10) fontface("Georgia") [text(string(θ), Point(40cos(θ), 40sin(θ)), angle=θ) for θ in 0:π/12:47π/24] -finish() # hide -nothing # hide ``` ![text rotation](../assets/figures/text-rotation.png) @@ -141,15 +115,16 @@ to parse the `LaTeXString`. You should load MathTeXEngine.jl !!! note - MathTeXEngine.jl is a package that renders + MathTeXEngine.jl is a package that renders many `LaTeXString`s without requiring a ``\LaTeX`` compiler. The package uses the fonts _Computer Modern_ and _New Computer Modern_. They're included with the MathTeXEngine package, and you can find them in your `julia` folder in `packages/MathTeXEngine/.../assets/fonts`. You should - make sure these have been installed before running - Luxor and writing ``\LaTeX`` strings. + make sure these have been copied to your system's + font directories before running Luxor and writing + ``\LaTeX`` strings. ```@example using Luxor @@ -179,6 +154,15 @@ nothing # hide ![textbox](../assets/figures/latexexample.svg) +!!! note + + The string macros in the + [LaTeXStrings.jl](https://github.com/stevengj/LaTeXStrings.jl) + package allow you to enter LaTeX equations + without having to escape backslashes and dollar signs + (and they'll add the dollar signs for you if you omit + them). + ## Notes on fonts Fonts are loaded when you first start using Luxor/Cairo in a Julia session. This partly explains why starting a Luxor/Cairo session can take a few seconds. @@ -223,10 +207,7 @@ For PNG files, the appearance of fonts when output is controlled to some extent `textoutlines(string, position)` converts the text into graphic path(s), places them starting at `position`, and applies the `action`. -```@example -using Luxor # hide -Drawing(400, 400, "../assets/figures/textoutlines.png") # hide -origin() # hide +```julia fontface("Times-Roman") fontsize(500) setline(4) @@ -235,8 +216,6 @@ textoutlines("&", O, :path, valign=:middle, halign=:center) fillpreserve() sethue("black") strokepath() -finish() # hide -nothing # hide ``` ![text outlines](../assets/figures/textoutlines.png) @@ -262,12 +241,7 @@ The `textextents(str)` function returns the dimensions of the string `str`, give The [`label`](@ref) function places text relative to a specific point, and you can use compass points or angles to indicate where it should be. So `:N` (for North) places a text label directly above the point, as does `3π/2`. -```@example -using Luxor # hide -Drawing(400, 350, "../assets/figures/labels.png") # hide -origin() # hide -background("white") # hide -sethue("black") +```julia fontsize(15) octagon = ngon(O, 100, 8, 0, vertices=true) @@ -277,9 +251,6 @@ for i in 1:8 circle(octagon[i], 5, :fill) label(string(compass[i]), compass[i], octagon[i], leader=true, leaderoffsets=[0.2, 0.9], offset=50) end - -finish() # hide -nothing # hide ``` ![labels](../assets/figures/labels.png) @@ -288,12 +259,7 @@ nothing # hide Use `textcurve(str)` to draw a string `str` on a circular arc or spiral. -```@example -using Luxor # hide -Drawing(800, 800, "../assets/figures/text-spiral.png") # hide - -origin() # hide -background("ivory") # hide +```julia sethue("royalblue4") # hide fontsize(7) fontface("Menlo") @@ -307,20 +273,13 @@ textcurve("this spiral contains every word in julia names(Base): " * textstring, fontsize(35) fontface("Avenir-Black") textcentered("julia names(Base)", 0, 0) -finish() # hide - -nothing # hide ``` ![text on a curve or spiral](../assets/figures/text-spiral.png) For shorter strings, [`textcurvecentered`](@ref) tries to place the text on a circular arc by its center point. -```@example -using Luxor # hide -Drawing(400, 250, "../assets/figures/text-centered.png") # hide -origin() # hide -background("white") # hide +```julia fontface("Arial-Black") fontsize(24) # hide sethue("black") # hide @@ -337,8 +296,6 @@ textcurvecentered("hello world", π/2, 100, O; letter_spacing = 0, baselineshift = 10 ) -finish() # hide -nothing # hide ``` ![text centered on curve](../assets/figures/text-centered.png) @@ -386,15 +343,6 @@ You can use newly-created text paths as a clipping region - here the text paths ![text clipping](../assets/figures/text-path-clipping.png) ```julia -using Luxor - -currentwidth = 1250 # pts -currentheight = 800 # pts -Drawing(currentwidth, currentheight, "/tmp/text-path-clipping.png") - -origin() -background("darkslategray3") - fontsize(600) # big fontsize to use for clipping fontface("Agenda-Black") str = "julia" # string to be clipped @@ -412,36 +360,26 @@ fontface("Monaco") fontsize(10) namelist = map(x->string(x), names(Base)) # get list of function names in Base. -let - x = -20 - y = -h - while y < currentheight - sethue(rand(7:10)/10, rand(7:10)/10, rand(7:10)/10) - s = namelist[rand(1:end)] - text(s, x, y) - se = textextents(s) - x += se[5] # move to the right - if x > w - x = -20 # next row - y += 10 - end +x = -20 +y = -h +while y < currentheight + sethue(rand(7:10)/10, rand(7:10)/10, rand(7:10)/10) + s = namelist[rand(1:end)] + text(s, x, y) + se = textextents(s) + x += se[5] # move to the right + if x > w + x = -20 # next row + y += 10 end end - -finish() -preview() ``` ## Text blocks, boxes, and wrapping Longer lines of text can be made to wrap inside an imaginary rectangle with [`textwrap`](@ref). Specify the required width of the rectangle, and the location of the top left corner. -```@example - -using Luxor # hide -Drawing(500, 400, "../assets/figures/text-wrapping.png") # hide -origin() # hide -background("white") # hide +```julia fontface("Georgia") fontsize(12) # hide sethue("black") # hide @@ -459,20 +397,13 @@ leo tristique, a condimentum tortor faucibus.""" setdash("dot") box(O, 200, 200, :stroke) textwrap(loremipsum, 200, O - (200/2, 200/2)) - -finish() # hide -nothing # hide ``` ![text wrapping](../assets/figures/text-wrapping.png) [`textwrap`](@ref) accepts a function that allows you to insert code that responds to the next line's linenumber, contents, position, and height. -```@example -using Luxor, Colors # hide -Drawing(500, 400, "../assets/figures/text-wrapping-1.png") # hide -origin() # hide -background("white") # hide +```julia fontface("Georgia") fontsize(12) # hide sethue("black") # hide @@ -492,9 +423,6 @@ textwrap(loremipsum, 200, O - (200/2, 200/2), sethue(Colors.HSB(rescale(lnumber, 1, 15, 0, 360), 1, 1)) text(string("line ", lnumber), pt - (50, 0)) end) - -finish() # hide -nothing # hide ``` ![text wrapped](../assets/figures/text-wrapping-1.png) @@ -503,12 +431,7 @@ The [`textbox`](@ref) function also draws text inside a box, but doesn't alter t This example counts the number of characters drawn, using a simple closure. The function returns the position of the start of what would have been the next line. -```@example -using Luxor, Colors # hide -Drawing(600, 300, "../assets/figures/textbox.png") # hide -origin() # hide -background("ivory") # hide -sethue("black") # hide +```julia fontface("Georgia") fontsize(30) @@ -539,9 +462,6 @@ finishpos = textbox(filter(!isempty, split(loremipsum, "\n")), fontsize(10) text(string(counter(0), " characters"), finishpos) - -finish() # hide -nothing # hide ``` ![textbox](../assets/figures/textbox.png) @@ -557,13 +477,7 @@ The tracking units depend on the current font size. In a 0.35mm, so a 1000 units of tracking for 12 point text produces about 4.2mm of space between each character. -```@example -using Luxor # hide -Drawing(600, 400, "../assets/figures/texttrack.svg") # hide -origin() # hide -background("white") # hide -sethue("black") # hide - +```julia function text_tracking_example() fonts = [ "Verdana", @@ -584,12 +498,10 @@ function text_tracking_example() texttrack("This is some text in $(f): it’s been tracked by -$(tracking)", nextgridpoint(grid), -tracking, fsize) end - - finish() # hide + finish() end text_tracking_example() -nothing # hide ``` ![textbox](../assets/figures/texttrack.svg) @@ -635,8 +547,6 @@ To animate the drawing of text, you can obtain and store the paths, and then bui ![text animation](../assets/figures/textanimation.gif) ```julia -using Luxor - function frame(scene, framenumber) background("black") sethue("gold") diff --git a/docs/src/index.md b/docs/src/index.md index 241efd00..bb7b21df 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -56,5 +56,5 @@ This documentation was built using [Documenter.jl](https://github.com/JuliaDocs) ```@example using Dates # hide -println("Documentation built $(Dates.now()) with Julia $(VERSION)") # hide +println("Documentation built $(Dates.now()) with Julia $(VERSION) on $(Sys.KERNEL)") # hide ``` diff --git a/test/polymorph-test.jl b/test/polymorph-test.jl new file mode 100644 index 00000000..8eb459ba --- /dev/null +++ b/test/polymorph-test.jl @@ -0,0 +1,32 @@ +using Luxor +using Test +using Random + +Random.seed!(42) + +function polymorph_test_1(fname) + Drawing(500, 500, fname) + background("grey20") + origin() + sethue("white") + + poly1 = [Point(70x, -200 + 20sin(x)) for x in -π:0.1:π] + poly2 = [Point(70x, 200 + 20sin(2x)) for x in -π:0.1:π] + + poly(poly1, :stroke) + poly(poly2, :stroke) + + # test that first points and last points remain the same x + for i in 0:0.02:1.0 + pm = polymorph(poly1, poly2, i, closed=false, samples=50) + poly.(pm, :stroke) + @test first(pm[1]).x ≈ poly1[1].x ≈ poly2[1].x + @test poly1[end].x ≈ poly2[end].x ≈ last(pm[1]).x + end + + @test finish() == true + + println("...finished test: output in $(fname)") +end + +polymorph_test_1("polymorph-test-1.png") diff --git a/test/runtests.jl b/test/runtests.jl index c69ec094..6f711162 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -48,6 +48,7 @@ function run_all_tests() include("convexandclockwise.jl") include("various-points-tests.jl") include("polyhull-test.jl") + include("polymorph-test.jl") end @testset "text" begin