# PyRevit Plug-in (Suddivide surface in triangles and rectangles)

**URL:** <https://forum.dynamobim.com/t/pyrevit-plug-in-suddivide-surface-in-triangles-and-rectangles/114748>\
**Category:** Revit\
**Tags:** python\
**Created:** [June 9, 2026, 7:54am UTC](https://forum.dynamobim.com/t/pyrevit-plug-in-suddivide-surface-in-triangles-and-rectangles/114748 "2026-06-09T07:54:48Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![andyvig00](https://avatars.discourse-cdn.com/v4/letter/a/a9adbd/32.png) [@andyvig00](https://forum.dynamobim.com/u/andyvig00)\
**Post date:** [June 9, 2026, 7:54am UTC](https://forum.dynamobim.com/t/pyrevit-plug-in-suddivide-surface-in-triangles-and-rectangles/114748/1 "2026-06-09T07:54:48Z")

</div>

Hello,  
Im trying to create a [pyRevit](https://discourse.pyrevitlabs.io/) plugin. I would like to create a python script where i can take a surface (from areas/rooms) and split its area in rectangles and triangle (if necessary i.e. curve/inclinated wall/room boundary/area boundary, ecc..). Is there some fromulas or criteria/ articles/ sites who can help me to create this program concept?  
Thanks

---

<div class="post-metadata">

**Author:** ![jacob.small](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.dynamobim.com/jacob.small/32/161030_2.png) [@jacob.small](https://forum.dynamobim.com/u/jacob.small)\
**Post date:** [June 9, 2026, 9:21am UTC](https://forum.dynamobim.com/t/pyrevit-plug-in-suddivide-surface-in-triangles-and-rectangles/114748/2 "2026-06-09T09:21:35Z")

</div>

No need for [PyRevit](https://discourse.pyrevitlabs.io/), but if you really want to use those tools the forums you linked would be best.

If you want to stay in the Dynamo ecosystem Look into algorithms for largest inscribed rectangle.

---

<div class="post-metadata">

**Author:** ![c.poupin](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.dynamobim.com/c.poupin/32/89152_2.png) [@c.poupin](https://forum.dynamobim.com/u/c.poupin)\
**Post date:** [June 9, 2026, 5:14pm UTC](https://forum.dynamobim.com/t/pyrevit-plug-in-suddivide-surface-in-triangles-and-rectangles/114748/3 "2026-06-09T17:14:51Z")

</div>

Hi, check out this great post of @Vikram_Subbaiah (code in DesignScript)

> [@How can i make rectangles, squares or triangles](https://forum.dynamobim.com/t/how-can-i-make-rectangles-squares-or-triangles/73610/12):
>
> Something like this? [divisions] Code available [here](https://gitbook.testingwaters.in/projects-1/rectangular-compartments) Related post

---

<div class="post-metadata">

**Author:** ![c.poupin](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.dynamobim.com/c.poupin/32/89152_2.png) [@c.poupin](https://forum.dynamobim.com/u/c.poupin)\
**Post date:** [June 11, 2026, 12:45pm UTC](https://forum.dynamobim.com/t/pyrevit-plug-in-suddivide-surface-in-triangles-and-rectangles/114748/4 "2026-06-11T12:45:46Z")

</div>

Here is a solution that divides the polygon into rectangular subregions by extending horizontal and vertical lines from the vertices using shapely.

```python
import clr
clr.AddReference('ProtoGeometry')
import Autodesk.DesignScript.Geometry as DS

import numpy as np
from itertools import combinations
from shapely import affinity
from shapely.geometry import Polygon, box
from shapely.ops import unary_union
from shapely.prepared import prep

def convert_poly_toDSPoly(geo):
    pts = [DS.Point.ByCoordinates(x, y, zvalue) for x, y in geo.exterior.coords]
    try:
        return DS.Polygon.ByPoints(DS.Point.PruneDuplicates(pts))
    except:
        return None

def get_largest_internal_rect(poly):
    rings = [poly.exterior] + list(poly.interiors)
    coords = np.vstack([np.asarray(r.coords)[:, :2] for r in rings])
    xs, ys = map(np.unique, coords.T)
    pp = prep(poly)

    rects = (
        box(x1, y1, x2, y2)
        for x1, x2 in combinations(xs, 2)
        for y1, y2 in combinations(ys, 2)
    )
    return max((r for r in rects if pp.contains(r)), key=lambda r: r.area, default=None)

def get_polys(geo):
    if geo.is_empty:
        return []
    if geo.geom_type == 'Polygon':
        return [geo]
    return [g for g in getattr(geo, 'geoms', []) if g.geom_type == 'Polygon']

def subtractive_decomposition(poly, max_rooms=15):
    remaining, rectangles = poly, []

    for _ in range(max_rooms):
        if remaining.is_empty or remaining.area < .01:
            break

        pieces = sorted(get_polys(remaining), key=lambda p: p.area, reverse=True)
        if not pieces:
            break

        target, others = pieces[0], pieces[1:]
        rect = get_largest_internal_rect(target)
        ok = rect is not None and rect.area >= .01

        rectangles.append(rect if ok else target)
        rest = [target.difference(rect)] if ok else []
        remaining = unary_union(rest + others) if rest or others else Polygon()

    return rectangles

ds_polygon = IN[0]
v = DS.Vector.XAxis()
cs = DS.BoundingBox.ByMinimumVolume([ds_polygon]).ContextCoordinateSystem
angle = v.AngleWithVector(cs.XAxis) * (1 if v.Cross(cs.XAxis).Z > 0 else -1)
zvalue = ds_polygon.Points[0].Z

poly = Polygon([(p.X, p.Y) for p in ds_polygon.Points]).buffer(0)
poly = affinity.rotate(poly, -angle, origin=(0, 0))
# grid-based search algo
final_decomposition = subtractive_decomposition(poly)
final_decomposition = [affinity.rotate(x, angle, origin=(0, 0)) for x in final_decomposition]

OUT = [convert_poly_toDSPoly(x) for x in final_decomposition if x.geom_type == 'Polygon' and len(x.exterior.coords) <= 5]

```
