SketchPlane.Create overload methods not working in Python

I’m trying to create a new SketchPlane based on a Face of a Ceiling element:

geoElement = element.get_Geometry(Options())
for geo in geoElement:
	for face in geo.Faces:
		if (face.Area > area):
			area = face.Area #update area size
			largestFace = face #save face
			#faceSurface = face.GetSurface()
			#faceRef = face.Reference
			faceNormal = face.FaceNormal
			faceOrigin = face.Origin

# Transaction
t2 = Transaction(doc, "Test")

#facePlane = Plane.CreateByNormalAndOrigin(faceNormal, faceOrigin)
facePlane = Plane.CreateByNormalAndOrigin(XYZ(0,0,1), faceOrigin)
#sketchPlane = SketchPlane.Create(doc, faceRef)
sketchPlane = SketchPlane.Create(doc, facePlane)
#sketchPlane = SketchPlane.Create.Overloads[Document, Plane](doc, facePlane)

As you can see from the commented lines, I’ve tried creating the SketchPlane with specific OverLoads, and also without, and using both the face’s GetSurface() as well as the face’s Reference, but nothing works.

I’m getting either:

Exception: Curve must be in the plane
Parameter name: pCurveCopy


TypeError: Multiple targets could match: Create(Document, Plane), Create(Document, Reference), Create(Document, ElementId)

Am I using the OverLoads method wrong?
Any ideas on how to successfully create the SketchPlane?

Any ideas?

Hi @AH_Yafim,

Try this and see if it works…

import clr

import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc =  DocumentManager.Instance.CurrentDBDocument

import Revit

from Autodesk.Revit.DB import *

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

e = tolist(UnwrapElement(IN[0]))[0]

btmFaceRef = HostObjectUtils.GetBottomFaces(e)

if not btmFaceRef == None:
	r = btmFaceRef[0]
	f = e.GetGeometryObjectFromReference(r)
	if f.GetType() == PlanarFace:
		skPl = SketchPlane.Create(doc, r)
		p = Plane.CreateByNormalAndOrigin(f.ComputeNormal(UV(0.5, 0.5)), f.Evaluate(UV(0.5, 0.5)))
		skPl = SketchPlane.Create(doc, p)
	OUT = skPl
	OUT = None 

You will notice that the way I am getting the Reference is slightly different as I am taking advantage of the fact you are using ceilings and this allows me to use the HostObjectUtils class to get a specific reference to a face (in my case the bottom face). Then I can retrieve this face from the Element by Reference. Now I have the Reference, if it is typeof PlanarFace, I can pass this directly into the SketchPlane.Create(doc, faceRef), otherwise, I am creating a new plane tangent at the midpoint of the surface and using this instead.

Hope you find this useful.



@Daniel_Woodcock1 Thanks.
It did help a bit.

I’m running into the same issue further down the code where I’m trying to offset the edges of the ceiling face and create a Model Curve from them:

crvSet = []
edgeArray = face.GetEdgesAsCurveLoops()

# Transaction
t2 = Transaction(doc, "Offset boundary")

for e in edgeArray[0]:

for line in edgeArray[0]:

	normal = line.Direction.Normalize()
	vecDir = XYZ(0,0,1)
	cross = normal.CrossProduct(vecDir)

	offsetCrv = line.CreateOffset(-10, cross)
	newCrv = doc.Create.NewModelCurve(offsetCrv, sketchP)


The error I get is:

Exception: Curve must be in the plane
Parameter name: pCurveCopy

I think it might be something to do with the Transaction, because I haven’t used the TransactionManager as you did. I didn’t use it because I’m not writing a python script in Dynamo, but rather in an IDE based on pyRevit.

I also tried using with Transaction(doc, 'Create Ceiling Boundary Offset') as t:
instead of the second t2 transaction, but that gave the same result.

What could be the problem…?

A potential issue is that your vecDir is hard-coded to be along the Z axis, this should be the normal of the face/SketchPlane (since the SketchPlane is aligned to this face). Otherwise it looks ok.

I don’t think it is the Transaction though, this error is stating that one or more curves are not in the same plane as the sketch plane you are giving it. You should try debugging a little and testing if each curve is coplanar with the SketchPlane, you can do this by projecting each endpoint to the Plane via Plane.Project, this should return UV and Distance, both ends should return a distance of 0.

1 Like

Thanks for the help!
I changed my vecDir to be vecDir = face.ComputeNormal(UV(0.5, 0.5)) and I also performed a test to see the endpoints of the line segment projected onto the face, but both endpoints gave 0.0 as the distance result:

startP = line.GetEndPoint(0)
endP = line.GetEndPoint(1)
output = face.Project(startP)

So basically everything should be fine, I still get the same error. Really strange.