# Changing python code to use surfaces instead of rooms

**URL:** <https://forum.dynamobim.com/t/changing-python-code-to-use-surfaces-instead-of-rooms/105393>\
**Category:** Revit\
**Tags:** python, geometry, dynamo\
**Created:** [October 25, 2024, 11:27am UTC](https://forum.dynamobim.com/t/changing-python-code-to-use-surfaces-instead-of-rooms/105393 "2024-10-25T11:27:58Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![hulppc](https://avatars.discourse-cdn.com/v4/letter/h/91b2a8/32.png) [@hulppc](https://forum.dynamobim.com/u/hulppc)\
**Post date:** [October 25, 2024, 11:27am UTC](https://forum.dynamobim.com/t/changing-python-code-to-use-surfaces-instead-of-rooms/105393/1 "2024-10-25T11:27:58Z")

</div>

Hi,

I have some code that I’d like to modify to use surfaces instead of rooms. Could someone help me with this? I’m not very familiar with programming in Dynamo/Python.

```auto
import clr
import sys
import os

localapp = os.getenv(r'LOCALAPPDATA')

sys.path.append(os.path.join(localapp, r'python-3.8.10-embed-amd64\Lib\site-packages'))

import System
#
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import Autodesk.DesignScript.Geometry as DS

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

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

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

import numpy as np
       
def cosine_similarity(point, vector):
    dot_prod = point.DotProduct(vector)
    mag_point = point.GetLength()
    mag_vector = vector.GetLength()
    # avoid division by zero if the magnitude is zero
    if mag_point == 0 or mag_vector == 0:
        return 0
    return dot_prod / (mag_point * mag_vector)

# Preparing input from Dynamo to Revit (a list of rooms)
rooms = [UnwrapElement(room) for room in IN[0]] # Unwrap the list of rooms
out = []
lst_debug = []
DEBUG = False

# Iterate over each room
for room in rooms:
    bound_opt = SpatialElementBoundaryOptions()
    bound_opt.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Finish
    room_curves = [s.GetCurve() for lst_segments in room.GetBoundarySegments(bound_opt) for s in lst_segments]
    ds_room_curves = [c.ToProtoType() for c in room_curves]

    # Coordinates system (vectors) orientation of the room
    lst_vector_ray = [XYZ.BasisX, XYZ.BasisY]
    # Get min point start
    ptstart = room.get_BoundingBox(None).Min
    ptstart = XYZ(ptstart.X, ptstart.Y, room_curves[0].GetEndPoint(0).Z)
    ptend = room.get_BoundingBox(None).Max
    ptend = XYZ(ptend.X, ptend.Y, room_curves[0].GetEndPoint(0).Z)
    max_size = max([ptend.Y - ptstart.Y, ptend.X - ptstart.X])

    # Scan with vector_ray_A and then vector_ray_B
    for idx, vector_ray in enumerate(lst_vector_ray):
        rayA = DB.Line.CreateUnbound(ptstart, vector_ray)
        # Offset ray each scan iteration
        for step in np.arange(0, max_size, 0.0033):
            perpendicular_vector = lst_vector_ray[abs(idx-1)] # Auto-switch between the inverse of idx
            ray_curve = rayA.CreateOffset(step, perpendicular_vector.CrossProduct(vector_ray))
            # DEBUG to ensure the ray location is correct drawing a small line of ray
            if DEBUG:
                line_bound = ray_curve.Clone()
                line_bound.MakeBound(0.1, 3.9)
                ds_line_bound = line_bound.ToProtoType()
                lst_debug.append(ds_line_bound)
            temp = []
            # Try to find room boundaries intersection
            for bound_curve in room_curves:
                outResultArray = IntersectionResultArray()
                comparisonResult, outResultArray = ray_curve.Intersect(bound_curve, outResultArray)
                if comparisonResult == SetComparisonResult.Overlap:
                    lst_intersect_pts = [i.XYZPoint for i in outResultArray]
                    temp.extend(lst_intersect_pts)
            # Sort points by vector
            sorted_points = sorted(temp, key=lambda p: cosine_similarity(p, vector_ray))
            # Iterate over pair points
            sorted_points = iter(sorted_points)
            for pta, ptb in zip(sorted_points, sorted_points):
                if 0.1 < pta.DistanceTo(ptb) <= 1.8 * 3.281: # If distance between points is under 1.8m
                    line_bad_part_area = DB.Line.CreateBound(pta, ptb)
                    out.append(line_bad_part_area.ToProtoType()) # Append the result for each room

# Output all the lines found in all rooms
OUT = out

```

---

<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:** [October 27, 2024, 9:45pm UTC](https://forum.dynamobim.com/t/changing-python-code-to-use-surfaces-instead-of-rooms/105393/2 "2024-10-27T21:45:45Z")

</div>

Hi,

you need to replace  
`get_BoundingBox(None)`  
by  
`get_BoundingBox(view_area_plan)`

where the `view_area_plan` is a view where the Area is visible

---

<div class="post-metadata">

**Author:** ![hulppc](https://avatars.discourse-cdn.com/v4/letter/h/91b2a8/32.png) [@hulppc](https://forum.dynamobim.com/u/hulppc)\
**Post date:** [October 28, 2024, 11:07am UTC](https://forum.dynamobim.com/t/changing-python-code-to-use-surfaces-instead-of-rooms/105393/3 "2024-10-28T11:07:52Z")

</div>

It’s not working. I provided my floor plan view, but I got an error saying that surfaces don’t have the attribute ‘GetBoundarySegments.’ I removed that part since I already have the surface and don’t need to get it from a room. However, it’s still not working.

---

<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:** [October 28, 2024, 11:09am UTC](https://forum.dynamobim.com/t/changing-python-code-to-use-surfaces-instead-of-rooms/105393/4 "2024-10-28T11:09:58Z")

</div>

Best to share a graph and Revit model that you’re working with - if someone (say myself or @c.poupin) were to try and code something up in say Revit 2025 using a quickly generated sample model, it might not work for you as you’re in Revit 2024, or maybe your surface has a shape edit, or maybe…

---

<div class="post-metadata">

**Author:** ![hulppc](https://avatars.discourse-cdn.com/v4/letter/h/91b2a8/32.png) [@hulppc](https://forum.dynamobim.com/u/hulppc)\
**Post date:** [October 28, 2024, 3:02pm UTC](https://forum.dynamobim.com/t/changing-python-code-to-use-surfaces-instead-of-rooms/105393/5 "2024-10-28T15:02:55Z")

</div>

I’m currently working in Revit 2023 with a sample model. I have just one floor with variously shaped rooms.  
[1,8m.dyn](https://forum.dynamobim.com/uploads/short-url/y9P6k0XUgmDsA0AnXWqZDjiBH4d.dyn) (230.9 KB)  
[1,8m check.rvt](https://forum.dynamobim.com/uploads/short-url/1ZceFoXLkYbsFXcNsFvRi85h9Wr.rvt) (5.3 MB)

---

<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:** [October 28, 2024, 3:06pm UTC](https://forum.dynamobim.com/t/changing-python-code-to-use-surfaces-instead-of-rooms/105393/6 "2024-10-28T15:06:58Z")

</div>

Now in transit for a team meeting which means I likely won’t be able to look at this for a week, but now others can help directly. I’ll take a look if I can. 🙂

---

<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:** [October 28, 2024, 7:35pm UTC](https://forum.dynamobim.com/t/changing-python-code-to-use-surfaces-instead-of-rooms/105393/7 "2024-10-28T19:35:21Z")

</div>

try this process

1. Instead of using `room.GetBoundarySegments()`, retrieve surface curves with the `surface.PerimeterCurves()` method
2. convert curves to Revit type with the `ToRevitType()` extension method
3. obtain the surface’s BoudingBox with `surface.BoundingBox` property
4. get the min and max points of BoundingBox and convert them with the `ToXyz()` extension method

At this point, you should have obtained the following variables:

- room\_curves
- ds\_room\_curves
- ptstart
- ptend

the rest of the code should remain unchanged

Resources

> **[Python 0.6.3 to 0.7.x Migration](https://github.com/DynamoDS/Dynamo/wiki/Python-0.6.3-to-0.7.x-Migration#geometryobjects)**
>
> Open Source Graphical Programming for Design. Contribute to DynamoDS/Dynamo development by creating an account on GitHub.
