diff options
| author | bozo.kopic <bozo@kopic.xyz> | 2021-12-27 23:03:52 +0100 |
|---|---|---|
| committer | bozo.kopic <bozo@kopic.xyz> | 2021-12-27 23:04:04 +0100 |
| commit | b0aedec7bb1eacf5967a8f086fc7740048873a58 (patch) | |
| tree | a56e148380f7818a18036daf95d0ebde036e505c /src_c/csp.c | |
| parent | fd0be422180178516d6d2bf3fb1f343c9ab79e53 (diff) | |
WIP c implementation
Diffstat (limited to 'src_c/csp.c')
| -rw-r--r-- | src_c/csp.c | 236 |
1 files changed, 194 insertions, 42 deletions
diff --git a/src_c/csp.c b/src_c/csp.c index 8ff94cc..9cd25ec 100644 --- a/src_c/csp.c +++ b/src_c/csp.c @@ -24,10 +24,10 @@ static void sort_panels(opcut_panel_t **first, opcut_panel_t **last) { for (opcut_panel_t *panel = (*first)->next; panel;) { opcut_panel_t *next = panel->next; - if (panel->area < pivot_first->area) { + if (panel->area > pivot_first->area) { panel->next = left_first; left_first = panel; - } else if (panel->area > pivot_first->area) { + } else if (panel->area < pivot_first->area) { panel->next = right_first; right_first = panel; } else { @@ -123,9 +123,11 @@ static void calculate_fitness(opcut_result_t *result, fitness_t *fitness) { max_unused_area = unused->area; } - fitness->fitness += (panel->area - used_areas) / result->panels_area; - fitness->fitness -= FITNESS_K * min_used_area * max_unused_area / - (result->panels_area * result->panels_area); + fitness->fitness += + (panel->area - used_areas) / result->params->panels_area; + fitness->fitness -= + FITNESS_K * min_used_area * max_unused_area / + (result->params->panels_area * result->params->panels_area); } fitness->unused_initial_count = 0; @@ -139,69 +141,219 @@ static void calculate_fitness(opcut_result_t *result, fitness_t *fitness) { } -static int cut_item_from_unused(opcut_item_t *item, opcut_unused_t *unused, - bool rotate, double cut_width, bool vertical, - opcut_used_t *new_used, - opcut_unused_t *new_unused, - size_t *new_unused_len) { +static inline bool item_fits_unused(opcut_item_t *item, opcut_unused_t *unused, + bool rotate) { + if (rotate && !item->can_rotate) + return false; + + double item_width = (rotate ? item->height : item->width); + double item_height = (rotate ? item->width : item->height); + + return unused->height >= item_height && unused->width >= item_width; +} + + +static int cut_item_from_unused(opcut_result_t *result, opcut_item_t *item, + opcut_unused_t *unused, bool rotate, + bool vertical) { double item_width = (rotate ? item->height : item->width); double item_height = (rotate ? item->width : item->height); if (unused->height < item_height || unused->width < item_width) - return OPCUT_UNSOLVABLE; + return OPCUT_ERROR; + + opcut_used_t *used = opcut_pool_alloc(result->used_pool); + if (!used) + return OPCUT_ERROR; + *used = (opcut_used_t){.panel = unused->panel, + .item = item, + .x = unused->x, + .y = unused->y, + .rotate = rotate, + .next = result->used}; + result->used = used; - new_used->panel = unused->panel; - new_used->item = item; - new_used->x = unused->x; - new_used->y = unused->y; - new_used->rotate = rotate; double width; double height; - *new_unused_len = 0; - width = unused->width - item_width - cut_width; + width = unused->width - item_width - result->params->cut_width; if (width > 0) { height = (vertical ? unused->height : item_height); - new_unused[(*new_unused_len)++] = - (opcut_unused_t){.panel = unused->panel, - .width = width, - .height = height, - .x = unused->x + item_width + cut_width, - .y = unused->y, - .area = width * height, - .initial = false}; + opcut_unused_t *new_unused = opcut_pool_alloc(result->unused_pool); + if (!new_unused) + return OPCUT_ERROR; + *new_unused = (opcut_unused_t){.panel = unused->panel, + .width = width, + .height = height, + .x = unused->x + item_width + + result->params->cut_width, + .y = unused->y, + .next = result->unused, + .area = width * height, + .initial = false}; + result->unused = new_unused; } - height = unused->height - item_height - cut_width; + height = unused->height - item_height - result->params->cut_width; if (height > 0) { width = (vertical ? item_width : unused->width); - new_unused[(*new_unused_len)++] = - (opcut_unused_t){.panel = unused->panel, - .width = width, - .height = height, - .x = unused->x, - .y = unused->y + item_height + cut_width, - .area = width * height, - .initial = false}; + opcut_unused_t *new_unused = opcut_pool_alloc(result->unused_pool); + if (!new_unused) + return OPCUT_ERROR; + *new_unused = (opcut_unused_t){.panel = unused->panel, + .width = width, + .height = height, + .x = unused->x, + .y = unused->y + item_height + + result->params->cut_width, + .next = result->unused, + .area = width * height, + .initial = false}; + result->unused = new_unused; } return OPCUT_SUCCESS; } -void opcut_sort_params(opcut_params_t *params) { - sort_panels(&(params->panels), NULL); - sort_items(&(params->items), NULL); +static int copy_unused(opcut_result_t *result, opcut_unused_t *exclude) { + opcut_unused_t *unused = NULL; + for (opcut_unused_t *i = result->unused; i; i = i->next) { + if (i == exclude) + continue; + + opcut_unused_t *temp = opcut_pool_alloc(result->unused_pool); + if (!temp) + return OPCUT_ERROR; + + *temp = *i; + temp->next = unused; + unused = temp; + } + + result->unused = NULL; + while (unused) { + opcut_unused_t *next = unused->next; + unused->next = result->unused; + result->unused = unused; + unused = next; + } + + return OPCUT_SUCCESS; } -int opcut_calculate(opcut_method_t method, opcut_params_t *params, - opcut_result_t *result) { +static void free_unused(opcut_result_t *result) { + while (result->unused) { + opcut_unused_t *next = result->unused->next; + opcut_pool_free(result->unused_pool, result->unused); + result->unused = next; + } +} + + +static void free_last_used(opcut_result_t *result) { + opcut_pool_free(result->used_pool, result->used); +} + + +static int calculate_greedy(opcut_result_t *result, opcut_item_t *items) { + for (opcut_item_t *item = items; item; item = item->next) { + opcut_result_t best_result; + fitness_t best_fitness; + bool solvable = false; + for (opcut_unused_t *unused = result->unused; unused; + unused = unused->next) { + for (size_t rotate = 0; rotate < 2; ++rotate) { + if (!item_fits_unused(item, unused, rotate)) + continue; + + for (size_t vertical = 0; vertical < 2; ++vertical) { + opcut_result_t temp_result = *result; + if (copy_unused(&temp_result, unused)) + return OPCUT_ERROR; + + if (cut_item_from_unused(&temp_result, item, unused, rotate, + vertical)) + return OPCUT_ERROR; + + fitness_t temp_fitness; + calculate_fitness(&temp_result, &temp_fitness); + + if (!solvable) { + best_result = temp_result; + best_fitness = temp_fitness; + solvable = true; + + } else if (compare_fitness(&temp_fitness, &best_fitness) < + 0) { + free_last_used(&best_result); + free_unused(&best_result); + best_result = temp_result; + best_fitness = temp_fitness; + + } else { + free_last_used(&temp_result); + free_unused(&temp_result); + } + } + } + } + + if (!solvable) + return OPCUT_UNSOLVABLE; + + free_unused(result); + *result = best_result; + } + + return OPCUT_SUCCESS; +} + + +static int calculate_forward_greedy(opcut_result_t *result, + opcut_item_t *items) { + for (opcut_item_t *item = items; item; item = item->next) { + } + + return OPCUT_SUCCESS; +} + + +int opcut_calculate(opcut_pool_t *used_pool, opcut_pool_t *unused_pool, + opcut_method_t method, opcut_params_t *params, + opcut_result_t *result) { + result->used_pool = used_pool; + result->unused_pool = unused_pool; result->params = params; result->used = NULL; result->unused = NULL; - result->panels_area = 0; - return OPCUT_SUCCESS; + sort_panels(&(params->panels), NULL); + sort_items(&(params->items), NULL); + + for (opcut_panel_t *panel = params->panels; panel; panel = panel->next) { + opcut_unused_t *unused = opcut_pool_alloc(unused_pool); + if (!unused) + return OPCUT_ERROR; + + *unused = (opcut_unused_t){.panel = panel, + .width = panel->width, + .height = panel->height, + .x = 0, + .y = 0, + .next = result->unused, + .area = panel->area, + .initial = true}; + result->unused = unused; + } + + if (method == OPCUT_METHOD_GREEDY) + return calculate_greedy(result, params->items); + + if (method == OPCUT_METHOD_FORWARD_GREEDY) + return calculate_forward_greedy(result, params->items); + + return OPCUT_ERROR; } |
