I have a difficult problem that I cannot find a solution for, but it seems so simple that perhaps i have overlooked something.
I want to make a vector that is perpendicular to an edge. Meaning, the vector should be on the plane of the connected face, going from the edge and perpendicularly out from the face. Does it make sense? Please see this image. The lone edge pointing out from the face should be the vector.
I could take the face edge and rotate it 90 degrees with the plane axis, but that does not ensure that the vector always goes in the right direction. Can I somehow detect which direction is away from the face? Or is there another solution?
Use the Line tool, click a point within the face [not on an edge].
An inference color will show as you move your cursor up from the face - an axial-color if the face is flat in an axis, or magenta otherwise as âperdendicularâ - or black of not near perpendicular.
Click to make the end point of the line.
That line is now perpendicular to the face.
Exit the Line tool and Select the line, click its start-end as your anchor point and drag the line to the edge of the face where you want this to beâŚ
If you are really trying to do this in code then norm = face.normal gives you the [unit] vector - add a new line using that vector to offset a point on an face-edge as the lineâs end [ entities.add_line(startpt, startp,offset(norm, length)) ] - the normal it is always âaway from the faceâ - but in your illustration the face is reversed so itâll be âdownâ, when I expect you want âupââŚ
I am sorry, I was not being clear. I mean to do this in ruby.
The vector I am trying to make is not perpendicular to the face, but perpendicular to an edge of the face. It is on the face plane, going perpendicularly from the face edge and out.
Maybe this illustrates it better:
The only almost fool proof but highly inelegant method I can think of is to offset the edge along the vector and check if the face area increases. If it does, the vector goes in the right direction, else I must reverse it. But that is a very ugly solution I think, is there a way to know what side of the edge has the face on it, or which direction of the vector goes away from the face?
So, you want vector thatâs parallel to the plane of the face, and also perpendicular to the edgeâŚ
You have the edge from which you can get the start & end and use those to make a vector, current parallel with that edge
You have the face.normal vector.
Make a transformation which rotates -90.degrees about a point on the edge and uses the face.normal vector as its axis of rotation. The -ve angle should move the new edge off face.
You might need to check if the edge is reversed in the face and adjust the angle accordinglyâŚ
Depending on the direction of the edge this produces a vector that goes either into the face or away from the face. But I would like for it to always go away from the edge. It is for scripting a tool that will do this routinely on many different edges, so I would like for it to do this automatically.
Perhaps you could create a test vector from edge start point to the face bounds center. Then check the angle between this test vector and your vector. If the angle less than 90 degrees you can reverse your vector.
face = edge.faces[0]
ang = -90.degrees
ang = -ang if edge.reversed_in?(face)
vector = edge.start.position.vector_to edge.end.position
vector_trans = Geom::Transformation.rotation(edge.bounds.center, face.normal, ang)
vector.transform!(vector_trans)
I might have got the reversed_in? test backwards⌠if so, then you just need to change the 2nd line to ang = 90.degrees
I canât test it myself right nowâŚ
Then add the new edge entities.add_line(edge.bounds.center, edge.bounds.center.offset(vector)
Oh my, I did not know the reversed_in method, and I am still not sure I understand what it does, but from my testing it seems to work as you wrote it. So this must be the answer! Brilliant!
I wasnât aware that an edge could be reverse, and I am curious as to what it means. Does it mean that in a face with all unreversed edges, those edges always form a loop that goes counter clockwise around the face? I am sorry if it is a silly question and you donât need to answer, I am just curious.
Typically a face has an outer loop of edges which go ccw [relative to the face.normal], conversely any hole-loops in a face should have edges which go cw.
However, when you draw a flat face at z=0, irrespective of the direction of the âloopâ. the face always faces down - assuming you want to pushpull up [this happens in code and also when you add a face manually]
Also subsequent manipulations of geometry [e.g. face reversals] can also result in situations where a face can have one or more of its edges which ârotateâ about its normal in the âwrongâ directionâŚ
The reverse_in? test tells you if the edge you are testing is oriented contrary to the âproperâ face loop direction of ccw etcâŚ
You can test this yourself by mixing manual operations and some trial codeâŚ
An Edge has a start Vertex and and end Vertex. The âdirectionâ of the Edge is from the start to the end.
As @TIG points out, in a Loop that defines the boundary of a Face, the Edges must proceed sequentially around the Loop. But, if a Face is created from pre-existing Edges, they might have their direction the wrong way for the Loop. For example, this always happens if the Face shares an Edge with an adjacent Face with its front side pointing the same way. That is, since each Face must trace its edges (say) ccw, they will go through the shared Edge in opposite directions.
To allow for this, a Loop actually refers to Edges via an intermediary EdgeUse object. One of the things an EdgeUse does is to track whether the Edge must be used in its natural direction or reversed so as to follow sequentially around the Loop. Thatâs what the reversed? method on an EdgeUse or the reversed_in? method of an Edge tells you.
Thank you so much for the diagram of loops, slbaumgartner. I think this is so essential that it ought to have a place in the ruby documentation. Perhaps if Trimble is listening, though I know the ruby documentation has always had many deficiencies. I never quite understood the concept of edgeuse, but this example brought me closer.
I too at first thought of using the face.bounds.center, but it would not always work, as for example in this case where the center is âin frontâ of the vector.
TIGâs solution reversing edges works in all situations I have tested.
FYI, I did not use the faceâs centroid. The code uses the center of the bounding box surrounding the face.
Also, the Geom::Point3d#project_to_line method picks the closest point on the line (in this case an edgeâs line,) which should be guaranteed to use a perpendicular ray to find the point.
Steve, can you show with diagrams a scenario in which this would not be so ?
What you show in your image is an arrow (placed in a certain position) not a vector.
A vector is an object that points in a direction and has magnitude. Such a vector can be placed anywhere (or used in your case to draw an arrow) wherever desired.
But I do see your point in this scenario. Perhaps it would be easier to just use the bounding box of the edge itself ? I was thinking this when I wrote the example above.
Anyway, if you are satisfied with the solution you have, we can move on.
Your assumption is that the center of the bounding box lies on the face. Not necessarily so. Thus cannot be used to determine the direction of the outward normal.
However, my statement in the previous post was not correct, as you pointed out. It will be perpendicular, however not always in the desired direction. But I did like the elegance of your snippet.