hello what was the solution? i have same issue, the rooms of another building appear on top of another building on the side overlapped, crazy…
Never skip the Primer
Its all there
1 Like
if that would be so simple I would have resolved already and i would not be here writing stupid post comment, i saw this but one of the nodes does not work in my revit 2023 Aligning linked geometry using Dynamo for Revit! - YouTube @GavinNicholls @Marcel_Rijsmus
I tried this following the video and still does not work correctly:
# IronPython 2.7 - Dynamo for Revit (no required inputs)
# OUT:
# [0] RevitLinkInstance[]
# [1] Types[]
# [2] CoordinateSystem[] (host-space, from each link's total transform)
# [3] elements[i][j] -> elements from linked doc for instance i, category j
# [4] dsGeom[i][j] -> DS geometry in link-space
# [5] dsGeomHost[i][j] -> DS geometry transformed to host-space
import clr, System
# --- guard IN so default-arg crashes never happen if node has no inputs
try:
IN
except:
IN = [None]
# Revit Services / API
clr.AddReference("RevitServices")
from RevitServices.Persistence import DocumentManager
clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import (
FilteredElementCollector, RevitLinkInstance, ElementCategoryFilter,
BuiltInCategory, Category, ElementId, Options, ViewDetailLevel,
GeometryInstance, Solid, Mesh, SpatialElement, SpatialElementGeometryCalculator
)
# Dynamo geometry
clr.AddReference("ProtoGeometry")
from Autodesk.DesignScript.Geometry import CoordinateSystem, Point, Vector, Geometry
# Dynamo Revit wrappers/extensions
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
doc = DocumentManager.Instance.CurrentDBDocument
# ----------------- helpers -----------------
def _unwrap(x):
try:
return UnwrapElement(x)
except:
return x
def _as_list(x):
return x if isinstance(x, list) else [x]
def _unique_by_eid(elems):
seen = set(); out = []
for e in elems:
try: k = e.Id.IntegerValue
except: k = id(e)
if k not in seen:
seen.add(k); out.append(e)
return out
def _to_bic_list(maybe_cats):
"""Accept None | Category | ElementId | BuiltInCategory | int | 'Rooms' | 'OST_Rooms' | list of any -> list[BuiltInCategory]."""
if not maybe_cats:
return [BuiltInCategory.OST_Rooms]
cats = _as_list(maybe_cats)
bics = []
for c in cats:
c = _unwrap(c)
# BuiltInCategory?
if str(type(c)).endswith("BuiltInCategory"):
bics.append(c); continue
# Category -> BIC
if isinstance(c, Category):
try:
bics.append(System.Enum.ToObject(BuiltInCategory, c.Id.IntegerValue)); continue
except: pass
# ElementId -> BIC
if isinstance(c, ElementId):
try:
bics.append(System.Enum.ToObject(BuiltInCategory, c.IntegerValue)); continue
except: pass
# int -> BIC
if isinstance(c, int):
try:
bics.append(System.Enum.ToObject(BuiltInCategory, c)); continue
except: pass
# string
if isinstance(c, basestring):
s = c.strip()
if s == "Rooms":
bics.append(BuiltInCategory.OST_Rooms); continue
try:
bics.append(getattr(BuiltInCategory, s)); continue
except: pass
if not bics:
bics = [BuiltInCategory.OST_Rooms]
return bics
# Geometry extraction from DB.Element -> list[DB.GeometryObject]
_opts = Options()
_opts.IncludeNonVisibleObjects = False
_opts.ComputeReferences = False
_opts.DetailLevel = ViewDetailLevel.Fine
# cache SpatialElementGeometryCalculator per document
_calc_cache = {}
def _get_room_solid(elem, rdoc):
try:
calc = _calc_cache.get(rdoc, None)
if calc is None:
calc = SpatialElementGeometryCalculator(rdoc)
_calc_cache[rdoc] = calc
res = calc.CalculateSpatialElementGeometry(elem)
return res.GetGeometry() # DB.Solid
except:
return None
def _expand_gobj(go):
out = []
if isinstance(go, Solid):
# keep non-empty solids
try:
if go.Volume > 1e-9:
out.append(go)
else:
# even "empty" solids may have faces
faces = list(go.Faces)
if len(faces) > 0: out.append(go)
except:
out.append(go)
elif isinstance(go, Mesh):
out.append(go)
elif isinstance(go, GeometryInstance):
ig = go.GetInstanceGeometry()
if ig:
for sub in ig:
out.extend(_expand_gobj(sub))
else:
# curves/symbolic lines often not useful for volume; skip
pass
return out
def _db_element_to_db_geom(elem, rdoc):
geos = []
try:
g = elem.get_Geometry(_opts)
if g:
for go in g:
geos.extend(_expand_gobj(go))
except:
pass
# Rooms: robust solid via SpatialElementGeometryCalculator
if isinstance(elem, SpatialElement) and not geos:
rs = _get_room_solid(elem, rdoc)
if rs is not None:
geos.append(rs)
return geos
def _dbgeom_to_ds(dbgeom_list):
ds = []
for go in dbgeom_list:
try:
ds.append(go.ToProtoType())
except:
# some geometry types may fail; skip safely
pass
return ds
# ----------------- main -----------------
# 1) link instances
instances = list(FilteredElementCollector(doc).OfClass(RevitLinkInstance))
instances = _unique_by_eid(instances)
# 2) types
types = []
for inst in instances:
try:
types.append(inst.Document.GetElement(inst.GetTypeId()))
except:
types.append(None)
# 3) coordinate systems from each instance's total transform (host-space)
coord_systems = []
for inst in instances:
t = inst.GetTotalTransform()
o = t.Origin; bx, by, bz = t.BasisX, t.BasisY, t.BasisZ
p = Point.ByCoordinates(o.X, o.Y, o.Z)
vx = Vector.ByCoordinates(bx.X, bx.Y, bx.Z)
vy = Vector.ByCoordinates(by.X, by.Y, by.Z)
vz = Vector.ByCoordinates(bz.X, bz.Y, bz.Z)
coord_systems.append(CoordinateSystem.ByOriginVectors(p, vx, vy, vz))
# category selection (default Rooms) — can wire IN[0] with Categories/BICs if desired
requested_bics = _to_bic_list(IN[0])
# 4) elements per instance per category
elements = [] # elements[i][j]
dsGeom = [] # dsGeom[i][j] in link-space
dsGeomHost = [] # dsGeomHost[i][j] transformed to host-space
CS_identity = CoordinateSystem.ByOrigin(0, 0, 0)
for idx, inst in enumerate(instances):
try:
ldoc = inst.GetLinkDocument()
except:
ldoc = None
inst_elems_per_cat = []
inst_ds_per_cat = []
inst_ds_host_per_cat = []
if ldoc is None:
# Unloaded link: fill empties per requested category
for _ in requested_bics:
inst_elems_per_cat.append([])
inst_ds_per_cat.append([])
inst_ds_host_per_cat.append([])
else:
for bic in requested_bics:
try:
coll = FilteredElementCollector(ldoc).WhereElementIsNotElementType().WherePasses(ElementCategoryFilter(bic))
cat_elems = list(coll.ToElements())
except:
cat_elems = []
inst_elems_per_cat.append(cat_elems)
# Convert to DS geometry (flatten by element)
link_ds_geo_flat = []
for e in cat_elems:
db_geo = _db_element_to_db_geom(e, ldoc)
link_ds_geo_flat.extend(_dbgeom_to_ds(db_geo))
inst_ds_per_cat.append(link_ds_geo_flat)
# Transform DS geometry to host using the instance CS
host_ds_geo_flat = []
cs_target = coord_systems[idx] if idx < len(coord_systems) else CS_identity
for g in link_ds_geo_flat:
try:
host_ds_geo_flat.append(Geometry.Transform(g, CS_identity, cs_target))
except:
# If any geometry fails to transform, skip it
pass
inst_ds_host_per_cat.append(host_ds_geo_flat)
elements.append(inst_elems_per_cat)
dsGeom.append(inst_ds_per_cat)
dsGeomHost.append(inst_ds_host_per_cat)
OUT = instances, types, coord_systems, elements, dsGeom, dsGeomHost
1 Like
Hi! Did you see this post: Geometry from linked file, by shared coordinates, appears on the wrong place in Dynamo - #12 by danail.momchilov
You could also send your graph here, along with a set of sample files and I could fix it for you


