Casting in Python

Hi,

I’m attempting to convert a dimension routine from C# (which I don’t use) to Python.

This is the C# code:

public void CreateDimFromFaces()
{
    Document doc = this.ActiveUIDocument.Document;
    UIDocument uidoc = this.ActiveUIDocument;
    Reference r1 = uidoc.Selection.PickObject(ObjectType.Face, "Pick face for dimension reference");
    Reference r2 = uidoc.Selection.PickObject(ObjectType.Face, "Pick face for dimension reference");
    Reference r3 = uidoc.Selection.PickObject(ObjectType.Face, "Pick face for view work plane");
    ReferenceArray ra = new ReferenceArray();
    ra.Append(r1);
    ra.Append(r2);
    Element e = doc.GetElement(r2);
    Location l = e.Location;
    LocationCurve lc = l as LocationCurve;
    Curve curve = lc.Curve;
    Line line = curve as Line;
    
    using (Transaction t = new Transaction(doc,"dim"))
    {
        t.Start();
        doc.ActiveView.SketchPlane = SketchPlane.Create(doc, r3);
        Dimension dim = doc.Create.NewDimension(doc.ActiveView, line, ra);
        t.Commit();
    }
}

The bit which I can’t work out the Python version are these lines:

    Element e = doc.GetElement(r2);
    Location l = e.Location;
    LocationCurve lc = l as LocationCurve;
    Curve curve = lc.Curve;
    Line line = curve as Line;

I believe this is where one type is cast into another?

I get the bit where the location for element ‘e’ is obtained (the first two lines), but its the 3rd line which I’m unsure about.

Is this a cast? Converting a Location into a LocationCurve? I didn’t know you could do that?

I’d appreciate some explanation from you chaps in the know!

Thanks.

Because C# is a strongly typed language you have to specify the type for every variable. That’s why it needs casting to a LocationCurve. Python on the other hand does the casting for you, so in this case you should be able to do something like this:
curve = l.Curve

Because you ask for .Curve property on a Location object Python will figure out that it needs to cast to LocationCurve and then return the Curve.

1 Like

Excellent - thanks for your explanation - that would explain why I don’t know too much about casting…

Strangely though when I try l.LocationCurve it states that the location class doesn’t have a method called LocationCurve, I guess the Revit API is no different in C# so I’m not when I get the error.

That’s because the Location Class doesn’t have a property called LocationCurve. Instead you should use l.Curve as .Curve is a property of the type LocationCurve.
In C# you first have to cast a Location type to a LocationCurve or LocationPoint. From there you can get the associated curve or point.
What I think happens in Python is this: as soon you query the Location property of an element, the Location type is directly cast to either LocationCurve or LocationPoint. So that in python you never really get to work with a Location class but rather one of its derived classes (LocationCurve & LocationPoint)

Yes - l.Curve worked.

But how do you know this? When I read the Revit 2017 API document, I can see anything that states that you can get a curve property from a location object?

The same thing happens a few lines down on the code above:

Curve curve = lc.Curve;
Line line = curve as Line;

It turns a Curve into a Line, but the Curve class has no property called Line…

Thanks.

1 Like

You are correct that a Location does not have the Curve property. You need to know that you can cast a Location to a LocationCurve. From there you can see that a LocationCurve does have the Curve property. When you look at the Revit API document you’ll there’s a section detailing the Inheritance Hierarchy. There you’ll see that LocationCurve and LocationPoint are derived from Location. This should tell you that you can cast a Location to a LocationCurve.
The same applies to the Curve class where you can see all the Curve’s derived classes (including Line).
image

1 Like

Thanks, thats very intersting, I’ve been watching a few Youtube videos on class inheritance…

Its strange though, when I previously tried the code, it worked and I obtained a curve.

Now when I try it, Python casts the Location class into a LocationPoint and not a LocationCurve.

What dictates how the casting happens? how does it choose the LocationPoint class rather than the LocationCurve class?

# Dynamo
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

#The inputs to this node will be stored as a list in the IN variables.
dataEnteringNode = IN

r1 = uidoc.Selection.PickObject(Selection.ObjectType.Face, "Pick face for dimension reference")
r2 = uidoc.Selection.PickObject(Selection.ObjectType.Face, "Pick face for dimension reference")
r3 = uidoc.Selection.PickObject(Selection.ObjectType.Face, "Pick face for view work plane")

ra = ReferenceArray()

ra.Append(r1)
ra.Append(r2)

e = doc.GetElement(r2)
l = e.Location

lc = l.Curve

#Assign your output to the OUT variable.
OUT = [r1, r2, r3, ra, e, l, lc]

In the above code variable lc generators an error because variable l is a LocationPoint and not a LocationCurve…

Cheers.

1 Like

I don’t know how the casting is done. I would figure that this ‘casting-decision’ is made somewhere under the hood (by the people that programmed the IronPython API for Revit/Dynamo). All of which is open-source I believe, so theoretically you could find the underlying logic of it all somewhere.

OK, thanks.

i don’t know if i am missing anything.
but isn’t it that we have line based classes like wall, “line based families”… and point based clases like windows, doors (point based).
for checking i would go like:

if isinstance (element, LocationCurve):
    do location line things
else:
    do location point things

Yes, I think your right, the reason I was getting a Location Point as opposed to a curve was due to the objects I was selecting in the first place.

I found that running the code on a wall produced a location curve, where as running the code on a generic model produced a location point…

@Kevin.Bell Clockwork package has already a node that can differentiate between “Point and Curve” of the elements.

image

1 Like