Tesi master theses
Devoto fabrication partner
CNC: real experiences | case studies
Acoustics projects | form | analisys
Custom Families Revit
Data Production model to data
Visual Basic scripting for Revit
Barrisol project for a conferece hall
We are trying to understand the potential of VB scripting within Revit, together with prof. Gian Marco Todesco
(thank you SO much!).
This post shows our attempt to generate a script that works on top of a given spline, drawn in Revit 2010.
Given a spline in R2010 the script:
1-attaches N reference points to it;
2-attaches a family to each refPoint;
This procedure seems pretty easy,
but we found it wasn't!
Here are the steps and the problems we faced:
0_DOCUMENT vs APPLICATION scripts
At first, i would like to underline that R2010 makes a difference in Syntax depending if the script is working within the current Document only, or in the whole Application.
What happens is that when we are in the Application ambient, we need to "call the document".
For instance, a command in Document mode should suond like
DoThis.ThisWay
while a command in Application is like
ActiveDocument.DoThis.ThisWay
It was important to clarify this
since that part appears several times in the scripts
i'm going to publish:
all of them are written in Application mode.
1_first bits of Script
When I've described the problem to prof Todesco, he took some days to study R2010 and after that he gave me this following bit of script: it puts 20 reference Points on the spline.
At first i need to select the spline, after That I launch the macro. The reason will be clear enough once you'll read the code.
The first, grey part of the script is mandatory for each VB script: I'll write it only once, but you need it for each of the scripts I am going to show.
'this part is mandatory- i will not replicate in following scripts but it is always needed
Imports Autodesk.Revit
Imports System.Collections
Imports Autodesk.Revit.Elements
<System.AddIn.AddIn("AppAddIn", Version:="1.0", Publisher:="", Description:="")> _
Partial Class ThisApplication
Private Sub Module_Startup(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Startup
End Sub
Private Sub Module_Shutdown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shutdown
End Sub
End of the mandatory part, beginning of the script!
Public Sub spline()
'checking i've taken the spline only
Dim selection As ElementSet = ActiveDocument.Selection.Elements
If (selection.Size <> 1) Then
MsgBox("A single component should be selected")
Return
End If
'checking i've taken a spline
Dim iter As IEnumerator = selection.ForwardIterator
iter.MoveNext()
Dim element As Autodesk.Revit.Element = iter.Current
If Not TypeOf element Is Autodesk.Revit.Elements.CurveElement Then
MsgBox("A curve should be selected")
Return
End If
Dim curve As Elements.CurveElement = element
Dim curveRef As Geometry.Reference = curve.GeometryCurve.Reference
'Me.ActiveDocument is the way to call the current instance
'Create n reference points along the spline
Dim n As Integer = 20
Me.ActiveDocument.BeginTransaction()
For i = 0 To n - 1
Dim t As Double = i / (n - 1)
Dim pointRef As PointOnEdge = Me.Create.NewPointOnEdge(curveRef, t)
Dim referencePoint As ReferencePoint = Me.ActiveDocument.FamilyCreate.NewReferencePoint(pointRef)
Next
Me.ActiveDocument.EndTransaction()
End Sub
I've underlined those lines because, if macro is running in Application, we need to specify that each cycle is a Transaction, otherwise it won't be read properly.
Few notes: we're dividing the spline into 20 pieces, but we are not controlling how.This control will be object of a future post. Moreover, first and last poing given by the macro are already existing in the spline, since these are driving geometry, so Revit says that there are superimposed refPoints somewhere.
1_inserting family instances.
After Receiving this bit of script, i've written a small procedure which loads a family and creates a number of instances, and maps a parameter (IMPORTANT! we are making conceptual mass).
'check if the family is loaded
If (Not ActiveDocument.LoadFamily("cubo.rfa")) Then
MsgBox("Loaded a family nono")
Return
End If
Dim fs As Symbols.FamilySymbol = Nothing
If (Not ActiveDocument.LoadFamilySymbol("cubo.rfa", "cubo", fs)) Then
MsgBox("Non riesco a caricare il family symbol. ciao ciao")
Return
End If
'declarations
Dim x As Double
Dim i As Integer
'creating a number of instances
Me.ActiveDocument.BeginTransaction()
For i = 1 To 20
x = i
Dim fi_pos As Geometry.XYZ = Application.Create.NewXYZ(0, 20 * x, 0)
Dim fi As FamilyInstance
fi = ActiveDocument.FamilyCreate.NewFamilyInstance(fi_pos, fs, Structural.Enums.StructuralType.NonStructural)
'setting the parameter
fi.ParametersMap("l").Set(Math.PI * 0.5 * x)
Next
Me.ActiveDocument.EndTransaction()
I've written this one departing from the one already existing on this website.
After that i've just copyied and pasted these two bits.
What we have is a macro that makes the two operations at the same time, but without any relation.
If i try and write them in the same transaction, something extremely important happens.
Revit cant create the first instace.
Since our cycle is defined
For i = 0 To n - 1
while the paramether expression is
fi.ParametersMap("l").Set(Math.PI * 0.5 * i)
the very first paramether value is 0. In the definition of revit's family THIS CONDITION IS NOT ACCEPTABLE since Volume parameter is defined as
V= K / l
When interfacing Revit to VB Script or other scripting sources, it is vital to build up families whose paramether are free to vary according to the values given by the macro, otherwise the interaction will be distructive only, like in this case.
3_Building Up Relations
We need now to build up some relations among these two parts.
First thing, i want each family instance to be attached to a refPoint. In order to do so, we shall just rewrite the script:
'declarations
Dim n As Integer = 20
Dim t As Double
Dim coord As Geometry.XYZ
Dim pointRef As PointOnEdge
Dim MagicPoint As ReferencePoint
Dim fi As FamilyInstance
Me.ActiveDocument.BeginTransaction()
'cycle
For i = 0 To n - 1
'dividing the spline
t = i / (n - 1)
'getting magicPoint's position
pointRef = Me.Create.NewPointOnEdge(curveRef, t)
MagicPoint = Me.ActiveDocument.FamilyCreate.NewReferencePoint(pointRef)
coord = MagicPoint.Position
'creating an instance
fi = ActiveDocument.FamilyCreate.NewFamilyInstance(coord, fs, Structural.Enums.StructuralType.NonStructural)
fi.ParametersMap("l").Set(Math.PI * 0.5 * i + 1)
Next
Me.ActiveDocument.EndTransaction()
What we see is that refPoint geometry is associative, while instances are not...seems like they are not hosted on ref points really. This situation is annoying.
On the other hand it is possible to control direction of the instances.
referenceDirection is the direction towards which instances are "looking at".
I can orientate them 45°.
Dim real_direction as Geometry.XYZ
real_direction = Application.Create.NewXYZ(1, 1, 0)
fi = ActiveDocument.FamilyCreate.NewFamilyInstance(coord, fs,real_direction ,MagicPoint, Structural.Enums.StructuralType.NonStructural)
...or along the spline...
real_direction = puntoMagico.GetCoordinateSystem.BasisX
...or i can orientate them from n-th to n-1-th point. I am publishing the full script for this version.
Public Sub insert_and_spline_HOST_discretize()
'load family
If (Not ActiveDocument.LoadFamily("cubo.rfa")) Then
MsgBox("Loaded a family nono")
Return
End If
Dim fs As Symbols.FamilySymbol = Nothing
If (Not ActiveDocument.LoadFamilySymbol("cubo.rfa", "cubo", fs)) Then
MsgBox("Non riesco a caricare il family symbol. ciao ciao")
Return
End If
'checking i've taken the spline only
Dim selection As ElementSet = ActiveDocument.Selection.Elements
If (selection.Size <> 1) Then
MsgBox("A single component should be selected")
Return
End If
'Get the selected element and check that it is a curve
Dim iter As IEnumerator = selection.ForwardIterator
iter.MoveNext()
Dim element As Autodesk.Revit.Element = iter.Current
If Not TypeOf element Is Autodesk.Revit.Elements.CurveElement Then
MsgBox("A curve should be selected")
Return
End If
Dim curve As Elements.CurveElement = element
Dim curveRef As Geometry.Reference = curve.GeometryCurve.Reference
'dichiarazioni
Dim n As Integer = 20
Dim t As Double
Dim coord_prev As Geometry.XYZ
Dim coord As Geometry.XYZ
Dim pointRef As PointOnEdge
Dim MagicPoint As ReferencePoint
Dim real_direction As Geometry.XYZ
Dim fi As FamilyInstance
Me.ActiveDocument.BeginTransaction()
'instance i=0
pointRef = Me.Create.NewPointOnEdge(curveRef, 0)
MagicPoint = Me.ActiveDocument.FamilyCreate.NewReferencePoint(pointRef)
coord = MagicPoint.Position
'cycle
For i = 0 To n - 1
'collecting magicPoint's position for the next iteration
coord_prev = coord
'dividing the spline
t = i / (n - 1)
'getting magicPoint's position
pointRef = Me.Create.NewPointOnEdge(curveRef, t)
MagicPoint = Me.ActiveDocument.FamilyCreate.NewReferencePoint(pointRef)
coord = MagicPoint.Position
'getting reference direction
real_direction = coord.Subtract(coord_prev)
'creating an instance
fi = ActiveDocument.FamilyCreate.NewFamilyInstance(coord, fs, real_direction, MagicPoint, Structural.Enums.StructuralType.NonStructural)
fi.ParametersMap("l").Set(Math.PI * 0.5 * i + 1)
Next
Me.ActiveDocument.EndTransaction()
End Sub
Another way of solving the problem of mismatch between Family Paramethers and Script Based - Paramether Map.
It will be vital now on to work on how to Host families to Revit geometrical entities.
Allegato | Dimensione |
---|---|
inserisci su spline.rfa | 364 KB |
cubo.rfa | 224 KB |
commenti
MarcoMondello
14 Luglio, 2009 - 00:37
Collegamento permanente
REVIT - VB drawing a line
In this "easy" script, Professor Todesco succeded in drawing a simple line into a project.
Public Sub line()
Dim p0 As Geometry.XYZ = Application.Create.NewXYZ(1.0, 0.0, 0.0)
Dim p1 As Geometry.XYZ = Application.Create.NewXYZ(0.0, 1.0, 0.0)
'creating a line by two points
Dim line As Geometry.Line = Application.Create.NewLine(p0, p1, True)
'creating a plane by normal + a point
Dim plane As Geometry.Plane = Application.Create.NewPlane(p0.Cross(p1), p1)
'sketchplanes are extremely important entities in revit: they allow to draw on them.
Dim skplane As SketchPlane = Document.Create.NewSketchPlane(plane)
'drawing this line on the sketchplane
Dim mCurve As ModelCurve = Document.Create.NewModelCurve(line, skplane)
End Sub
marco.mondello@gmail.com
MarcoMondello
17 Luglio, 2009 - 20:45
Collegamento permanente
families+script: updating parameter value problem
I've found a problem when changing parameter of a via-script built-in family.
Changing a paramether is something we do every day, but this seems to be a problem when re-executing a macro.
For instance i've changeda paramether in my family: it's about changing an inverse law into a quadratic law for height variation of this box. I have not touched the paramether mapped by the macro.
Indeed, it is possble to make the cannge effective into the .rfa by loading the family (as usual....)
On the other hand, if i try and re-launch the macro, this execution fails. It says that i am trying to modify the macro ouside the transaction (i'm making a move outside the transaction- which move, according to me, corresponds to the reloading of the family).
It will be necessary to make the routine able to allow the riparametrization of a buildt in instance, otherwise most of revit feautures won't be able to be effective when using macros.
marco.mondello@gmail.com