Populate rooftop avoiding obstacles

Hello everyone. I am fairly new to Dynamo and I am trying to figure out a way of automatically populating a parametric roof I created with PV panels.
I have more or less the idea of what I have to do, but not the knowledge of how to implement it. So I have a roof with some kind of obstacle (any geometry I add on the surface - HVAC or exhausters) on it and what I would like to happen is that the script automatically creates the biggest rectangle possible on the roof avoiding the obstacle(s), and within that rectangle, add the maximum number of smaller geometries representing the PV panels.

That’s more or less a diagram of what I would like to happen:

Any direction on how to proceed would be greatly appreciated!

Thank you,


I suspect you want to look at ‘Bin Packing’ here’s a link which discusses some options…

Though if your example is as simple as you describe ie. a rectangle with some other rectangles… It’s possible you could extract the roof geometry, subtract the clash cuboid, use the void edges to split the roof into rectangles and populate those with your grid of PV rectangles?

Hopefully that is useful,



Hello Mark,

Thank you so much for your comment. It actually helped me get started with this script.
So yes, everything is meant to be really simple since I am moving from Rhino GH to Dynamo and I am still learning the basics.
From the information I got from your comment, I started by creating my surface (my roof geometry), adding points + circles to my geometry to represent the ‘obstacles’, and then subtracting them (I selected only two of them to subtract).
This is the result:

But I am kind of lost on the next steps… How can I use the void edges to split the surface roof? Ideally now, I would like to split the roof into two sides, the left and right side of the clash cuboid, and select the bigger side to populate with my PV rectangles.
(https://1drv.ms/u/s!AlORhB2zZdFxgptQ1ZfZtQSWNBCqjQ?e=3pc6AU) link with my really basic script, I cant upload files into this forum yet.

Again, thank you so much for your help. This forum is proving fundamental to my learning experience!


Just an idea, but how about if you create a rectangle instead of a circle? Perhaps you could extract the sides and extend those until they hit the edge of the roof? The created sub-rectangles might be useful?

I guess an alternative method might be to create a grid across the roof and check whether the ‘circles’ intersect each grid square? that would maybe let you build a yes / no kind of option for whether a PV could live there?

Sorry I can’t be of more help, it’s not my specialism! :slight_smile:



I wouldn’t use a solid here - stick to the abstracted surface instead. Simpler shapes process faster and are more comprehend-able.

Generally speaking it helps to sketch the steps you want to take when building a geometric process. I personally prefer the sketchbook app on my iPad for this as it has a recording feature to generate a video which thereby captures my sequence so I know what has to happen in what order, but any sketching tool will do.

I’d go a similar route to @Mark.Ackerley, but you needn’t limit yourself to orthogonal penetrations - just build the shape you want. My thoughts on how that might be managed are in the collapsed list below:

Possible Process
  • First I’d shift my surface (not an entire solid) to be as close to orthogonaly aligned as possible. Read the vectors of each edge, take the average, and rotate the form by the angles formed with the global X axis (if you’re already orthogonal you’ll rotate by 0). No need to ‘flatten’ this - you won’t gain any added speed in doing so. This will allow you to utilize bounding boxes for the other shapes, which will quickly ‘square things off’.

  • Next pull the perimeter curves from the rotated surface, and group them. I believe that there is a handy node in archi-lab package for this called “Group Curves”. Turn each of the groups into a polycurve, which will represent the ‘perimeter polygon’, and all the interior obstruction polygons.

  • Sort the polycurves by the inverse of the area of the surface formed by each, so that the ‘largest’ polycurve (the one which contains all the rest) is the first item in the list. List.SortByKey will help here - remember you want to sort the polycurves not the surfaces or their areas). Then use a List.Deconstruct to pull the ‘surface’ out from the list of obstructions.

  • Build a bounding box for each of the obstrucitons (Boundingbox.ByGeometry), convert the Bounding Boxes into a solid (Boundingbox.ToCuboid), and then merge the solids into one with a Solid.ByUnion node.

  • Build a surface from the roof polycurve (the one which was taken out with the deconstruct), and remove the combined solid from the roof surface. Pull the vertices from the surface (Topology.Vertices) a get the associated point geometry. Convert the points to UV parameters (Surface.UVParameterAtPoint), and pull the U and V values into lists (UV.U and UV.V). Get the unique UV values (List.Unique) and use those create two lists of Isocurves (Curve.ByIsoCurveOnSurface node) on the U and V axis.

  • Extrude each group of Isocurves on the Z axis to create a group of surfaces, and combine them into two polysurfaces (one for the U axis, and one for the V). Split the roof surface with the obstruction voids (previous paragraph) using the U, and the the V polysurfaces. You now have a series of rectangles which make up the larger rectangle.

  • The next step will be the hard part - I recommend looking into the use of topology to get adjacent ‘sets’ of rectangular cells from the matrix. Face.AdjacentEdges and Edge.AdjacentFaces will help here - use of that on cell X will get you the four adjacent Cells, if they exist. Where there is an obstruction you won’t have a face. Remember that to use all four faces on a cell you need to catch the corner as well. In the matrix of [ [1,2,3], [4,X,6], [7,8,9] ], where X is the ‘starting’ cell, you need to gather 9 if you gather both 6 and 8 - if 9 doesn’t exist, you’re no longer a rectangle, but an L and you should go with the larger of the two (6 or 8), and try to capture 2 or 4 with it to maximize area. Generative design might help you quickly iterate this if you’re struggling with ensuring you ‘grab the biggest possible’ due to iterations.

  • Once you have the combination sets you’ll want to generate a bounding box of the shape, convert that into a cuboid, and intersect the cuboid with the complete (no-voids) roof surface to get a rectangle.That rectangle can act as a host for your solar panels, (coordinate system at parameter), which can then be rotated into position by using the inverse of the angle from the first bullet point.

What may feels like a simple task by hand is in no way simple - this is because our brains are quite adept at solving this stuff as we have a TON of practice. We start the ‘make the shape fit in the opening’ very early, and we learn over time, well usually) and the number of edge cases for a task like this is very high. Hopefully your grasshopper background has prepared you a good bit and the terms I used above aren’t too foreign. While it’s ambitious, it will prepare you to do some really high level stuff and can pay dividends.