Skip to content

Commit

Permalink
getcells
Browse files Browse the repository at this point in the history
  • Loading branch information
cormullion committed Oct 5, 2023
1 parent 0cd67eb commit 2bc9e93
Show file tree
Hide file tree
Showing 8 changed files with 328 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ See https://github.com/JuliaGraphics/Cairo.jl/pull/357.

### Added

- `markcells()` and `getcells()`

### Changed

- fixes for `drawpath(p, f)` to do the Bezier curve truncation better
Expand Down
8 changes: 4 additions & 4 deletions docs/src/howto/images.md
Original file line number Diff line number Diff line change
Expand Up @@ -454,14 +454,14 @@ fontsize(15)
sethue("white")
setline(1)
transform([0 1 1 0 0 0])
cells = Table(10, 10, 512 / 10, 512 / 10, Point(512 / 2, 512 / 2))
for (pos, n) in cells
t = Table(10, 10, 512 / 10, 512 / 10, Point(512 / 2, 512 / 2))
for (pos, n) in t
text(string(n), pos, halign = :center, valign = :middle)
box(pos, 512 / 10, 512 / 10, :stroke)
end
setline(5)
highlightcells(cells, collect(1:100)[[2, 4, 35, 69]], :stroke,
color = colorant"blue")
sethue("blue")
markcells(t, getcells(t, [2, 4, 35, 69]))
M
```

Expand Down
28 changes: 28 additions & 0 deletions docs/src/howto/tables-grids.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,34 @@ nothing # hide

![array table](../assets/figures/arraytable.svg)

## Selecting and highlighting cells

With `getcells()` and `markcells()` you can mark particular cells of Tables and Tilers. By default the `markcells()` function draws a box around each cell. You can choose the `:fill` action, or supply a four-argument function that adds graphics relevant to the cell's position, width, height, and number.

```@example
using Luxor # hide
@drawsvg begin
background("antiquewhite")
t = Tiler(600, 300, 12, 12)
sethue("purple")
markcells(t, getcells(t, [1, 6:12, 24, 24:6:96, 144]))
sethue("red")
setopacity(0.5)
markcells(t, getcells(t, 10:80), action=:fill)
setcolor("black")
fontsize(12)
markcells(t, getcells(t, 1:144), func = (pt, w, h, n) -> begin
sethue("white")
circle(pt, h/2, :fill)
sethue("black")
text(string(n), pt, halign=:center, valign=:middle)
end)
end 600 300
```

## Grids

You might also find a use for a grid. Luxor provides a simple grid utility. Grids are lazy: they'll supply the next point on the grid when you ask for it.
Expand Down
4 changes: 2 additions & 2 deletions src/Luxor.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ include("basics.jl")
include("Turtle.jl")
include("shapes.jl")
include("BoundingBox.jl")
include("Table.jl")
include("polygons.jl")
include("triangles.jl")
include("hexagons.jl")
Expand All @@ -65,7 +66,6 @@ include("animate.jl")
include("bars.jl")
include("bezierpath.jl")
include("mesh.jl")
include("Table.jl")
include("Boxmaptile.jl")
include("noise.jl")
include("deprecations.jl")
Expand Down Expand Up @@ -137,7 +137,7 @@ export Drawing,
translationmatrix, cairotojuliamatrix,
juliatocairomatrix, getrotation, getscale,
gettranslation, setmode, getmode, GridHex, GridRect, nextgridpoint, Table,
highlightcells, readpng, readsvg, placeimage, placeeps,
highlightcells, getcells, markcells, readpng, readsvg, placeimage, placeeps,
svgstring, julialogo, juliacircles, barchart, mesh, setmesh, add_mesh_patch, mask,

# animation
Expand Down
13 changes: 1 addition & 12 deletions src/Table.jl
Original file line number Diff line number Diff line change
Expand Up @@ -282,18 +282,7 @@ end

box(t::Table, cellnumber::Int; action = :none, vertices = false) = box(t, cellnumber, action, vertices = vertices)

"""
highlightcells(t::Table, cellnumbers, action::Symbol=:stroke;
color::Colorant=colorant"red",
offset = 0)
Highlight (draw or fill) one or more cells of table `t`. `cellnumbers` is a range,
array, or an array of row/column tuples.
highlightcells(t, 1:10, :fill, color=colorant"blue")
highlightcells(t, vcat(1:5, 150), :stroke, color=colorant"magenta")
highlightcells(t, [(4, 5), (3, 6)])
"""
# superseded, will be deprecated
function highlightcells(t::Table, cellnumbers, action::Symbol = :stroke;
color::Colorant = colorant"red",
offset = 0)
Expand Down
164 changes: 164 additions & 0 deletions src/tiles-grids.jl
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ function Base.getindex(pt::Tiler, i::Int)
return (Point(xcoord, ycoord), i)
end

function Base.getindex(t::Tiler, r::Int, c::Int)
n = ((r - 1) * t.ncols) + c
return first(t[n])
end

function Base.size(pt::Tiler)
return (pt.nrows, pt.ncols)
end
Expand Down Expand Up @@ -387,3 +392,162 @@ Return the Bounding Box enclosing the tile at row `r` column `c`.
function BoundingBox(t::Tiler, r, c)
return BoundingBox(t, ((r - 1) * t.ncols) + c)
end

"""
markcells(t::Union{Tiler, Table}, cells;
action = :stroke,
func = nothing)
Mark the cells of Tiler/Table `t` in the `cells`.
By default a box is drawn around the cell using the current settings and filled or stroked according to `action`.
You can supply a function for the `func` keyword that can do anything you want. The function should accept four arguments, `position`, `width`, `height`, and `number`.
## Example
This code draws 30 circles in 5 rows and 6 columns, numbered and
colored sequentially in four colors. `getcells()` obtains a selection of the cells from the Tiler.
```julia
@draw begin
fontsize(30)
#t = Table(5, 6, 60, 60)
t = Tiler(400, 400, 5, 6)
markcells(t, getcells(t, 1:30),
func = (pos, w, h, n) -> begin
sethue(["red", "green", "blue", "purple"][mod1(n, end)])
circle(pos, w / 2, :fill)
sethue("white")
text(string(n), pos, halign = :center, valign = :middle)
end)
end
```
"""
function markcells(t::Union{Tiler,Table}, cells;
action = :stroke,
func = nothing)
@layer begin
for cell in cells
pos, n = cell
row, col = (1 + div(n - 1, t.ncols)), mod1(n, t.ncols)
if t isa Table
w = t.colwidths[col]
h = t.rowheights[row]
else
w = t.tilewidth
h = t.tileheight
end
if isnothing(func)
# just draw a box with current settings
box(pos, w, h, action)
else
func(pos, w, h, n)
end
end
end
end

"""
getcells(t, rows, columns)
Get the Tiler or Table cells in `t` corresponding to `rows` and `columns`.
- `t` is a Tiler or Table
- `rows` is an array or range of row numbers
- `cols` is an array or range of column numbers
Use `:` for "all rows" or "all columns".
Returns an array of Tuples, where each Tuple is `(Point, Number)`.
`markcells()` can use the result of this function to mark selected cells.
## Example
```julia
@draw begin
chessboard = Tiler(600, 600, 8, 8)
# odd rows odd columns
s = getcells(chessboard, 1:2:12, 1:2:12)
markcells(chessboard, s, action = :fill)
# even rows even columns
s = getcells(chessboard, 2:2:12, 2:2:12)
markcells(chessboard, s, action = :fill)
end
```
"""
function getcells(t::Union{Table,Tiler}, rows, columns)
result = Tuple[]
for r in rows
r < 1 && continue
r > t.nrows && continue
for c in columns
c < 1 && continue
c > t.ncols && continue
n = ((r - 1) * t.ncols) + c
push!(result, (t[r, c], n))
end
end
return result
end

getcells(t::Table, ::Colon, ::Colon) = getcells(t, 1:(t.nrows), 1:(t.ncols))
getcells(t::Table, ::Colon, columns) = getcells(t, 1:(t.nrows), columns)
getcells(t::Table, rows, ::Colon) = getcells(t, rows, 1:(t.ncols))

getcells(t::Tiler, ::Colon, ::Colon) = getcells(t, 1:(t.nrows), 1:(t.ncols))
getcells(t::Tiler, ::Colon, columns) = getcells(t, 1:(t.nrows), columns)
getcells(t::Tiler, rows, ::Colon) = getcells(t, rows, 1:(t.ncols))

"""
getcells(t, n::T) where T <: AbstractRange
Get the Tiler/Table cells with numbers in range `n`.
Returns an array of Tuples, where each Tuple is `(Point, Number)`.
"""
function getcells(t, n::T) where {T<:AbstractRange}
result = Tuple[]
for i in n
append!(result, getcells(t, i))
end
return result
end

"""
getcells(t, a::T) where T <: AbstractArray
Get the Tiler/Table cells with numbers in array `a`.
Returns an array of Tuples, where each Tuple is `(Point, Number)`.
"""
function getcells(t, a::T) where {T<:AbstractArray}
result = Tuple[]
for i in a
append!(result, getcells(t, i))
end
return result
end

"""
getcells(t, n::Int)
Get the cell `n` in Tiler or Table `t`.
Returns an array of Tuples, where each Tuple is `(Point, Number)`.
!!! note
Luxor Tables and Tilers are numbered by row then column, rather than the usual Julia column-major numbering:
```
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
```
"""
getcells(t::Table, n::Int) = [(t[n], n)] # array of tuples
getcells(t::Tiler, n::Int) = [(t[n])] # array of tuples
Loading

0 comments on commit 2bc9e93

Please sign in to comment.