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 do you bring numbers in as a precondition

ron_morelandron_moreland Member Posts: 79 ✭✭
I want to bring a simple unitless number in as a multiplier. I also want to restrict the range and assign a default value.
annotation { "Name" : "Scale" }
        isLength(definition.scale, { (inch) : [1, 1.059463, 1.07463] } as LengthBoundSpec);
this works, but I think I want this:
annotation { "Name" : "Scale" }
        isLength(definition.scale, { (unitless) : [1, 1.059463, 1.07463] } as LengthBoundSpec);
which doesn't. Should I bring it in as an "inch" then divide by"inch" later?
Tagged:

Best Answer

Answers

  • ron_morelandron_moreland Member Posts: 79 ✭✭
    isReal. I tried float, double.. the usual suspects.
    Thanks
  • mahirmahir Member, Developers Posts: 1,291 ✭✭✭✭✭
    edited January 2018
    @ron_moreland, the FeatureScript help page has a wealth of information. OS does a pretty good job on documentation.
  • ron_morelandron_moreland Member Posts: 79 ✭✭
    I agree the documentation is good. What I find frustrating is a lack of conceptual training. Featurescript operates at a very abstracted level. I'm used to arrays of vertices/connected faces, pretty low-level stuff. Here's an example from evDistance:

    EXAMPLE

    result = evDistance(context, { "side0" : qEverything(EntityType.VERTEX), "side1" : qEverything(EntityType.VERTEX), "maximum" : true }) computes the pair of vertices farthest apart. qNthElement(qEverything(EntityType.VERTEX), result.sides[0].index) queries for one of these vertices.

    Everything is queries. Not an array in sight, except "sides[0]", and what the heck is it doing there? For someone with my background, it's very hard to get my head around. It's difficult to know if I'm passing the correct parameters and hard to decipher what came back.
  • mahirmahir Member, Developers Posts: 1,291 ✭✭✭✭✭
    I felt the same way at first and still do to some degree. However, once you wrap your head around the queries, it's a very flexible and powerful way to work. You're not locked into explicitly declared variables or ordered  arrays. Everything has context. The second thing you selected isn't just selection[1], it's instead identified by what kind of entity and/or body it is. Getting queries to do what you want can be annoying, but I like it :)
  • ron_morelandron_moreland Member Posts: 79 ✭✭

    Here's another example. I want to use "canBePlane()". Here's the documentation:

    canBePlane (value) predicate

    Typecheck for Plane

    What is "value"? I think I've passed it a plane, or a planar face, but it always fails. Should it be a query? a map? either?

    I know featurescript is incredibly powerful, but where I am, I spend most of my time trying to determine if what I'm asking for and getting are correct. Very little time is spent on data manipulation.


  • mahirmahir Member, Developers Posts: 1,291 ✭✭✭✭✭
    From what I can tell, all of the various canBeX(Y) functions just check to make sure that variable Y is actually of type X. So if you pass it an object of type Plane, canBePlane() will return true. Otherwise, it's false. You can pass whatever you want to canBePlane(), but it will only return true if you're passing it something of datatype Plane (not just a flat surface). Here's the help file for predicates, of which typeChecks are one type.
  • Jake_RosenfeldJake_Rosenfeld Moderator, Onshape Employees, Developers Posts: 1,646
    Hi @ron_moreland

    I saw your discussions in this thread and the other thread, and thought it may be useful to clear up some stuff about types in FeatureScript.

    For every type <X> in FeatureScript there is a canBe<X>() method, which is the typecheck for that type.  You should never need to actually call the canBe<X>() method, its just a construction for declaring types.

    Some examples of types in FeatureScript:
    • Query
    • Vector
    • Matrix
    • Transform
    • Line
    • Plane
    • BoundingBox
    • ValueWithUnits (length, angle, volume, etc)
    Here's an example:
    var planeQuery = qNthElement(qGeometry(qEverything(EntityType.FACE), GeometryType.PLANE), 0);
    var isPlane1 = planeQuery is Plane; // false
    var isQuery1 = planeQuery is Query; // true
    
    var planeEvaluated = evPlane(context, { "face" : planeQuery });
    var isPlane2 = planeEvaluated is Plane; // true
    var isQuery2 = planeEvaluated is Query; // false
    If you look in the documentation, you'll see that evPlane returns a 'Plane':
    https://cad.onshape.com/FsDoc/library.html#evPlane-Context-map
    And that a 'Plane' is just a special map that contains the mathematical information about a plane in 3D space:
    https://cad.onshape.com/FsDoc/library.html#Plane

    You can use these 'is <X>' predicates to check whether a variable that you have is of the type that you expect, but you can't use 'is Line' to check if a 'Query' references a linear edge (because 'Query is Query'). 

    You could use 'evLine()' to both check if the edge is linear, and find out the mathematical information about the line:
    var line = try silent(evLine(context, { "edge" : someQuery }));
    if (line == undefined)
    {
        // This could indicate lots of things.  Maybe the query doesn't reference one entity,
        // or the one entity it references is not an edge, or not a linear edge.
        throw regenError("someQuery was not a line");
    }
    else
    {
        var recievedLineDefinition = line is Line; // true
        var origin = line.origin;
        var direction = line.direction;
    }
    https://cad.onshape.com/FsDoc/library.html#evLine-Context-map
    https://cad.onshape.com/FsDoc/library.html#Line

    Or, you could just make sure the user passes linear edges into your feature:

    annotation { "Feature Type Name" : "Evaluate line" }
    export const myFeature = defineFeature(function(context is Context, id is Id, definition is map)
        precondition
        {
            annotation { "Name" : "Line", "Filter" : GeometryType.LINE, "MaxNumberOfPicks" : 1 }
            definition.lineQuery is Query;
        }
        {
            var lineDefinition = evLine(context, {
                    "edge" : definition.lineQuery
            });
        });

    Hope this isn't just adding confusion.  Let us know if you still have questions.
    Jake Rosenfeld - Modeling Team
  • ron_morelandron_moreland Member Posts: 79 ✭✭
    Thanks for taking the time to lay that out. It's very helpful. Some of the problems I get into are syntax related, but these I can run down. The conceptual issues are harder. Your answer is another view into "Featurescript Think". I'm starting to get it.
    Thanks.
  • mahirmahir Member, Developers Posts: 1,291 ✭✭✭✭✭
    @Jake_Rosenfeld, so if checking of geometry type is always done with "varX is typeX", what exactly are the canBeX typechecks used for? I get they are used internally for custom types, but for what? From what I can tell canBeX() is redundant since we have "evX() is X"?
  • ilya_baranilya_baran Onshape Employees, Developers, HDM Posts: 1,173
    They are executed at certain points when monitoring a part studio and warnings are generated if they fail.  So if your custom feature does
    "this is a string" as Plane
    If you monitor a part studio that uses that feature, you'll be warned about a typecheck failure.
    Ilya Baran \ VP, Architecture and FeatureScript \ Onshape Inc
  • Jake_RosenfeldJake_Rosenfeld Moderator, Onshape Employees, Developers Posts: 1,646
    edited January 2018
    @mahir

    I may be misunderstanding your question, but 'varX is typeX' cannot be used to check geometry types of queries, it can only be used to check what type a FeatureScript variable is.

    To answer the second part of your question in detail, you can't have 'evX() is X' without declaring 'canBeX()'.

    Here's an example:

    export predicate canBeVehicle(value)
    {
        value is map;
        value.numWheels is number;
        value.color is Color;
    }
    
    export type Vehicle typecheck canBeVehicle;
    
    export function vehicle(numWheels is number, color is Color)
    {
        return { "numWheels" : numWheels, "color" : color } as Vehicle;
    }
    
    annotation { "Feature Type Name" : "Make vehicles" }
    export const myFeature = defineFeature(function(context is Context, id is Id, definition is map)
        precondition
        {        
        }
        {
            // These variables both have type: Vehicle
            var redCar = vehicle(4, color(1, 0, 0));
            var blueMotorcycle = vehicle(2, color(0, 0, 1));
        });
    

    You fundamentally can't have 'Vehicle's without 'canBeVehicle()'.  You can now check if a variable is a Vehicle with 'someVariable is Vehicle', but only because you wrote out its definition using the 'canBe' predicate.

    'canBeVehicle()' is a construction of FeatureScript, and is used internally by the system to make sure that things declared 'as Vehicle' actually qualify for this role.  

    Another example:

    var fakeVehicle = { "numWheels" : 5, "color" : color(0, 0, 0) };
    var check1 = fakeVehicle is Vehicle; // false.  fakeVehicle is a map, it was never declared to be a Vehicle.
    var check2 = canBeVehicle(fakeVehicle); // true.  fakeVehicle follows all the rules of what a vehicle should be.
    var vehicle = fakeVehicle as Vehicle; // doesn't fail because canBeVehicle() passes.
    var check3 = vehicle is Vehicle; // true.  vehicle was declared as a Vehicle.

    In short: you should never need to call 'canBeX()' yourself.  It's used by the system to declare variable types.



    Coming full circle: It's not really useful to check whether something 'is Plane' or 'is Line' or 'canBePlane' or 'canBeLine'.  If you end up with something of these variable types, you'll already know that you have them (because you would have had to call 'evPlane()' or 'evLine()' or similar to get those).  To check if some piece of geometry is a plane, you can do:
    var isPlane = try silent(evPlane(context, { "face" : faceQuery })) != undefined;
    --- or ---
    var queryContainsPlane = size(evaluateQuery(context, qGeometry(someQuery, GeometryType.PLANE))) != 0;

    Jake Rosenfeld - Modeling Team
  • mahirmahir Member, Developers Posts: 1,291 ✭✭✭✭✭
    Thanks, @Jake_Rosenfeld. That was a great explanation.
  • ron_morelandron_moreland Member Posts: 79 ✭✭
    edited January 2018
    This has been a great discussion for me. The original question is bland so I doubt if it will attract much attention. I think a lot of people would benefit from the information shared here.
Sign In or Register to comment.