I need to calculate the distance between a beam and a sloped roof. I have the geometry of both elements (solids) and the location line of the beam. The beam is parallel to the roof.
Using the DistanceTo node provides the shortest distance, what I need is the vertical distance (Delta Z.)
I was wondering if anyone can help with what method would be most efficient/effective to accomplish this. The one method I thought of is drawing a line from the edge of the beam going up a ways and then getting the closest intersection, but I feel like there are better ways to do this.
I’d try one of two options:
- Project a point from one geometry to the other, in the Z direction. Then get the distance between points.
- Similarly, create a line in the Z direction that extends from or beyond both geometries. Get the intersection points and find the distance.
If you have the slope of the elements you could also just use trigonometry to calculate the hypotenuse (Z axis) from the shortest length.
I was dropping the beam thinking it would be easier to measure the distance across the gap, instead I just had the idea to leave the beam and the roof intersecting, get the bounding box intersect geometry, and grab the minimum value which gave me the correct Z elevation I needed. Seems to be working well.
For the gap I like the point projection, thanks for the suggestion.
If the beam is sloped and skewed, such as a roof hip beam, there are some issues I am having, but ideally I think what I need to do is:
Get the location lines at the beam left side and right side at the top (as it may be different on the two sides). I’m unsure of the best way to do this. I tried using the curve.offset node but there doesn’t seem to be a way to specify a direction, and in my testing I have seen it offset in the Z Direction. What is the best way to do this?
Get the midpoint of these lines, as at the ends the lines may stick past the roof. I don’t see a midpoint node, do I just need to calculate it out manually?
Get the Delta Z projecting these midpoints onto the roof solid. I think I’ve got this working. And then use the appropriate one of the two values (smaller if the beam is below the roof surface.)
Get the beam solids and explode to surfaces. Filter out surfaces where the area is not equal to the beam width and thickness. Sort the surfaces by the Z value of the normal. Get the last surface in the sorted list. Pull the perimeter curves, sort by length and take the last two (left and right side, in no particular order).
Curve.PointAtParameter should work as your curves would be uniform.
Thanks, this is helpful. I think I have got all the steps, except I am still trying to figure out how to filter out the correct surfaces. It will not be the same calculations for a steel beam with many sides and a rectangular profile wood beam.
Am I getting the Z value of the normal at the center points (u/v param 0.5?)
If your beams are drawn with top alignment (which is pretty common for roofs) then you should be able to use the location curve directly. If not, you could offset the location curve by half the beam height (in the direction of orientation).
Perhaps this screenshot will help illustrate the issue. Depending on placement, the distance of the beam to the roof is not the same across the location line and at both faces of the beam. The beam may be at a slope and skew to further complicate the issue. I need both of these dimensions pictured here to determine where to place the beam (the beam in this picture should be at - 2 3/8" z offset with the beam’s location line at the roof edge pictured.) I tried offsetting the line to get the top location line of the two faces, but the curve offset node does not have a direction and on the beams that are sloped, it has offset the line in the Z direction, I guess because they are not planar. Getting the distance at any curve I’ve got figured out using several methods.
I think I could use the geometry.translate node to offset the line, and this may actually be the easiest method, but I would need the correct vectors. How would I obtain them?
If you need the intersection of both edges then you can get the location line (center) and offset by half the beam width in both directions. Then project that curve onto the roof surface and measure the distance.
Yes I understand, but how do I obtain the correct vectors to offset the curve? The beam may not be planar so the offset node does not work correctly.
EDIT: I could try flattening the curves by overriding the z value, offsetting them, and then replacing the z values… but I’d like to learn how to do this properly.
This seems to work to get the vector:
I can then offset the line using geometry.transform, and project points onto the roof geometry.
I’d still like to master the technique describe by Jacob, though.
I’m talking about something like this. With the normal of the curve (
NormalAtParameter is based on curve direction not drawing plane) and the width of the beam, we can offset (via
Transform) our location curve by a half width in both normal directions (positive and negative) to get the edge locations of the beam.
Then we can project those edge curves up to the roof and measure.
Thanks, I still don’t quite understand what defines a normal; a line is a 2D element and can be offset perpendicularly in an infinite number of directions forming a circle, and the vector of this line has non-zero values for all 3 axes. But NormalAtParameter 0.5 works.
So I don’t need an actual Z Offset, I don’t know why I was thinking that, I need the distance between the beam and the roof solid perpendicular to the beam. How do I get the correct vector to offset the point towards the roof surface? An explanation to my pondering above should help with this.
So I solved it, perhaps there is an easier solution, but here is what I did and it seems to be working well:
- Determine width of beam using parameters (can’t find a script that works to automatically determine beam depth for skewed elements but I will work on that in the future.)
- Offset location line of beam in both directions by half the width of beam (this was described above by Nick.)
- Create a plane along the location line using the line’s points and the normal that was obtained in the previous step.
- Rotate the location line 90 degrees at the midpoint along the plane from the previous step.
- Get the vector from rotated line’s start and end points.
- Drop the two offset lines below the roof, project points along the vector to the roof solid.
- Subtract the distance I offset, and get the Z Offset Value.
Still not sure how a normal is derived for a line. Perhaps I will make another topic.
The best way to learn this is to play. Draw a line in Dynamo, and generate a coordinate system at parameter, and it will all start to make some sense.
Just when I think I had this working perfect, I encounter this scenario lol. I can think of three options:
- Create a ton of offset lines, attempt to brute force it. Feels kind of bad.
- Get that bottom edge, create a plane from it, measure the distance between the plane and the beam top surface along the proper vector (keep in mind both the roof and beam are sloped and skewed so I can’t use bounding box min/max values, among other possible solutions that won’t work.)
- Fudge it and call it a day.
I have pulled a list of curves from the edges of the roof that intersect the beam, but that’s where I hit a wall for today.
To help provide a process to handle every possible edge case is a difficult ask, especially when we haven’t received a Revit model with the issues, code, or other data set to work with.
Can you post something to reproduce the issue?
Sorry, this is obvious a pretty complex script handling a lot of different cases and I am not asking you to write it for me, I want to figure this out myself. I’ve got the process going and it is working very well, save for this one case. I am not looking to reinvent the wheel. I can separate out this as a different case with a different solution.
My only question it how to get the curve (line) for that roof valley edge that is parallel to the beam and intersecting the beam pictured above. I’ll figure the rest out.
Intersect the geometry of the roofs with the geometry of the beam. Pull all the vertexes from the resulting solid and convert to points. Find the lowest of those, pull it to the maximum height of the beams and then project it doenwards with a Point.Project method.
Well I didn’t try that, I will play around some more to give it a shot, but what I did was get all the edges of the roof that intersect the beam, find the one that has a parallel vector to the beam to give me my edge. Make a plane from the edge, measure the distance to the beam, and get my value.
Lets see how long it takes to break this with another weird case
It would be really nice if there was a distanceto node along a specified vector.
This is basically the line intersect workaround mentioned previously. You can draw a line from your base point, along a vector, and then intersect with the roof to get the distance. Depending on the geometry you have, there’s also a node to project geometry along a vector that could simplify this.
Also, don’t feel like you have to develop graph logic for every single edge case. It’s ok to develop automation for the top 90% and say “this logic only works for these cases - others must be handled manually”. It may be more efficient to rework the design process to fit your automation than to try and build your automation around the design process. Of course without knowing your exact situation it’s hard to say whether this a valid option or not, but I think it’s good general advice either way.
Don’t let “perfect” be the enemy of “good”.