Setting the Sketch Plane of Model Lines created by Curves.FromCADLayers (bimorph node)

Hi all, I’m trying to use the bimorph node CAD.CurvesFromCADLayers node to Revitize (to a small degree…) a handful of DWG assignment plans… I am uncertain as to how/what determines the curves’ work plane (or SketchPlane) when “createModelCurves” is set to true.

curvesfromcadlayers
When I ran this graph, the lines seemed to come in at about 3-4 different planes (when there are actually 100), and when selecting the lines, the properties showed their work plane was “not associated” (image below are the properties of a marquee selection of lines produced from the node).
image

Question #1:

How/what determines the work plane/sketchplane of model curves created with this node? (@Thomas_Mahon I imagine you would know best :grin: ) I assumed it would be the plane in which the CAD Link resides, but the results did not reflect that.

Question/issue #2:

Maybe this isn’t necessary if I am given more insight as to how the curves planes are determined via that node, but, I thought, “oh, just connect the output curves from the bimorph node to a Python script that sets their sketch plane”. Since the parameter “Work Plane” is read only, I decided to go the Python route and use the Create Sketch Plane method (http://www.revitapidocs.com/2016/25da7bd5-04d2-b50f-ff22-8e82e263f7fe.htm) Rather than testing out any Python with the high number of curves I’m trying to create from CAD, I tried running it on two manually created Model Lines, and I’m given the error “TypeError: expected Plane, got Plane”, which is a real head scratcher for me. I wouldn’t be surprised if there is just some Python malpractice on my end, as I’m no expert. Here is the test code I started and received the error from:

import clr
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import System

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.Elements)

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

curves = UnwrapElement(IN[0])
planes = UnwrapElement(IN[1])
setplane = []

for curve in curves:
	for plane in planes:
		setplane.append(curve.SketchPlane.Create(doc, plane))

OUT = setplane

Any thoughts/insights on these issues are fully appreciated :slight_smile: (judgments on this hacky-in-between-AutoCAD-and-Revit workflow are only welcome if given in tandem with a better solution)

3 Likes

Doesn’t feel hacky to me. You have Autocad data. You want Revit data. This feels like it’s actually an ideal use for the tool.

Two troubleshooting questions here.

  1. Do the lines have any elevations in the CAD file?
  2. Do the results of the script change if you set the workplane before you run it? That is to say Open your default 3D view and set the plane to level 1, and run the script, then change the work plane to level 2 and run the script again.
1 Like

This article is a little old (2009) but I see two interesting clues in it:

One can create any line on any plane, for instance using the Revit SDK ModelLines sample. As an example, I created a vertical line using the first SketchPlane stored in the Revit database, which always seems to be the XY plane.”

Alternatively, you would have to place the model curves on a new sketch plane, which will probably require recreating them from scratch”.

Edit: there are also these Method and Property for CurveElement:
http://www.revitapidocs.com/2016/99c03261-aeb7-032f-d71e-1e03716cbfb3.htm
http://www.revitapidocs.com/2017.1/e8c6a9e9-e048-d750-2951-6f45ac7f350d.htm

This was introduced in Revit 2015:
The new method CurveElement.SetSketchPlaneAndCurve() sets the sketch plane and the curve for the CurveElement simultaneously (allowing the SketchPlane to be successfully modified in a way that would be incompatible if set separately). This method will not affect the geometry of any current joined curve elements.”

2 Likes

@jacob.small The CAD lines do not have elevations - however, they are each linked on separate levels so I assumed their lines would come in in relation to the CAD links’ respective levels. I did not try running the node with a 3D view with a workplane open; I hadn’t thought that this node’s function was dependent on the active view, but I will try it. However, I’m thinking now, I should relink the DWGs as “Visible In All Views” rather than “View Specific” - am rerunning the graph that created the levels/views and DWG links with this modification now and will try seeing if that will allow the Curves.FromCADLayers node to correctly associate the work planes.

1 Like

Thank you for the links @Yna_Db - the SetSketchPlane Method is what brought me to the starts of the code above, because its two parameters are a SketchPlane and a Curve, so it seemed to me that the SketchPlane first needs to be created… My thoughts were, create the SketchPlane, then use the SetSketchPlane method. This very well might have been an incorrect interpretation of that method, but in any case, I didn’t get to the point of utilizing the method since I couldn’t create a SketchPlane (due to the “expected Plane, Got Plane” error).

Also after reading Jeremy’s article, it seems as if creating a whole bunch of SketchPlanes isn’t good practice anyway, but maybe that article is moot since the introduction of the method in 2015. :thinking:

I really can’t tell. I understand from this article that it might be possible to create a sketch plane from 3 points on the curve. Wouldn’t it be an appropriate solution?

Well I’ve solved the model line workplane issue :grin: - The workplane of model lines created by the Curves.FromCADLayers node are correctly associated if the linked CAD is linked as “Visible In All Views”.

So now that Python code for modifying a line’s sketch plane is not needed. I still am curious as to figuring out a working code to modify model lines’ work plane, but I probably won’t be investing more time into that immediately since I no longer need it as a solution. However, I would still like to understand how/why a Python script would return an error saying it got the exact type it was expecting (in this case, “expected Plane, got Plane”), but I suppose this might be an entirely separate topic at this point.

2 Likes

A last thing to clarify maybe: I did not see in your explanation where the planes you used as an input came from, did I miss something?

@Yna_Db I didn’t provide what my plane inputs were, sorry about that :slight_smile: I was using the Clockwork node Level.Plane (my thinking was I would get the Level of the view each CAD link was in to correctly associate each with the output curves from the Curves.FromCADLayers node) In my test to attempt the Python code, I was just passing a Level selection through the Level.Plane node:

Here is with error showing:

Interesting, my intuition would be that there could be different kinds of planes all called “plane”. I will add this information here as soon as I find a related link. Thanks for the tip that will avoid time loss for anyone involved in this kind of workflow :slightly_smiling_face:

2 Likes

I agree. I think I’ve figured out the difference; the object type for the Dynamo plane is “Autodesk.DesignScript.Geometry.Plane” while a Sketch Plane is an “Autodesk.Revit.DB.Plane”… so both return as “Plane”, but the former can’t be used as a parameter for the creation of the latter.

2 Likes

I’ve gotten this before (with a few different objects) and it’s usually because of what @Yna_Db said, multiple objects with the same name. Usually the difference is between Revit and Dynamo objects.

EDIT: Looks like you got there all by yourself! :grin::+1:

2 Likes

When I initially got the error I was like, “how what why are you telling me I gave you exactly what you’re expecting?!?” but it makes perfect sense to me now :sweat_smile: I’m curious as to what is behind the error returns that reduces the naming in such a way that the difference between the two is indistinguishable… is it the Revit API, Dynamo, or IronPythonShell? :thinking:

1 Like

I was so mad the first time I ran into this error.

I guess it would be Python that’s returning just the name? I only say this because Dynamo shows a differentiation between Revit objects and Dynamo objects, and Revit doesn’t recognize Dynamo objects. It also makes sense that Python is the only one that would recognize both, but I’m just guessing.

Hi @awilliams

The CurveFromCADLayers use the host plane of the CAD instance by default. However, if it cant be determined (typically because its been aligned to a section or elevation view), the fallback is to extract the host plane from the curve explicitly using CurveUtils.GetPlaneFromCurve() method from Dynamo’s RevitNodes library. This method also provides the support for curves in 3D space, and is the same method used by the OOTB Curve.ModelCurve node.

View specific CAD instance host plane use the global XY plane by default, as you observed. It’s been on my list of updates for a while incidentally! However, there are different rules required to handle this for instances linked to plans, sections and elevations and I haven’t had time to establish all the possibilities and implement the necessary functions…its in the pipeline though, so watch this space :wink:

Creating a custom fix is the best approach for the timebeing and I see you’ve already got there using Python. As you’ve rightly stated, the exception with the Plane input is the fact this class exists in both the RevitAPI and ProtoGeometry libraries so there is a clash, which is why Python cant determine which class you are referring to. In these cases, qualifying the class is indeed the correct solution:
Autodesk.Revit.DB.Plane and you’ll fix the problem.

2 Likes

Could you just clarify where this can be observed?
Thanks :slight_smile:

You can extract the total transform from the Instance, gets it origin and the Z should always read 0.0 if I recall correctly (its been about a year since I last looked at it!).

2 Likes

Thanks for the explanation @Thomas_Mahon - I ended up ditching the Python fix after getting the lines in the correct plane by relinking my DWGs as “Visible In All Views”; it wasn’t a problematic resolution because they ultimately were being unlinked anyway!

I wish I had better documented the result of running the graph when they were all view specific links, because they did in fact come in on a few different Z planes, not all at zero. I may try rerunning it that way just to get a better gauge of what was occurring, since none of the CAD files have 3D geometry to them, it is strange that there were different planes. :thinking:

1 Like

@awilliams I’m interested to know too - if you can upload one of your DWGs I’ll investigate.

@Thomas_Mahon I reran the graph, but first created line styles for each file and layer so I could identify which files produced lines that were not at zero.and which layers they were. It turns out that 37 out of 100 dwgs had plumbing fixture blocks that were at elevations other than zero…

I will admit, I really do not know AutoCAD, so I don’t have a great understanding of how blocks work or what error in AutoCAD usage would have put these at different elevations :see_no_evil: At first I thought, maybe their elevations corresponded with their mounting heights for some reason? But I’ve never seen a urinal mounted at 6 feet (well, I don’t find myself in men’s bathrooms very often so maybe they’re out there), and I’ve most definitely never seen a sink at -2.5 feet below finish floor elevation :rofl:

I realize now I’m also lacking an understanding as to how the CurvesFromCADLayers node works or maybe lacking an understanding as to how CAD Link geometry functions; I assumed that if the links were View Specific, then their lines no longer would carry their AutoCAD elevations, but clearly that was an incorrect assumption.

1 Like