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.

First project & request for more examples

julian_lelandjulian_leland Member, OS Professional, Mentor Posts: 59 PRO
edited January 2016 in FeatureScript
Hi all,

I'm starting to fiddle around with FeatureScript, and have an idea for a feature that I'd like to build out. I've run into some trouble, and would appreciate any suggestions folks have.

My Idea: Briefly, I'll explain what I'm trying to do. I want to create a feature to automatically split cylindrical features with a radial spline, like this:
My goal is to let the user specify a cylindrical body; a plane which is perpendicular to the axis of the cylinder (and thus, necessarily intersecting it - right?); the height of the teeth; and the number of teeth.

I should also mention that I've never worked with JavaScript before, and am not familiar with the syntax - I'm hacking together my code from what I can find in the documentation and peeking at the FeatureScript in the Part Studio.

Where I am: I've successfully built the feature in Onshape manually for 3- and 4-tooth cases, and am working out a general algorithm for N teeth (building the feature manually was really helpful for figuring out how to write the FeatureScript). Here's the 4-tooth case:

I've also written the following pseudocode to try to automate this process:
FeatureScript 275;
import(path : "onshape/std/geometry.fs", version : "275.0");

annotation { "Feature Type Name" : "Radial Spline" }
export const radSpline = defineFeature(function(context is Context, id is Id, definition is map)
        // Define the parameters of the function definition
        // What we need to create the feature:
        // - Cylindrical solid
        annotation { "Name" : "Cylindrical Face", "Filter" : GeometryType.CYLINDER, "MaxNumberOfPicks" : 1 }
        definition.CylindFaces is Query;
        // - Plane that intersects solid and is perpendicular to cylinder
        annotation { "Name" : "Tooth Plane", "Filter" : GeometryType.PLANE && ConstructionObject.YES, "MaxNumberOfPicks" : 1 }
        definition.CutPlane is Query;
        // TODO: Check cylinder intersects & is perpendicular to plane; check plane doesn't intersect other features that cylinder touches (not sure if I have to do this)
        // - Height of spline teeth
        annotation { "Name" : "Tooth Height" }
        isLength(definition.ToothHeight, LENGTH_BOUNDS);
        // - Number of teeth (one tooth = full period of revolution
        annotation { "Name" : "Number of Teeth" }
        isLength(definition.numTeeth, LENGTH_BOUNDS);
        // TODO: Check that this is >= 1
        // Define the function's action
        // 1) Create point on CutPlane at center of CylindFaces
        // 2) Create 2 planes separated by 1/2 ToothHeight
        // annotation { "Feature Name" : "CutPlane1" }
        cPlane(context, id, { "entities" : definition.CutPlane, "cplaneType" : CPlaneType.OFFSET, "offset" : (definition.ToothHeight/2) * millimeter, "oppositeDirection" : false, "angle" : 0.0 * degree, "flipAlignment" : false, "size" : 150.0 * millimeter });
        // 3) Cut body into 3 parts with new planes
        // 4) On central plane, create circle (intersection of cylinder with plane) with 2*N radial lines from center to edge
        // 5) 'Use' even points to upper plane, and odd points to lower plane
        // 6) Tooth creation: Not sure whether to do this by creating each plane and splitting in a loop, or creating all planes, then splitting.
        // 6a) Create a plane between each set of high and low points
        // 6b) Section middle body with new Plane
        // 7) Recombine all bodies to create spline:
        //  - Boolean add all bodies that have faces that are coincident to upper and lower shaft faces to those shafts
        //  - Need to figure out some way to handle bodies that don't share faces with either shaft.
    }, { /* default parameters */ });

As far as I've written them, the preconditions work (although I'm obviously not testing for intersection/perpendicularity, or that the spacing value is legitimate). My syntax in the action section - which I copied from the way a plane is built in the Part Studio - doesn't throw any errors in the editor, but chokes in the Part Studio. I know that I'm inserting "ToothHeight" incorrectly, but I haven't yet figured out how.

What I need help with: In the short term, if anyone can give me pointers on what I'm doing wrong with the definition of the construction plane, or example code for plane creation, I'd appreciate it greatly.

Longer-term, though, what I - and, I suspect, other FS users like me - would find really useful is a set of heavily-commented, simple examples that showcase how just one or two aspects of FS work, and are structured for people like me who have some coding ability but aren't experienced enough to just work from the current documentation. For example, having example code to support the explanation of queries at https://cad.onshape.com/FsDoc/features.html would be really helpful.



  • 3dcad3dcad Member, OS Professional, Mentor Posts: 2,470 PRO
    I agree with your longer-term requests. Well commented examples of many different type of features is a lot easier to get started than fully documented library.

    Change something, see what happens, change more and eventually get a grip of plain documentation.. 
  • kevin_o_toole_1kevin_o_toole_1 Onshape Employees, Developers, HDM Posts: 565
    edited January 2016
    Great to see you trying out FeatureScript. This looks like a perfect first project!

    It's also encouraging to see you prototyping in the Part Studio. 
    Since both Part Studios and Feature Studios just FeatureScript under the hood, the same design principles will apply in the Feature Studio, and the geometry will fail/succeed in the same places.

    I made a quick video of how I might design such a thing with native features in the part studio (Well, almost all native. I did have to steal @ilya_baran's handy 3D spline tool). 

    I'd rather have made this document public, but it's got FeatureScript in it, so that's not allowed (yet!).

    A few notes:
    1. Let Onshape do the hard work! Here, I'm simply lofting between a point (the origin) and a 3D spline. By defining it in the simplest way possible, you save yourself a bunch of math, and probably improve performance by not needing to combine all the surfaces you've proposed.
      (To be clear, there are certainly situations where you might need finer-grain control than the default loft provides, but the quick experiment shows that's not the case here).
    2. In the part studio, I had to make actual geometry to define my spline points, which was probably more work than needed. In FeatureScript, this isn't necessary, since I can just call opFitSpline() directly with the list of points.
    3. I only put points on the top and the bottom of the tooth to save myself making tons of extra, difficult-to-coordinate sketches. However, since is straightforward to do in FS (see above), your curve could probably benefit from more points. This depends on how precise you need those profiles to be (and how good your dentist says your teeth should look!)
    4. The 3D spline is just an interpolation. If you look at it from the top view, the actual path doesn't *quite* lie on a circle. This is why the spline's circles are over-dimensioned compared to the original cylinder: Otherwise, the split would fail.
    Hopefully this all means the path ahead will be easier than you thought. Let us know if you hit any snags, and good luck!

  • kevin_o_toole_1kevin_o_toole_1 Onshape Employees, Developers, HDM Posts: 565
    On construction planes, here's how I debugged the issue:
    1. The error was "precondition failed". We're going to try to make this error more helpful in the future, but for now: the failure gives you a stacktrace down to the point of failure. In your case, the failure happened in line 73 of cplane.fs
    2. Opening up cplane in the public document std, we can see that the line 73 defines the offset distance, which it says should be a length.
    3. For offset distance, you passed in (definition.ToothHeight/2) * millimeter. So, what's wrong with that? 
    4. You can use println() to show the result of that statement. The result you get is 1.27e-05 meter^2.
    5. meter^2 is your clue. defintion.ToothHeight already has length units (the user passes in something like "1 in", and the their default units apply). Multiplying by one millimeter gives it area units, and therefore, it can't be used for an offset distance.
  • julian_lelandjulian_leland Member, OS Professional, Mentor Posts: 59 PRO
    Thanks, @kevin_o_toole_1, @3dcad! Kevin, I'm definitely going to try your method of creating a lofted surface from a 3D spline - I didn't know that I could loft surfaces like that. I suspect that if I wanted more control over the tooth form, I could create a 3D sketch of straight line segments with a different tool.

    I also appreciate your suggestions for debugging the construction plane issues. I think I may have been shown the std document before, but I'd forgotten how to access it. Being able to use println() is also a handy feature - thanks!
Sign In or Register to comment.