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.
curve fillet help
EvanReese
Member, Mentor Posts: 2,605 PRO
I'm working on a feature that will need to take two co-planar curves as inputs and create a fillet between them (as part of a bigger thing). I'm not sure how to create an arc segment that will hit tangent to the curves. I recall the fillet code that @ilya_baran (and others?) did for 3D Lines, which is a start for me, but I think this code only works for fillets between lines. I also recall @Alex_Kempen making a curve fillet feature, which used construction surfaces and opFillet to bypass the need for doing all of the math, but I'd like to avoid that if I can for performance (it's a good fallback). Is there something more general purpose that would handle curved inputs and behave more like a sketch fillet? Maybe one of the devs can share some more about how the sketch fillet is done?
0
Answers
If they are not both lines, then you would need to generate an offset curve similar to how the lines work here, I left the else code empty because that can be very complicated.
FeatureScript 1930; import(path : "onshape/std/common.fs", version : "1930.0"); annotation { "Feature Type Name" : "Curve Fillet" } export const curveFillet = defineFeature(function(context is Context, id is Id, definition is map) precondition { annotation { "Name" : "Edges", "Filter" : EntityType.EDGE && EdgeTopology.WIRE, "MaxNumberOfPicks" : 2 } definition.edges is Query; annotation { "Name" : "Radius" } isLength(definition.radius, LENGTH_BOUNDS); } { var edges =evaluateQuery(context, definition.edges); var intDist = evDistance(context, { "side0" : edges[0], "side1" : edges[1] }); var edgeBodies =evaluateQuery(context,qUnion([ qOwnerBody(edges[0]),qOwnerBody(edges[1])])); var tls = [undefined,undefined]; tls[0] = evEdgeTangentLine(context, { "edge" : edges[0], "parameter" : intDist.sides[0].parameter }); tls[1] = evEdgeTangentLine(context, { "edge" : edges[1], "parameter" : intDist.sides[1].parameter }); //Make sure they are pointing away from eachother. adjust directions of the lines here so they are at their minimum vector angle apart if(intDist.sides[0].parameter +0.01>=1) tls[0].direction *=-1; if(intDist.sides[1].parameter +0.01>=1) tls[1].direction *=-1; //now to create a true fillet, we need a plane var lineInt =intersection(tls[0], tls[1]); var pln; if(lineInt.dim !=0) { } if(lineInt.dim==0) { pln = plane(lineInt.intersection,cross(tls[0].direction, tls[1].direction)); if(isQueryEmpty(context, qGeometry(edges[0], GeometryType.LINE))==false && isQueryEmpty(context, qGeometry(edges[1], GeometryType.LINE))==false) { //2 lines, easy peasy var plns=[undefined,undefined]; for(var i in [0,1]) { plns[i] = plane(tls[i].origin,pln.normal,tls[i].direction); plns[i].yAxis = yAxis(plns[i]);//store for quick use } //adjust the stored y axis so that the offset goes in the correct direction if(angleBetween(plns[0].yAxis, tls[1].direction)> 90*degree) { plns[0].yAxis *=-1; } if(angleBetween(plns[1].yAxis, tls[0].direction)> 90*degree) { plns[1].yAxis *=-1; } var offLines = [tls[0],tls[1]]; for(var i in [0,1]) { offLines[i].origin = offLines[i].origin + plns[i].yAxis * definition.radius; } var arcCenterInt =intersection(offLines[0], offLines[1]); var sk = newSketchOnPlane(context, id+"arcSketch", { "sketchPlane" : pln }); var trans = worldToPlane3D(pln); var centerToApexDirection =normalize( pln.origin - arcCenterInt.intersection); var arcMid = arcCenterInt.intersection + (centerToApexDirection * definition.radius); var arcSt = project(tls[0],arcCenterInt.intersection); var arcEnd = project(tls[1], arcCenterInt.intersection); arcMid = trans * arcMid; arcSt = trans * arcSt; arcEnd = trans * arcEnd; skArc(sk, "arc", { "start" : vector(arcSt[0], arcSt[1]), "mid" : vector(arcMid[0], arcMid[1]), "end" : vector(arcEnd[0], arcEnd[1]) }); skSolve(sk); opExtractWires(context, id+"extractArc", { "edges" : sketchEntityQuery(id+"arcSketch", EntityType.EDGE, "arc") }); opDeleteBodies(context, id+"cleanup", { "entities" : qCreatedBy(id+"arcSketch", EntityType.BODY) }); var edgeDists = [undefined,undefined]; for(var i in [0,1]) { edgeDists[i] =evDistance(context, { "side0" :qCreatedBy(id+"extractArc", EntityType.EDGE), "side1" : edges[i], "arcLengthParameterization":false }); if(edgeDists[i].distance <0.001*millimeter)//leave some tolerance as distance may return a very small number { edges[i] = makeRobustQuery(context, edges[i]);//probably not needed opSplitEdges(context, id + "trimEdge" + i + "trim", { "edges" : edges[i], "parameters" : [[edgeDists[i].sides[1].parameter]], "arcLengthParameterization":false }); var qBdyEdges = edgeBodies[i]->qOwnedByBody( EntityType.EDGE); qBdyEdges=qUnion(qBdyEdges,qSplitBy(id + "trimEdge" + i + "trim", EntityType.EDGE, false)); qBdyEdges=qUnion(qBdyEdges,qSplitBy(id + "trimEdge" + i + "trim", EntityType.EDGE, true)); var ct =size(evaluateQuery(context, qBdyEdges)); if(ct>1) { var distToInt =evDistance(context, { "side0" :qBdyEdges, "side1" : tls[i].origin }); opExtractWires(context, id + "trimEdge" + i + "extractRemainingEdge", { "edges" : qSubtraction(qBdyEdges, qNthElement(qBdyEdges, distToInt.sides[0].index)) }); } else { println("only : "~ct~"edges found"); } } else { opFitSpline(context, id + "trimEdge" + i + "extendTo", { "points" : [edgeDists[i].sides[0].point,edgeDists[i].sides[1].point] }); } } } else { //need to find a way to offset the edge in the same way as 2 lines. } } });
The Onsherpa | Reach peak Onshape productivity
www.theonsherpa.com