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.

Options

drawing a line with Features Script

hervé_piponhervé_pipon Member Posts: 60 ✭✭
Hello I want to draw a sphere and its radius.

I wrote this code:
annotation { "Feature Type Name" : "drawSphere" }
export const myFeature = defineFeature(function(context is Context, id is Id, definition is map)
    precondition
    {
        // Define the parameters of the feature type
        annotation { "Name" : "Radius" }
        isLength(definition.Radius, NONNEGATIVE_LENGTH_BOUNDS);
       
        annotation { "X" : "X coord" }
        isLength(definition.Xcoord, LENGTH_BOUNDS);
       
        annotation { "Y" : "X coord" }
        isLength(definition.Ycoord, LENGTH_BOUNDS);
       
        annotation { "Z" : "Z coord" }
        isLength(definition.Zcoord, LENGTH_BOUNDS);
       
    }
    {
        println("start");
        var R = definition.Radius;
        var x0 = definition.Xcoord;
        var y0 = definition.Ycoord;
        var z0 = definition.Zcoord;
        println("R = " ~ R);
        println("x0 = " ~ x0);


        // Créez une esquisse 2D sur un plan de votre choix
        var sketch = newSketch(context, id + "sketch", {
            "sketchPlane" : qCreatedBy(makeId("Top"), EntityType.FACE)
        });
        const sphereCenter = vector(x0, y0, z0) * meter; // Centre de la sphère
        const sphereRadius =  vector(R.value, 0 , 0 ) * meter ;        
        println("sphereCenter = " ~ sphereCenter);
        println("sphereRadius = " ~ sphereRadius);

        
        // Ajoutez une ligne à l'esquisse
        const startPoint = sphereCenter  ; // Point de départ de la ligne Can not add ValueWithUnits (map) and number
        const endPoint = sphereCenter + sphereRadius; // Point d'arrêt de la ligne
        
        skLineSegment(sketch, "myLine", {
            "start" : startPoint,
            "end" : endPoint
        });
   
        opSphere(context, id, {
                "radius" : R,
                "center" : vector(definition.Xcoord, definition.Ycoord, definition.Zcoord)
        });
       
    });

The FeatureScript Notice shows :
start
R = ValueWithUnits : { "unit" : UnitSpec : { "meter" : 1 } , "value" : 0.1 }
x0 = ValueWithUnits : { "unit" : UnitSpec : { "meter" : 1 } , "value" : 0 }
sphereCenter = Vector : [ ValueWithUnits : { "unit" : UnitSpec : { "meter" : 2 } , "value" : 0 } , ValueWithUnits : { "unit" : UnitSpec : { "meter" : 2 } , "value" : 0 } , ValueWithUnits : { "unit" : UnitSpec : { "meter" : 2 } , "value" : 0 } ]
sphereRadius = Vector : [ ValueWithUnits : { "unit" : UnitSpec : { "meter" : 1 } , "value" : 0.1 } , ValueWithUnits : { "unit" : UnitSpec : { "meter" : 1 } , "value" : 0 } , ValueWithUnits : { "unit" : UnitSpec : { "meter" : 1 } , "value" : 0 } ]
  Result: Regeneration complete


with an error : 

Precondition of operator+ failed (lhs.unit == rhs.unit)

for the line
const endPoint = sphereCenter + sphereRadius; // Point d'arrêt de la ligne

I don't know why ?? 

Can somebody explain me ?


I also saw that sphereCenter has unit { "meter" : 2 } , but sphereRadius has unit { "meter" : 1 } ?? 
I don't understand

https://cad.onshape.com/documents/b5eb7563c9f8d34013c45353/w/a8328a22ba0852fc6de829ba/e/3946d40111b0b87308a02466

Comments

  • Options
    _anton_anton Member, Onshape Employees Posts: 278
    edited November 2023
    vector(x0, y0, z0) * meter
    This is multiplying a vector of three lengths by another length. Remove the "* meter".
  • Options
    Jacob_CorderJacob_Corder Member Posts: 126 PRO
    just use opFitSpline with 2 3d points. it is the fastest at creating a line. 
  • Options
    hervé_piponhervé_pipon Member Posts: 60 ✭✭
    @Jacob_Corder Thank you, that is really easier  :smiley:  

    opFitSpline(context, id + "line_1" , { "points" : [ startPoint, endPoint ] });

  • Options
    hervé_piponhervé_pipon Member Posts: 60 ✭✭
    @_anton Thank you, I understand why there is { "meter" : 2 } on SphereCenter

    However I got another error  ( I use my own LineSegment function to see the error ...)

    const startPoint = sphereCenter  ;
    const endPoint = sphereCenter + sphereRadius; 
    	  
    println("A = " ~   (startPoint is undefined)  ~ " " ~  startPoint );
    println("B = " ~ is2dPoint(startPoint));
    
    LineSegment(sketch, "myLine", {
    	"start" : startPoint,
    	"end" : endPoint
    });
    export function LineSegment(sketch is Sketch, lineId is string, value is map)
    precondition
    {
        value.start is undefined ; <<<< ERROR
        is2dPoint(value.start);
        value.end is undefined || is2dPoint(value.end);
        value.construction is undefined || value.construction is boolean;
    }
    {
        return @skLineSegment(sketch, lineId, value);
    }

     The printout is 

    A = false Vector : [ ValueWithUnits : { "unit" : UnitSpec : { "meter" : 1 } , "value" : 0 } , ValueWithUnits : { "unit" : UnitSpec : { "meter" : 1 } , "value" : 0 } , ValueWithUnits : { "unit" : UnitSpec : { "meter" : 1 } , "value" : 0 } ]
    B = false

    But I got the error Precondition of LineSegment failed (value.start is undefined) on line value.start is undefined ;

    Do you know why , as println("A = " ~ (startPoint is undefined)) prints false ?
  • Options
    chadstoltzfuschadstoltzfus Member, Developers, csevp Posts: 131 PRO
    edited November 2023

    The "is" keyword is reserved for typechecks, so it's actually checking to see if startPoint passes a typecheck on type "undefined." You want to use the equality/inequality operators instead when checking inside of the precondition and for the println() checks. 
    Ignore that (explained in comment below)

    export function LineSegment(sketch is Sketch, lineId is string, value is map)
    precondition
    {
        value.start != undefined;
        is2dPoint(value.start);
        value.end is undefined || is2dPoint(value.end);
        value.construction is undefined || value.construction is boolean;
    }
    {
        return @skLineSegment(sketch, lineId, value);
    }

    Your 2D point check will still fail though. So you will want to make sure you are creating a 2D vector instead of a 3D one. Since you are using the top plane, you can just remove the Z inputs from your points and it shouldn't throw any more errors for you. 
    Also don't forget to solve your sketch when you're done, otherwise you won't see the line that you just programmed. 

    LineSegment(sketch, "myLine", {
                        "start" : startPoint,
                        "end" : endPoint
                    });
    
            skSolve(sketch);

    Applications Developer at Premier Custom Built
    chadstoltzfus@premiercb.com
  • Options
    hervé_piponhervé_pipon Member Posts: 60 ✭✭
    @chadstoltzfus Thank you, I forgot that we are working on  2D vector instead of a 3D on sketch , It works when I remove z axis !

    Concerning 
    value.start != undefined; and value.start is undefined ; I don't really understand the use :
    In the skLineSegment the check is on 
    value.start is undefined || is2dPoint(value.start); what's the use ?
  • Options
    chadstoltzfuschadstoltzfus Member, Developers, csevp Posts: 131 PRO
    Oh that's my bad you're right, "value.start == undefined" and "value.start is undefined" should return the same thing.

    So the precondition is checking to make sure all boolean statements evaluate to true in order to execute the next block of code. So in skLineSegment the line is 
    value.start is undefined || is2dPoint(value.start);This is checking to make sure value.start is a defined value and that it is also a 2D point. And since is2DPoint evaluates to true the precondition does not fail. 

    However, if you separate them out,
    value.start is undefined;will evaluate to false (since value.start is defined). So that will cause the precondition to fail. 

    I'm assuming that Onshape's function is checking if the field is undefined so that way the error is thrown by skLineSegment instead of in is2dPoint, as sending an undefined argument to is2dPoint would have the error thrown in that function and maybe return a more ambiguous error.
    Applications Developer at Premier Custom Built
    chadstoltzfus@premiercb.com
  • Options
    hervé_piponhervé_pipon Member Posts: 60 ✭✭
    @chadstoltzfus Thanks a lot, it's clearer, I understand my mistake; I wanted to separate the two clauses, to find out which one was in problem, but in fact I created a new error.
Sign In or Register to comment.