Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * Contributor(s): Campbell Barton 00019 * 00020 * ***** END GPL LICENSE BLOCK ***** 00021 */ 00022 00028 #include <stdlib.h> /* for qsort */ 00029 00030 #include "MEM_guardedalloc.h" 00031 #include "BLI_boxpack2d.h" 00032 00033 /* BoxPacker for backing 2D rectangles into a square 00034 * 00035 * The defined Below are for internal use only */ 00036 00037 typedef struct boxVert { 00038 float x; 00039 float y; 00040 short free; 00041 00042 struct boxPack *trb; /* top right box */ 00043 struct boxPack *blb; /* bottom left box */ 00044 struct boxPack *brb; /* bottom right box */ 00045 struct boxPack *tlb; /* top left box */ 00046 00047 /* Store last intersecting boxes here 00048 * speedup intersection testing */ 00049 struct boxPack *isect_cache[4]; 00050 00051 int index; 00052 } boxVert; 00053 00054 /* free vert flags */ 00055 #define eps 0.0000001f 00056 #define BLF 1 00057 #define TRF 2 00058 #define TLF 4 00059 #define BRF 8 00060 #define CORNERFLAGS (BLF|TRF|TLF|BRF) 00061 00062 #define BL 0 00063 #define TR 1 00064 #define TL 2 00065 #define BR 3 00066 00067 #define BOXLEFT(b) b->v[BL]->x 00068 #define BOXRIGHT(b) b->v[TR]->x 00069 #define BOXBOTTOM(b) b->v[BL]->y 00070 #define BOXTOP(b) b->v[TR]->y 00071 #define BOXAREA(b) (b->w * b->h) 00072 00073 #define UPDATE_V34X(b) b->v[TL]->x = b->v[BL]->x;\ 00074 b->v[BR]->x = b->v[TR]->x 00075 #define UPDATE_V34Y(b) b->v[TL]->y = b->v[TR]->y;\ 00076 b->v[BR]->y = b->v[BL]->y 00077 #define UPDATE_V34(b) UPDATE_V34X(b); UPDATE_V34Y(b) 00078 00079 #define SET_BOXLEFT(b, f) b->v[TR]->x = f + b->w;\ 00080 b->v[BL]->x = f;\ 00081 UPDATE_V34X(b) 00082 #define SET_BOXRIGHT(b, f) b->v[BL]->x = f - b->w;\ 00083 b->v[TR]->x = f;\ 00084 UPDATE_V34X(b) 00085 #define SET_BOXBOTTOM(b, f) b->v[TR]->y = f + b->h;\ 00086 b->v[BL]->y = f;\ 00087 UPDATE_V34Y(b) 00088 #define SET_BOXTOP(b, f) b->v[BL]->y = f - b->h;\ 00089 b->v[TR]->y = f;\ 00090 UPDATE_V34Y(b) 00091 #define BOXINTERSECT(b1, b2)\ 00092 (!( BOXLEFT(b1)+eps>=BOXRIGHT(b2) ||\ 00093 BOXBOTTOM(b1)+eps>=BOXTOP(b2) ||\ 00094 BOXRIGHT(b1)-eps<=BOXLEFT(b2) ||\ 00095 BOXTOP(b1)-eps<=BOXBOTTOM(b2) )) 00096 00097 #define MIN2(x,y) ( (x)<(y) ? (x) : (y) ) 00098 #define MAX2(x,y) ( (x)>(y) ? (x) : (y) ) 00099 00100 /* #define BOXDEBUG(b)\ 00101 * printf("\tBox Debug i %i, w:%.3f h:%.3f x:%.3f y:%.3f\n",\ 00102 * b->index, b->w, b->h, b->x, b->y) */ 00103 00104 /* qsort function - sort largest to smallest */ 00105 static int box_areasort(const void *p1, const void *p2) 00106 { 00107 const boxPack *b1= p1, *b2= p2; 00108 const float a1= BOXAREA(b1); 00109 const float a2= BOXAREA(b2); 00110 00111 if ( a1 < a2 ) return 1; 00112 else if ( a1 > a2 ) return -1; 00113 return 0; 00114 } 00115 00116 /* qsort vertex sorting function 00117 * sorts from lower left to top right It uses the current box's width and height 00118 * as offsets when sorting, this has the result of not placing boxes outside 00119 * the bounds of the existing backed area where possible 00120 * */ 00121 static float box_width; 00122 static float box_height; 00123 static boxVert *vertarray; 00124 00125 static int vertex_sort(const void *p1, const void *p2) 00126 { 00127 boxVert *v1, *v2; 00128 float a1, a2; 00129 00130 v1 = vertarray + ((int *) p1)[0]; 00131 v2 = vertarray + ((int *) p2)[0]; 00132 00133 a1 = MAX2(v1->x+box_width, v1->y+box_height); 00134 a2 = MAX2(v2->x+box_width, v2->y+box_height); 00135 00136 /* sort largest to smallest */ 00137 if ( a1 > a2 ) return 1; 00138 else if ( a1 < a2 ) return -1; 00139 return 0; 00140 } 00141 /* Main boxpacking function accessed from other functions 00142 * This sets boxes x,y to positive values, sorting from 0,0 outwards. 00143 * There is no limit to the space boxes may take, only that they will be packed 00144 * tightly into the lower left hand corner (0,0) 00145 * 00146 * boxarray - a pre allocated array of boxes. 00147 * only the 'box->x' and 'box->y' are set, 'box->w' and 'box->h' are used, 00148 * 'box->index' is not used at all, the only reason its there 00149 * is that the box array is sorted by area and programs need to be able 00150 * to have some way of writing the boxes back to the original data. 00151 * len - the number of boxes in the array. 00152 * tot_width and tot_height are set so you can normalize the data. 00153 * */ 00154 void boxPack2D(boxPack *boxarray, const int len, float *tot_width, float *tot_height) 00155 { 00156 boxVert *vert; /* the current vert */ 00157 int box_index, verts_pack_len, i, j, k, isect; 00158 int quad_flags[4]= {BLF,TRF,TLF,BRF}; /* use for looping */ 00159 boxPack *box, *box_test; /*current box and another for intersection tests*/ 00160 int *vertex_pack_indices; /*an array of indices used for sorting verts*/ 00161 00162 if (!len) { 00163 *tot_width = 0.0f; 00164 *tot_height = 0.0f; 00165 return; 00166 } 00167 00168 /* Sort boxes, biggest first */ 00169 qsort(boxarray, len, sizeof(boxPack), box_areasort); 00170 00171 /* add verts to the boxes, these are only used internally */ 00172 vert = vertarray = MEM_mallocN( len*4*sizeof(boxVert), "boxPack Verts"); 00173 vertex_pack_indices = MEM_mallocN( len*3*sizeof(int), "boxPack Indices"); 00174 00175 for (box=boxarray, box_index=0, i=0; box_index < len; box_index++, box++) { 00176 00177 vert->blb = vert->brb = vert->tlb = 00178 vert->isect_cache[0] = vert->isect_cache[1] = 00179 vert->isect_cache[2] = vert->isect_cache[3] = NULL; 00180 vert->free = CORNERFLAGS &~ TRF; 00181 vert->trb = box; 00182 vert->index = i; i++; 00183 box->v[BL] = vert; vert++; 00184 00185 vert->trb= vert->brb = vert->tlb = 00186 vert->isect_cache[0] = vert->isect_cache[1] = 00187 vert->isect_cache[2] = vert->isect_cache[3] = NULL; 00188 vert->free = CORNERFLAGS &~ BLF; 00189 vert->blb = box; 00190 vert->index = i; i++; 00191 box->v[TR] = vert; vert++; 00192 00193 vert->trb = vert->blb = vert->tlb = 00194 vert->isect_cache[0] = vert->isect_cache[1] = 00195 vert->isect_cache[2] = vert->isect_cache[3] = NULL; 00196 vert->free = CORNERFLAGS &~ BRF; 00197 vert->brb = box; 00198 vert->index = i; i++; 00199 box->v[TL] = vert; vert++; 00200 00201 vert->trb = vert->blb = vert->brb = 00202 vert->isect_cache[0] = vert->isect_cache[1] = 00203 vert->isect_cache[2] = vert->isect_cache[3] = NULL; 00204 vert->free = CORNERFLAGS &~ TLF; 00205 vert->tlb = box; 00206 vert->index = i; i++; 00207 box->v[BR] = vert; vert++; 00208 } 00209 vert = NULL; 00210 00211 00212 /* Pack the First box! 00213 * then enter the main box-packing loop */ 00214 00215 box = boxarray; /* get the first box */ 00216 /* First time, no boxes packed */ 00217 box->v[BL]->free = 0; /* Can't use any if these */ 00218 box->v[BR]->free &= ~(BLF|BRF); 00219 box->v[TL]->free &= ~(BLF|TLF); 00220 00221 *tot_width = box->w; 00222 *tot_height = box->h; 00223 00224 /* This sets all the vertex locations */ 00225 SET_BOXLEFT(box, 0.0f); 00226 SET_BOXBOTTOM(box, 0.0f); 00227 box->x = box->y = 0.0f; 00228 00229 for (i=0; i<3; i++) 00230 vertex_pack_indices[i] = box->v[i+1]->index; 00231 verts_pack_len = 3; 00232 box++; /* next box, needed for the loop below */ 00233 /* ...done packing the first box */ 00234 00235 /* Main boxpacking loop */ 00236 for (box_index=1; box_index < len; box_index++, box++) { 00237 00238 /* These static floatds are used for sorting */ 00239 box_width = box->w; 00240 box_height = box->h; 00241 00242 qsort(vertex_pack_indices, verts_pack_len, sizeof(int), vertex_sort); 00243 00244 /* Pack the box in with the others */ 00245 /* sort the verts */ 00246 isect = 1; 00247 00248 for (i=0; i<verts_pack_len && isect; i++) { 00249 vert = vertarray + vertex_pack_indices[i]; 00250 /* printf("\ttesting vert %i %i %i %f %f\n", i, 00251 * vert->free, verts_pack_len, vert->x, vert->y); */ 00252 00253 /* This vert has a free quadrant 00254 * Test if we can place the box here 00255 * vert->free & quad_flags[j] - Checks 00256 * */ 00257 00258 for (j=0; (j<4) && isect; j++) { 00259 if (vert->free & quad_flags[j]) { 00260 switch (j) { 00261 case BL: 00262 SET_BOXRIGHT(box, vert->x); 00263 SET_BOXTOP(box, vert->y); 00264 break; 00265 case TR: 00266 SET_BOXLEFT(box, vert->x); 00267 SET_BOXBOTTOM(box, vert->y); 00268 break; 00269 case TL: 00270 SET_BOXRIGHT(box, vert->x); 00271 SET_BOXBOTTOM(box, vert->y); 00272 break; 00273 case BR: 00274 SET_BOXLEFT(box, vert->x); 00275 SET_BOXTOP(box, vert->y); 00276 break; 00277 } 00278 00279 /* Now we need to check that the box intersects 00280 * with any other boxes 00281 * Assume no intersection... */ 00282 isect = 0; 00283 00284 if (/* Constrain boxes to positive X/Y values */ 00285 BOXLEFT(box)<0.0f || BOXBOTTOM(box) < 0.0f || 00286 /* check for last intersected */ 00287 ( vert->isect_cache[j] && 00288 BOXINTERSECT(box, vert->isect_cache[j]) ) 00289 ) { 00290 /* Here we check that the last intersected 00291 * box will intersect with this one using 00292 * isect_cache that can store a pointer to a 00293 * box for each quadrant 00294 * big speedup */ 00295 isect = 1; 00296 } else { 00297 /* do a full search for colliding box 00298 * this is really slow, some spacialy divided 00299 * data-structure would be better */ 00300 for (box_test=boxarray; box_test != box; box_test++) { 00301 if BOXINTERSECT(box, box_test) { 00302 /* Store the last intersecting here as cache 00303 * for faster checking next time around */ 00304 vert->isect_cache[j] = box_test; 00305 isect = 1; 00306 break; 00307 } 00308 } 00309 } 00310 00311 if (!isect) { 00312 00313 /* maintain the total width and height */ 00314 (*tot_width) = MAX2(BOXRIGHT(box), (*tot_width)); 00315 (*tot_height) = MAX2(BOXTOP(box), (*tot_height)); 00316 00317 /* Place the box */ 00318 vert->free &= ~quad_flags[j]; 00319 00320 switch (j) { 00321 case TR: 00322 box->v[BL]= vert; 00323 vert->trb = box; 00324 break; 00325 case TL: 00326 box->v[BR]= vert; 00327 vert->tlb = box; 00328 break; 00329 case BR: 00330 box->v[TL]= vert; 00331 vert->brb = box; 00332 break; 00333 case BL: 00334 box->v[TR]= vert; 00335 vert->blb = box; 00336 break; 00337 } 00338 00339 /* Mask free flags for verts that are 00340 * on the bottom or side so we don't get 00341 * boxes outside the given rectangle ares 00342 * 00343 * We can do an else/if here because only the first 00344 * box can be at the very bottom left corner */ 00345 if (BOXLEFT(box) <= 0) { 00346 box->v[TL]->free &= ~(TLF|BLF); 00347 box->v[BL]->free &= ~(TLF|BLF); 00348 } else if (BOXBOTTOM(box) <= 0) { 00349 box->v[BL]->free &= ~(BRF|BLF); 00350 box->v[BR]->free &= ~(BRF|BLF); 00351 } 00352 00353 /* The following block of code does a logical 00354 * check with 2 adjacent boxes, its possible to 00355 * flag verts on one or both of the boxes 00356 * as being used by checking the width or 00357 * height of both boxes */ 00358 if (vert->tlb && vert->trb && 00359 (box == vert->tlb || box == vert->trb)) { 00360 if (vert->tlb->h > vert->trb->h) { 00361 vert->trb->v[TL]->free &= ~(TLF|BLF); 00362 } else if (vert->tlb->h < vert->trb->h) { 00363 vert->tlb->v[TR]->free &= ~(TRF|BRF); 00364 } else { /*same*/ 00365 vert->tlb->v[TR]->free &= ~BLF; 00366 vert->trb->v[TL]->free &= ~BRF; 00367 } 00368 } else if (vert->blb && vert->brb && 00369 (box == vert->blb || box == vert->brb)) { 00370 if (vert->blb->h > vert->brb->h) { 00371 vert->brb->v[BL]->free &= ~(TLF|BLF); 00372 } else if (vert->blb->h < vert->brb->h) { 00373 vert->blb->v[BR]->free &= ~(TRF|BRF); 00374 } else { /*same*/ 00375 vert->blb->v[BR]->free &= ~TRF; 00376 vert->brb->v[BL]->free &= ~TLF; 00377 } 00378 } 00379 /* Horizontal */ 00380 if (vert->tlb && vert->blb && 00381 (box == vert->tlb || box == vert->blb) ) { 00382 if (vert->tlb->w > vert->blb->w) { 00383 vert->blb->v[TL]->free &= ~(TLF|TRF); 00384 } else if (vert->tlb->w < vert->blb->w) { 00385 vert->tlb->v[BL]->free &= ~(BLF|BRF); 00386 } else { /*same*/ 00387 vert->blb->v[TL]->free &= ~TRF; 00388 vert->tlb->v[BL]->free &= ~BRF; 00389 } 00390 } else if ( vert->trb && vert->brb && 00391 (box == vert->trb || box == vert->brb) ) { 00392 if (vert->trb->w > vert->brb->w) { 00393 vert->brb->v[TR]->free &= ~(TRF|TRF); 00394 } else if (vert->trb->w < vert->brb->w) { 00395 vert->trb->v[BR]->free &= ~(BLF|BRF); 00396 } else { /*same*/ 00397 vert->brb->v[TR]->free &= ~TLF; 00398 vert->trb->v[BR]->free &= ~BLF; 00399 } 00400 } 00401 /* End logical check */ 00402 00403 00404 for (k=0; k<4; k++) { 00405 if (box->v[k] != vert) { 00406 vertex_pack_indices[verts_pack_len] = 00407 box->v[k]->index; 00408 verts_pack_len++; 00409 } 00410 } 00411 /* The Box verts are only used internally 00412 * Update the box x and y since thats what external 00413 * functions will see */ 00414 box->x = BOXLEFT(box); 00415 box->y = BOXBOTTOM(box); 00416 } 00417 } 00418 } 00419 } 00420 } 00421 00422 /* free all the verts, not really needed because they shouldn't be 00423 * touched anymore but accessing the pointers would crash blender */ 00424 for (box_index=0; box_index < len; box_index++) { 00425 box = boxarray+box_index; 00426 box->v[0] = box->v[1] = box->v[2] = box->v[3] = NULL; 00427 } 00428 MEM_freeN(vertex_pack_indices); 00429 MEM_freeN(vertarray); 00430 } 00431