PanelCutting.jl

This package implements a utility for determining the optimal sequence of cuts to produce a set of rectangular panels of specified sizes from sheet good stock (e.g. plywood).

New users will probably want to go straight to the box example to get started.

Panels

The search is mediated by a progression of panels of various types:

PanelCutting.BoughtPanelType
BoughtPanel

a BoughtPanel is created to wrap an AvailablePanel when we add it to the working set. This ensured that when it is cut it has a distinct identity from any other BoughtPanel of the same size.

source
PanelCutting.FinishedPanelType
FinishedPanel

FinishedPanel wraps a Panel that matches an AbstractWantedPanel and associates that AbstractWantedPanel with the cut Panel.

source
PanelCutting.FlippedPanelType
FlippedPanel

FlippedPanel wraps a WantedPanel to indicate that its want can be satisfied by a panel even if its length and width are swapped.

This allows the user to control whether flipping is allowed of if they care about grain direction.

When either the original or the flipped panel is finished then its counterpart will be removed from the unsatisfied wants as well. The function wantsmatch is used for this test.

source
PanelCutting.PanelType
Panel

Panel represents a panel that has been cut from an AvailablePanel but does not yet match an AbstractWantedPanel.

source
PanelCutting.WantedPanelType
WantedPanel

WantedPanel describes a panel that we need to have cut from some sheet stock. A Set of AbstractWantedPanels establishes the goal of our search.

source
PanelCutting.PanelsType
Panels

An immutable collections of Panels

Our SearchState objects contain several collections of panels. We'd like these collections to be immutable, like the SearchStates themselves.

When transitioning from one SearchState to its possible successor states, these collections could change in the following ways:

  • a WantedPanel and possibly its flipped counterpart, might be removed and a FinishedPanel added
  • one or two CuttablePanels added to stock panels
  • CuttablePanels moved from stock to waste if they are too small for any remaining wanted panels
source
PanelCutting.progenitorFunction
progenitor(panel)

Return the BoughtPanel that this panel was cut from.

An AbstractPanel is its own progenitor.

A WantedPanel is its own progenitor.

A FlippedPanel is its own progenitor.

progenitor is used in the overlap test: panels can not overlap if they have different progenitors.

source

Methodology

We start with a goal of producing a set of WantedPanels of specified sizes.

We then select an AvailablePanel and cut it. Each cut potentially produces two new offcut Panels.

When one of these Panels matches a WanterPanel we associate that Panel with the WantedPanel using a FinishedPanel.

We give Panels an X and Y 'origin' origin as well as a length (along x) and width (along y) to simplify SVG generation.

Everything Else

PanelCutting.callerFileFunction
callerFile()

Return the path of the file of the function that called callerFile's caller. Also return the line number.

source
PanelCutting.cutFunction
cut(panel, axis, at; kerf, cost)::(panel1, panel2)

Cut panel at the specified distance along axis. The first returned panel is the piece cut to that distance. The second is what remains (accounting for kerf).

An empty Tuple is returned if the cut can't be made.

source
PanelCutting.eltFunction
elt(f, tagname::AbstractString, things...)
elt(tagname::AbstractString, things...)

Return an XML element. f is called with a single argument: either an XML.AbstractXMLNode or a Pair describing an XML attribute to be added to the resulting element.

source
PanelCutting.fitsinFunction
fitsin(small::AbstractPanel, big::AbstractPanel)::Bool

See if small can be cut from big.

source
PanelCutting.inPlutoFunction
inPluto()::Bool

Return true if the notebook is being run in Pluto, artyher than directly in Julia (e.g. command line or REPL).

source
PanelCutting.orFlippedFunction
orFlipped(::WantedPanel)

Return a Vector of AbstractWantedPanel consisting of the WantedPanel and possibly its corresponding FlippedPanel.

source
PanelCutting.panelUIDFunction
panelUID()

Generate a unique identifier for each panel when it is created. We do this because Julia does not have a notion of equality that distibguishes between two separately created immutable structs with the same contents.

source
PanelCutting.panelrectFunction
panelrect(panel::AbstractPanel, numbering::FinishedPanelNumbering)

Return an SVG element that will draw the representation of the panel.

source
PanelCutting.replace0Function
replace0(defaultX, defaultY, newX, newY)

Return newX and newY so long as they are not 0. If zero, use the corresponding default value.

source
PanelCutting.reportFunction
report(::Searcher)

Generate an HTML fragment that provides a detailed report of our cut search and results.

source
PanelCutting.runCmdFunction
runCmd(cmd::Cmd, cmdOutput::IO)::IO

Run the external command cmd, which will write output to cmdOutput. The stream that's returnd can be written to to provide inoput to the command. The second return value is the stderr stream.

source
PanelCutting.smallerFunction
smaller(p1::AbstractPanel, p2::AbstractPanel)::Bool

An ordering function for sorting panels by size. smaller(p1, p2) does not imply fitsin(p1, p2).

source
PanelCutting.SearcherType
Searcher

This Searcher implements A* search using a PriorityQueue.

One could implement other searchers to implement, for example, depth or breadth first search.

source
PanelCutting.SupplierType

Supplier(name::String, costpercut, kerf, available_stock::Vector{AvailablePanel})

A single supplier of sheet stock.

Some suppliers will cut shet stock down to the customer's specifications. kerf is the width of their saw custs. cost_per_cut is what they charge for each cut.

source

Index