diff --git a/docs/src/assets/luxor-docs.css b/docs/src/assets/luxor-docs.css index 58a42772..f190a4bc 100644 --- a/docs/src/assets/luxor-docs.css +++ b/docs/src/assets/luxor-docs.css @@ -1,7 +1,7 @@ @font-face { font-family: JuliaMono-Regular; src: - local('JuliaMono-Regular'), + local('JuliaMono'), url("https://cdn.jsdelivr.net/gh/cormullion/juliamono/webfonts/JuliaMono-Regular.woff2"); } diff --git a/docs/src/explanation/imagematrix.md b/docs/src/explanation/imagematrix.md index bdd1daa0..6ba8508e 100644 --- a/docs/src/explanation/imagematrix.md +++ b/docs/src/explanation/imagematrix.md @@ -2,9 +2,15 @@ # Images as matrices -While drawing, you can copy the current graphics in a drawing as a matrix of pixels, using the [`image_as_matrix`](@ref) function. +While drawing, you can copy the current graphics in a +drawing as a matrix of colored pixels, using the +[`image_as_matrix`](@ref) function. And with the +[`@imagematrix`](@ref) macro, you can create your drawing +with vector graphics in the usual way, and then return the +result as a matrix of colored pixels. -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. +The next example draws an ampersand and then processes the +pixels further in Images.jl. ``` using Luxor, Colors, Images, ImageFiltering @@ -28,13 +34,59 @@ imfilter(img, Kernel.gaussian(10)) ![image matrix](../assets/figures/ampersand-matrix.png) -[`image_as_matrix`](@ref) returns a array of ARGB32 values. Each ARGB value encodes the Red, Green, Blue, and Alpha values of a pixel into a single 32 bit integer. +[`image_as_matrix`](@ref) returns a array of ARGB32 +(AlphaRedGreenBlue) values. Each ARGB value encodes the Red, +Green, Blue, and Alpha values of a pixel into a single 32 +bit integer. -The next example draws a red rectangle, then copies the drawing into a matrix called `mat1`. Then it adds a blue triangle, and copies the updated drawing into `mat2`. In the second drawing, values from the two matrices are tested, and table cells are randomly colored depending on the corresponding values ... this is a primitive Boolean operation. +You can display the matrix using, for example, Images.jl. + +``` +using Luxor, Images + +# in Luxor + +Drawing(250, 250, :png) +origin() +background(randomhue()...) +sethue("red") +fontsize(200) +fontface("Georgia") +text("42", halign=:center, valign=:middle) +mat = image_as_matrix() +finish() + +# in Images + +img = RGB.(mat) +# img = Gray.(mat) # for greyscale + +imfilter(img, Kernel.gaussian(10)) +``` + +In Luxor: + +![42 image array](../assets/figures/42.png) + +In Images: + +![42 image array](../assets/figures/42gaussian.png) + +The next example makes two drawings. The first draws a red rectangle, then copies the +drawing in its current state into a matrix called `mat1`. Next it adds a blue +triangle, and copies the updated drawing state into `mat2`. + +In the second drawing, values from these two matrices are +tested, and table cells are randomly colored depending on +the corresponding values ... this is a primitive Boolean +operation. ```@example using Luxor, Colors, Random # hide Random.seed!(42) # hide + +# first drawing + Drawing(40, 40, :png) origin() background("black") @@ -78,36 +130,3 @@ In the second drawing, a table with 1600 squares is colored according to the val ![image drawings](../assets/figures/image-drawings.svg) (You can use `collect` to gather the re-interpreted values together.) - -You can display the matrix using, for example, Images.jl. - -``` -using Luxor, Images - -# in Luxor - -Drawing(250, 250, :png) -origin() -background(randomhue()...) -sethue("red") -fontsize(200) -fontface("Georgia") -text("42", halign=:center, valign=:middle) -mat = image_as_matrix() -finish() - -# in Images - -img = RGB.(mat) -# img = Gray.(mat) # for greyscale - -imfilter(img, Kernel.gaussian(10)) -``` - -In Luxor: - -![42 image array](../assets/figures/42.png) - -In Images: - -![42 image array](../assets/figures/42gaussian.png) diff --git a/docs/src/explanation/transforms.md b/docs/src/explanation/transforms.md index 0d4033cb..991f06e5 100644 --- a/docs/src/explanation/transforms.md +++ b/docs/src/explanation/transforms.md @@ -41,7 +41,7 @@ nothing # hide ```@example using Luxor, Colors, Random # hide -Drawing(800, 250, "../assets/figures/scale.png") # hide +Drawing(800, 300, "../assets/figures/scale.png") # hide background("antiquewhite") # hide Random.seed!(1) # hide setline(1) # hide @@ -172,7 +172,7 @@ julia> getmatrix() 0.0 ``` -[`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. +[`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 @@ -218,7 +218,7 @@ If you use [`translate`](@ref) to move the origin to different places on a drawi ```@example using Luxor, Random # hide -Drawing(600, 400, "../assets/figures/getworldposition.png") # hide +Drawing(800, 400, "../assets/figures/getworldposition.png") # hide background("antiquewhite") # hide Random.seed!(3) # hide setline(1) # hide @@ -241,14 +241,14 @@ nothing # hide ## Coordinate conventions -In Luxor, by default, the y axis points downwards, and the x axis points to the right. +In Luxor, by convention, the y axis points downwards, and the x axis points to the right. There are basically two main conventions for computer graphics: -- mathematical illustrations, such as graphs, figures, Plots.jl, plots, etc., use the "y upwards" convention - - most computer graphics systems (HTML, SVG, Processing, Cairo, Luxor, image processing, most GUIs, etc) use "y downwards" convention +- mathematical illustrations, such as graphs, figures, Plots.jl, plots, etc., which use the "y upwards" convention + ```@setup conventions using Luxor diagram = @drawsvg begin @@ -261,10 +261,13 @@ diagram = @drawsvg begin text("y", O + (20, -200)) arrow(O, O + (200, 0)) text("x", O + (200, 20)) + + text("maths: y upwards", O + (0, 100), halign=:center) end @layer begin translate(table[2]) + text("computing: y downwards", O + (0, 100), halign=:center) rulers() end @@ -272,10 +275,10 @@ end 800 450 ``` ```@example conventions -diagram +diagram # hide ``` -You could use a transformation matrix to reflect the Luxor drawing space in the x-axis. +You could use a transformation matrix to reflect the Luxor drawing space in the x axis. ```@example using Luxor # hide @@ -301,13 +304,17 @@ end 800 450 # hide !!! note - If you do this, all your text will be incorrectly drawn, so you'd need to use enclose text functions with antoher matrix transformation. + If you do this and try to place text, all your text will be incorrectly drawn upside down, so you'd need to enclose any text placement with more matrix transformations. ## Advanced transformations -For more powerful transformations, consider using Julia packages which are designed specifically for the purpose. +For more powerful transformations of graphic elements, +consider using Julia packages which are designed +specifically for the purpose. -The following example sets up some transformations, which can then be composed in the correct order to transform points. +The following example sets up some transformations which +can then be composed in the correct order to transform +points. ``` rawpts = [ diff --git a/docs/src/howto/simplegraphics.md b/docs/src/howto/simplegraphics.md index 10d91d32..212c7496 100644 --- a/docs/src/howto/simplegraphics.md +++ b/docs/src/howto/simplegraphics.md @@ -1104,35 +1104,49 @@ There's a matching [`epitrochoid`](@ref) function. ## Ticks -The [`tickline`](@ref) function lets you divide a distance between two points into ticks: short lines positioned equidistant between the two end points. +The [`tickline`](@ref) function lets you divide the space +between two points by drawing ‘ticks’, short parallel lines +positioned equidistant between the two points. -In its simplest form it can used to draw basic number lines, complete with text labels. +In its simplest form the function can used to draw basic +number lines, complete with automatic text labels. ```@example using Luxor # hide @drawsvg begin - background("antiquewhite") - tickline(Point(-350, -100), Point(350, -100)) - tickline(Point(-350, 0), Point(350, 0), - major=3, - startnumber=0, finishnumber=100) - tickline(Point(-350, 100), Point(350, 100), major=3, minor=4) +background("antiquewhite") + +# major defaults to 1 +tickline(Point(-350, -100), Point(350, -100)) + +# three major ticks inserted +tickline(Point(-350, 0), Point(350, 0), + major=3, + startnumber=0, finishnumber=100) + +# four minor ticks inserted between each major +tickline(Point(-350, 100), Point(350, 100), major=3, minor=4) + end 800 350 # hide ``` -These spaced positions (linear or logarithmic) are useful even when you switch off the text display and just return points (using `vertices=true`). - The function returns the positions of the generated ticks in two arrays of points - the locations of the major and minor ticks. +The spaced positions (linear or logarithmic) are useful even when you switch off the display of text (using `vertices=true`) and just return points. + ```@example using Luxor # hide @drawsvg begin # hide background("antiquewhite") # hide +# no axis tickline(Point(-350, -100), Point(350, -100), minor=9, axis=false) +# logarithmic majticks, minticks = tickline(Point(-350, 0), Point(350, 0), major=9, + startnumber=1, + finishnumber=10, log=true, vertices=false) @@ -1179,22 +1193,24 @@ Sometimes you just want a sequence of spaced points. ```@example using Luxor, Colors # hide -@drawsvg begin # hide -background("black") # hide -_, minticks = tickline(Point(-400, 0), Point(420, 0), - major=1, minor=25, + +_, minticks = tickline(Point(-400, 0), Point(260, 0), + major=0, minor=40, log=true, axis=false, vertices=true) +@drawsvg begin # hide +background("black") for (n, pt) in enumerate(minticks) - k = rescale(n, 0, length(minticks), 0, 1) - sethue(LCHab(40, 100, 360k)) - setline(12k) - wave = [pt + Point(50k * sin(y), (360/2π) * y) for y in -2π:π/12:2π] + k = rescale(n, 1, length(minticks), 0, 1) + sethue(LCHab(60, 100, 360k)) + setline(1/k) + wave = [pt + Point(120k * sin(y), 600/2π * y) for y in -π:π/20:π] poly(wave, :stroke) end -end 800 700 # hide + +end 800 600 # hide ``` ## Cropmarks diff --git a/src/arrows.jl b/src/arrows.jl index f690114d..f6918852 100644 --- a/src/arrows.jl +++ b/src/arrows.jl @@ -706,9 +706,9 @@ function tickline(startpos, finishpos; # 1 major/minor division means 3 ticks (beginning, middle, end) if log == true - majorticklocations = between.(O, newfinishpos, rescale.(exp10.(range(0, 1, length=(major+2))), 1, 10, 0, 1)) + majorticklocations = between.(O, newfinishpos, log10.(range(1, 10, length=(major+2)))) n_minorticks = ((major + 1) * (minor + 1)) + 1 - minorticklocations = between.(O, newfinishpos, rescale.(exp10.(range(0, 1, length=n_minorticks)), 1, 10, 0, 1)) + minorticklocations = between.(O, newfinishpos, log10.(range(1, 10, length=n_minorticks))) else majorticklocations = between.(O, newfinishpos, range(0, 1, length=(major+2))) n_minorticks = ((major + 1) * (minor + 1)) + 1