Create number of random rectangles inside bigger outer rectangle without intersect each other

If I have an outer rectangle and need to create some of the small inner rectangles by random without intersecting each other

what is the best workflow to do that?

Inner rectangles inside outer bigger rectangle

Two options are below.

  1. Make it pseudorandom. Divide your surface into a 2 way grid and inset boxes in each cell by random ranges. This means no rectangle could overlap as they are bound to their cell.

  2. Use Python and a while loop to generate shapes iteratively and test for intersections each time. If one occurs omit it from the results and keep the loop going until a desired number of rectangles are made. Quite complex and dangerous assuming you ask for too many rectangles to fit. Make sure to use an overload counter concurrently ro set a maximum number of iterations to run.

If 2 doesn’t make any sense I’d focus on 1 as it can be done without Python.

2 Likes

One need not use Python, but imperative Design Script would be a pre-req for the alternative.

You could also use some bin packing nodes followed up with a light relaxation algorithm to space them out. Without seeing the base inputs and constraints it is tough to give better guidance though.

3 Likes

Thanks for your reply, if this option need design script

I invite design script leader @Vikram_Subbaiah to help me for that :blush:

1 Like

Will certainly contribute if I can, but as @JacobSmall suggested above, you will need to outline the goal better. Providing some context and samples of your attempts will help the rest of us understand your objective.

2 Likes

I may fold a similar exercise into a coming webinar. If so I will drop a definition which could get you started later.

1 Like

Something to try:


def populateRectangles (srf,count)
 {
    rectangles = [Imperative]
    {
        attempts = 0;
        results = [];
        while (DSCore.List.Count(results) < count && attempts < 10)
        {
            attempts = attempts +1;

            csSet =
               Surface.CoordinateSystemAtParameter(
                    srf,
                    Math.RandomList(count),
                    Math.RandomList(count)
                );

            rects =
                Rectangle.ByWidthLength(
                    Math.RandomList(count/2),
                    Math.RandomList(count/2)
                );

            rects =
                Surface.ByPatch(
                    Geometry.Transform(
                        rects,
                        csSet
                    )
                );
            rects = DSCore.List.Join([results, rects]);

            set = [];
            for (i in0..DSCore.List.Count(rects))
            {
                set =
List.AllFalse(Geometry.DoesIntersect(rects[i],set))?
                        DSCore.List.Join([set,rects[i]]):
                        set;

            };

            results = set;
        };
return = results;
        rectangles = Geometry.Intersect(rects,srf);
    };
    rectSet = DSCore.List.Flatten(Geometry.Intersect(rectangles, srf),-1);
return = rectSet[0..count-1];
 };

Having some formatting errors (posting from my phone due to some internet issues), but the actual definition can be seen in this screenshot, where I placed up to 1000 rectangles in a 5x5 square.

11 Likes

Wizardry. I stand corrected - glad to see someone proposed an option 3!

1 Like

Awesome, Jacob :slight_smile:

Scaled rectangles in a grid to create this …

rectSub.dyn (11.6 KB)

// Dimensions
wdt01 = 50;
lgt01 = 50;
cnt01 = 100;

// Divisions
are01 = wdt01 * lgt01;
sqr01 = Math.Ceiling(Math.Sqrt(cnt01));
prp01 = wdt01/lgt01;
wdv01 = Math.Ceiling(sqr01*prp01);
ldv01 = Math.Ceiling(cnt01/wdv01);

// Scaled
rct00 = Rectangle.ByWidthLength(wdt01,lgt01);
rct01 = Rectangle.ByWidthLength(wdt01/wdv01,lgt01/ldv01);
rct02 = rct01.Translate((-wdt01+(wdt01/wdv01))/2,(-lgt01+(lgt01/ldv01))/2,0);
rct03 = List.Flatten(rct02.Translate((0..#wdv01..(wdt01/wdv01))<1>,(0..#ldv01..(lgt01/ldv01))<2>,0));
rnd01 = Math.RemapRange(Math.RandomList(List.Count(rct03)),0.3,0.9);
rnd02 = Math.RemapRange(Math.RandomList(List.Count(rct03)),0.3,0.9);
pln01 = Plane.ByOriginNormal(rct03.Center(),Vector.ZAxis());
rct04 = List.TakeItems(List.Shuffle(rct03.Scale(pln01,rnd01,rnd02,1)),cnt01);

// Third Dimension
rnd03 = Math.RemapRange(Math.RandomList(List.Count(rct03)),1,5);
rnd04 = Math.Ceiling(List.Chop(Math.RemapRange(Math.RandomList(List.Count(rct03)*3),0,255),List.Count(rct03)));
clr01 = Color.ByARGB(200,rnd04[0],rnd04[1],rnd04[02]);
cbd01 = rct04.ExtrudeAsSolid(rnd03);
cbd02 = GeometryColor.ByGeometryColor(cbd01,clr01);
[rct00,cbd02];
5 Likes

Thanks @JacobSmall
Thanks @Vikram_Subbaiah
Wow it’s very useful

1 Like

Another Pythonic alternative :grinning:

randomRectangle

import sys
import clr
import System
import random
import math
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('DSCoreNodes')
from DSCore import *
clr.AddReference('GeometryColor')
from Modifiers import GeometryColor

def generator(container, nbr = 1, ratioMax = 5):
    outrect = []
    bbxcont = container.BoundingBox
    minPoint = bbxcont.MinPoint
    maxPoint = bbxcont.MaxPoint
    w = maxPoint.X - minPoint.X
    h = maxPoint.Y - minPoint.Y
    minDim = minPoint.DistanceTo(maxPoint) / nbr
    minSurf = (w * h) / nbr
    i = 1
    while len(outrect) < nbr and i < 200000:
        pta = Point.ByCoordinates(random.uniform(minPoint.X, maxPoint.X ), random.uniform(minPoint.Y, maxPoint.Y ), 0)
        ptd = Point.ByCoordinates(random.uniform(pta.X, w/nbr), random.uniform(pta.Y ,h/nbr), 0.1)
        bbxCandiate = BoundingBox.ByCorners(pta, ptd)
        w1 = bbxCandiate.MaxPoint.X - bbxCandiate.MinPoint.X
        h1 = bbxCandiate.MaxPoint.Y - bbxCandiate.MinPoint.Y
        if any((x[0].Intersects(bbxCandiate)) for x in outrect) or w1 * h1 > minSurf or w1 / h1 > ratioMax or h1 / w1 > ratioMax:
            pass
        else:
            geom = bbxCandiate.ToCuboid()
            color = Color.ByARGB(255,random.randint(0,255),random.randint(0,255),random.randint(0,255))
            objColor = GeometryColor.ByGeometryColor(geom, color)
            outrect.append([bbxCandiate, objColor])
        i += 1
        pta.Dispose()
        ptd.Dispose()
    return outrect

container = IN[0]

OUT = generator(container, IN[1])
4 Likes

Nice use of bounding boxes. :slight_smile:

1 Like

Now i have 3 option :smiley:
Wow, awesome community here

2 Likes

cool!

2 Likes