diff options
| -rw-r--r-- | schemas/opcut.yaml | 2 | ||||
| -rw-r--r-- | src_js/common.js | 3 | ||||
| -rw-r--r-- | src_js/states.js | 1 | ||||
| -rw-r--r-- | src_js/vt.js | 21 | ||||
| -rw-r--r-- | src_py/opcut/common.py | 3 | ||||
| -rw-r--r-- | src_py/opcut/csp.py | 15 |
6 files changed, 40 insertions, 5 deletions
diff --git a/schemas/opcut.yaml b/schemas/opcut.yaml index a6d5d0b..47e0a7f 100644 --- a/schemas/opcut.yaml +++ b/schemas/opcut.yaml @@ -11,6 +11,8 @@ definitions: properties: cut_width: type: number + min_initial_usage: + type: boolean panels: type: object patternProperties: diff --git a/src_js/common.js b/src_js/common.js index 1928624..c106f04 100644 --- a/src_js/common.js +++ b/src_js/common.js @@ -120,6 +120,8 @@ function createCalculateParams() { if (cutWidth < 0) throw 'Invalid cut width'; + const minInitialUsage = r.get('form', 'min_initial_usage'); + const panels = {}; for (const panel of r.get('form', 'panels')) { if (!panel.name) @@ -167,6 +169,7 @@ function createCalculateParams() { return { cut_width: cutWidth, + min_initial_usage: minInitialUsage, panels: panels, items: items }; diff --git a/src_js/states.js b/src_js/states.js index a696007..bf3584e 100644 --- a/src_js/states.js +++ b/src_js/states.js @@ -3,6 +3,7 @@ export const main = { form: { method: 'forward_greedy', cut_width: 0.3, + min_initial_usage: false, panels: [], items: [] }, diff --git a/src_js/vt.js b/src_js/vt.js index 8320f75..ce16d3d 100644 --- a/src_js/vt.js +++ b/src_js/vt.js @@ -68,7 +68,11 @@ function leftPanel() { ['label', 'Cut width'], numberInput(r.get('form', 'cut_width'), u.isNumber, - val => r.set(['form', 'cut_width'], val)) + val => r.set(['form', 'cut_width'], val)), + ['label'], + checkboxInput('Minimize initial panel usage', + r.get('form', 'min_initial_usage'), + val => r.set(['form', 'min_initial_usage'], val)) ], ['div.content', leftPanelPanels(), @@ -240,7 +244,8 @@ function leftPanelItems() { ], ['td.col-rotate', ['div', - checkboxInput(item.can_rotate, + checkboxInput(null, + item.can_rotate, val => r.set([itemsPath, index, 'can_rotate'], val)) ] ], @@ -473,8 +478,8 @@ function numberInput(value, validator, onChange) { } -function checkboxInput(value, onChange) { - return ['input', { +function checkboxInput(label, value, onChange) { + const input = ['input', { props: { type: 'checkbox', checked: value @@ -483,6 +488,14 @@ function checkboxInput(value, onChange) { change: evt => onChange(evt.target.checked) } }]; + + if (!label) + return input; + + return ['label', + input, + ` ${label}` + ]; } diff --git a/src_py/opcut/common.py b/src_py/opcut/common.py index 90a8b00..9fbb7dd 100644 --- a/src_py/opcut/common.py +++ b/src_py/opcut/common.py @@ -29,6 +29,7 @@ class Item(typing.NamedTuple): class Params(typing.NamedTuple): cut_width: float + min_initial_usage: bool panels: typing.List[Panel] items: typing.List[Item] @@ -81,6 +82,7 @@ def params_to_json(params: Params) -> json.Data: """Convert params to json serializable data specified by ``opcut://opcut.yaml#/definitions/params``""" return {'cut_width': params.cut_width, + 'min_initial_usage': params.min_initial_usage, 'panels': {panel.id: {'width': panel.width, 'height': panel.height} for panel in params.panels}, @@ -94,6 +96,7 @@ def params_from_json(data: json.Data) -> Params: """Convert json serializable data specified by ``opcut://opcut.yaml#/definitions/params`` to params""" return Params(cut_width=data['cut_width'], + min_initial_usage=data.get('min_initial_usage', False), panels=[Panel(id=k, width=v['width'], height=v['height']) diff --git a/src_py/opcut/csp.py b/src_py/opcut/csp.py index 43b8e1f..eb08314 100644 --- a/src_py/opcut/csp.py +++ b/src_py/opcut/csp.py @@ -145,4 +145,17 @@ def _fitness(result): fitness -= (_fitness_K * min(used_areas, default=0) * max(unused_areas, default=0) / (total_area * total_area)) - return fitness + + if not result.params.min_initial_usage: + return fitness + + unused_initial_count = sum(1 for unused in result.unused + if _is_unused_initial(unused)) + return (-unused_initial_count, fitness) + + +def _is_unused_initial(unused): + return (unused.x == 0 and + unused.y == 0 and + unused.width == unused.panel.width and + unused.height == unused.panel.height) |
