2

Hey we are facing a space utilization problem or I am not clear what name I should give to problem.

Basically its a mesh problem.

I have tried to explain my problem using an image.

enter image description here

Problem statement is somewhat like below.

  1. The box with the diagonal line is an item which has to be distributed in best proportion such as it should fit in all available container.
  2. Containers are shown in different colors.
  3. Now all containers will be in rectangle shape.
  4. All containers has to be placed either in portrait mode or in landscape mode.

Both containers and item can be measured in width and height, for program they are pixels basically.

Based on comments of fellow members,Spektre and Lasse V. Karlsen here are the clarification on the same

  1. It's a 2D arrangement
  2. Yes we can rearrange the containers to achieve the best possible pattern.
  3. No part of item should be in blank space. Item has to be a part of any container.
  4. Item can overlap the container, and height and width can be vary from container to container. And Item's height width can also vary, but shape will remain rectangle always.
  5. Location of Item is preferable if it sticks to top-left.
  6. Yes it is somewhat like bin packing algorithm, but only problem with that algorithm is , in Bin packing items are more and container is one, in our case item is one and containers are more. So basically its a distribution problem.
  7. Idea is the problem actually that we have the size of the container and need to place the containers so that we can create that rectangle.

The program should give following output

  1. Position of the container
  2. Part of item the container has inside.
  3. And Arrangement pattern.
10
  • Just some question for better understanding: is it 2D? 2.you want to rearrange containers (not just single container) to achieve: that 1. no part of item is in blank space, 2. item is overlapping all of the containers 3. what is the preferred container coverage? (on image item can be shifted a bit in each direction so what is the best location or it does not matter?) ... btw looks like some special case of bin packing problem How many containers there will be used? Commented Jan 23, 2015 at 9:39
  • Define "fit". Do you mean you want the largest surface area of a rectangle that can be placed inside the area covered by the other containers? Does it have to overlap all of them or is surface area the biggest concern? Do you have some width/height ratio that needs to be maintained? Commented Jan 23, 2015 at 9:46
  • Are the container rectangles placed already, or is the problem actually that you have the size of the container and need to place the containers so that you can create that rectangle? You need to specify more of the criteria and allowed operations here. Commented Jan 23, 2015 at 9:47
  • I modified the question and accommodate your queries guys. You understood my problem in correct manner. Commented Jan 23, 2015 at 10:01
  • so the Item does not need to overlap all of the containers? it is sufficient that it fits inside some of them ... I would start with rearranging containers to meet inscribed rectangle area size. find which axis is the worst to achieve and strat constructing from it ... Commented Jan 23, 2015 at 10:49

1 Answer 1

1

here something unsophisticated unoptimal but easy as a start point

  • Based on mine comments
  • exploiting common container size 480px

Algorithm:

  1. rotate all containers (bins) to get 480 height
  2. sort bins by width after rotation descending
  3. need ceil(1080/480)=3 lines of 480px bins
  4. use the widest bins to fill all the lines but never crossing 1920px

    • they are sorted so use the first ones
    • all used ones mark as used
    • use only unused bins
  5. arrange rest of the bins to lines (goes to the shortest line)

    • so take unused bins
    • determine which line is shortest
    • if the shortest line is already 1920px wide or more then stop
    • if not move the bin to that line and mark it as used

C++ source code (ugly static allocation but simple and no lib used):

//---------------------------------------------------------------------------
struct _rec { int x,y,xs,ys,_used; };
_rec bin[128],item; int bins=0;
//---------------------------------------------------------------------------
void bin_generate(int n)    // generate problem
    {
    int i;
    Randomize();
    item.x=0;
    item.y=0;
    item.xs=1920;
    item.ys=1080;
    for (bins=0;bins<n;bins++)
        {
        bin[bins].x=0;
        bin[bins].y=0;
        i=Random(2);
             if (i==0) { bin[bins].xs=320; bin[bins].ys=480; }
        else if (i==1) { bin[bins].xs=480; bin[bins].ys=800; }
        else i=i;
//      if (i==2) { bin[bins].xs=1920; bin[bins].ys=1080; }
        }
    }
//---------------------------------------------------------------------------
void bin_solve()            // try to solve problem
    {
    int i,e,n,x,y,x0[128],y0[128],common=480;
    _rec *r,*s,t;

    // rotate bins to ys=480
    for (r=bin,i=0;i<bins;i++,r++) if (r->xs==common) { x=r->xs; r->xs=r->ys; r->ys=x; }
    // sort bins by xs desc
    for (e=1;e;) for (e=0,r=bin,s=r+1,i=1;i<bins;i++,r++,s++) if (r->xs<s->xs) { t=*r; *r=*s; *s=t; e=1; }
    // prepare lines needed ... n is num of lines, _rest is one common side height line is needed to add
    n=item.ys/common; if (item.ys%common) n++; item.x=0; item.y=0;
    for (i=0;i<n;i++) { x0[i]=0; y0[i]=common*i; }
    for (r=bin,i=0;i<bins;i++,r++) r->_used=0;
    // arrange wide bins to lines
    for (e=0;e<n;e++)
     for (r=bin,i=0;i<bins;i++,r++)
      if (!r->_used)
       if (x0[e]+r->xs<=item.xs)
        {
        r->x=x0[e];
        r->y=y0[e];
        r->_used=1;
        x0[e]+=r->xs;
        if (x0[e]>=item.xs) break;
        }
    // arrange rest bins to lines (goes to the shortest line)
     for (r=bin,i=0;i<bins;i++,r++)
      if (!r->_used)
        {
        // find shortest line
        for (e=0,x=0;x<n;x++) if (x0[e]>x0[x]) e=x;
        // stop if shortest line is already wide enough
        if (x0[e]>=item.xs) break;
        // fit the bin in it
        r->x=x0[e];
        r->y=y0[e];
        r->_used=1;
        x0[e]+=r->xs;
        }
    // arrange the unused rest below
    for (x=0,y=n*common+40,r=bin,i=0;i<bins;i++,r++) if (!r->_used) { r->x=x; r->y=y; x+=r->xs; }
    }
//---------------------------------------------------------------------------

Usage:

  • bin_generate(7); // generate n random devices to bin[bins] array of rectangles
  • bin_solve(); // try to solve problem ... just rearrange the bin[bins] values
  • example
  • this is not optimal but with some tweaks could be enough
  • for example last 2 lines need 600px of height together so if you have devices at that size or closely larger you can use them to fill the 2 last lines as 1 line ...
  • if not then may be some graph or tree approach will be better (due to low container count)

[Edit1] universal sizes

when you have not guarantied fixed common container size then you have to compute it instead...

//---------------------------------------------------------------------------
struct _rec { int x,y,xs,ys,_used;      _rec(){}; _rec(_rec& a){ *this=a; }; ~_rec(){}; _rec* operator = (const _rec *a) { *this=*a; return this; }; /*_rec* operator = (const _rec &a) { ...copy... return this; };*/ };
List<_rec> bin,bintype;
_rec item;
//---------------------------------------------------------------------------
void bin_generate(int n)    // generate problem
    {
    int i;
    _rec r;
    Randomize();
    // target resolution
    item.x=0; item.xs=1920;
    item.y=0; item.ys=1080;
    // all used device sizes in portrait start orientation
    bintype.num=0; r.x=0; r.y=0; r._used=0;
    r.xs= 320; r.ys= 480; bintype.add(r);
    r.xs= 480; r.ys= 800; bintype.add(r);
    r.xs= 540; r.ys= 960; bintype.add(r);
//  r.xs=1080; r.ys=1920; bintype.add(r);
    // create test case
    bin.num=0; for (i=0;i<n;i++) bin.add(bintype[Random(bintype.num)]);
    }
//---------------------------------------------------------------------------
void bin_solve()            // try to solve problem
    {
    int i,j,k,e,x,y;
    _rec *r,s;
    List<int> hsiz,hcnt;    // histogram of sizes
    List< List<int> > lin;  // line of bins with common size
    // compute histogram of sizes
    hsiz.num=0; hcnt.num=0;
    for (r=bin.dat,i=0;i<bin.num;i++,r++)
        {
        x=r->xs; for (j=0;j<hsiz.num;j++) if (x==hsiz[j]) { hcnt[j]++; j=-1; break; } if (j>=0) { hsiz.add(x); hcnt.add(1); }
        x=r->ys; for (j=0;j<hsiz.num;j++) if (x==hsiz[j]) { hcnt[j]++; j=-1; break; } if (j>=0) { hsiz.add(x); hcnt.add(1); }
        }
    // sort histogram by cnt desc (most occurent sizes are first)
    for (e=1;e;) for (e=0,j=0,i=1;i<hsiz.num;i++,j++) if (hcnt[j]<hcnt[i])
        {
        x=hsiz[i]; hsiz[i]=hsiz[j]; hsiz[j]=x;
        x=hcnt[i]; hcnt[i]=hcnt[j]; hcnt[j]=x; e=1;
        }
    // create lin[][]; with ys as common size (separate/rotate bins with common sizes from histogram)
    lin.num=0;
    for (r=bin.dat,i=0;i<bin.num;i++,r++) r->_used=0;
    for (i=0;i<hsiz.num;i++)
        {
        lin.add(); lin[i].num=0; x=hsiz[i];
        for (r=bin.dat,j=0;j<bin.num;j++,r++)
            {
            if ((!r->_used)&&(x==r->xs)) { lin[i].add(j); r->_used=1; y=r->xs; r->xs=r->ys; r->ys=y; }
            if ((!r->_used)&&(x==r->ys)) { lin[i].add(j); r->_used=1; }
            }
        }
    for (i=0;i<lin.num;i++) if (!lin[i].num) { lin.del(i); i--; }
    // sort lin[][] by xs desc (widest bins are first)
    for (i=0;i<lin.num;i++)
     for (e=1;e;) for (e=0,k=0,j=1;j<lin[i].num;j++,k++)
      if (bin[lin[i][k]].xs<bin[lin[i][j]].xs)
        { s=bin[lin[i][j]]; bin[lin[i][j]]=bin[lin[i][k]]; bin[lin[i][k]]=s; e=1; }
    // arrange lines to visually check previous code (debug) ... and also compute the total line length (width)
    for (y=item.ys+600,i=0;i<lin.num;i++,y+=r->ys) for (x=0,j=0;j<lin[i].num;j++) { r=&bin[lin[i][j]]; r->x=x; r->y=y; x+=r->xs; }
    for (i=0;i<lin.num;i++)
        {
        j=lin[i][lin[i].num-1];                         // last bin in line
        hsiz[i]=bin[j].x+bin[j].xs;                     // total width
        hcnt[i]=bin[j].ys;                              // line height
        }
    // now compute solution
    for (r=bin.dat,i=0;i<bin.num;i++,r++) r->_used=0;   // reset usage first
    for (y=0,k=1,i=0;i<lin.num;i++)                     // process lines with common size
     while(hsiz[i]>=item.xs)                            // stop if line shorter then needed
        {
        x=0;
        // arrange wide bins to line
        for (j=0;j<lin[i].num;j++)
            {
            r=&bin[lin[i][j]];
            if ((!r->_used)&&(x+r->xs<=item.xs))
                {
                r->x=x; hsiz[i]-=x; x+=r->xs;
                r->y=y; r->_used=k;
                if (x>=item.xs) break;
                }
            }
        // arrange short bins to finish line
        if (x<item.xs)
         for (j=lin[i].num-1;j>=0;j--)
            {
            r=&bin[lin[i][j]];
            if (!r->_used)
                {
                r->x=x; hsiz[i]-=x; x+=r->xs;
                r->y=y; r->_used=k;
                if (x>=item.xs) break;
                }
            }
        // remove unfinished line
        if (x<item.xs)
            {
            for (j=0;j<lin[i].num;j++)
                {
                r=&bin[lin[i][j]];
                if (r->_used==k)
                    {
                    r->x=0; r->y=0;
                    r->_used=0;
                    hsiz[i]+=r->xs;
                    }
                }
            break;
            }
        // next line
        y+=hcnt[i];
        if (y>=item.ys) break;  // solution found already?
        }
    // rotate unused rest to have ys>=as needed but as wide as can be to form last line
    e=item.ys-y; x=0;
    if (e>0) for (r=bin.dat,i=0;i<bin.num;i++,r++)
     if (!r->_used)
        {
        if ((r->xs<e)&&(r->ys<e)) continue; // skip too small bins
        if (r->xs<r->ys) { j=r->xs; r->xs=r->ys; r->ys=j; }
        if (r->ys<    e) { j=r->xs; r->xs=r->ys; r->ys=j; }
        r->x=x; x+=r->xs;
        r->y=y; r->_used=1;
        }
    }
//---------------------------------------------------------------------------
  • it is almost the same as before but prior to solution histogram of container sizes is computed
  • choose most occurent ones and form groups of compatible bins (containers)
  • then apply the algorithm ...
  • I added usage of dynamic array template List<> because on static allocation I would go mad before writing this ...
  • List<int> x; is the same as int x[];
  • x.num is the number of items inside x[]
  • x.add() adds new item to end of x[]
  • x.add(q) adds new item = q to end of x[]
  • x.del(i) deletes i-th item from x[] ... indexing is from zero
  • so rewrite to what ever you use instead ...
  • List< List<int> > y; is 2D array y[][] ...
  • at last form last line from unused bins ...
  • This is not robust nor safe but it mostly works (it need some tweaking but I am too lazy for that)
  • the solution depends also on the input set order so you can find more solutions for the same input set if you shuffle it a bit ... (if some common sizes has the same count)

example2

Sign up to request clarification or add additional context in comments.

11 Comments

Looks very potential thing, I am definitely gonna try this today. Will let you know if this solved my problem and also in case of any query. Many thanks
Meanwhile we can not assume that 480 is a common container size. It can be 540(w) x 960(h) also.
@HardikTrivedi you should create few test scenarios due to low count of devices is hard to create valid random device sets so a real input case will be a good idea to share
@ spektre Hey I am still working on your approach, can u tell me what for (y=item.ys+600,i=0;i<lin.num;i++,y+=r->ys) means ??? Why we keep 600 for addition ?
@HardikTrivedi that was just to place the sorted groups bellow item as lines to check if the grouping and sorting code above it works does not matter for solution ... (it is a leftover from the start of coding when solution was not yet coded) the only thing used from it now is the computation of total line/group length to see if is enough devices to form a line inside item... my solution is at x=0,y=0 to avoid some ifs ... so in my test case 600px below item was enough space to not overlap with solution
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.