Calculating Room Leasable area for Retail as per Indian NBC

I am looking to calculate the leasable room area for Retail and commercial design as per Indian NBC. Basically to calculate the area of the room which will calculate the exterior edge of the exterior walls, centre of Partition walls as they share with other Tenant and Exterior edge of the interior wall. Can I do this using any plugin or Dynamo Script?

I can use different wall types for Revit to identify which is Exterior, Interior and Partition Wall.

Welcome. Please read the community guidelines for posting: How to get help on the Dynamo forums - FAQ - Dynamo

There are two ways I can see this going. I’d probably start with this option:

1. Locate rooms and usage types (tenant or non-tenant).
2. Identify bounding wall types and widths.
3. Extend room boundaries by conditional offset (full width or half width).
4. Assign area value.

But you could also try this:

1. Identify wall types and conditions.
2. Determine offset based on requirements.
3. "Enclose" areas (there will likely be gaps between wall connections).
4. Match enclosure with room and assign area value.

I did try unsuccessfully creating a Dynamo script and Python using Chatgpt. Can you please help me in creating the required script? I have a very basic level of understanding and creating the script.

You need to show us what you’ve tried so far and where you’re running into issues. Again, if you read the post I linked above, you’ll see that this is not a forum for requesting other people to do work for you. We need to see what you’ve been able to put together so we can suggest how you might fix things or move forward.

1 Like

I have tried to use Chatgpt to generate the script on the basis of the solution you provided.
I skipped the locate room part, because I first tried to test if it works for all the rooms (tenants or not). Identifying wall boundaries and Assign a area to new shared paramter “Leasable Area.”

Unfortunately all the python scripts that chatgpt produces runs into some or the other error. I am attaching the script sample as well. I want to avoid the python scripting all together if possible to make it clean without errors.


Being a new user, I am unable to upload the sample script.

ChatGPT is not good at determining Dynamo node structure. It can be helpful at outlining general logic and core python, but it struggle with the specifics of Dynamo and the Revit API.

We can’t even tell you what it’s doing wrong without seeing the code. If you want to avoid python then I recommend searching the library for nodes that deal with rooms and geometry that your process will require.

I’ve elevated your permission levels so you can share files now.

1 Like

Hi, I have tried extracting wall thickness and deriving area in new paramter “Leasable Area”. If you can check and recommend changes. I am getting error while extracting curves and combining them.


Sample Dynamo Script.dyn (66.6 KB)
Sample Project.rvt (5.9 MB)

Hey @Nick_Boyts - Would you be able to please check and review. Really need your inputs here.

Can’t tell you what’s going on if we can’t see it. Please share a new screenshot with all the node preview bubbles pinned.

I can tell you that there’s still some weird logic in your code at this point. Combining the wall and boundary geometry doesn’t make sense as you’re duplicating the dataset but also filtering only part of it.

Hi @Nick_Boyts

I have pinned all bubbles as requested.
Kindly check & help me with direction on how to resolve.

Sample Project.rvt (6.4 MB)
Sample Dynamo Script 20250623.dyn (61.9 KB)

@viraj.lodayaJCJFE It’s worth checking these settings in Revit as well

I recommend doing this on only the active view, as it WILL require manual review as the rules for any one national standard for leasable area have far too many exceptions to automate completely, so I like to push the qa on the user at the time of use.

  1. Get all rooms
  2. for each room
    1. Get the room boundary segments
    2. For each segment, get the bounding element and extract it’s width if it is a wall; if not skip it as this is an area separation curve which can’t demise tenant space per any standard I know of
    3. get the room on the other side via the derivatives and wall width
    4. if the occupant is the same as the original room, ignore it
    5. elif the occupant is null, move the boundary curve by 1/2 of the wall thickness out of the room and append that to the list of curves to use for separation lines
    6. elif the occupant is not the same append it to the list of curves to use for separation lines
  3. get all unique curves using the center point as the key
  4. generate room separation lines at each unique curve
  5. generate a base area
  6. again, for each room:
    1. Move the area to the center of the room location point
    2. if the Area has an area value, append it to the results list and make a new area
    3. else move onto the next room
  7. delete the last Area if it isn’t in the list of areas

The Revit API is required as I do not know of any packages or tools which allow passing the boundary as an object. As such I would recommend either custom Python script in Dynamo, a custom node (C# or DYF) in Dynamo, or an add-in. If any of the steps above don’t make sense you likely will want to hire a developer.

2 Likes

Hi,

  • DB.CurveLoop.CreateViaOffset method can be used to create custom offsets for each curve, and we can find the bounding element (wall) for each boundary segment.

python code (need to adapt if necessary)

import clr
import sys
import System
from System.Collections.Generic import List, IList, Dictionary, HashSet
#
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import Autodesk.DesignScript.Geometry as DS

#import Revit API
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)

#import transactionManager and DocumentManager (RevitServices is specific to Dynamo)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument

    
class CustomRoom:
    def __init__(self, room):
        self._room = room
        s_opt = SpatialElementBoundaryOptions()
        s_opt.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Center
        self._outsegments = max(self._room.GetBoundarySegments(s_opt), key=lambda loop : sum(l.GetCurve().Length for l in loop))
        
    @property
    def OutCurveLoop(self):
        return CurveLoop.Create(List[DB.Curve]([x.GetCurve() for x in self._outsegments]))
        
    @property
    def Room(self):
        return self._room
        
    @property
    def LeasableSurface(self):
        lst_offset = List[System.Double]()
        for curve in self.OutCurveLoop:
            # get the associated wall via the segment.
            assoc_segment = next((s for s in self._outsegments if s.GetCurve().Intersect(curve) == SetComparisonResult.Equal), None)
            assoc_wall = doc.GetElement(assoc_segment.ElementId)
            # if interior wall do no offset
            if assoc_wall.GetTypeId() in lst_walls_type_partition_Ids:
                lst_offset.Add(0)
            # if  exterior wall offset it 
            else:
                lst_offset.Add(assoc_wall.Width / 2)
        # offset curveloop
        extendLoop = DB.CurveLoop.CreateViaOffset(self.OutCurveLoop, lst_offset, XYZ.BasisZ)
        # create Surface
        return DS.PolyCurve.ByJoinedCurves([c.ToProtoType() for c in extendLoop], 0.001, False, 0).Patch()

def toList(x):
    if isinstance(x, (list, dict)) or \
            (hasattr(x, "GetType") and x.GetType().GetInterface("ICollection") is not None):
        return x
    else : return [x]

#Preparing input from dynamo to revit
lst_rooms = toList(UnwrapElement(IN[0]))
lst_walls_type_partition = toList(UnwrapElement(IN[1]))
lst_walls_type_partition_Ids = [x.Id for x in lst_walls_type_partition]

out = []
for room in lst_rooms:
    if room.Area > 0.001: # edit 25/06/2025
        c_room = CustomRoom(room)
        out_surf = c_room.LeasableSurface
        out.append([c_room.Room, out_surf, out_surf.PerimeterCurves(), out_surf.Area])

OUT = out
5 Likes

Thanks a ton Cyril @c.poupin . Its lot simpler and more precise.

I would liken your help little further.

  1. Is there a way to select all wall types for Interior Partition at once, all with the name “Partition” in it, instead of adding all partition wall types.
  2. I am getting a warning in Surface area node (Asked to convert non-convertible types), although the Leasable area is generating correctly. Can you please check if I should avoid or is there a way to resolve this?


    Room Area Calculation.dyn (18.5 KB)
  3. While generating Area from the geometry- It is showing in mm units, possible to show it in m units?
  4. Python Script works fine for the 1st time, when I try to re-run after adding few other rooms - Python script node is showing below error.

Share a simple RVT file in which the error appears.

Here, it’s the same sample file. In some cases, after the 2nd time, Python error appears when run for 3rd time
Sample Project.rvt (6.1 MB)
.

I don’t love using partition types to identify area separations. They tend to be too varied so users loose track (“oh I forgot to add that partition type for this run”), and you might also have one within the same tenant or within common areas.

This code will look at the occupant of a room, and put a demising line at the outside face (if no room is found or if the room has an occupant of “Common”), at the center line if the occupants differ, or skip putting the demising line if they are the same.

area by rule

Area by Rule.dyn (14.3 KB)

1 Like

the code has been fixed in my previous post

2 Likes

Thankyou @c.poupin . This works fine. Should I ignore the warning in Surface area node (Asked to convert non-convertible types) because the value is generating correctly?

@jacob.small - Thanks, that makes sense. I agree—partition types can get tricky to manage consistently. Right now, I’m using a Python script to handle area calculations for Retail design, which works well. But I can definitely see your approach being really useful during the As-built stage when accuracy and clarity in demising lines become more critical. Appreciate the insight! :slight_smile:

in your case, you can replace in the python script
out.append([c_room.Room, out_surf, out_surf.PerimeterCurves(), out_surf.Area])
by
out.append(out_surf.Area)

1 Like