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.
evDistance(), but for paths?
I'm looking for a way to find the closest point on a path and, most importantly to find the parameter of the point found. For a single curve, I'd use evDistance(), which would return a DistanceResult containing the parameter, but this doesn't work on paths that I'm aware. Any other methods?
I considered hacking it by using opSplineThroughEdges() to make a spline I could use with evDistance(), but it only takes tangent continuous chains, and I didn't like the overhead, and approximation anyway.
Answers
FeatureScript 2491;
import(path : "onshape/std/geometry.fs", version : "2491.0");
//export import(path : "onshape/std/evaluate.fs", version : "2491.0");
import(path : "onshape/std/query.fs", version : "2491.0");
//
import(path : "onshape/std/containers.fs", version : "2491.0");
import(path : "onshape/std/units.fs", version : "2491.0");
import(path : "onshape/std/math.fs", version : "2491.0");
/**
side0
and geometry onside1
. "Geometry" means entities, points, or lines.evDistance(context, { "side0" : vector(1, 2, 3) * meter, "side1" : query }).distance
result = evDistance(context, { "side0" : qEverything(EntityType.VERTEX), "side1" : qEverything(EntityType.VERTEX), "maximum" : true })
*/
export function evDistanceEx(context is Context, definition is map) returns map
{
var side0 = definition.side0;
var side1 = definition.side1;
var side0WasPath = false;
var side1WasPath = false;
if (definition.side0 is Path)
{side0WasPath = true;
}
else if(definition.side0 is map)
{
if(definition.side0.edges is array)
{
side0WasPath=true;
}}if (definition.side1 is Path)
{side1WasPath = true;
}
else if(definition.side1 is map)
{
if(definition.side1.edges is array)
{
side1WasPath=true;
}}
if(side0WasPath)
{
side0 = qUnion(definition.side0.edges);
}
if(side1WasPath)
{
side1 = qUnion(definition.side1.edges);
}
var def = definition;
def.side0 = side0;
def.side1 = side1;
var distRes = evDistance(context, def);
if (side0WasPath)
{
var param = GetPathParameter(context, definition.side0, definition.side0.edges[distRes.sides[0].index], distRes.sides[0].parameter);
distRes.sides[0].edgeParameter = distRes.sides[0].parameter;
distRes.sides[0].parameter = param;
}
if (side1WasPath)
{
if(distRes.sides[1].parameter >=-.01 && distRes.sides[1].parameter <=1.01)
{
var param = GetPathParameter(context, definition.side1, definition.side1.edges[distRes.sides[1].index], distRes.sides[1].parameter);
distRes.sides[1].parameter = param;distRes.sides[1].edgeParameter = distRes.sides[1].parameter;
}
else
{
println("Invalid parameter returned from evDistance. Parameter: "~distRes.sides[1].parameter);
}}
return distRes;
}
function GetPathParameter(context is Context, path is Path, edge is Query, edgeParam is number) returns number
{
var totalLength is ValueWithUnits = evPathLength(context, path);
var curLen = 0 * meter;
for (var i = 0; i < size(path.edges); i += 1)
{
var edLen = evLength(context, { "entities" : path.edges[i] });
if (size(evaluateQuery(context, qIntersection([path.edges[i], edge]))) > 0)
{
var curParam = curLen / totalLength;
var edgeMultiplier = edLen / totalLength;
if (path.flipped[i])
{
edgeParam = 1 - edgeParam;
}
return curParam + (edgeParam * edgeMultiplier);
}
else
{
curLen = curLen + edLen;
}
}
throw "Cannot find the edge in the path";
}
You can calculate it,
evDistance → set one side to qunion(path.edges)
evDistance will give you the parameter (of the closest edge) but also the index. The order of the edges is preserved with qUnion across an array, so the index will match the path index.
get total length of the path,
get the first X lengths with like evLength(qUnion(subarray(path.edges, index))
get the length of the closest edge
(check if its flipped)
length along closest edge is len*parameter (or 1-(len*parameter) if flipped)
add that length to the total of the previous
partial length / total path length → parameter.
Example:
https://cad.onshape.com/documents/fcdb4df9ade805c9057c2f51/w/3dcd322bf609a31bd074d1cb/e/531e02b4bd7b366654bb577b
Custom FeatureScript and Onshape Integrated Applications