Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/.vscode/
/Manifest.toml
.DS_Store
_local/
66 changes: 19 additions & 47 deletions project/vizgadget.jl
Original file line number Diff line number Diff line change
@@ -1,38 +1,16 @@
using UnitDiskMapping, Graphs
using UnitDiskMapping.TikzGraph, Graphs
using UnitDiskMapping: crossing_ruleset, Pattern, source_graph, mapped_graph

function command_graph(locs, graph, pins, dx, dy, r, name)
cmd = ""
function command_graph!(canvas, locs, graph, pins, dx, dy, r, name)
for (i,loc) in enumerate(locs)
if count(==(loc), locs) == 2
type = 2
else
type = 1
Node(loc[1]+dx, loc[2]+dy, fill="none", id="ext-$name$i", minimum_size="$(1.5*r)cm") >> canvas
end
cmd *= command_node(loc[1]+dx, loc[2]+dy, type, i ∈ pins, "$name$i", r) * "\n"
Node(loc[1]+dx, loc[2]+dy, fill=i∈pins ? "red" : "black", draw="none", id="$name$i", minimum_size="$(r)cm") >> canvas
end
for e in edges(graph)
cmd *= command_edge("$name$(e.src)", "$name$(e.dst)") * "\n"
Line("$name$(e.src)", "$name$(e.dst)"; line_width=1.0) >> canvas
end
return cmd
end

function command_node(x, y, type::Int, ispin::Bool, id, r)
if type == 2
return "\\node[fill=black,circle,radius=$(r)cm,inner sep=0cm, minimum size=$(r)cm] at ($x, $y) () {};\n\\node[draw=black,fill=none,circle,radius=$(1.5*r)cm,minimum size=$(1.5*r)cm,inner sep=0cm] at ($x, $y) ($id) {};"
elseif abs(type) == 1
if ispin
color = "red"
else
color = "black"
end
return "\\node[fill=$color,circle,radius=$(r)cm,inner sep=0cm, minimum size=$(r)cm] at ($x, $y) ($id) {};"
else
error("")
end
end

function command_edge(i, j)
return "\\draw[thick] ($i) -- ($j);"
end

function viz_gadget(p::Pattern)
Expand All @@ -45,28 +23,22 @@ function viz_gadget(p::Pattern)
xmid, ymid = Wx/2-0.5, Wy/2-0.5
dx1, dy1 = xmid-Gx, 0
dx2, dy2 = xmid+1, 0
source_nodes = command_graph(locs1, g1, pin1, dx1, dy1, 0.3, "s")
mapped_nodes = command_graph(locs2, g2, pin2, dx2, dy2, 0.3, "d")
return """
\\documentclass[crop,tikz]{standalone}% 'crop' is the default for v1.0, before it was 'preview'
\\begin{document}
\\begin{tikzpicture}[scale=0.8]
\\useasboundingbox (-1,-1) rectangle ($Wx,$Wy);
\\draw[step=1cm,gray,very thin] ($dx1,$(dy1)) grid ($(Gx+dx1-1),$(Gy+dy1-1));
$source_nodes
\\draw[step=1cm,gray,very thin] ($dx2,$(dy2)) grid ($(Gx+dx2-1),$(Gy+dy2-1));
$mapped_nodes
\\node at ($xmid, $ymid) {\$\\mathbf{\\rightarrow}\$};
\\end{tikzpicture}

\\end{document}
"""
return canvas(; props=Dict("scale"=>"0.8")) do c
BoundingBox(-1,Wx-1,-1,Wy-1) >> c
Mesh(dx1, Gx+dx1-1, dy1, Gy+dy1-1; step="1cm", draw=rgbcolor!(c, 100,200,200), line_width=0.5) >> c
command_graph!(c, locs1, g1, pin1, dx1, dy1, 0.3, "s")
Mesh(dx2, Gx+dx2-1, dy2, Gy+dy2-1; step="1cm", draw=rgbcolor!(c, 200,100,100), line_width=0.03) >> c
command_graph!(c, locs2, g2, pin2, dx2, dy2, 0.3, "d")
PlainText(xmid, ymid, "\$\\mathbf{\\rightarrow}\$") >> c
end
end

function pattern2tikz(folder::String)
for (p, sub) in UnitDiskMapping.crossing_ruleset
open(joinpath(folder, sub*"-udg.tex"), "w") do f
for p in crossing_ruleset
open(joinpath(folder, string(typeof(p).name.name)*"-udg.tex"), "w") do f
write(f, viz_gadget(p))
end
end
end
end

pattern2tikz(joinpath("_local"))
2 changes: 1 addition & 1 deletion src/UnitDiskMapping.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ include("weighted.jl")
include("simplifiers.jl")
include("extracting_results.jl")
include("pathdecomposition/pathdecomposition.jl")
#include("shrinking/compressUDG.jl")
include("tikz/tikz.jl")

end
18 changes: 9 additions & 9 deletions src/gadgets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,20 @@ abstract type Pattern end
"""
abstract type CrossPattern <: Pattern end

abstract type Node end
struct SimpleNode{T} <: Node
abstract type AbstractNode end
struct SimpleNode{T} <: AbstractNode
x::T
y::T
end
SimpleNode(xy::Tuple{Int,Int}) = SimpleNode(xy...)
SimpleNode(xy::Vector{Int}) = SimpleNode(xy...)
getxy(p::SimpleNode) = (p.x, p.y)
chxy(p::SimpleNode, loc) = SimpleNode(loc...)
Base.iterate(p::Node, i) = Base.iterate((p.x, p.y), i)
Base.iterate(p::Node) = Base.iterate((p.x, p.y))
Base.length(p::Node) = 2
Base.getindex(p::Node, i::Int) = i==1 ? p.x : (@assert i==2; p.y)
offset(p::Node, xy) = chxy(p, getxy(p) .+ xy)
Base.iterate(p::AbstractNode, i) = Base.iterate((p.x, p.y), i)
Base.iterate(p::AbstractNode) = Base.iterate((p.x, p.y))
Base.length(p::AbstractNode) = 2
Base.getindex(p::AbstractNode, i::Int) = i==1 ? p.x : (@assert i==2; p.y)
offset(p::AbstractNode, xy) = chxy(p, getxy(p) .+ xy)

export source_matrix, mapped_matrix
function source_matrix(p::Pattern)
Expand All @@ -53,7 +53,7 @@ function mapped_matrix(p::Pattern)
locs2matrix(m, n, locs)
end

function locs2matrix(m, n, locs::AbstractVector{NT}) where NT <: Node
function locs2matrix(m, n, locs::AbstractVector{NT}) where NT <: AbstractNode
a = fill(empty(_cell_type(NT)), m, n)
for loc in locs
add_cell!(a, loc)
Expand Down Expand Up @@ -387,7 +387,7 @@ for T in [:RotatedGadget, :ReflectedGadget]
end

for T in [:RotatedGadget, :ReflectedGadget]
@eval _apply_transform(r::$T, node::Node, center) = chxy(node, _apply_transform(r, getxy(node), center))
@eval _apply_transform(r::$T, node::AbstractNode, center) = chxy(node, _apply_transform(r, getxy(node), center))
end
function _apply_transform(r::RotatedGadget, loc::Tuple{Int,Int}, center)
for _=1:r.n
Expand Down
2 changes: 1 addition & 1 deletion src/simplifiers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function vertices_on_boundary(locs, m, n)
findall(loc->loc[1]==1 || loc[1]==m || loc[2]==1 || loc[2]==n, locs)
end

struct GridGraph{NT<:Node}
struct GridGraph{NT<:AbstractNode}
size::Tuple{Int,Int}
nodes::Vector{NT}
end
Expand Down
154 changes: 154 additions & 0 deletions src/tikz/tikz.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
module TikzGraph
export rgbcolor!, Node, Line, BoundingBox, Mesh, Canvas, >>, command, canvas, generate_standalone, StringElement, PlainText

const instance_counter = Ref(0)
abstract type AbstractTikzElement end

struct Canvas
header::String
colors::Dict{String, Tuple{Int,Int,Int}}
contents::Vector{AbstractTikzElement}
props::Dict{String,String}
end

function canvas(f; header="", colors=Dict{String,Tuple{Int,Int,Int}}(), props=Dict{String,String}())
canvas = Canvas(header, colors, AbstractTikzElement[], props)
f(canvas)
return canvas
end

Base.:(>>)(element::AbstractTikzElement, canvas::Canvas) = push!(canvas.contents, element)
Base.:(>>)(element::String, canvas::Canvas) = push!(canvas.contents, StringElement(element))

function rgbcolor!(canvas::Canvas, red::Int, green::Int, blue::Int)
instance_counter[] += 1
colorname = "color$(instance_counter[])"
canvas.colors[colorname] = (red,green,blue)
return colorname
end
function generate_rgbcolor(name, red, green, blue)
return "\\definecolor{$name}{RGB}{$red,$green,$blue}"
end

struct StringElement <: AbstractTikzElement
str::String
end
command(s::StringElement) = s.str

struct BoundingBox <: AbstractTikzElement
xmin::Float64
xmax::Float64
ymin::Float64
ymax::Float64
end
function command(box::BoundingBox)
return "\\useasboundingbox ($(box.xmin),$(box.ymin)) rectangle ($(box.xmax-box.xmin),$(box.ymax-box.ymin));"
end

struct Node <: AbstractTikzElement
x::Float64
y::Float64
shape::String
id::String
text::String
props::Dict{String,String}
end

function Node(x, y;
shape::String = "circle",
id = string((instance_counter[] += 1; instance_counter[])),
text::String = "",
fill = "none",
draw = "black",
inner_sep = "0cm",
minimum_size = "0.2cm",
line_width = 0.03,
kwargs...)
props = build_props(;
fill = fill,
draw = draw,
inner_sep = inner_sep,
minimum_size = minimum_size,
line_width = line_width,
kwargs...)
return Node(x, y, shape, id, text, props)
end
function build_props(; kwargs...)
Dict([replace(string(k), "_"=>" ")=>string(v) for (k,v) in kwargs])
end

function command(node::Node)
return "\\node[$(node.shape), $(command(node.props))] at ($(node.x), $(node.y)) ($(node.id)) {$(node.text)};"
end

struct Mesh <: AbstractTikzElement
xmin::Float64
xmax::Float64
ymin::Float64
ymax::Float64
props::Dict{String,String}
end

function Mesh(xmin, xmax, ymin, ymax; step="1.0cm", draw="gray", line_width=0.03, kwargs...)
Mesh(xmin, xmax, ymin, ymax, build_props(; step=step, draw=draw, line_width=line_width, kwargs...))
end
function command(grid::Mesh)
return "\\draw[$(command(grid.props))] ($(grid.xmin),$(grid.ymin)) grid ($(grid.xmax),$(grid.ymax));"
end

struct Line <: AbstractTikzElement
src::String
dst::String
controls::Vector{Int}
props::Dict{String,String}
end

function Line(src, dst; controls=Int[], line_width = "0.03", kwargs...)
Line(string(src), string(dst), controls, build_props(; line_width=line_width, kwargs...))
end
Line(src::Node, dst::Node; kwargs...) = Line(src.id, dst.id)

function command(edge::Line)
head = "\\draw[$(command(edge.props))]"
if isempty(edge.controls)
return "$head ($(edge.src)) -- ($(edge.dst));"
else
return "$head ($(edge.src)) .. controls $(join(["($c)" for c in edge.controls], " and ")) .. ($(edge.dst));"
end
end

struct PlainText <: AbstractTikzElement
x::Float64
y::Float64
text::String
props::Dict{String,String}
end
function PlainText(x, y, text; kwargs...)
PlainText(x, y, text, build_props(; kwargs...))
end
function command(text::PlainText)
"\\node[$(command(text.props))] at ($(text.x), $(text.y)) {$(text.text)};"
end

function command(node::Dict) # properties
return join(["$k=$v" for (k,v) in node], ", ")
end

function generate_standalone(header::String, props::Dict, content::String)
return """
\\documentclass[crop,tikz]{standalone}
$(header)
\\begin{document}
\\begin{tikzpicture}[$(command(props))]
$content
\\end{tikzpicture}
\\end{document}
"""
end
generate_standalone(canvas::Canvas) = generate_standalone(canvas.header, canvas.props, join([[generate_rgbcolor(k,v...) for (k,v) in canvas.colors]..., command.(canvas.contents)...], "\n"))

function Base.write(io::IO, canvas::Canvas)
write(io, generate_standalone(canvas))
end

end
2 changes: 1 addition & 1 deletion src/weighted.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function Base.show(io::IO, x::WeightedCell)
end
Base.show(io::IO, ::MIME"text/plain", cl::WeightedCell) = Base.show(io, cl)

struct WeightedNode{T,WT} <: Node
struct WeightedNode{T,WT} <: AbstractNode
x::T
y::T
weight::WT
Expand Down
4 changes: 4 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,7 @@ end
@testset "weighted" begin
include("weighted.jl")
end

@testset "tikz" begin
include("tikz/tikz.jl")
end
30 changes: 30 additions & 0 deletions test/tikz/tikz.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using UnitDiskMapping.TikzGraph, Test

@testset "commands" begin
n = Node(0.2, 0.5)
@test command(n) isa String
m = Node(0.6, 0.5)
@test command(n) isa String
l = Line(m, n)
@test command(n) isa String
b = BoundingBox(0, 10, 0, 10)
@test command(b) isa String
g = Mesh(0, 10, 0, 10)
@test command(g) isa String
s = StringElement("jajaja")
@test command(s) == "jajaja"
s = PlainText(20.0, 3.0, "jajaja")
@test command(s) isa String
end

@testset "canvas" begin
res = canvas() do c
Node(0.2, 0.5; draw=rgbcolor!(c, 21, 42, 36)) >> c
"jajaja" >> c
end
@test res isa Canvas
@test generate_standalone(res) isa String
write("test.tex", res)
@test isfile("test.tex")
rm("test.tex")
end