Roof Gutter/Soffit by python script

python
#10

Indeed, so explode the roof solid, filter to get the top surface, choose an edge (probably easiest to be the one which aligns to the one we used to set the slope?)

It’s the reference array creation from the edge that I am interested to see :slight_smile:

0 Likes

#11

New gutter from Model Line:

import clr

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

#Import DocumentManager and TransactionManager
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

#Import ToDSType(bool) extensions method
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

#Reference the active Document and application
doc = DocumentManager.Instance.CurrentDBDocument

#Start scripting here:

gt = UnwrapElement(IN[0])

line = UnwrapElement(IN[1])

ref = Reference(line)

TransactionManager.Instance.EnsureInTransaction(doc)

gutter = doc.Create.NewGutter(gt, ref).ToDSType(False)

TransactionManager.Instance.TransactionTaskDone()

#Assign your output to the OUT variable.
OUT = gutter

I’ll give the roof a go aswell, as that might be a little more interesting :slight_smile:

3 Likes

#12

Arg… I won’t be able to finish this… still needs a bit of sorting to get the right edges, but maybe one of you can work with this :slight_smile:

import clr

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

#Import DocumentManager and TransactionManager
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

#Import ToDSType(bool) extensions method
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

#Reference the active Document and application
doc = DocumentManager.Instance.CurrentDBDocument

gt = UnwrapElement(IN[0])

roof = UnwrapElement(IN[1])

#Get the roof geometry -> Solid -> Edges
opt = Options()
opt.ComputeReferences = True

#the overloaded method get_Geometry will get the solid
roofSolid = roof.get_Geometry(opt)

#get the edges of the solid as references 
edgeRefs = []
temp = []
for i in roofSolid:
	edges = i.Edges
	for j in edges:
		edgeRefs.append(j.Reference)

gutter = []
TransactionManager.Instance.EnsureInTransaction(doc)

for i in edgeRefs:
	try:
		newGutter = doc.Create.NewGutter(gt, i)
		gutter.append(newGutter.ToDSType(False))
	except:
		gutter.append('No gutters on vertical or sloped edges :-(')

TransactionManager.Instance.TransactionTaskDone()

#Assign your output to the OUT variable.
OUT = gutter
3 Likes

#13

Great work :slight_smile:

It’s very interesting to see the Python approach in that way. I’m happy to use nodes to get the edge, it’s easy to check the right one has been selected.

I do slightly despair that providing the input described in the API failed… It’s a painful learning process!

Thanks,

Mark

0 Likes

#14

@MartinSpence looks good, I’ve tried to use the code with roof script to set the item index of roof line for creating the gutter but it doesn’t work. can you see the issue?

import clr
import math
#Import Revit Nodes
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

# Import RevitAPI
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
from clr import StrongBox
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

# Import DocumentManager and TransactionManager
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

#The inputs to this node will be stored as a list in the IN variables.
roof = UnwrapElement(IN[0])
type = UnwrapElement(IN[1])
index = IN[2]

gutter = []

doc = DocumentManager.Instance.CurrentDBDocument
TransactionManager.Instance.EnsureInTransaction(doc)

opt = Options()
opt.ComputeReferences = True
roofSolid = roof.get_Geometry(opt)

edgeRefs = []
temp = []


for i in roofSolid:
	edges = i.Edges
	for j in edges:
		edgeRefs.append(j.Reference)

ref = edgeRefs.Item[index]
gutter = doc.Create.NewGutter(type, ref)
		gutter.append(gutter.ToDSType(False))

TransactionManager.Instance.TransactionTaskDone()


OUT = output
0 Likes

#15

Hey,

Here’s a working version of your python…
RoofGutterIndex.dyn (6.1 KB)

I am not sure your method is so helpful though, because I don’t know how to check that the Index is the edge you want…

Incidently, because you don’t have the Else statement, the Python doesn’t tell you if the edge is unable to have a gutter (as Martin’s does)

Here’s a workflow as I outlined above…
RoofGutter.dyn (18.0 KB)

Because it is node based, we get the 3D preview in Dynamo and can review which edge is chosen. The big problem I had was maintaining the Reference, it was easy to filter as defined above, but I couldn’t get a Reference from the Edge. So you will see that I am going through some hoops to keep the References and Edges list structures aligned.

Hope that’s useful,

Mark

2 Likes

Autodesk.Revit.DB.Reference to Curve
#16

Excellent solution, Mark :metal::grin:. You are right, it’s much easier to manage using nodes :sweat_smile:

0 Likes

#17

You’re too kind, it’s not excellent, but it does the job :stuck_out_tongue:

I’m sure someone will point out a much more elegant way!

It’s a trade off isn’t it… Python is so concise and precise… Nodes are easy to understand but very verbose…

0 Likes

#18

It doesn’t work for me, I believe it is because of revit version I’m using (2016) :frowning:
Any way thanks Mark, will try to make it in my Revit version

1 Like

#19

I have got to a dead end and don’t understand what is the issue :frowning:

import clr
import math
#Import Revit Nodes
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

# Import RevitAPI
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
from clr import StrongBox
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

# Import DocumentManager and TransactionManager
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

#The inputs to this node will be stored as a list in the IN variables.
roof = UnwrapElement(IN[0])
type = UnwrapElement(IN[1])
index = IN[2]

gutter = []

doc = DocumentManager.Instance.CurrentDBDocument
TransactionManager.Instance.EnsureInTransaction(doc)

opt = Options()
opt.ComputeReferences = True
roofSolid = roof.get_Geometry(opt)

edgeRefs = []
temp = []

for i in roofSolid:
	edges = i.Edges
	for j in edges:
		edgeRefs.append(j.Reference)

ref = edgeRefs.Item[index]
gutter = doc.Create.NewGutter(type, ref)
		gutter.append(gutter.ToDSType(False))

TransactionManager.Instance.TransactionTaskDone()


OUT = gutter

Line Based Roof with slope and gutter.dyn (25.0 KB)

is it because of revit version again?

0 Likes

#20

The warning says: unexpected indent, I guess it’s the line gutter.append(gutter.ToDSType(False)), that should not be indented

1 Like

#21

thanks @lucamanzoni , you are right, I’ve deleted the row, now it gives another error:

Warning: IronPythonEvaluator.EvaluateIronPythonScript operation failed. 
Traceback (most recent call last):
  File "<string>", line 34, in <module>
AttributeError: 'List[object]' object has no attribute 'get_Geometry'

probably the Option syntax in Revit API 2016 is different

0 Likes

#22

The python script that outputs the roof wouldn’t happen to return a list, would it?

0 Likes

#23

Hi Teo,

I’m slightly confused, I included a working version your python above, RoofGutterIndex.dyn, but you aren’t using it?

Why not try the version I gave you?

My version has this code:

newGutter = doc.Create.NewGutter(type, ref)
gutter.append(newGutter.ToDSType(False))

I believe yours is partly failing because you are redefining gutter as not being a list, then you are trying to append as if it were still a list (someone will probably have a better explanation than me).

Hope that helps,

Mark

0 Likes

#24

Dear @Mark.Ackerley , congrats with your forum celebration :slight_smile: !
Sorry, I am more confused as I just started using Dynamo and Python so I am messing everything :slight_smile: I need some time to get my head around the coding
to be honest I didn’t understand your nodes mostly because of this, please have a look at attached screenshot

0 Likes

#25

Hi Teo, not sure about the slice of cake, it makes me hungry! :slight_smile:

Not that dyn, the other one…

RoofGutterIndex.dyn (7.0 KB)

That node is in Rhythm, but you could use Select Model Element, or any other method of getting the roof…

Hope that helps,

Mark

1 Like

#26

I know it is confusing, the other graph looks complicated, but all it’s really doing is filtering down the edges to get the one you want…

I expect you need that control, but you could filter however you want…

What you will see is that I am sending the edges both as lines and references out of the first python…

The lines can be used to get properties such as being horizontal and at the top of the bottom edge… Then I apply that same filtering to the references, as only the references can be used to create the gutter.

Hope that helps,

Mark

1 Like

#27

I used your Python code and still the same error comes:

Warning: IronPythonEvaluator.EvaluateIronPythonScript operation failed. 
Traceback (most recent call last):
  File "<string>", line 34, in <module>
AttributeError: 'List[object]' object has no attribute 'get_Geometry'

Line Based Roof with slope and gutter 1.dyn (26.3 KB)

0 Likes

#28

Hi Teo,

Try this, Line Based Roof with slope and gutter-MKA.dyn (26.8 KB)
the output from the roof was a list (containing a single item, but still a list), so it threw an exception, using a codeblock to call the first index of the list stops that…

Also, it didn’t like a number input… it was interpreting this as a number with a decimal, which it calls a float… you can’t use a float to call an index, because indexes are always whole numbers (integer)… So I changed that.

I had to use an Integer of 2, because, as described above, for whatever reason, 1 is not acceptable, perhaps it is a sloped edge…

Hope that helps,

Mark

1 Like

#29

@Mark.Ackerley You legend, it worked!!!
you are a real genius, thank you a lot

1 Like