# Divide a Surface in Rectangles

**URL:** <https://forum.dynamobim.com/t/divide-a-surface-in-rectangles/27681>\
**Category:** Share\
**Tags:** geometry\
**Created:** [October 26, 2018, 8:48am UTC](https://forum.dynamobim.com/t/divide-a-surface-in-rectangles/27681 "2018-10-26T08:48:06Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![mellouze](https://avatars.discourse-cdn.com/v4/letter/m/e47774/32.png) [@mellouze](https://forum.dynamobim.com/u/mellouze)\
**Post date:** [October 26, 2018, 8:48am UTC](https://forum.dynamobim.com/t/divide-a-surface-in-rectangles/27681/1 "2018-10-26T08:48:06Z")

</div>

Hello community 🙂

I wanted to share with you a quick script a did on Python that allows you to divide a given surface into rectangles, maybe this could be useful to somebody…

## Restrictions : (It is possible to remove them, but currently don’t have the time to do so, maybe i’ll do it sometime)

- The surface must be contained in one of the 3 main planes : (XY), (XZ), (YZ)
- The surface must only have edges that are parallel to one of the 2 axis of the plane it is contained in.

## Notes :

- If the surface is too detailed, you may have to wait for about a minute to get the result. The example below took about 3 seconds.

[Divide Surface in Rectangles.dyn](https://forum.dynamobim.com/uploads/short-url/cq50gFOyeSKadmqRH1Noqxarggn.dyn) (15.9 KB)

 ![2018-10-26%2010_38_47-Dynamo](https://us1.discourse-cdn.com/flex022/uploads/dynamobim/original/3X/3/5/35c2b6a4d1e0773ff889a2bf53bf20c2a9d3ef43.png) ![2018-10-26%2010_39_08-Dynamo](https://us1.discourse-cdn.com/flex022/uploads/dynamobim/original/3X/a/a/aad84604fe78f82600b04538c951ab16d5fce669.png) ![Capture5](https://us1.discourse-cdn.com/flex022/uploads/dynamobim/original/3X/1/3/13c1385fb854654ac055bc01ae10f1309586ce4b.png)

```
#Author : Mustapha ELLOUZE
#Date : 25-10-2018
#Contact : mellouze (Dynamo Forum username)

import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

surf = IN[0] #surface to divide in rectangles
polyg = IN[1] #polygon created from the surface
Xs = IN[2] #Unique and sorted X coordinates
Ys = IN[3] #Unique and sorted Y coordinates
Zs = IN[4] #Unique and sorted Zs coordinates

class Rect :
	#Class : rectangles that compose the surface
	
	def __init__ (self, u_min, u_max, v_min, v_max, w, direction):
		#Constructor : u_min,u_max,v_min and v_max are the extreme coordinates on both directions, w is the coordinate in the third direction (all extreme points share this coordinate), direction is the plane that contains the Rect
		
		self.direction = direction; #defines the direction of the Rect
		
		self.w = w; #defines the third coordinate of the Rect
		
		self.u_min = u_min;
		self.u_max = u_max;
		self.v_min = v_min;
		self.v_max = v_max;
		
		#Definition of the 4 points that define the Rect, plus the center of the Rect (pt0)
		if(direction=="X"):
			self.pt1 = Point.ByCoordinates(w,u_min,v_min);
			self.pt2 = Point.ByCoordinates(w,u_min,v_max);
			self.pt3 = Point.ByCoordinates(w,u_max,v_max);
			self.pt4 = Point.ByCoordinates(w,u_max,v_min);
			self.pt0 = Point.ByCoordinates(w,0.5*u_min+0.5*u_max,0.5*v_min+0.5*v_max);
		elif(direction == "Y"):
			self.pt1 = Point.ByCoordinates(u_min,w,v_min);
			self.pt2 = Point.ByCoordinates(u_min,w,v_max);
			self.pt3 = Point.ByCoordinates(u_max,w,v_max);
			self.pt4 = Point.ByCoordinates(u_max,w,v_min);
			self.pt0 = Point.ByCoordinates(0.5*u_min+0.5*u_max,w,0.5*v_min+0.5*v_max);
		else:
			self.pt1 = Point.ByCoordinates(u_min,v_min,w);
			self.pt2 = Point.ByCoordinates(u_min,v_max,w);
			self.pt3 = Point.ByCoordinates(u_max,v_max,w);
			self.pt4 = Point.ByCoordinates(u_max,v_min,w);
			self.pt0 = Point.ByCoordinates(0.5*u_min+0.5*u_max,0.5*v_min+0.5*v_max,w);
	
	def contenu(self, polyg):
		#Determines if the Rect is contained by a polygon
		return Polygon.ContainmentTest(polyg,self.pt0)
		
	def fusionnable(self,autre_rect):
		#Determines if two Rect can be merged, i.e. if they share exactly a side
		bool1 = (self.u_max == autre_rect.u_min or self.u_min == autre_rect.u_max) and (self.v_min == autre_rect.v_min and self.v_max == autre_rect.v_max)
		bool2 = (self.v_max == autre_rect.v_min or self.v_min == autre_rect.v_max) and (self.u_min == autre_rect.u_min and self.u_max == autre_rect.u_max)
		return (bool1 or bool2);
		
	def fusion(self, autre_rect):
		#Returns a new Rect that is the fusion of two mergeable Rect
		u_m = min(self.u_min,autre_rect.u_min);
		u_M = max(self.u_max,autre_rect.u_max);
		v_m = min(self.v_min,autre_rect.v_min);
		v_M = max(self.v_max,autre_rect.v_max);
		
		return Rect(u_m,u_M,v_m,v_M,self.w,self.direction);

#Determination of the direction of the initial surface, then compute the extreme coordinates of the axis (the chosen axis depends on the direction)
if(len(Xs)==1):
	direction = "X";
	u_min = min(Ys);
	u_max = max(Ys);
	v_min = min(Zs);
	v_max = max(Zs);
	w = Xs[0];
	u_range = Ys;
	v_range = Zs;
elif(len(Ys)==1):
	direction = "Y";
	u_min = min(Xs);
	u_max = max(Xs);
	v_min = min(Zs);
	v_max = max(Zs);
	w = Ys[0];
	u_range = Xs;
	v_range = Zs;
else:
	direction = "Z";
	u_min = min(Xs);
	u_max = max(Xs);
	v_min = min(Ys);
	v_max = max(Ys);
	w = Zs[0];
	u_range = Xs;
	v_range = Ys;	

#Creation of the initial rectangles.
liste_rect = [];

for i in range(len(u_range)-1):
	for j in range(len(v_range)-1):
		new_rect = Rect(u_range[i],u_range[i+1],v_range[j],v_range[j+1],w,direction); #creation of a Rect that might be contained in the surface
		if(new_rect.contenu(polyg)): #if it is indeed inside the surface
			liste_rect.append(new_rect); #we add it to the list
			
#Fusion of all the Rect

i = 0 #index of the Rect we are currently looking at

while(True): #Nota : please don't mess with the break statements...
	
	#Break condition : we stop if we looked to all the Rect in the list (i.e. currently looking to the last Rect)
	if(i == len(liste_rect)):
		break;
	
	rect_courant = liste_rect[i]; #Current Rect
	
	indice = -1; #Initialization of index of a potential Rect to merge with current Rect
	
	#Try to find a Rect to merge with the current rect
	for j in range(i+1,len(liste_rect)): #for each Rect in the list that is not the current rect
		if(rect_courant.fusionnable(liste_rect[j])): #if the two Rect are mergeable, we keep the index and we get out of this for loop
			indice = j;
			break;
	
	#If we did not find anything, we go to the next Rect
	if(indice==-1):
		i = i+1;
		continue;
	
	#If we did find something, we merge the two Rect and we delete the two old Rect from the list
	liste_rect[i] = rect_courant.fusion(liste_rect[j]);
	liste_rect.pop(j);
	
	#And we go back to the very first Rect (we might have created a Rect that is mergeable)
	i = 0;

#Initialisation of the output (list of all the sub-surfaces
resultat = []
for i in range(len(liste_rect)):
	resultat.append(Surface.ByPatch(PolyCurve.ByPoints([liste_rect[i].pt1,liste_rect[i].pt2,liste_rect[i].pt3,liste_rect[i].pt4], True)))
	

OUT = resultat
```

---

<div class="post-metadata">

**Author:** ![mellouze](https://avatars.discourse-cdn.com/v4/letter/m/e47774/32.png) [@mellouze](https://forum.dynamobim.com/u/mellouze)\
**Post date:** [October 30, 2018, 10:24am UTC](https://forum.dynamobim.com/t/divide-a-surface-in-rectangles/27681/2 "2018-10-30T10:24:17Z")

</div>

Hi again !

Now works with openings ! 😃 Here are the updated files. Note that this version requires the GroupCurves node made by @Konrad_K_Sobon (archi-lab package).

[Divide Surface In Rectangles.dyn](https://forum.dynamobim.com/uploads/short-url/kr8uWv7ZzfWAcxUMoAxXMwL0vou.dyn) (23.3 KB)

 ![Capture](https://us1.discourse-cdn.com/flex022/uploads/dynamobim/original/3X/4/1/41a22e364d19009e9fb6cc3bda8d4223d78e4e4d.png)

 ![2018-10-30%2011_21_18-Dynamo](https://us1.discourse-cdn.com/flex022/uploads/dynamobim/original/3X/d/9/d9bd5261a2da70a5c904999f3f6095008a8e05f1.png) ![2018-10-30%2011_21_29-Dynamo](https://us1.discourse-cdn.com/flex022/uploads/dynamobim/original/3X/6/6/66ecd7f94f0232ceb1a67d757c744096d15c6a29.png)

```
#Author : Mustapha ELLOUZE
#Date : 30-10-2018
#Contact : mellouze (Dynamo Forum username)

import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

polyg = IN[0] #polygon created from the main surface
polyg_opening = IN[1] #polygon created from the openings
Xs = IN[2] #Unique and sorted X coordinates
Ys = IN[3] #Unique and sorted Y coordinates
Zs = IN[4] #Unique and sorted Zs coordinates

class Rect :
	#Class : rectangles that compose the surface
	
	def __init__ (self, u_min, u_max, v_min, v_max, w, direction):
		#Constructor : u_min,u_max,v_min and v_max are the extreme coordinates on both directions, w is the coordinate in the third direction (all extreme points share this coordinate), direction is the plane that contains the Rect
		
		self.direction = direction; #defines the direction of the Rect
		
		self.w = w; #defines the third coordinate of the Rect
		
		self.u_min = u_min;
		self.u_max = u_max;
		self.v_min = v_min;
		self.v_max = v_max;
		
		#Definition of the 4 points that define the Rect, plus the center of the Rect (pt0)
		if(direction=="X"):
			self.pt1 = Point.ByCoordinates(w,u_min,v_min);
			self.pt2 = Point.ByCoordinates(w,u_min,v_max);
			self.pt3 = Point.ByCoordinates(w,u_max,v_max);
			self.pt4 = Point.ByCoordinates(w,u_max,v_min);
			self.pt0 = Point.ByCoordinates(w,0.5*u_min+0.5*u_max,0.5*v_min+0.5*v_max);
		elif(direction == "Y"):
			self.pt1 = Point.ByCoordinates(u_min,w,v_min);
			self.pt2 = Point.ByCoordinates(u_min,w,v_max);
			self.pt3 = Point.ByCoordinates(u_max,w,v_max);
			self.pt4 = Point.ByCoordinates(u_max,w,v_min);
			self.pt0 = Point.ByCoordinates(0.5*u_min+0.5*u_max,w,0.5*v_min+0.5*v_max);
		else:
			self.pt1 = Point.ByCoordinates(u_min,v_min,w);
			self.pt2 = Point.ByCoordinates(u_min,v_max,w);
			self.pt3 = Point.ByCoordinates(u_max,v_max,w);
			self.pt4 = Point.ByCoordinates(u_max,v_min,w);
			self.pt0 = Point.ByCoordinates(0.5*u_min+0.5*u_max,0.5*v_min+0.5*v_max,w);
	
	def contenu(self, polyg, polyg_opn):
		#Determines if the Rect is contained in the surface
		result = Polygon.ContainmentTest(polyg,self.pt0)
		for i in range(len(polyg_opn)):
			result = result and (not (Polygon.ContainmentTest(polyg_opn[i],self.pt0)))
		return result
		
	def fusionnable(self,autre_rect):
		#Determines if two Rect can be merged, i.e. if they share exactly a side
		bool1 = (self.u_max == autre_rect.u_min or self.u_min == autre_rect.u_max) and (self.v_min == autre_rect.v_min and self.v_max == autre_rect.v_max)
		bool2 = (self.v_max == autre_rect.v_min or self.v_min == autre_rect.v_max) and (self.u_min == autre_rect.u_min and self.u_max == autre_rect.u_max)
		return (bool1 or bool2);
		
	def fusion(self, autre_rect):
		#Returns a new Rect that is the fusion of two mergeable Rect
		u_m = min(self.u_min,autre_rect.u_min);
		u_M = max(self.u_max,autre_rect.u_max);
		v_m = min(self.v_min,autre_rect.v_min);
		v_M = max(self.v_max,autre_rect.v_max);
		
		return Rect(u_m,u_M,v_m,v_M,self.w,self.direction);

#Determination of the direction of the initial surface, then compute the extreme coordinates of the axis (the chosen axis depends on the direction)
if(len(Xs)==1):
	direction = "X";
	w = Xs[0];
	u_range = Ys;
	v_range = Zs;
elif(len(Ys)==1):
	direction = "Y";
	w = Ys[0];
	u_range = Xs;
	v_range = Zs;
else:
	direction = "Z";
	w = Zs[0];
	u_range = Xs;
	v_range = Ys;	

#Creation of the initial rectangles.
liste_rect = [];

for i in range(len(u_range)-1):
	for j in range(len(v_range)-1):
		new_rect = Rect(u_range[i],u_range[i+1],v_range[j],v_range[j+1],w,direction); #creation of a Rect that might be contained in the surface
		if(new_rect.contenu(polyg, polyg_opening)): #if it is indeed inside the surface
			liste_rect.append(new_rect); #we add it to the list
			
#Fusion of all the Rect

i = 0 #index of the Rect we are currently looking at

while(True): #Nota : please don't mess with the break statements...
	
	#Break condition : we stop if we looked to all the Rect in the list (i.e. currently looking to the last Rect)
	if(i == len(liste_rect)):
		break;
	
	rect_courant = liste_rect[i]; #Current Rect
	
	indice = -1; #Initialization of index of a potential Rect to merge with current Rect
	
	#Try to find a Rect to merge with the current rect
	for j in range(i+1,len(liste_rect)): #for each Rect in the list that is not the current rect
		if(rect_courant.fusionnable(liste_rect[j])): #if the two Rect are mergeable, we keep the index and we get out of this for loop
			indice = j;
			break;
	
	#If we did not find anything, we go to the next Rect
	if(indice==-1):
		i = i+1;
		continue;
	
	#If we did find something, we merge the two Rect and we delete the two old Rect from the list
	liste_rect[i] = rect_courant.fusion(liste_rect[j]);
	liste_rect.pop(j);
	
	#And we go back to the very first Rect (we might have created a Rect that is mergeable)
	i = 0;

#Initialisation of the output (list of all the sub-surfaces
resultat = []
for i in range(len(liste_rect)):
	resultat.append(Surface.ByPatch(PolyCurve.ByPoints([liste_rect[i].pt1,liste_rect[i].pt2,liste_rect[i].pt3,liste_rect[i].pt4], True)))
	

OUT = resultat

```

**GroupCurves** Script :

```
#Copyright(c) 2015, Konrad Sobon
# @arch_laboratory, http://archi-lab.net

import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

#The inputs to this node will be stored as a list in the IN variable.
dataEnteringNode = IN

inputCurves = IN[0]

#join/group curves function
def groupCurves(Line_List): 
	ignore_distance = 0.1 # Assume points this close or closer to each other are touching 
	Grouped_Lines = [] 
	Queue = set() 
	while Line_List: 
		Shape = [] 
		Queue.add(Line_List.pop()) # Move a line from the Line_List to our queue 
		while Queue: 
			Current_Line = Queue.pop() 
			Shape.append(Current_Line) 
			for Potential_Match in Line_List: 
				Points = (Potential_Match.StartPoint, Potential_Match.EndPoint)
				for P1 in Points: 
					for P2 in (Current_Line.StartPoint, Current_Line.EndPoint): 
						distance = P1.DistanceTo(P2) 
						if distance <= ignore_distance: 
							Queue.add(Potential_Match) 
			Line_List = [item for item in Line_List if item not in Queue]
		Grouped_Lines.append(Shape) 
	return Grouped_Lines

OUT = groupCurves(inputCurves)
```

---

<div class="post-metadata">

**Author:** ![NoamR](https://avatars.discourse-cdn.com/v4/letter/n/b5a626/32.png) [@NoamR](https://forum.dynamobim.com/u/NoamR)\
**Post date:** [April 3, 2019, 11:32am UTC](https://forum.dynamobim.com/t/divide-a-surface-in-rectangles/27681/3 "2019-04-03T11:32:27Z")

</div>

Hi Mellouze!  
Just wanted to say I used your code (and modified it a little to only connect rectangle right on top of each other.)  
This is brilliant, thank you!!  
Uploading my edited code here if someone wants to check it out in future:

> **My Code**
>
> #Author : Mustapha ELLOUZE  
> #Date : 25-10-2018  
> #Contact : mellouze (Dynamo Forum username)
> 
> import clr  
> clr.AddReference(‘ProtoGeometry’)  
> from Autodesk.DesignScript.Geometry import \*
> 
> surf = IN[0] #surface to divide in rectangles  
> polyg = IN[1] #polygon created from the surface  
> Xs = IN[2] #Unique and sorted X coordinates  
> Ys = IN[3] #Unique and sorted Y coordinates  
> Zs = IN[4] #Unique and sorted Zs coordinates
> 
> class Rect :  
> #Class : rectangles that compose the surface
> 
> ```
> def __init__ (self, horizontal_min, horizontal_max, vertical_min, vertical_max, w, direction):
> #Constructor : horizontal_min,horizontal_max,vertical_min and vertical_max are the extreme coordinates on both directions, w is the coordinate in the third direction (all extreme points share this coordinate), direction is the plane that contains the Rect
> 	
> self.direction = direction; #defines the direction of the Rect
> 	
> self.w = w; #defines the third coordinate of the Rect
> 	
> self.horizontal_min = horizontal_min;
> self.horizontal_max = horizontal_max;
> self.vertical_min = vertical_min;
> self.vertical_max = vertical_max;
> 	
> #Definition of the 4 points that define the Rect, plus the center of the Rect (pt0)
> if(direction=="X"):
> self.pt1 = Point.ByCoordinates(w,horizontal_min,vertical_min);
> self.pt2 = Point.ByCoordinates(w,horizontal_min,vertical_max);
> self.pt3 = Point.ByCoordinates(w,horizontal_max,vertical_max);
> self.pt4 = Point.ByCoordinates(w,horizontal_max,vertical_min);
> self.pt0 = Point.ByCoordinates(w,0.5*horizontal_min+0.5*horizontal_max,0.5*vertical_min+0.5*vertical_max);
> elif(direction == "Y"):
> self.pt1 = Point.ByCoordinates(horizontal_min,w,vertical_min);
> self.pt2 = Point.ByCoordinates(horizontal_min,w,vertical_max);
> self.pt3 = Point.ByCoordinates(horizontal_max,w,vertical_max);
> self.pt4 = Point.ByCoordinates(horizontal_max,w,vertical_min);
> self.pt0 = Point.ByCoordinates(0.5*horizontal_min+0.5*horizontal_max,w,0.5*vertical_min+0.5*vertical_max);
> else:
> self.pt1 = Point.ByCoordinates(horizontal_min,vertical_min,w);
> self.pt2 = Point.ByCoordinates(horizontal_min,vertical_max,w);
> self.pt3 = Point.ByCoordinates(horizontal_max,vertical_max,w);
> self.pt4 = Point.ByCoordinates(horizontal_max,vertical_min,w);
> self.pt0 = Point.ByCoordinates(0.5*horizontal_min+0.5*horizontal_max,0.5*vertical_min+0.5*vertical_max,w);
> 
> def doesContain(self, polyg):
> #Determines if the Rect is contained by a polygon
> return Polygon.ContainmentTest(polyg,self.pt0)
> 	
> def fusionnable(self,other_rectangle):
> #Determines if two Rect can be merged, i.e. if they share exactly a side
> bool1 = (self.vertical_max == other_rectangle.vertical_min or self.vertical_min == other_rectangle.vertical_max) and (self.horizontal_max==other_rectangle.horizontal_max) and (self.horizontal_min==other_rectangle.horizontal_min) #and (self.vertical_min == other_rectangle.vertical_min and self.vertical_max == other_rectangle.vertical_max)
> #bool2 = (self.vertical_max == other_rectangle.vertical_min or self.vertical_min == other_rectangle.vertical_max) and (self.horizontal_min == other_rectangle.horizontal_min and self.horizontal_max == other_rectangle.horizontal_max)
> return (bool1); #or bool2);
> 	
> def fusion(self, other_rectangle):
> #Returns a new Rect that is the fusion of two mergeable Rect
> u_m = min(self.horizontal_min,other_rectangle.horizontal_min);
> u_M = max(self.horizontal_max,other_rectangle.horizontal_max);
> v_m = min(self.vertical_min,other_rectangle.vertical_min);
> v_M = max(self.vertical_max,other_rectangle.vertical_max);
> 	
> return Rect(u_m,u_M,v_m,v_M,self.w,self.direction);
> 
> ```
> 
> #Determination of the direction of the initial surface, then compute the extreme coordinates of the axis (the chosen axis depends on the direction)  
> if(len(Xs)==1):  
> direction = “X”;  
> horizontal\_min = min(Ys);  
> horizontal\_max = max(Ys);  
> vertical\_min = min(Zs);  
> vertical\_max = max(Zs);  
> w = Xs[0];  
> u\_range = Ys;  
> v\_range = Zs;  
> elif(len(Ys)==1):  
> direction = “Y”;  
> horizontal\_min = min(Xs);  
> horizontal\_max = max(Xs);  
> vertical\_min = min(Zs);  
> vertical\_max = max(Zs);  
> w = Ys[0];  
> u\_range = Xs;  
> v\_range = Zs;  
> else:  
> direction = “Z”;  
> horizontal\_min = min(Xs);  
> horizontal\_max = max(Xs);  
> vertical\_min = min(Ys);  
> vertical\_max = max(Ys);  
> w = Zs[0];  
> u\_range = Xs;  
> v\_range = Ys;
> 
> #Creation of the initial rectangles.  
> rectangle\_list = ;
> 
> for i in range(len(u\_range)-1):  
> for j in range(len(v\_range)-1):  
> new\_rect = Rect(u\_range[i],u\_range[i+1],v\_range[j],v\_range[j+1],w,direction); #creation of a Rect that might be contained in the surface  
> if(new\_rect.doesContain(polyg)): #if it is indeed inside the surface  
> rectangle\_list.append(new\_rect); #we add it to the list
> 
> #Fusion of all the Rect
> 
> i = 0 #index of the Rect we are currently looking at
> 
> while(True): #Nota : please don’t mess with the break statements…
> 
> ```
> #Break condition : we stop if we looked to all the Rect in the list (i.e. currently looking to the last Rect)
> if(i == len(rectangle_list)):
> break;
> 
> current_rectangle = rectangle_list[i]; #Current Rect
> 
> indice = -1; #Initialization of index of a potential Rect to merge with current Rect
> 
> #Try to find a Rect to merge with the current rect
> for j in range(i+1,len(rectangle_list)): #for each Rect in the list that is not the current rect
> if(current_rectangle.fusionnable(rectangle_list[j])): #if the two Rect are mergeable, we keep the index and we get out of this for loop
> indice = j;
> break;
> 
> #If we did not find anything, we go to the next Rect
> if(indice==-1):
> i = i+1;
> continue;
> 
> #If we did find something, we merge the two Rect and we delete the two old Rect from the list
> rectangle_list[i] = current_rectangle.fusion(rectangle_list[j]);
> rectangle_list.pop(j);
> 
> #And we go back to the very first Rect (we might have created a Rect that is mergeable)
> i = 0;
> 
> ```
> 
> #Initialisation of the output (list of all the sub-surfaces  
> result =   
> for i in range(len(rectangle\_list)):  
> result.append(Surface.ByPatch(PolyCurve.ByPoints([rectangle\_list[i].pt1,rectangle\_list[i].pt2,rectangle\_list[i].pt3,rectangle\_list[i].pt4], True)))
> 
> OUT = result

---

<div class="post-metadata">

**Author:** ![mellouze](https://avatars.discourse-cdn.com/v4/letter/m/e47774/32.png) [@mellouze](https://forum.dynamobim.com/u/mellouze)\
**Post date:** [April 4, 2019, 7:21am UTC](https://forum.dynamobim.com/t/divide-a-surface-in-rectangles/27681/4 "2019-04-04T07:21:15Z")

</div>

Hi 🙂  
Glad it could help someone in any manner. Thanks for the share !

---

<div class="post-metadata">

**Author:** ![janderson](https://avatars.discourse-cdn.com/v4/letter/j/b77776/32.png) [@janderson](https://forum.dynamobim.com/u/janderson)\
**Post date:** [August 9, 2019, 8:27pm UTC](https://forum.dynamobim.com/t/divide-a-surface-in-rectangles/27681/5 "2019-08-09T20:27:04Z")

</div>

Hello! I tried your code and it works great! I am curious if you know of a way to take this exact idea, but give the new rectangles maximum width’s and heights? So if a rectangle is over a certain dimension, it would be divided up into equal segments? Thank you in advance!

---

<div class="post-metadata">

**Author:** ![mellouze](https://avatars.discourse-cdn.com/v4/letter/m/e47774/32.png) [@mellouze](https://forum.dynamobim.com/u/mellouze)\
**Post date:** [August 19, 2019, 8:36am UTC](https://forum.dynamobim.com/t/divide-a-surface-in-rectangles/27681/6 "2019-08-19T08:36:03Z")

</div>

> [@janderson](#):
>
> I am curious if you know of a way to take this exact idea, but give the new rectangles maximum width’s and heights?

Hi 🙂  
To be quite honest, I do not have the time right now to modify this code, but the way I would do it is by changing the **Rect.fusionnable()** method.  
This method returns a boolean that indicates if the the two rectangles should be merged. You should modify it so it returns **False** if the height/width the final rectangle would have is superior to the maximum height/width.

Hope this helps.

Ps : Might take a look at it in a few days…

---

<div class="post-metadata">

**Author:** ![janderson](https://avatars.discourse-cdn.com/v4/letter/j/b77776/32.png) [@janderson](https://forum.dynamobim.com/u/janderson)\
**Post date:** [August 19, 2019, 1:50pm UTC](https://forum.dynamobim.com/t/divide-a-surface-in-rectangles/27681/7 "2019-08-19T13:50:19Z")

</div>

Hi @mellouze  
Thank you for the reply! I was able to use the code just as you have it, then split the geometry with planes, so I think it’s taken care of. Thank you again for posting this and for replying to me! Much appreciated!

---

<div class="post-metadata">

**Author:** ![yanveras](https://avatars.discourse-cdn.com/v4/letter/y/5daacb/32.png) [@yanveras](https://forum.dynamobim.com/u/yanveras)\
**Post date:** [December 9, 2019, 10:02pm UTC](https://forum.dynamobim.com/t/divide-a-surface-in-rectangles/27681/8 "2019-12-09T22:02:22Z")

</div>

I am trying to made dynamo calculate some design metrics and I tryed to use it, but it report an error in Dynamo Engine X.X

 ![image](https://us1.discourse-cdn.com/flex022/uploads/dynamobim/original/3X/c/2/c246169a13e7fafc26a48efe0318170397457fa2.png)

Does it work in 2.xx version ?

This was the testing surface:

 ![image](https://us1.discourse-cdn.com/flex022/uploads/dynamobim/original/3X/a/1/a11b85491bb558eb4386da5027e094ee6ce5c413.png)

---

<div class="post-metadata">

**Author:** ![mellouze](https://avatars.discourse-cdn.com/v4/letter/m/e47774/32.png) [@mellouze](https://forum.dynamobim.com/u/mellouze)\
**Post date:** [December 10, 2019, 9:01am UTC](https://forum.dynamobim.com/t/divide-a-surface-in-rectangles/27681/9 "2019-12-10T09:01:41Z")

</div>

Hi,

Yes, the script does work on Dynamo 2 (tested on 2.0.3).  
I think the problem is that your surface is not continous. Try only feeding the script continuous/contiguous surfaces.

---

<div class="post-metadata">

**Author:** ![nuno.pedrinho](https://avatars.discourse-cdn.com/v4/letter/n/b9bd4f/32.png) [@nuno.pedrinho](https://forum.dynamobim.com/u/nuno.pedrinho)\
**Post date:** [February 25, 2020, 11:18am UTC](https://forum.dynamobim.com/t/divide-a-surface-in-rectangles/27681/10 "2020-02-25T11:18:32Z")

</div>

Hi!! Thank you all. This is a great one.

Anyone getting this to work with Dynamo 2.3?  
For me is not working.

I’m getting this errors:

at Code Block:  
Warning: Multiple definitions for ‘Curve’ are found as Autodesk.DesignScript.Geometry.Curve, Curve  
Method ‘If()’ not found  
Internal error, please report: Dereferencing a non-pointer.

at Phyton Script:  
Warning: Multiple definitions for ‘Curve’ are found as Autodesk.DesignScript.Geometry.Curve, Curve  
Method ‘If()’ not found  
Internal error, please report: Dereferencing a non-pointer.

Can you help me updating ?

Thank you in advance.

---

<div class="post-metadata">

**Author:** ![timhevel](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.dynamobim.com/timhevel/32/109364_2.png) [@timhevel](https://forum.dynamobim.com/u/timhevel)\
**Post date:** [October 20, 2021, 1:54pm UTC](https://forum.dynamobim.com/t/divide-a-surface-in-rectangles/27681/11 "2021-10-20T13:54:58Z")

</div>

How about multiple input surfaces? can you make that work to?

---

<div class="post-metadata">

**Author:** ![mellouze](https://avatars.discourse-cdn.com/v4/letter/m/e47774/32.png) [@mellouze](https://forum.dynamobim.com/u/mellouze)\
**Post date:** [October 20, 2021, 2:18pm UTC](https://forum.dynamobim.com/t/divide-a-surface-in-rectangles/27681/12 "2021-10-20T14:18:58Z")

</div>

I’d suggest creating a custom node of both nodes of my method, indicate to Dynamo that the input is supposed to be a surface, then feed the custom node a list of Surfaces.

---

<div class="post-metadata">

**Author:** ![timhevel](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.dynamobim.com/timhevel/32/109364_2.png) [@timhevel](https://forum.dynamobim.com/u/timhevel)\
**Post date:** [October 20, 2021, 4:17pm UTC](https://forum.dynamobim.com/t/divide-a-surface-in-rectangles/27681/13 "2021-10-20T16:17:00Z")

</div>

thanks, i got it working.  
another question, how could i manipulate the “direction” or prefer the more square rectangles?

---

<div class="post-metadata">

**Author:** ![mellouze](https://avatars.discourse-cdn.com/v4/letter/m/e47774/32.png) [@mellouze](https://forum.dynamobim.com/u/mellouze)\
**Post date:** [October 21, 2021, 1:24pm UTC](https://forum.dynamobim.com/t/divide-a-surface-in-rectangles/27681/14 "2021-10-21T13:24:09Z")

</div>

I didn’t undestrand your question 😕

- Do you want to have as many square as possible (maximize the number of square) ?
- Do you want to have the biggest square possible ? And the fill the rest in the best way possible ?
- Do you want to force the direction of the rectangles ?

---

<div class="post-metadata">

**Author:** ![timhevel](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.dynamobim.com/timhevel/32/109364_2.png) [@timhevel](https://forum.dynamobim.com/u/timhevel)\
**Post date:** [October 21, 2021, 2:25pm UTC](https://forum.dynamobim.com/t/divide-a-surface-in-rectangles/27681/15 "2021-10-21T14:25:48Z")

</div>

The second one, except it doesn’t have to be perfectly square.

 ![image](https://us1.discourse-cdn.com/flex022/uploads/dynamobim/original/3X/2/e/2e2530844d95e055733e94ea6c94b368f5af08dc.png)

 ![image](https://us1.discourse-cdn.com/flex022/uploads/dynamobim/original/3X/4/d/4d45b0217dab9777d71a1429be8f358d5f32da4a.png)

I want to determine the best spot for Dynamo to place an Area Tag.

the blue lines are the areaboundaries.  
the points are the chosen locations.

---

<div class="post-metadata">

**Author:** ![mellouze](https://avatars.discourse-cdn.com/v4/letter/m/e47774/32.png) [@mellouze](https://forum.dynamobim.com/u/mellouze)\
**Post date:** [October 21, 2021, 3:02pm UTC](https://forum.dynamobim.com/t/divide-a-surface-in-rectangles/27681/16 "2021-10-21T15:02:13Z")

</div>

OK, so I have a few ideas, but I think you’ll have to test them yourselves and tweak them a little bit.  
Basically, they all revolve around the fact that the shape of the output rectangles heavily depends on the ordre in which you cycle through the items of `liste_rect` in my Python script.

- Idea 1 : You can create `liste_rect` along the other direction by switching the order of the two following lines (the main directions of the rectangles will be switched.

```auto
for i in range(len(u_range)-1):
	for j in range(len(v_range)-1):

```

- Idea 2 : You could run the script two times for each surface and make the script choose the best decomposition based on the biggest surface that it could produce.
- Idea 3 : You could choose the direction based on the ratio between the two “principal lengths”.
- Idea 4 : You could determine the center of each of your surfaces and make the `while` loop start at the Rect object that is the closest to the center (to force a bigger rectangle to be created at that place).
- Idea 5 : You could sort the Rect objects in `liste_rect` based on their distance to the center of your surface.

Etc.

But at the end of the day, I think that the best solution will heavily depend on your project and on the way you define “best spot” 😅
