Welcome to the Onshape forum! Ask questions and join in the discussions about everything Onshape.

First time visiting? Here are some places to start:

  1. Looking for a certain topic? Check out the categories filter or use Search (upper right).
  2. Need support? Ask a question to our Community Support category.
  3. Please submit support tickets for bugs but you can request improvements in the Product Feedback category.
  4. 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.

How to calculate distance across a surface?

chris_houserchris_houser Member Posts: 6
My goal is to write a script to add a hexagonal pattern of hexagonal tiles across a series of adjacent surfaces. However, I'm new to Featurescript so at an early stage.

Where I'm stuck at the moment is trying to convert from real-world distances to the "2d unitless parameter-space" used as parameters to evFaceTangentPlanes. I'd like the user to be able to specify something like 5mm, and for the script to calculate how much to add to the x or y of the 2d vector to move 5mm across the surface.

I figured out how to get the length along the curve of each perimeter edge, which is close:
for (var q in evaluateQuery(context, qEdgeAdjacent(definition.Face, EntityType.EDGE))) {
  println("len: " ~ evLength(context, {"entities": q}));
}
In particular, evLength's distance along a curve is like what I want but not along the edges, rather along the curve of the surface in whatever direction evFaceTangentPlanes's coordinates run.

I tried to figure out how to get a coordinate system from the surface, figuring I could then use coordSystem conversion functions like toWorld and fromWorld, but I don't know if that would work, and could figure out how to get a coordinate system anyway.

Anyone have any ideas? 

You can see my attempts so far here. My document is a bit messy, both the geometry and the code. Let me know if cleaning it up would help answer my question. I started with the Surface Pattern script, and most of it's still there. I'm successfully creating an almost-hexagonal pattern of spheres, but still depending on Surface Pattern's parameters of number of repeats in the u and v directions, rather than being able to specify the distance between them. 

Best Answer

  • chris_houserchris_houser Posts: 6
    Accepted Answer
    The ratio of surface-parameter distance to 3d world distance is not constant across the surface. Moreover, I don't think it's geometrically possible to get exactly what I want.

    However, I may be able to get close enough.  I don't plan to actually apply hexagonal tiles to any spheres. This is what I have so far:
    /**
     * Estimate the 3d location of a point across a surface in a given vector direction.
     * @param face {Query} : Surface across which distances will be estimated
     * @param start3d {Vector} : 3d world coordinate of the starting point from which to step (should be a point on the surface)
     * @param start2d {Vector} : 2d unitless vector corresponding to the start3d point
     * @param step2d {Vector} : 2d unitless vector, a direction and an initial guess for the final return step
     * @param target_distance : desired length from starting point to the point this function will return.
     */
    function surfaceStep(context is Context, face is Query, start3d is Vector, start2d is Vector, step2d is Vector, target_distance)
    {
        var next_tan_plane;
        for (var i = 0; i < 3; i += 1) {
            next_tan_plane = evFaceTangentPlane(context, { "face" : face, "parameter" : step2d + start2d });
            debug(context, start3d, next_tan_plane.origin);
            var step_norm = norm( start3d - next_tan_plane.origin );
            println("dist: " ~ step_norm ~ " target: " ~ target_distance);
            
            step2d = target_distance * step2d / step_norm;
        }
        return {"step2d": step2d, "target": next_tan_plane};
    }
    That could be cleaned up quite a bit: maybe more convenient parameters and using a target epsilon (distance error) rather than hardcoding 3 loop iterations.  Anyway, I'm using that to compute step sizes near the origin on the surface, and using those step sizes to lay out a pattern of spheres along the surface. Here's that script applied to a few surfaces:

Answers

  • MBartlett21MBartlett21 Member Posts: 1,536 EDU
    @chris_houser
    Is this only meant to be for planar surfaces?
    MB - I make FeatureScripts: view FS (My FS's have "Official" beside them)
  • chris_houserchris_houser Member Posts: 6
    @chris_houser
    Is this only meant to be for planar surfaces?
    Nope, that would be too easy. :smiley: I'd like surfaces of extrusions, revolutions, etc.

  • MBartlett21MBartlett21 Member Posts: 1,536 EDU
    You may be able to split the surface and work out the width +  height from there.
    MB - I make FeatureScripts: view FS (My FS's have "Official" beside them)
  • chris_houserchris_houser Member Posts: 6
    Well, I've now created a couple planes to find collisions. That might work for some surfaces, but I think there will be a couple problems.
    1. Some surfaces don't intersect a plane going through their origin.
    2. When they do intersect, it may not cover the full range from 0 to 1 of the surface parameter space.
    So I think my next attempt will be to use evFaceTangentPlane to get real-world 3d coords of two points: the origin, and a point very close in the 'u' direction, like vector(0.1, 0). Finding the distance between those points should let me calibrate the surface parameter dimension to real-world distance. Do that again for the 'v' direction, and maybe that'll be enough info to space things properly. ...assuming the correlation is constant across the surface. :-P
  • chris_houserchris_houser Member Posts: 6
    Accepted Answer
    The ratio of surface-parameter distance to 3d world distance is not constant across the surface. Moreover, I don't think it's geometrically possible to get exactly what I want.

    However, I may be able to get close enough.  I don't plan to actually apply hexagonal tiles to any spheres. This is what I have so far:
    /**
     * Estimate the 3d location of a point across a surface in a given vector direction.
     * @param face {Query} : Surface across which distances will be estimated
     * @param start3d {Vector} : 3d world coordinate of the starting point from which to step (should be a point on the surface)
     * @param start2d {Vector} : 2d unitless vector corresponding to the start3d point
     * @param step2d {Vector} : 2d unitless vector, a direction and an initial guess for the final return step
     * @param target_distance : desired length from starting point to the point this function will return.
     */
    function surfaceStep(context is Context, face is Query, start3d is Vector, start2d is Vector, step2d is Vector, target_distance)
    {
        var next_tan_plane;
        for (var i = 0; i < 3; i += 1) {
            next_tan_plane = evFaceTangentPlane(context, { "face" : face, "parameter" : step2d + start2d });
            debug(context, start3d, next_tan_plane.origin);
            var step_norm = norm( start3d - next_tan_plane.origin );
            println("dist: " ~ step_norm ~ " target: " ~ target_distance);
            
            step2d = target_distance * step2d / step_norm;
        }
        return {"step2d": step2d, "target": next_tan_plane};
    }
    That could be cleaned up quite a bit: maybe more convenient parameters and using a target epsilon (distance error) rather than hardcoding 3 loop iterations.  Anyway, I'm using that to compute step sizes near the origin on the surface, and using those step sizes to lay out a pattern of spheres along the surface. Here's that script applied to a few surfaces:

  • MBartlett21MBartlett21 Member Posts: 1,536 EDU
    It seems that planar, extruded, and cylindrical surfaces give a proper spacing with uv directions
    MB - I make FeatureScripts: view FS (My FS's have "Official" beside them)
  • mahirmahir Member, Developers Posts: 850 ✭✭✭✭
    Patterning on any surface with compound curvature would require something more complex than just incrementing distances along UV lines. I don't have any functional code, but you could try developing a recursive algorithm that would distribute seed locations from an origin point and then continue to generate pattern locations around each new seed. Each iteration would check proximity to existing locations to make sure you're not overlapping. Geometrically, it would be like intersecting a sphere with your surface that is centered at your seed point. The resulting curve could then be used to generate equidistant points. Rinse and repeat. This is at least an N^2 calculation and would likely lead to long rebuild times. There is probably a more elegant solution out there, but that's all I can think of at the moment. Mind you, this isn't a new problem. Here's one solution I found specifically for spherical surfaces.
  • chris_houserchris_houser Member Posts: 6
    That's interesting. Thanks for the link!
Sign In or Register to comment.