Revit Wall and Window Object via SpecklePy

Hi @izzylys,
i ve watched your tutorial on how to create a revit beam via python. thanks!

  1. could you kindly extend your example and show how to create a Revit Wall and Revit Window object via SpecklePy?

  2. Could you provide a reference document of all attributes and types that exist in speckle and their
    parameters? e.g. Revit Beam, Revit Steel Beam, ArchiCAD Wall etc…

  3. Since you define the Revit Wall type here, are those types also understood by ArchiCAD?

  4. Im receiving the following error when executing the Script multiple times. Perhaps you know how to solve it too :slight_smile:

ValueError: The speckle_type: Objects.BuiltElements.Level is already registered for type: Level. Please choose a different type name.

At:
  C:\Users/Public/Documents/cadwork/USERPROFIL_30/3d/API.x64/kumiki\Lib\site-packages\specklepy\objects\base.py(174): __init_subclass__
  C:\Users\mhelmrei\Documents\GitHub\kumiki\src\kumiki\ui\main_window.py(82): <module>
  <frozen importlib._bootstrap>(241): _call_with_frames_removed
  <frozen importlib._bootstrap_external>(883): exec_module
  <frozen importlib._bootstrap>(703): _load_unlocked
  <frozen importlib._bootstrap>(1006): _find_and_load_unlocked
  <frozen importlib._bootstrap>(1027): _find_and_load
  C:/Users/Public/Documents/cadwork/USERPROFIL_30/3d/API.x64/kumiki/kumiki.py(28): <module>

Thanks a lot!
Matthias

we managed to go around question #4 with the following functions… but maybe not ideal.
cheers, matthias


def get_fully_qualified_name(cls):
    return f"{cls.__module__}.{cls.__qualname__}"


keys_to_remove = []

for key, value in _RegisteringBase._type_registry.items():
    print(key, value)
    if get_fully_qualified_name(value).startswith("kumiki"):
        keys_to_remove.append(key)

for key in keys_to_remove:
    stype = _RegisteringBase._type_registry.get(key)
    if stype:
        del _RegisteringBase._type_registry[key]

Hi @mhelmrei,

Sorry about late reply. Let’s go over your questions.

Unfortunately, I can’t provide you a document that shows all the classes Speckle has, but even better, I can provide you the source code. You can find all the types and attributes here.

For creating custom objects with Specklepy, using these references, I’ll attach some examples below.

Here how you can create a RevitBeam:

from specklepy.objects import Base
from specklepy.objects.geometry import Line, Point
from specklepy.api.wrapper import StreamWrapper
from specklepy.api import operations
from typing import List, Optional


class Level(Base, speckle_type="Objects.BuiltElements.Level"):
    """
    A custom Level class
    """

    name: str = None
    elevation: float = None

    def __repr__(self) -> str:
        return f"Level(id: {self.id}, name: {self.name}, elevation: {self.elevation})"


class RevitBeam(
    Base, speckle_type="Objects.BuiltElements.Revit.RevitBeam", detachable={"level"}
):
    """
    A custom RevitBeam class
    """

    family: str = None
    type: str = None
    baseLine: Line = None
    level: Level = None
    units: str = None
    displayValue: list = None  # List[Mesh]
    parameters: Base = None
    elementId: str = None

    def __repr__(self) -> str:
        return f"RevitBeam(id: {self.id}, family: {self.family}, type: {self.type}, level: {self.level}, baseLine: {self.baseLine})"


# Create a level
level = Level(name="Level 0", elevation=0)

# Create a beam
beam = RevitBeam(
    family="Structural Framing",
    type="UB305x165x40",
    level=level,
    baseLine=Line(start=Point(x=0, y=0, z=0), end=Point(x=4, y=10, z=0)),
    units="m",
)

# Create commit object
commit_obj = Base()
commit_obj["@revit beam from python"] = beam

# Send to Speckle
wrap = StreamWrapper(
    "<YOUR_URL>"
)
client = wrap.get_client()
transport = wrap.get_transport()
obj_id = operations.send(commit_obj, [transport])
client.commit.create(wrap.stream_id, obj_id)

print(f"Successfully sent beam with ID: {obj_id}")

You’ll only see a base line in the viewer, but if you receive in Revit, this will create a Revit Beam for you.

And you can extend this logic to create other custom classes in python. For example to create a Revit Wall, following the same logic:

from specklepy.objects import Base
from specklepy.objects.geometry import Line, Point
from specklepy.api.wrapper import StreamWrapper
from specklepy.api import operations


class Level(Base, speckle_type="Objects.BuiltElements.Level"):
    """
    A custom Level class
    """

    name: str = None
    elevation: float = None

    def __repr__(self) -> str:
        return f"Level(id: {self.id}, name: {self.name}, elevation: {self.elevation})"


class RevitWall(
    Base, speckle_type="Objects.BuiltElements.Revit.RevitWall", detachable={"level"}
):
    """
    A custom RevitWall class
    """

    family: str = None
    type: str = None
    baseLine: Line = None
    level: Level = None
    height: float = None

    def __repr__(self) -> str:
        return f"RevitWall(id: {self.id}, type: {self.type}, level: {self.level}, baseLine: {self.baseLine})"


# Create a level
level = Level(name="Level 0", elevation=0)

# Create a wall
wall = RevitWall(
    family="Basic Wall",
    type="Wall-Ext_102Bwk-75Ins-100LBlk-12P",
    level=level,
    baseLine=Line(start=Point(x=0, y=0, z=0), end=Point(x=5, y=0, z=0)),
    height=3.0,
)

# Create commit object
commit_obj = Base()
commit_obj["@revit wall from python"] = wall

# Send to Speckle
wrap = StreamWrapper(
    "<YOUR_URL>"
)
client = wrap.get_client()
transport = wrap.get_transport()
obj_id = operations.send(commit_obj, [transport])
client.commit.create(wrap.stream_id, obj_id)

print(f"Successfully sent wall with ID: {obj_id}")

When you receive this stream in Revit:

These types are built for Revit, and not going to be native for ArchiCad. But Speckle object is dynamic, it’s up to you to extend it :slight_smile:

Hope this helps.

I’ll be here for further questions.
Dogukan