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?
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?
Two options are below.
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.
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.
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.
Thanks for your reply, if this option need design script
I invite design script leader @Vikram_Subbaiah to help me for that
Will certainly contribute if I can, but as @jacob.small 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.
I may fold a similar exercise into a coming webinar. If so I will drop a definition which could get you started later.
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.
Wizardry. I stand corrected - glad to see someone proposed an option 3!
Awesome, Jacob
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];
Thanks @jacob.small
Thanks @Vikram_Subbaiah
Wow it’s very useful
Another Pythonic alternative
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])
Nice use of bounding boxes.
Now i have 3 option
Wow, awesome community here
cool!
Another approach would be to start from the outer rectangle and randomly subdivide in two along the biggest dimension ( vertically or horizontally, with a random radio between 0.3 and 0.7 imho to get good results).
Repeat this step iteratively on the two resulting rectangles. The stopping could be for example if the resulting rectangles areas are smaller than the root’s area multiplied by a given threshold < 1.
Then keep only those last rectangles. The number of final rectangles would be pair but you could change the stopping criterion if this is an issue…
Hey everyone,
I am new to python and especiallywithin the Revit scope.
I watched some videos but for some reason could not get this definition to work and it is the perfect script for what I am doing.
Can somebody help??
I keep getting “IN” expected
@Vikram_Subbaiah do you have any suggestions?
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];
};
This isn’t working as it isn’t Python but design script. Double click in the canvas to place a code block, and past the code I posted above into the text editor there.