Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
uvahotspot
GitHub Repository: uvahotspot/HotSpot
Path: blob/master/shape.c
612 views
1
#include <stdio.h>
2
#ifdef _MSC_VER
3
#define strcasecmp _stricmp
4
#define strncasecmp _strnicmp
5
#else
6
#include <strings.h>
7
#endif
8
#include <string.h>
9
#include <stdlib.h>
10
#include <math.h>
11
12
#include "shape.h"
13
#include "flp.h"
14
#include "util.h"
15
16
/* make a shape curve from area and aspect ratios */
17
shape_t *shape_from_aspect(double area, double min,
18
double max, int rotable,
19
int n_orients)
20
{
21
shape_t *shape;
22
double r=1, minx, maxx, tmin, tmax;
23
int i, overlap = 0;
24
25
/* rotatable blocks have 2n no. of orients */
26
if (n_orients <= 1 || (n_orients & 1))
27
fatal("n_orients should be an even number greater than 1\n");
28
29
shape = (shape_t *) calloc(1, sizeof(shape_t));
30
if (!shape)
31
fatal("memory allocation error\n");
32
if (min == max)
33
shape->size = 1 + (!!rotable);
34
else
35
shape->size = n_orients;
36
37
shape->x = (double *) calloc(shape->size, sizeof(double));
38
shape->y = (double *) calloc(shape->size, sizeof(double));
39
if (!shape->x || !shape->y)
40
fatal("memory allocation error\n");
41
42
/* overlapping regions of aspect ratios */
43
if (rotable && min <= 1.0 && max >= 1.0) {
44
overlap = 1;
45
tmin = MIN4(min, max, 1.0/min, 1.0/max);
46
tmax = MAX4(min, max, 1.0/min, 1.0/max);
47
min = tmin;
48
max = tmax;
49
}
50
51
if (!rotable || overlap) {
52
minx = sqrt(area * min);
53
maxx = sqrt(area * max);
54
if (shape->size > 1)
55
r = pow((maxx / minx) , 1.0/(shape->size-1));
56
for (i = 0; i < shape->size; i++) {
57
shape->x[i] = minx * pow(r, i);
58
shape->y[i] = area / shape->x[i];
59
}
60
/* rotable but no overlap, hence two sets of orientations */
61
} else {
62
int n = shape->size / 2;
63
/* orientations with aspect ratios < 1 */
64
tmin = MIN(min, 1.0/min);
65
tmax = MIN(max, 1.0/max);
66
minx = sqrt(area * MIN(tmin, tmax));
67
maxx = sqrt(area * MAX(tmin, tmax));
68
if ( n > 1)
69
r = pow((maxx / minx) , 1.0/(n-1));
70
for (i = 0; i < n; i++) {
71
shape->x[i] = minx * pow(r, i);
72
shape->y[i] = area / shape->x[i];
73
}
74
/* orientations with aspect ratios > 1 */
75
tmin = MAX(min, 1.0/min);
76
tmax = MAX(max, 1.0/max);
77
minx = sqrt(area * MIN(tmin, tmax));
78
maxx = sqrt(area * MAX(tmin, tmax));
79
if ( n > 1)
80
r = pow((maxx / minx) , 1.0/(n-1));
81
for (i = 0; i < n; i++) {
82
shape->x[n+i] = minx * pow(r, i);
83
shape->y[n+i] = area / shape->x[n+i];
84
}
85
}
86
return shape;
87
}
88
89
void free_shape(shape_t *shape)
90
{
91
free (shape->x);
92
free (shape->y);
93
if(shape->left_pos) {
94
free(shape->left_pos);
95
free(shape->right_pos);
96
free(shape->median);
97
}
98
free(shape);
99
}
100
101
void print_shape_entry(shape_t *shape, int i)
102
{
103
fprintf(stdout, "%g\t%g", shape->x[i], shape->y[i]);
104
if (shape->left_pos)
105
fprintf(stdout, "\t%d\t%d\t%g", shape->left_pos[i],
106
shape->right_pos[i], shape->median[i]);
107
fprintf(stdout, "\n");
108
}
109
110
/* debug print */
111
void print_shape(shape_t *shape)
112
{
113
int i;
114
if (!shape) {
115
fprintf(stdout, "printing shape curve: NULL\n");
116
return;
117
}
118
fprintf(stdout, "printing shape curve with %d elements\n", shape->size);
119
for (i=0; i < shape->size; i++)
120
print_shape_entry(shape, i);
121
fprintf(stdout, "\n");
122
}
123
124
/* shape curve arithmetic */
125
shape_t *shape_add(shape_t *shape1, shape_t *shape2, int cut_type)
126
{
127
int i=0, j=0, k=0, total=0, m, n;
128
shape_t *sum;
129
130
sum = (shape_t *) calloc(1, sizeof(shape_t));
131
if (!sum)
132
fatal("memory allocation error\n");
133
134
/* shortcuts */
135
m = shape1->size;
136
n = shape2->size;
137
138
/* determine result size */
139
while(i < m && j < n) {
140
if (cut_type == CUT_VERTICAL) {
141
if (shape1->y[i] >= shape2->y[j])
142
i++;
143
else
144
j++;
145
} else {
146
if (shape1->x[m-1-i] >= shape2->x[n-1-j])
147
i++;
148
else
149
j++;
150
}
151
total++;
152
}
153
154
sum->x = (double *) calloc(total, sizeof(double));
155
sum->y = (double *) calloc(total, sizeof(double));
156
sum->left_pos = (int *) calloc(total, sizeof(int));
157
sum->right_pos = (int *) calloc(total, sizeof(int));
158
sum->median = (double *) calloc(total, sizeof(double));
159
if (!sum->x || !sum->y || !sum->left_pos ||
160
!sum->right_pos || !sum->median)
161
fatal("memory allocation error\n");
162
sum->size = total;
163
164
i=j=0;
165
while(i < m && j < n) {
166
/* vertical add */
167
if (cut_type == CUT_VERTICAL) {
168
sum->x[k] = shape1->x[i] + shape2->x[j];
169
sum->y[k] = MAX(shape1->y[i], shape2->y[j]);
170
sum->left_pos[k] = i;
171
sum->right_pos[k] = j;
172
sum->median[k] = shape1->x[i];
173
if (shape1->y[i] >= shape2->y[j])
174
i++;
175
else
176
j++;
177
/* horizontal add */
178
} else {
179
/*
180
* direction of increasing 'y' is the reverse of the
181
* regular direction of the shape curve. hence reverse
182
* the curve before adding
183
*/
184
sum->x[total-1-k] = MAX(shape1->x[m-1-i], shape2->x[n-1-j]);
185
sum->y[total-1-k] = shape1->y[m-1-i] + shape2->y[n-1-j];
186
sum->left_pos[total-1-k] = m-1-i;
187
sum->right_pos[total-1-k] = n-1-j;
188
sum->median[total-1-k] = shape1->y[m-1-i];
189
if (shape1->x[m-1-i] >= shape2->x[n-1-j])
190
i++;
191
else
192
j++;
193
}
194
k++;
195
}
196
197
return sum;
198
}
199
200
/* copy a shape curve */
201
shape_t *shape_duplicate(shape_t *shape)
202
{
203
shape_t *copy;
204
int i;
205
copy = (shape_t *) calloc(1, sizeof(shape_t));
206
if (!copy)
207
fatal("memory allocation error\n");
208
copy->size = shape->size;
209
copy->x = (double *) calloc(copy->size, sizeof(double));
210
copy->y = (double *) calloc(copy->size, sizeof(double));
211
if (!copy->x || !copy->y)
212
fatal("memory allocation error\n");
213
if (shape->left_pos) {
214
copy->left_pos = (int *) calloc(copy->size, sizeof(int));
215
copy->right_pos = (int *) calloc(copy->size, sizeof(int));
216
copy->median = (double *) calloc(copy->size, sizeof(double));
217
if(!copy->left_pos || !copy->right_pos || !copy->median)
218
fatal("memory allocation error\n");
219
}
220
for(i=0; i < shape->size; i++) {
221
copy->x[i] = shape->x[i];
222
copy->y[i] = shape->y[i];
223
if (shape->left_pos) {
224
copy->left_pos[i] = shape->left_pos[i];
225
copy->right_pos[i] = shape->right_pos[i];
226
copy->median[i] = shape->median[i];
227
}
228
}
229
return copy;
230
}
231
232
/* tree node stack operations */
233
234
/* constructor */
235
tree_node_stack_t *new_tree_node_stack(void)
236
{
237
tree_node_stack_t *stack;
238
stack = (tree_node_stack_t *)calloc(1, sizeof(tree_node_stack_t));
239
if (!stack)
240
fatal("memory allocation error\n");
241
/* first free location */
242
stack->top = 0;
243
return stack;
244
}
245
246
/* destructor */
247
void free_tree_node_stack(tree_node_stack_t *stack)
248
{
249
free(stack);
250
}
251
252
/* is empty? */
253
int tree_node_stack_isempty(tree_node_stack_t *stack)
254
{
255
if (stack->top <= 0)
256
return TRUE;
257
return FALSE;
258
}
259
260
/* is full? */
261
int tree_node_stack_isfull(tree_node_stack_t *stack)
262
{
263
if (stack->top >= MAX_STACK)
264
return TRUE;
265
return FALSE;
266
}
267
268
/* push */
269
void tree_node_stack_push(tree_node_stack_t *stack, tree_node_t *node)
270
{
271
if (!tree_node_stack_isfull(stack)) {
272
stack->array[stack->top] = node;
273
stack->top++;
274
} else
275
fatal("attempting to push into an already full stack\n");
276
}
277
278
/* pop */
279
tree_node_t *tree_node_stack_pop(tree_node_stack_t *stack)
280
{
281
if (!tree_node_stack_isempty(stack)) {
282
stack->top--;
283
return stack->array[stack->top];
284
} else {
285
fatal("attempting to pop from an already empty stack\n");
286
return NULL;
287
}
288
}
289
290
/* clear */
291
void tree_node_stack_clear(tree_node_stack_t *stack)
292
{
293
stack->top = 0;
294
}
295
296
/* slicing tree routines */
297
298
/* construct floorplan slicing tree from NPE */
299
tree_node_t *tree_from_NPE(flp_desc_t *flp_desc,
300
tree_node_stack_t *stack,
301
NPE_t *expr)
302
{
303
int i;
304
tree_node_t *node = NULL, *left, *right;
305
306
if (!tree_node_stack_isempty(stack))
307
fatal("stack not empty\n");
308
309
for (i=0; i < expr->size; i++) {
310
node = (tree_node_t *) calloc(1, sizeof(tree_node_t));
311
if (!node)
312
fatal("memory allocation error\n");
313
/* leaf */
314
if (expr->elements[i] >= 0) {
315
node->curve = shape_duplicate(flp_desc->units[expr->elements[i]].shape);
316
node->left = node->right = NULL;
317
node->label.unit = expr->elements[i];
318
/* internal node denoting a cut */
319
} else {
320
right = tree_node_stack_pop(stack);
321
left = tree_node_stack_pop(stack);
322
node->curve = shape_add(left->curve, right->curve, expr->elements[i]);
323
node->left = left;
324
node->right = right;
325
node->label.cut_type = expr->elements[i];
326
}
327
tree_node_stack_push(stack, node);
328
}
329
330
tree_node_stack_clear(stack);
331
return node;
332
}
333
334
void free_tree(tree_node_t *root)
335
{
336
if (root->left != NULL)
337
free_tree(root->left);
338
if (root->right != NULL)
339
free_tree(root->right);
340
free_shape(root->curve);
341
free(root);
342
}
343
344
/* debug print */
345
void print_tree(tree_node_t *root, flp_desc_t *flp_desc)
346
{
347
if(root->left != NULL)
348
print_tree(root->left, flp_desc);
349
if (root->right != NULL)
350
print_tree(root->right, flp_desc);
351
352
if (root->label.unit >= 0)
353
fprintf(stdout, "printing shape curve for %s\n", flp_desc->units[root->label.unit].name);
354
else if (root->label.cut_type == CUT_VERTICAL)
355
fprintf(stdout, "printing shape curve for VERTICAL CUT\n");
356
else if (root->label.cut_type == CUT_HORIZONTAL)
357
fprintf(stdout, "printing shape curve for HORIZONTAL CUT\n");
358
else
359
fprintf(stdout, "unknown cut type\n");
360
361
print_shape(root->curve);
362
}
363
364
/*
365
* print only the portion of the shape curves
366
* corresponding to the `pos'th entry of root->curve
367
*/
368
void print_tree_relevant(tree_node_t *root, int pos, flp_desc_t *flp_desc)
369
{
370
if(root->left != NULL)
371
print_tree_relevant(root->left, root->curve->left_pos[pos], flp_desc);
372
if (root->right != NULL)
373
print_tree_relevant(root->right, root->curve->right_pos[pos], flp_desc);
374
375
if (root->label.unit >= 0)
376
fprintf(stdout, "printing orientation for %s:\t", flp_desc->units[root->label.unit].name);
377
else if (root->label.cut_type == CUT_VERTICAL)
378
fprintf(stdout, "printing orientation for VERTICAL CUT:\t");
379
else if (root->label.cut_type == CUT_HORIZONTAL)
380
fprintf(stdout, "printing orientation for HORIZONTAL CUT:\t");
381
else
382
fprintf(stdout, "unknown cut type\n");
383
384
print_shape_entry(root->curve, pos);
385
}
386
387
int min_area_pos(shape_t *curve)
388
{
389
int i = 1, pos = 0;
390
double min = curve->x[0] * curve->y[0];
391
for (; i < curve->size; i++)
392
if (min > curve->x[i] * curve->y[i]) {
393
min = curve->x[i] * curve->y[i];
394
pos = i;
395
}
396
return pos;
397
}
398
399
/*
400
* recursive sizing - given the slicing tree containing
401
* the added up shape curves. 'pos' denotes the current
402
* added up orientation. 'leftx' & 'bottomy' denote the
403
* left and bottom ends of the current bounding rectangle
404
*/
405
int recursive_sizing (tree_node_t *node, int pos,
406
double leftx, double bottomy,
407
int dead_count, int compact_dead,
408
double compact_ratio,
409
#if VERBOSE > 1
410
double *compacted_area,
411
#endif
412
flp_t *flp)
413
{
414
/* shortcut */
415
shape_t *self = node->curve;
416
417
/* leaf node. fill the placeholder */
418
if (node->label.unit >= 0) {
419
flp->units[node->label.unit].width = self->x[pos];
420
flp->units[node->label.unit].height = self->y[pos];
421
flp->units[node->label.unit].leftx = leftx;
422
flp->units[node->label.unit].bottomy = bottomy;
423
} else {
424
/* shortcuts */
425
int idx;
426
double x1, x2, y1, y2;
427
shape_t *left = node->left->curve;
428
shape_t *right = node->right->curve;
429
430
/* location of the first dead block + offset */
431
idx = (flp->n_units + 1) / 2 + dead_count;
432
433
x1 = left->x[self->left_pos[pos]];
434
x2 = right->x[self->right_pos[pos]];
435
y1 = left->y[self->left_pos[pos]];
436
y2 = right->y[self->right_pos[pos]];
437
438
/* add a dead block - possibly of zero area */
439
if (node->label.unit == CUT_VERTICAL) {
440
/*
441
* if a dead block has been previously compacted away from this
442
* bounding rectangle, absorb that area into the child also
443
*/
444
if(self->y[pos] > MAX(y1, y2)) {
445
left->y[self->left_pos[pos]] += (self->y[pos] - MAX(y1, y2));
446
right->y[self->right_pos[pos]] += (self->y[pos] - MAX(y1, y2));
447
y1 = left->y[self->left_pos[pos]];
448
y2 = right->y[self->right_pos[pos]];
449
}
450
if(self->x[pos] > (x1+x2)) {
451
right->x[self->right_pos[pos]] += self->x[pos]-(x1+x2);
452
x2 = right->x[self->right_pos[pos]];
453
}
454
455
flp->units[idx].width = (y2 >= y1) ? x1 : x2;
456
flp->units[idx].height = fabs(y2 - y1);
457
flp->units[idx].leftx = leftx + ((y2 >= y1) ? 0 : x1);
458
flp->units[idx].bottomy = bottomy + MIN(y1, y2);
459
460
/*
461
* ignore dead blocks smaller than compact_ratio times the area
462
* of the smaller of the constituent rectangles. instead, increase
463
* the size of the rectangle by that amount
464
*/
465
if (compact_dead && fabs(y2-y1) / MIN(y1, y2) <= compact_ratio) {
466
#if VERBOSE > 1
467
*compacted_area += (flp->units[idx].width * flp->units[idx].height);
468
#endif
469
if (y2 >= y1)
470
left->y[self->left_pos[pos]] = y2;
471
else
472
right->y[self->right_pos[pos]] = y1;
473
} else {
474
dead_count++;
475
}
476
477
/* left and bottom don't change for the left child */
478
dead_count = recursive_sizing(node->left, self->left_pos[pos],
479
leftx, bottomy, dead_count, compact_dead,
480
compact_ratio,
481
#if VERBOSE > 1
482
compacted_area,
483
#endif
484
flp);
485
dead_count = recursive_sizing(node->right, self->right_pos[pos],
486
leftx + self->median[pos], bottomy,
487
dead_count, compact_dead, compact_ratio,
488
#if VERBOSE > 1
489
compacted_area,
490
#endif
491
flp);
492
} else {
493
if(self->x[pos] > MAX(x1, x2)) {
494
left->x[self->left_pos[pos]] += (self->x[pos] - MAX(x1, x2));
495
right->x[self->right_pos[pos]] += (self->x[pos] - MAX(x1, x2));
496
x1 = left->x[self->left_pos[pos]];
497
x2 = right->x[self->right_pos[pos]];
498
}
499
if(self->y[pos] > (y1+y2)) {
500
right->y[self->right_pos[pos]] += self->y[pos]-(y1+y2);
501
y2 = right->y[self->right_pos[pos]];
502
}
503
504
flp->units[idx].width = fabs(x2 - x1);
505
flp->units[idx].height = (x2 >= x1) ? y1 : y2;
506
flp->units[idx].leftx = leftx + MIN(x1, x2);
507
flp->units[idx].bottomy = bottomy + ((x2 >= x1) ? 0 : y1);
508
509
if (compact_dead && fabs(x2-x1) / MIN(x1, x2) <= compact_ratio) {
510
#if VERBOSE > 1
511
*compacted_area += (flp->units[idx].width * flp->units[idx].height);
512
#endif
513
if (x2 >= x1)
514
left->x[self->left_pos[pos]] = x2;
515
else
516
right->x[self->right_pos[pos]] = x1;
517
} else {
518
dead_count++;
519
}
520
521
/* left and bottom don't change for the left child */
522
dead_count = recursive_sizing(node->left, self->left_pos[pos],
523
leftx, bottomy, dead_count, compact_dead,
524
compact_ratio,
525
#if VERBOSE > 1
526
compacted_area,
527
#endif
528
flp);
529
dead_count = recursive_sizing(node->right, self->right_pos[pos],
530
leftx, bottomy + self->median[pos],
531
dead_count, compact_dead, compact_ratio,
532
#if VERBOSE > 1
533
compacted_area,
534
#endif
535
flp);
536
}
537
}
538
return dead_count;
539
}
540
541
/*
542
* convert slicing tree into actual floorplan
543
* returns the number of dead blocks compacted
544
*/
545
int tree_to_flp(tree_node_t *root, flp_t *flp, int compact_dead,
546
double compact_ratio)
547
{
548
/* for now, only choose the floorplan with
549
* the minimum area regardless of the overall
550
* aspect ratio
551
*/
552
int pos = min_area_pos(root->curve);
553
#if VERBOSE > 1
554
double compacted_area = 0.0;
555
#endif
556
int dead_count = recursive_sizing(root, pos, 0.0, 0.0, 0,
557
compact_dead, compact_ratio,
558
#if VERBOSE > 1
559
&compacted_area,
560
#endif
561
flp);
562
563
int compacted = (flp->n_units - 1) / 2 - dead_count;
564
flp->n_units -= compacted;
565
#if VERBOSE > 1
566
fprintf(stdout, "%d dead blocks, %.2f%% of the core compacted\n", compacted,
567
compacted_area / (get_total_area(flp)-compacted_area) * 100);
568
#endif
569
return compacted;
570
}
571
572