An Example
Suppose we want to make an open-topped box whose outside dimensions are 12 inches long, 6 inches wide and 4 inches deep out of 1/4 inch plywood.
using PanelCutting
using Unitful
using UnitfulUS
box_length = 12u"inch"
box_width = 6u"inch"
box_depth = 4u"inch"
stock_thickness = (1/4)u"inch"
0.25 inch
What Do We Want?
To use PanelCutting
we must first describe the target dimensions of sheet stock after it is cut. For each panel we must make a WantedPanel
.
Note that these dimensions don't account for any joinery. For this simple example all panels are butt jointed, with the sides and ends sitting on top of the bottom and the ends inset between the sides.
Also note that we do not yet include the thickness of stock when selecting material to cut. so far my projects have been simple enough that I've only needed one thickness of stock. In the furure we should also model stock thickness and material type.
WANTED = [
WantedPanel(
label = "bottom",
# the bottom will occupy the full footprint of the box with
# the sides and ends sitting on top of it
length = box_length,
width = box_width,
material = "Baltic Birch",
thickness = (1/4)u"inch"),
# Sometimes we need several instances of the same shaped panel.
# WantedPanel can take a pre-multiplier:
(2 * WantedPanel(
label = "side",
length = box_length - 2 * stock_thickness,
width = box_depth - stock_thickness,
material = "Baltic Birch",
thickness = (1/4)u"inch")
)..., # Pre-multiplying gives a Vector, which we must spread.
(2 * WantedPanel(
label = "end",
length = box_width - 2 * stock_thickness,
width = box_depth - stock_thickness,
material = "Baltic Birch",
thickness = (1/4)u"inch")
)...
]
5-element Vector{WantedPanel}:
WantedPanel(225028, 12 inch, 6 inch, 0.25 inch, "Baltic Birch", "bottom")
WantedPanel(225030, 11.5 inch, 3.75 inch, 0.25 inch, "Baltic Birch", "side 1/2")
WantedPanel(225031, 11.5 inch, 3.75 inch, 0.25 inch, "Baltic Birch", "side 2/2")
WantedPanel(225033, 5.5 inch, 3.75 inch, 0.25 inch, "Baltic Birch", "end 1/2")
WantedPanel(225034, 5.5 inch, 3.75 inch, 0.25 inch, "Baltic Birch", "end 2/2")
If you don't care about grain direction you can include a flipped version of a WantedPanel
:
orFlipped(WantedPanel(
label = "bottom",
length = box_length,
width = box_width,
material = "Baltic Birch",
thickness = (1/4)u"inch",))
2-element Vector{AbstractWantedPanel}:
WantedPanel(225035, 12 inch, 6 inch, 0.25 inch, "Baltic Birch", "bottom")
FlippedPanel(225036, WantedPanel(225035, 12 inch, 6 inch, 0.25 inch, "Baltic Birch", "bottom"))
but we will not include these in our example.
What Are We Starting With?
We must describe what sheet stock is available to cut from. We do this with AvailablePanel
. Each size of AvailablePanel
only needs to be instantiated once. It is assumed that the supply of AvailablePanel
s is unlimited for our purposes. These sizes and prices are taken from my local plywood supplier. My supplier will accurately cut down stock to specified dimensions at a reasonable price, so we also note the cost per cut and the kerf width:
BOULTER_PLYWOOD = Supplier(
name = "Boulter Plywood",
kerf = (1/8)u"inch",
cost_per_cut = money(1.50),
available_stock = [
AvailablePanel(;
label = "1/4 5 × 5 Baltic Birch",
material = "Baltic Birch",
thickness = (1/4)u"inch",
length = 5u"ft",
width = 5u"ft",
cost = 84.00 # I've not been able to get UnitfulCurrency to work
),
AvailablePanel(;
label = "1/4 30 × 60 Baltic Birch",
material = "Baltic Birch",
thickness = (1/4)u"inch",
length = 60u"inch",
width = 30u"inch",
cost = 51.00
),
AvailablePanel(;
label = "1/4 30 × 30 Baltic Birch",
material = "Baltic Birch",
thickness = (1/4)u"inch",
length = 30u"inch",
width = 30u"inch",
cost = 36.00)
])
Supplier("Boulter Plywood", 1.5, 0.125 inch, AvailablePanel[AvailablePanel(225037, "1/4 5 × 5 Baltic Birch", 5 ft, 5 ft, 0.25 inch, "Baltic Birch", 84.0), AvailablePanel(225038, "1/4 30 × 60 Baltic Birch", 30 inch, 60 inch, 0.25 inch, "Baltic Birch", 51.0), AvailablePanel(225039, "1/4 30 × 30 Baltic Birch", 30 inch, 30 inch, 0.25 inch, "Baltic Birch", 36.0)])
What To Buy And Where To Cut?
Now that we have described what we want and what we're starting with, we can search for an optimal cut pattern.
# The cut optimization is performed by a Searcher:
searcher = Searcher(BOULTER_PLYWOOD, WANTED)
search(searcher)
The most efficient cut pattern (least expensive in terms of stock used and number of cuts) is in searcher.cheapest
. The resulting panels there are represented by FinishedPanel
s which have tracked how they were cut:
searcher.cheapest.finished
(FinishedPanel(225158, WantedPanel(225033, 5.5 inch, 3.75 inch, 0.25 inch, "Baltic Birch", "end 1/2"), Panel(225156, 5.5 inch, 3.75 inch, Panel(225099, 5.5 inch, 18.375 inch, Panel(225096, 5.5 inch, 22.25 inch, Panel(225082, 11.5 inch, 22.25 inch, Panel(225056, 11.5 inch, 26.125 inch, Panel(225053, 11.5 inch, 30.0 inch, Panel(225044, 17.875 inch, 30.0 inch, BoughtPanel(225042, AvailablePanel(225039, "1/4 30 × 30 Baltic Birch", 30 inch, 30 inch, 0.25 inch, "Baltic Birch", 36.0)), 12.0 inch, LengthAxis(), 12.125 inch, 0.0 inch, 22.43723849372385), 11.5 inch, LengthAxis(), 12.125 inch, 0.0 inch, 15.50863339029996), 3.75 inch, WidthAxis(), 12.125 inch, 3.875 inch, 14.873658487751847), 3.75 inch, WidthAxis(), 12.125 inch, 7.75 inch, 14.012073128941482), 5.5 inch, LengthAxis(), 12.125 inch, 7.75 inch, 7.500343051356321), 3.75 inch, WidthAxis(), 12.125 inch, 11.625 inch, 7.474861178245081), 3.75 inch, WidthAxis(), 12.125 inch, 11.625 inch, 1.8441495571736468)), FinishedPanel(225100, WantedPanel(225034, 5.5 inch, 3.75 inch, 0.25 inch, "Baltic Birch", "end 2/2"), Panel(225098, 5.5 inch, 3.75 inch, Panel(225096, 5.5 inch, 22.25 inch, Panel(225082, 11.5 inch, 22.25 inch, Panel(225056, 11.5 inch, 26.125 inch, Panel(225053, 11.5 inch, 30.0 inch, Panel(225044, 17.875 inch, 30.0 inch, BoughtPanel(225042, AvailablePanel(225039, "1/4 30 × 30 Baltic Birch", 30 inch, 30 inch, 0.25 inch, "Baltic Birch", 36.0)), 12.0 inch, LengthAxis(), 12.125 inch, 0.0 inch, 22.43723849372385), 11.5 inch, LengthAxis(), 12.125 inch, 0.0 inch, 15.50863339029996), 3.75 inch, WidthAxis(), 12.125 inch, 3.875 inch, 14.873658487751847), 3.75 inch, WidthAxis(), 12.125 inch, 7.75 inch, 14.012073128941482), 5.5 inch, LengthAxis(), 12.125 inch, 7.75 inch, 7.500343051356321), 3.75 inch, WidthAxis(), 12.125 inch, 7.75 inch, 1.5254818731112407)), FinishedPanel(225083, WantedPanel(225030, 11.5 inch, 3.75 inch, 0.25 inch, "Baltic Birch", "side 1/2"), Panel(225081, 11.5 inch, 3.75 inch, Panel(225056, 11.5 inch, 26.125 inch, Panel(225053, 11.5 inch, 30.0 inch, Panel(225044, 17.875 inch, 30.0 inch, BoughtPanel(225042, AvailablePanel(225039, "1/4 30 × 30 Baltic Birch", 30 inch, 30 inch, 0.25 inch, "Baltic Birch", 36.0)), 12.0 inch, LengthAxis(), 12.125 inch, 0.0 inch, 22.43723849372385), 11.5 inch, LengthAxis(), 12.125 inch, 0.0 inch, 15.50863339029996), 3.75 inch, WidthAxis(), 12.125 inch, 3.875 inch, 14.873658487751847), 3.75 inch, WidthAxis(), 12.125 inch, 3.875 inch, 2.3615853588103626)), FinishedPanel(225057, WantedPanel(225031, 11.5 inch, 3.75 inch, 0.25 inch, "Baltic Birch", "side 2/2"), Panel(225055, 11.5 inch, 3.75 inch, Panel(225053, 11.5 inch, 30.0 inch, Panel(225044, 17.875 inch, 30.0 inch, BoughtPanel(225042, AvailablePanel(225039, "1/4 30 × 30 Baltic Birch", 30 inch, 30 inch, 0.25 inch, "Baltic Birch", 36.0)), 12.0 inch, LengthAxis(), 12.125 inch, 0.0 inch, 22.43723849372385), 11.5 inch, LengthAxis(), 12.125 inch, 0.0 inch, 15.50863339029996), 3.75 inch, WidthAxis(), 12.125 inch, 0.0 inch, 2.134974902548112)), FinishedPanel(225047, WantedPanel(225028, 12 inch, 6 inch, 0.25 inch, "Baltic Birch", "bottom"), Panel(225045, 12.0 inch, 6.0 inch, Panel(225043, 12.0 inch, 30.0 inch, BoughtPanel(225042, AvailablePanel(225039, "1/4 30 × 30 Baltic Birch", 30 inch, 30 inch, 0.25 inch, "Baltic Birch", 36.0)), 12.0 inch, LengthAxis(), 0 inch, 0 inch, 15.06276150627615), 6.0 inch, WidthAxis(), 0 inch, 0 inch, 3.326412352724917)))
We can generate a more readable report for our box:
report(searcher;
includeCutDiagram=true,
includeCutGraph=false,
filename="example_panel_cut_report.html")
"example_panel_cut_report.html"
You can see the report here.