Create a stiffener element on face.

Create a stiffener element on face.

sobon.konrad
Advocate Advocate
916 Views
4 Replies
Message 1 of 5

Create a stiffener element on face.

sobon.konrad
Advocate
Advocate

I am testing out creating a stiffener element on a face. There is a example code for placing new instance families by face reference, line and symbol that I was following and it always returns the same error: cannot be placed because line is outside of face. 

 

I am pretty sure that line that I am creating is inside of the face, or at least two points are that I am creating the line from because when queried for Face.IsInside(pt) it return True for all of them. 

Now, if I am creating a line from those points, is it possible that the line doesn't lie on the surface? 

 

Here's how I get my face:

 

def getFace(element):
	#create geometry options/compute references
	geoOptions = Options()
	geoOptions.ComputeReferences = True
	#extract geometry
	geoElement = element.get_Geometry(geoOptions)
	geoSet = List[GeometryInstance]()
	elemIter = geoElement.GetEnumerator()
	elemIter.Reset()
	while elemIter.MoveNext():
		curElem = elemIter.Current
		geoSet.Add(curElem)
	#extract faces from solids
	for i in geoSet:
		solids = i.SymbolGeometry
		for i in solids:
			faces = i.Faces
	return faces[0]

 Here's my stiffener:

 

stiffeners = FilteredElementCollector(doc).OfClass(FamilySymbol).OfCategory(BuiltInCategory.OST_StructuralStiffener)
symbol = []
for i in stiffeners:
	symbol.append(i)

 

and here's where it fails: 

 

#"Start" the transaction
TransactionManager.Instance.EnsureInTransaction(doc)

pts = []
for i in points:
	famSymbol = symbol[0]
	faceRef = getFace(faces[0]).Reference
	face = getFace(faces[0])
	uv1 = Autodesk.Revit.DB.UV(i[0].X, i[0].Y)
	uv2 = Autodesk.Revit.DB.UV(i[1].X, i[1].Y)
	line = Autodesk.Revit.DB.Line.CreateBound(face.Evaluate(uv1),face.Evaluate(uv2))
	pts.append(face.IsInside(uv1))
	pts.append(face.IsInside(uv2))
	pts.append(line)
	#doc.Create.NewFamilyInstance(faceRef,line,famSymbol)

# "End" the transaction
TransactionManager.Instance.TransactionTaskDone()

 Keep in mind that points input is really a list of UV points in the domain of 0-1 so assuming that this surface is normalized (and when asked for BoundingBox.min and max it returns 0 and 1 so it is) those points will fall on it. 

pts output is just for me to see if points are inside of surface. They are. 

Is it possible that when I do face.Evaluate(uv1) it returns a point that is not within surface anymore? 

0 Likes
917 Views
4 Replies
Replies (4)
Message 2 of 5

jeremytammik
Autodesk
Autodesk

Dear Konrad,

 

Thank you for your query.

 

Sorry for the late answer.

 

I am happy to see that you are using Python to drive the Revit API. Neat!

 

Your question is impossible to answer as it stands, unfortunately, since I cannot see how the array 'points' is defined.

 

Regarding the use of the face.Evaluate method, I would suggest feeding it with UV data that you retrieve from the face itself, e.g. by first determining the max and min UV values from the Face.GetBoundingBox method and then navigating within that area.

 

Something similar is demonstrated here by the Building Coder:

 

http://thebuildingcoder.typepad.com/blog/2013/07/football-and-space-adjacency-for-heat-load-calculat...

 

I hope this helps.

 

Best regards,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 3 of 5

sobon.konrad
Advocate
Advocate

Jeremy,

 

points are an Array of UV coordinates that I get from other sources like (Rhino, Grasshopper). The whole excercise is about interoperability between Rhino/Grasshopper and Revit/Dynamo. 

 

Anyways, points are a UV coordinates of a surface that was normalized so the UV's are all in a domain between 0-1. My assumption was that a surface/face in Revit would be normalized as well, thus this method would work easily. If that's not the case then I can very much do as you suggested and re-scale them to that surface/face domain. 

 

Example:

 

minX = float(surface.BoundingBox.MinPoint.X)
minY = float(surface.BoundingBox.MinPoint.Y)

maxX = float(surface.BoundingBox.MaxPoint.X)
maxY = float(surface.BoundingBox.MaxPoint.Y)

xval.append(minX+(maxX-minX)*point.U)
yval.append(minY+(maxY-minY)*point.V)

 Again, "point" would be a UV point ,from Grasshopper for example, that is normalized. 

 

I looked at the example that you provide and I dont understand why are the UV coordinates obtained either via Evaluating a UV on a face or by Projecting a point on a face. I find the Project method a bit scary, because I am not sure how it works. I wish I could use Project with a vector to specify the direction in which I want to project the point. Otherwise how am I to be sure that it really failed to hit something that I was hoping it would hit. 

 

Do you know anything about the weird Revit behavior where if the surface is planar it has a different domain (not normalized i think) vs. if surface is curvy it will have a normalized domain of 0-1? Is that typical behaviour? 

 

Thank you,

0 Likes
Message 4 of 5

jeremytammik
Autodesk
Autodesk

Dear Konrad,

 

Oh, I see, the Python is for Dynamo. Cool.

 

I am pretty sure that your assumption that the parameterisation coordinates are normalised to lie within the interval [0,1] is false, at least sometimes.

 

I think i have seen cases of curves where it does not hold, and faces are so much more complex.

 

There is nothing scary about any of this.

 

I believe projection always happens perpendicuarly onto the face.

 

And I would simply never assume that the UV coordinates are normalised in any way whatsoever, regardless of whether the surface is curvy or not.

 

If you make any such assumptions, you should sprinkle your code liberally with assumptions that test them.

 

I am sure they will fail fast.

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 5 of 5

Anonymous
Not applicable

Dear Jeremy,

 

i want to distribute a generic family on a face on an equal distance between them. the face can be planarface, cylindricalface, conicalface, Revolvedface, RuledFace or HermiteFace. i'm able to achieve results if i'm working on a planarface by getting the boundingboxUV, but it is not working the the other type of faces.

 

Kindly advise.

0 Likes