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.


Struggling with a custom table of "lengths"

eric_pestyeric_pesty Member Posts: 1,607 PRO
Here's my issue:
My custom feature has 2 "modes" of operation, in one case it creates a spline between 2 points (and does a sweep).
I have a table that lists the length of that spline and it works fine, I add the name attribute to the spline and the table adds a row for each one it finds.

The second mode (which I am adding) gives the option of selecting a "path" instead of the feature creating a spline. This "path" can be several "segments" edges or whatever. However when a path has multiple segments it lists them separately in the table and I can't seem to make it somehow "combine" these and give them a single attribute...

I've tried using a constructPath and also tried doing a compositeCurve (but I'm struggling to even get that to work and not even sure that would work)...

I think I might be a bit confused on how the tables work... I could compute the total length of the segments easily enough in the code for each "modes" but I'm not sure how to show that in a table later.

Any thoughts on how to approach this problem at a "higher level" (which I think might be my issue...)?


  • Options
    MichaelPascoeMichaelPascoe Member Posts: 1,748 PRO
    edited August 2022
    The composite curve approach is what I would try. From your info it sounds like you want this composite curve to show the total curve length in it's property? Or do you just need it to show up in the table?

    Tables can be tricky if you aren't used to them. Here is a feature I wrote a while back that has some nice comments with brief explanations for each component of the tables code. See lines 448 through 523 in my Cut list custom feature.

    Cut list custom feature not to be confused with the native Frames cut list feature.

    I grabbed most of this table code from the original Beams feature by @NeilCooke.
    annotation { "Table Type Name" : "Cut List", "Icon" : icon::BLOB_DATA }
    export const cutListTable = defineTable(function(context is Context, definition is map) returns Table
            annotation { "Name" : "Sort by", "UIHint" : "SHOW_LABEL" }
            definition.sortBy is SORT_COLUMNS;
            annotation { "Name" : "Sort order", "UIHint" : "SHOW_LABEL" }
            definition.sortOrder is SORT_ORDER;
            //Gets the measured variables from the feature
            var variableList = getVariable(context, "Cut list");
            var columnId = getVariable(context, "Column ID's");
            // var varValTableTitle = columnId[0];
            var varValColumn1 = columnId[1];
            var varValColumn2 = columnId[2];
            var varValColumn3 = columnId[3];
            var varValColumn4 = columnId[4];
            var varValColumn5 = columnId[5];
            //Creates an array of columns
            var columns = [
                tableColumnDefinition("id", varValColumn1),
                tableColumnDefinition("quantity", varValColumn2),
                tableColumnDefinition("length", varValColumn3),
                tableColumnDefinition("width", varValColumn4),
                tableColumnDefinition("thickness", varValColumn5),
            // tableColumnDefinition("count", "Item Number"),
            // tableColumnDefinition("varVal", "Qty"),
            //Creates an array of rows
            var rows = [];
            for (var i = 0; i < size(variableList); i += 1)
                //valueArray[0] equals length
                //valueArray[1] equals width
                //valueArray[2] equals thickness
                //valueArray[3] equals quantity
                var groupName = keys(variableList)[i];
                var varValLength = variableList[keys(variableList)[i]][0];
                var varValWidth = variableList[keys(variableList)[i]][1];
                var varValThickness = variableList[keys(variableList)[i]][2];
                var varValQuantity = variableList[keys(variableList)[i]][3];
                rows = append(rows, tableRow({
                                // "count" : i + 1,
                                "id" : groupName,
                                "length" : varValLength,
                                "width" : varValWidth,
                                "thickness" : varValThickness,
                                "quantity" : varValQuantity
            //Returns the table
            // return table("Measurements", columns, rows);
            const order = definition.sortOrder == SORT_ORDER.ascending ? 1 : -1;
            rows = sort(rows, function(row1, row2)
                    return order * sortRows(row1.columnIdToCell[toString(definition.sortBy)], row2.columnIdToCell[toString(definition.sortBy)]);
            return table("Cut List", columns, rows);
            //return table("Cutlist", columnDefinitions, rows);

    Learn more about the Gospel of Christ  ( Here )

    CADSharp  -  We make custom features and integrated Onshape apps!   cadsharp.com/featurescripts 💎
  • Options
    Jacob_CorderJacob_Corder Member Posts: 129 PRO
    cant you just build the paths in the table code and use evPathLength and use that output? or are you dealing with multiple paths and dont know how to break them up into multiple paths? 

    do you a link to the document?
  • Options
    eric_pestyeric_pesty Member Posts: 1,607 PRO
    Thanks for the input, I was off for a couple of days so I haven't worked on this...

    The way it currently works is by "tagging" the curves, which means when you mouse over the table it highlights the corresponding curves in the display area, which is nice. If I remember correctly I mostly copied the "freeform spline" table code (since the original feature just created a spline it was super easy to adapt).
    My first thought was to use a composite to create something I could "process" just like the original spline but I'm not sure what it needs. It requires a "map" for the input but the documentation is just one line and doesn't explain what should be in the "map". I would have expected that it would want a bunch of edges to return a single curve... 
    I think I just realized my issue is that there is no "opcompositeCurve" function so I am calling the actual feature compositeCurve, which explains the "map" part... I think I should be able to figure that one out from some examples!

    It looks like one other option would be to "retrieve" a variable calculated in the feature which I don't know how to do but it looks like that's what you are doing at line 461/462 (i.e. it looks like "getVariable" does that?). I think that's what @Jacob_Corder is suggesting.

    I'll give that a try as well, I am just wondering how the "cross highlighting" will behave with that method...

  • Options
    MichaelPascoeMichaelPascoe Member Posts: 1,748 PRO
    Sounds like you have the right idea. Let us know if you get stuck.

    Learn more about the Gospel of Christ  ( Here )

    CADSharp  -  We make custom features and integrated Onshape apps!   cadsharp.com/featurescripts 💎
  • Options
    eric_pestyeric_pesty Member Posts: 1,607 PRO
    I am now able to create a composite curve so that part is working, but I am running into issues as it doesn't look like I can use "evLength" on a composite curve somehow, which is unfortunate as defeats the purpose...
  • Options
    MichaelPascoeMichaelPascoe Member Posts: 1,748 PRO
    Try Jacob's approach, something like this:
    compositeCurve(context, id + "compCurve", {
                        "edges" : definition.curves
    const compCurves = qCreatedBy(id + "compCurve", EntityType.EDGE);
    const curvePath = constructPath(context, compCurves);
    const curveLength = evPathLength(context, curvePath);
    debug(context, curveLength, DebugColor.RED);

    Learn more about the Gospel of Christ  ( Here )

    CADSharp  -  We make custom features and integrated Onshape apps!   cadsharp.com/featurescripts 💎
  • Options
    eric_pestyeric_pesty Member Posts: 1,607 PRO
    The code you are showing above would be in the feature itself, correct?

    I could try to package the "single spline" case into a composite as well for consistency, then if I can adapt the above to "extract" the edges back out of the composite in the table the table doesn't need to know if it's composite or not.

    Is the "debug" code a workaround for displaying the curve, that wouldn't work in the table, or would it?

    I need to finish the "featurescript" self guided course to see if it will help me better understand table at a conceptual level (I'm pretty fuzzy on on that front...) and/or study some more examples. As you can probably tell I only have the vaguest idea what I'm doing! 
  • Options
    eric_pestyeric_pesty Member Posts: 1,607 PRO
    edited August 2022
    I'm kind of going around in circles with the composite curve... It doesn't looks like I can set the "name" attribute for a composite the way I was doing it for a spline for some reason...
    So now I'm not sure how to get the table to "find" the curves...

    Here's what I had in the body:
        var compcurve = compositeCurve(context, id, definition);
    setAttribute(context, {
            "entities" : qCreatedBy(id + "Straightjumper1", EntityType.EDGE),
            "name" : "Jumper",
            "attribute" : {
            "featureId" : id + "Straightjumper1"

    And then in the table I was doing this:

    var entitiesWithSplineAttribute = evaluateQuery(context, qHasAttribute("Jumper"));

            for (var curve in entitiesWithSplineAttribute)
                var length = evLength(context, {
                        "entities" : qCreatedBy(curve, EntityType.EDGE)

      I was hoping to use "compcurve" for the entities in the setAttribute part. I also don't want to get the "EDGES" of the composite as this would take me back to having the individual segments listed in the table...
  • Options
    antlu65antlu65 Member Posts: 55 EDU
    @eric_pesty, do you still need any help with this issue?
  • Options
    eric_pestyeric_pesty Member Posts: 1,607 PRO
    I'll take another stab at it after I complete the "Featurescript Fundamentals" course and I study the example you made and we'll how that goes!
  • Options
    eric_pestyeric_pesty Member Posts: 1,607 PRO
    Just a follow up in case something is looking at this and wondering what the solution was...

    It turned out to be much simpler (as is often the case), I didn't need any composites, etc...

    The key was realizing you can attach "attributes" to the body created by the feature. So now I just add a "length" (as well as OD, and min. bend radius) attribute to the body itself and read those in the table. I was originally trying to go through the "sweep path" curves of each feature and compute the length in the table, which was a terrible way to go about it! 

    And now the table cross highlights the parts and displays all the information I need without having to "re-compute" anything (since I already had all the data computed in variables when creating the feature).

    Thanks @antlu65 and @MichaelPascoefor the tips and helping me figure this stuff out!

  • Options
    MichaelPascoeMichaelPascoe Member Posts: 1,748 PRO
    Nice work!

    Learn more about the Gospel of Christ  ( Here )

    CADSharp  -  We make custom features and integrated Onshape apps!   cadsharp.com/featurescripts 💎
Sign In or Register to comment.