Skip to content

Commit

Permalink
support ternary collision detection
Browse files Browse the repository at this point in the history
  • Loading branch information
guo-yong-zhi committed Apr 4, 2023
1 parent c2f4141 commit 4fd41da
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 11 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Stuffing
[![CI](https://github.com/guo-yong-zhi/Stuffing.jl/actions/workflows/ci.yml/badge.svg)](https://github.com/guo-yong-zhi/Stuffing.jl/actions/workflows/ci.yml) [![CI-nightly](https://github.com/guo-yong-zhi/Stuffing.jl/actions/workflows/ci-nightly.yml/badge.svg)](https://github.com/guo-yong-zhi/Stuffing.jl/actions/workflows/ci-nightly.yml) [![codecov](https://codecov.io/gh/guo-yong-zhi/Stuffing.jl/branch/main/graph/badge.svg?token=43TOrL25V7)](https://codecov.io/gh/guo-yong-zhi/Stuffing.jl) [![DOI](https://zenodo.org/badge/349631351.svg)](https://zenodo.org/badge/latestdoi/349631351)
This's an algorithm for solving **2D irregular nesting problems** (also known as cutting problems or packing problems).
The algorithm accepts arbitrary **binary raster masks** as inputs and is good at handling the nesting problems of many gadgets. The implementation is based on quadtree & gradient optimization. Also, it can be parallelized if you start `julia` with `julia --threads k`. This package is used by [WordCloud.jl](https://github.com/guo-yong-zhi/WordCloud.jl).
The algorithm accepts arbitrary **binary or ternary raster masks** as inputs and is good at handling the nesting problems of many gadgets. The implementation is based on quadtree & gradient optimization. Also, it can be parallelized if you start `julia` with `julia --threads k`. This package is used by [WordCloud.jl](https://github.com/guo-yong-zhi/WordCloud.jl).
Examples: [collision detection](./examples/collision.jl), [dynamic collision detection](./examples/dynamiccollisions.jl), [packing](./examples/packing.jl)
Benchmark: [collision benchmark](./examples/collision_benchmark.jl), [fit benchmark](https://github.com/guo-yong-zhi/WordCloud/blob/master/examples/benchmark.jl)
***
Expand Down
14 changes: 10 additions & 4 deletions src/Stuffing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,20 @@ include("utils.jl")

@info "Threads.nthreads() = $(Threads.nthreads())"

function qtree(pic::AbstractMatrix{UInt8}, args...)
qt = ShiftedQTree(pic, args..., default=QTrees.EMPTY) |> buildqtree!
return qt
end
function qtree(pic::AbstractArray{Bool,2}, args...)
pic = map(x -> ifelse(x, QTrees.FULL, QTrees.EMPTY), pic)
qt = ShiftedQTree(pic, args..., default=QTrees.EMPTY) |> buildqtree!
# @show size(pic),m,s
return qt
return qtree(pic, args...)
end
function qtree(pic::AbstractMatrix, args...; background=pic[1])
qtree(pic .!= background, args...)
end

function maskqtree(pic::AbstractArray{Bool,2})
pic = map(x -> ifelse(x, QTrees.EMPTY, QTrees.FULL), pic)
function maskqtree(pic::AbstractMatrix{UInt8})
ms = max(size(pic)...)
b = max(ms * 0.024, 20)
s = 2^ceil(Int, log2(ms + b))
Expand All @@ -35,6 +37,10 @@ function maskqtree(pic::AbstractArray{Bool,2})
setcshift!(qt[1], (s - b) ÷ 2)
return qt |> buildqtree!
end
function maskqtree(pic::AbstractArray{Bool,2})
pic = map(x -> ifelse(x, QTrees.EMPTY, QTrees.FULL), pic)
return maskqtree(pic)
end
function maskqtree(pic::AbstractMatrix; background=pic[1])
maskqtree(pic .!= background)
end
Expand Down
16 changes: 10 additions & 6 deletions src/qtree_functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ function collision_dfs(Q1::AbstractStackedQTree, Q2::AbstractStackedQTree, i=(le
return i
end
r = -i[1], i[2], i[3]
for cn in 1:4 # MIX
ci = child(i, cn)
r = collision_dfs(Q1, Q2, ci)
if r[1] > 0 return r end
if i[1] > 1
for cn in 1:4 # MIX
ci = child(i, cn)
r = collision_dfs(Q1, Q2, ci)
if r[1] > 0 return r end
end
end
return r # no collision
end
Expand All @@ -36,7 +38,9 @@ function _collision_randbfs(Q1::AbstractStackedQTree, Q2::AbstractStackedQTree,
if q1 == EMPTY
continue
elseif q1 == MIX
push!(q, ci)
if ci[1] > 1
push!(q, ci)
end
continue
else
return ci
Expand Down Expand Up @@ -430,7 +434,7 @@ function overlap(p1::UInt8, p2::UInt8)
elseif p1 == EMPTY && p2 == EMPTY
return EMPTY
else
error("roung code")
return MIX
end
end

Expand Down
12 changes: 12 additions & 0 deletions test/test_qtrees.jl
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,16 @@ testqtree = Stuffing.testqtree
@test QTrees.totalcollisions_native([qt1, qt2]) |> isempty
@test QTrees.totalcollisions_spacial([qt1, qt2]) |> isempty
@test QTrees.partialcollisions([qt1, qt2]) |> isempty
# ternary tree
qt1 = qtree(fill(0x03, 5, 6))
qt2 = qtree(fill(0x03, 5, 6))
qt3 = qtree(fill(0x02, 5, 6))
qt4 = qtree(fill(0x01, 5, 6))
@test QTrees.collision(qt1, qt2)[1] < 0
@test QTrees.collision(qt1, qt3)[1] > 0
@test QTrees.collision(qt1, qt4)[1] < 0
@test QTrees.collision_dfs(qt1, qt2)[1] < 0
@test QTrees.collision_dfs(qt1, qt3)[1] > 0
@test QTrees.collision_dfs(qt1, qt4)[1] < 0
@test QTrees.totalcollisions_spacial([qt1, qt2]) |> isempty
end

2 comments on commit 4fd41da

@guo-yong-zhi
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator register()

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/80994

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.8.5 -m "<description of version>" 4fd41dab806a76f33ddc82d4937ee57d541d10c2
git push origin v0.8.5

Please sign in to comment.