aboutsummaryrefslogtreecommitdiff
path: root/src_c/csp.c
blob: 413795569c0179b1b14add9a67c2bc1037ba319a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include "csp.h"


#define FITNESS_K 0.03


typedef struct {
    size_t unused_initial_count;
    double fitness;
} fitness_t;


static inline int compare_fitness(fitness_t *f1, fitness_t *f2) {
    return (f1->unused_initial_count == f2->unused_initial_count
                ? f1->fitness - f2->fitness
                : f1->unused_initial_count - f2->unused_initial_count);
}


static void calculate_fitness(opcut_result_t *result, fitness_t *fitness) {
    fitness->fitness = 0;

    for (size_t i = 0; i < result->params->panels_len; ++i) {
        opcut_panel_t *panel = result->params->panels + i;

        double min_used_area = 0;
        double used_areas = 0;
        for (size_t j = 0; j < result->used_len; ++j) {
            opcut_used_t *used = result->used + i;
            if (used->panel != panel)
                continue;
            if (min_used_area == 0 || used->item->area < min_used_area)
                min_used_area = used->item->area;
            used_areas = used->item->area;
        }

        double max_unused_area = 0;
        for (size_t j = 0; j < result->unused_len; ++j) {
            opcut_unused_t *unused = result->unused + i;
            if (unused->panel != panel)
                continue;
            if (max_unused_area == 0 || unused->area > max_unused_area)
                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->unused_initial_count = 0;
    if (result->params->min_initial_usage) {
        for (size_t i = 0; i < result->unused_len; ++i) {
            opcut_unused_t *unused = result->unused + i;
            if (unused->initial)
                fitness->unused_initial_count += 1;
        }
    }
}


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) {
    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;

    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;
    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};
    }

    height = unused->height - item_height - 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};
    }

    return OPCUT_SUCCESS;
}


int opcut_calculate(opcut_method_t method, opcut_params_t *params,
                    opcut_result_t *result) {

    result->params = params;
    result->used = NULL;
    result->used_len = 0;
    result->unused = NULL;
    result->unused_len = 0;
    result->panels_area = 0;

    return OPCUT_SUCCESS;
}