Direct Shape repeated use

Hi everybody,

I have a question concerning the DirectShape.ByGeometry Node. I import several points from Excel, create solids by sweets and then I want to get the geometry permanently into Revit. It works fine with DirectShape.ByGeometry node. But, when I change the excel file, because I want to import the next geometry, the direct shape form the first run disappears. I there a way to let’s say glue the direct shape permanently into Revit?
Otherwise I have to save the Revit file, close everything and reload the Revit file again, to be able to create new geometry with Dynamo.
Is there a best practice to bring solids permanently to revit?


There are several methods indeed, but simply using the Dynamo Player should help, though I never tried using it with an Excel input.

Hi @ilja.prinz

You mean like this:

@Kulkul exactly!
Are you willing to tell me more?

The general solution would be as follows:

  • Open springs.Directshape custom node for your task
  • Open the python script and look for the line(s) that contains “ToDSType(False)” and change it “ToDSType(True)”

Hi @Kulkul

I am not sure I got you right. But there is no ToDSType in this node.
And thank you for your help!

#Copyright(c) 2017, Dimitar Venkov
# @5devene,

import clr
import System
from System.Collections.Generic import *

from itertools import repeat

pf_path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86)
import sys
sys.path.append("%s\IronPython 2.7\Lib" %pf_path)
import traceback

from Autodesk.DesignScript.Geometry import *

import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
app = DocumentManager.Instance.CurrentUIApplication.Application
isRvt2017 = int(app.VersionNumber) > 2016

import Revit

import Autodesk.Revit.DB as RVT

class SpringsDirectShape(object):
	def __init__(self, ds):
		self.InternalElement = ds
	def ToString(self):
		return "%s %i" % (RVT.Element.Name.__get__(self.InternalElement), self.InternalElement.Id.IntegerValue)

def tolist(obj1):
	if hasattr(obj1,"__iter__"): return obj1
	else: return [obj1]

def output1(l1):
	if len(l1) == 1: return l1[0]
	else: return l1

def PadLists(lists):
	len1 = len(lists[0])
	for i in xrange(1,len(lists)):
		len2 = len(lists[i])
		if len2 == len1 : continue
		elif len2 > len1: lists[i] = lists[i][:len1]
		else : lists[i].extend(repeat(lists[i][-1],len1 - len2))
	return lists

def NewDS(s1, cat1, name1):
	message = None
	temp_path = System.IO.Path.GetTempPath()
	sat_path = "%s%s.sat"% (temp_path, name1)
		if factor != 1:
			s1 = s1.Scale(factor)
		sat1 = Geometry.ExportToSAT(s1, sat_path)
		satId = doc.Import(sat1, satOpt, view1)
		el1 = doc.GetElement(satId)
		geom1 = el1.get_Geometry(opt1)
		enum = geom1.GetEnumerator()
		geom2 = enum.Current.GetInstanceGeometry()
		enum2 = geom2.GetEnumerator()
		s1 = enum2.Current
		if cat1 is None or not RVT.DirectShape.IsValidCategoryId(cat1.Id, doc):
			cat1Id = RVT.ElementId(RVT.BuiltInCategory.OST_GenericModel)
			cat1Id = cat1.Id

		if name1 in dst_enum:
			old_type = dst_enum[name1]
			fec1 = RVT.FilteredElementCollector(doc).OfClass(RVT.DirectShape).WhereElementIsNotElementType()
			insts = [i for i in fec1 if i.GetTypeId().Equals(old_type.Id)]
			if insts:
				ds1 = insts[0]
				dsLib.AddDefinitionType(name1, old_type.Id)
				if isRvt2017:
					ds1 = RVT.DirectShape.CreateElementInstance(doc, old_type.Id, cat1Id, name1, tf1)
					ds1 = RVT.DirectShape.CreateElementInstance(doc, old_type.Id, cat1Id, name1, tf1, "Dynamo", "spring nodes")
			dsType1 = RVT.DirectShapeType.Create(doc, name1, cat1Id)
			dsLib.AddDefinitionType(name1, dsType1.Id)
			if isRvt2017:
				ds1 = RVT.DirectShape.CreateElementInstance(doc, dsType1.Id, cat1Id, name1, tf1)
				ds1 = RVT.DirectShape.CreateElementInstance(doc, dsType1.Id, cat1Id, name1, tf1, "Dynamo", "spring nodes")

		return ueWrapper.Invoke(None, (ds1, False) )
		return traceback.format_exc()

solids = tolist(IN[0])
cat = tolist(IN[1])
cat = [UnwrapElement(c) for c in cat]
names = tolist(IN[2])

satOpt = RVT.SATImportOptions()
satOpt.Placement = RVT.ImportPlacement.Origin
satOpt.Unit = RVT.ImportUnit.Foot
opt1 = RVT.Options()
opt1.ComputeReferences = True

acceptable_views = "ThreeD, FloorPlan, EngineeringPlan, CeilingPlan, Elevation, Section"
view_fec = RVT.FilteredElementCollector(doc).OfClass(RVT.View)
view1 = None
for v in view_fec:
	if v.ViewType.ToString() in acceptable_views and not v.IsTemplate:
		view1 = v

units = doc.GetUnits().GetFormatOptions(RVT.UnitType.UT_Length).DisplayUnits
factor = RVT.UnitUtils.ConvertToInternalUnits(1, units)

dsLib = RVT.DirectShapeLibrary.GetDirectShapeLibrary(doc)
tf1 = RVT.Transform.Identity

dst_fec = RVT.FilteredElementCollector(doc).OfClass(RVT.DirectShapeType)
dst_enum = dict([(RVT.Element.Name.__get__(i), i) for i in dst_fec])

ueWrapper = None
wrappers = clr.GetClrType(Revit.Elements.ElementWrapper).GetMethods()
for w in wrappers:
	if w.ToString().startswith("Revit.Elements.UnknownElement"):
		ueWrapper = w

if len(solids) == len(names):
	if not len(solids) == len(cat):
		padded = PadLists( (solids, cat) )
		cat = padded[1]
	OUT = output1(map(NewDS, solids, cat, names) )
else :
	OUT = "Make sure that each geometry\nobject has a unique type name."

@ilja.prinz Change this:


1 Like

Thank you again. Note to myself…Learn Python :sweat_smile:
Unfortunately this node expects a list of n different names tolist(IN[2]). I guess I have to change this somehow, since I only have the geometry and no names in my Excel file.

How many geometries you have?

@ilja.prinz Not sure what your workflow and intent is, but could you not just first create all the Dynamo geometry, combine them in a list and create all instances of DirectShape simultaneously?

1 Like

@Kulkul and @Vikram_Subbaiah
Thank you again for your help! :vulcan_salute:

I have different lists (Excel files) with point coordinates. From this coordinates i create lines and sweeps with a certain profiles. Simply said, I want to have axis of different tracks inside my Revit model as a 3D body.
On example of the basic data I get is:
KLEINP_3684_li_Planung.xlsx (583.0 KB)
I have four of this excel files and a unknown number to come…
You can see my workflow in this dyn file. It would help a lot, If I could just change the source (Excel file) and create new geometry every time I start the script. Somthing like “overwrite true/false”.
import_track_from_excel.dyn (35.9 KB)

I don’t think that would be possible. As you seem to already know, the way to do so is to close and reopen the Revit file

However, going with my earlier suggestion of creating geometry simultaneously (not sure if it’s practical or addresses your concern) you could probably read from multiple excel files at once.

Just a thought: In the Beaker package is the Utilities.BakeElements Node. That seems to be what you’re looking for?

Did you try with Dynamo Player? I don’t have R2018 installed but it seems that a file path can be an input (and I would be curious to see if it works):

The names of the shapes would obviously need to be different.
Edit: it works in R2017 but indeed with a BakeElement node in the end

Hi everybody,

sorry my delayed replay. The hint from @Bjorn_Keulemans1 was absolutely helpful. That is exactly what I was searching for!
I also tried the dynamo player. I guess it is the same but only without the visible nodes. One has the possibility to set up the parameters without opening the script itself.

However, the image node was the solution.

Thank you very much!

1 Like

It happened to me that a similar workflow did not work when directly run from Dynamo but went well when using the Player. As for reference: