Welcome to the Onshape forum! Ask questions and join in the discussions about everything Onshape.
First time visiting? Here are some places to start:- Looking for a certain topic? Check out the categories filter or use Search (upper right).
- Need support? Ask a question to our Community Support category.
- Please submit support tickets for bugs but you can request improvements in the Product Feedback category.
- Be respectful, on topic and if you see a problem, Flag it.
If you would like to contact our Community Manager personally, feel free to send a private message or an email.
Featurescript to create plane from an edge and a direction
gauthier_östervall
Member Posts: 99 ✭✭
I'm only just learning about Featurescript.
This is (a step towards) what I want: from an edge, create a plane that contains the edge and is vertical. Here is my attempt.
I've tried opPlane, but that requires a point and a normal. I don't have the normal (yet).
I've tried cPlane (seems like a logical choice, this what I want is practically the builtin "Line-angle" plane), but I can't find the documentation for the map it expects (auto-complete in the editor only says "definition").
My questions are:
- which one is the right way? opPlane, cPlane, something else, and why?
- how do I find out what the "definition" for cPlane should look like? I don't even know the name of the keys for that map.
- while trying opPlane, I noticed I couldn't even create a normal, that is a vector perpendicular to edge, and horizontal. I couldn't even extract the vertices at the end of Edge.
- isn't there an easier way to get a plane from an edge and a direction?
Some background: the plane is going to have a sketch with the projection of a face, then I'll do an Extrude between that face and the original face.
This is (a step towards) what I want: from an edge, create a plane that contains the edge and is vertical. Here is my attempt.
I've tried opPlane, but that requires a point and a normal. I don't have the normal (yet).
I've tried cPlane (seems like a logical choice, this what I want is practically the builtin "Line-angle" plane), but I can't find the documentation for the map it expects (auto-complete in the editor only says "definition").
My questions are:
- which one is the right way? opPlane, cPlane, something else, and why?
- how do I find out what the "definition" for cPlane should look like? I don't even know the name of the keys for that map.
- while trying opPlane, I noticed I couldn't even create a normal, that is a vector perpendicular to edge, and horizontal. I couldn't even extract the vertices at the end of Edge.
- isn't there an easier way to get a plane from an edge and a direction?
Some background: the plane is going to have a sketch with the projection of a face, then I'll do an Extrude between that face and the original face.
Tagged:
0
Comments
but "plane" seems to want a vector first, not a vertex:
I couldn't watch the webinar to the end. I'll do that ASAP, and hopefully learn to convert a query to an entity.
I have the original plane, its normal, and now I want to compute the normal of the new plane by zeroing the z of the old normal.
I do see the normal of the original plane, but nothing when I put its z dimension to 0.
I feel that I am missing something fundamental here...
Generally zeroing out the z direction is not going to make for a great feature, because then you are operating on global Z direction rather than a direction that has anything to do with your geometry. (Imagine if the face normal of the selected face was a plane whose normal was [0, 0, 1], then zeroing out the z direction is always just a zero vector)
If you are worried though because your `debug` prints look different, it is because you need to call normalize to make your vector a unit vector:
I think I see what you mean, I should probably let the user give the direction they need for that. But zeroing z would at least get me started.
Normalizing worked, thanks! I'm not sure why the opPlane operation couldn't work with a unnormalized vector, but I can live with that.
Now that I'm continuing my journey with this feature, I think I should go with a cross product instead. In this case, a cross product of a vector aligned with the user selected edge, and [0, 0, 1] (or user selected direction as you mentioned) would give me a normal to the plane I intend to create.
To be clear: I want a vertical plane that contains the user defined edge.
So `edge_vector x plane_second_direction` should do. I'd like to test this at least, but I can't find a way to create a vector, from the user selected edge. I could do a line with `evEdgeTangentLine`, but that doesn't help me since I need a vector to `cross()`.
evEdgeTangentLine returns an Line: https://cad.onshape.com/FsDoc/library.html#Line
So once you have that line, you can ask for `edgeLine.direction` to find the direction of the line:
Victory! I've got a vertical plane containing the user-defined edge. This is my code:
The debug lines show output in the console, but no red vectors show up, though.
I would expect the debug directions to show up at the origin, so maybe if your view if off to the side, you are not seeing them?
A couple tips that may be useful:
- width and height parameters of opPlane are optional, you can get rid of them if you wish.
- It is not common to nest calls like evVertexPoint inside a call to opPlane. For clarity, we usually do this first, and store it in a const.
- Your call to evVertexPoint is actually redundant with your call to evEdgeTangentLine. If you use the .origin of the return of evEdgeTangentLine, it will be the location of one of the vertices of the line, and you could skip calling evVertexPoint altogether for a nice performance gain.
Any more simplifications? I'm happy to learn best practice.
Still, no vector showing as a result of debug, see here: https://cad.onshape.com/documents/23e65351356c7baa6e1c9983/w/bb9b70f6fa40ceca6840ff95/e/bc4704f512dae5f04d10f782
I am nearly there! Extruding a user-defined face, up to an edge, horizontally to a vertical plane.
Now I just need to join the resulting part, with the part that owned the face. I thought it would be easy, just as the "Add" option of standard Extrude.
The problem is that I can't get a query to the original part. I'd like to union with the part adjacent to the definition.edge, or definition.faceToRotate, but cannot seem to get qAdjacent to do that. Here is what I have:
I'd expect this to give me the body that has an edge in common with definition.faceToRotate, but it doesn't:
How do I get the part to merge with, without prompting the user?
The error I get is this: "Precondition of qAdjacent failed (entityType != EntityType.BODY)". Does this mean that qAdjacent only can take as input the same type as is is required to return as output?
(the project)
Also, what you're doing seems similar to what I did in the Captive Nut feature when using the Embedded mode. It finds all faces that are on one side of a body, and extrudes them up to a plane (see the grey part below). If this is relevant feel free to reference that and ask anything that comes up.
qAdjacent is a topological query used for finding vertices, edges, or faces that are adjacent (in other words, attached to) other vertices, edges, or faces.
So some examples of using that query might be finding all the edges coming into a vertex, or finding the two faces attached to a specific edge.
Note that qAdjacent is NOT a geometric query. It does not have any notion of edges of different bodies being coincident, or any notion of where things exist in 3d space at all. So it can only find topological connections within a body.
To find what you are looking for, you will want to do what @Evan_Reese is saying: use qOwnerBody on definition.faceToRotate
Additionally, it is possible that qCreatedBy(id + "split1") is not the right query for the tool that you want to join. You may need qCreatedBy(id + "extrude1"), since the body is created by extrude 1, and just edited by the split.
Finally, it is likely that your custom feature would want to maintain the identity of the input body (it's name, color, any properties, etc). To do this, you will want to make the existing body the first body in the qUnion array going into opBoolean.
So all together, your `tools` input should be: qUnion([qOwnerBody(definition.faceToRotate), qCreatedBy(id + "extrude1", EntityType.BODY)])
Yes!
You were right about using the result of the split, it didn't work. But I don't get why. Is there a distinction between "Created" and "Modified"? I mean the split operation does have an output, why doesn't "CreatedBy" use that on the split?
{ queryType : UNION , subqueries : [ { disambiguationData : [ { disambiguationType : ORIGINAL_DEPENDENCY , originals : [ { entityType : EDGE , historyType : CREATION , operationId : [ FXw4Mfq1r1b0Xs2_0.wireOp ] , queryType : SKETCH_ENTITY , sketchEntityId : SvyLNHGyWj9W } ] } ] , entityType : BODY , historyType : CREATION , operationId : [ FPRjScDcjS49GJl_0.opExtrude ] , queryType : SWEPT_BODY } ] }
Jake, am I close?
The println() on a query will only work if that is one of the original queries from the definition that was obtained by just clicking on an entity. What you are looking at is the generated query based on the history of the entity, which is meant to be robust in the face of model changes. Imagine you were to extrude a block, and then fillet one of the edges of the block. Then, you moved the rollback bar to before the fillet, and split the block in half (cutting the selected edge in half). Then, when you roll forward the fillet, you will see that both of those edges will be filleted.
The query we generate for that selection tracks the history of that edge. Essentially saying "the top cap edge created by extruding this specific sketch edge". Now, when we insert the split into the feature list, we can still resolve that query, because the split does not create two new edges, it splits an existing edge.
Maybe that example makes it a bit clearer, but it really does break down to just entities are only created once, and things like splits and geometric modifications are not considered creation of a new entity.