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 Copy a Part with featurescript

patrick_farleypatrick_farley Member Posts: 37 ✭✭
Hi, i am trying to make a feature script that could make a Wall or 2x4 for a house.
i was able to make the script that built the 2x4 and name it, but i have a hard time figuring how to repeat the part.

i try to repeat the sketch with an offset, but i have to create a new sketch with a new variable name each time and i don't know how to put that in a for loop (creating name of a variable depending on the counter of the for next loop).

check the 2x4,  at if (definition.size == Size.X204)


i am able to repeat all the code with an offset, but i don't thinks that make sense if i what 32 times  2x4

Thanks for the help
Pat F








Best Answer

Answers

  • MBartlett21MBartlett21 Member, OS Professional, Developers Posts: 2,034 EDU
    You can use opPattern
    mb - draftsman - also FS author: View FeatureScripts
    IR for AS/NZS 1100
  • ilya_baranilya_baran Onshape Employees, Developers, HDM Posts: 1,173
    Eduardo is correct -- that will fix the immediate issue, but I would second Morgan's recommendation for opPattern -- it will work faster.
    Ilya Baran \ VP, Architecture and FeatureScript \ Onshape Inc
  • otaolafrotaolafr Member Posts: 113 EDU
    edited January 2020
    Eduardo is correct -- that will fix the immediate issue, but I would second Morgan's recommendation for opPattern -- it will work faster.
    hi ilya,
    i need to scale a part and keep the original one, (so i need to copy before scaling isnt it?) 
    for the scaling i was using opTransform, but i can not finish understanding how to,at the same time, be able to copy it, i say that if I put two transforms 
    transform1*transform2 it does in order, but i can not find how to do the first transform to copy it, is it possible? as i didnt find it in the list of transform types (https://cad.onshape.com/FsDoc/library.html#Transform) but i found that there is makeCopy in transform (https://cad.onshape.com/FsDoc/library.html#module-transformCopy.fs)
    i can not get the difference between each other, one is a parameter inside optransform and the other one is a function itself? i dont get it at all....
    (i am having a headache with the op..... :'(  ) 
    could you please help me to understand the difference between them? and how i could solve my problem? best regards

    to be exactly, i want to take a part, scale it, see if a point is contained in the scaled version, insert a second object in that point if it is the case, and then intersect that second object to the original one....
  • NeilCookeNeilCooke Moderator, Onshape Employees Posts: 5,310
    @Otaola_Franco if you use opPattern (which essentially takes the same inputs as opTransform) it will copy for you.
    Senior Director, Technical Services, EMEAI
  • otaolafrotaolafr Member Posts: 113 EDU
    NeilCooke said:
    @Otaola_Franco if you use opPattern (which essentially takes the same inputs as opTransform) it will copy for you.
    thanks neil,
    is there any part to read a little bit about the op operations? i am looking at the https://cad.onshape.com/FsDoc/library.html#opPattern-Context-Id-map
    but i dont finish to get how the work exactly, for example the opPattern/transform, or right now i am having issues about calling a created bodie from a opBoolean... i know that i can post it in the forum and someone will help but i feel a little bit guilty about... i am reading the info in the link before and i saw your video (https://www.onshape.com/videos/the-beginners-guide-to-building-custom-cad-features-in-featurescript-010819) but i would love to learn a little bit more... (actually the video was super helpfull...thanks for that!)
  • NeilCookeNeilCooke Moderator, Onshape Employees Posts: 5,310
    edited January 2020
    Sometimes the docs are not easy to follow because there are no examples.

    First, don't call the result of the opBoolean, call the first feature used in the opBoolean, for example
    qCreatedBy(id+"extrude1", EntityType.BODY);
    so something like:

    opPattern(context, id+"pattern", {
           entities: qCreatedBy(id+"extrude1", EntityType.BODY), 
           transforms: [scaleUniformly(2)],   // note this is an array
          instanceNames: ["1"]
    }

    ^ I typed this from memory, so hopefully I made no typos.
    Senior Director, Technical Services, EMEAI
  • otaolafrotaolafr Member Posts: 113 EDU

    perfect! thanks :) have a few last questions (with an answer already for some, so maybe is going to be more of a confirmation of what i am understanding :) )

     

    when i was doing the opBoolean i created several cylinders that i used a qUnion to put them all together for the Boolean for example:

    Q1/2_

    var cyls=qUnion([qCreatedBy(id+"cylinder1", EntityType.BODY),qCreatedBy(id+"cylinder2", EntityType.BODY),qCreatedBy(id+"cylinder3", EntityType.BODY),qCreatedBy(id+"cylinder4", EntityType.BODY),qCreatedBy(id+"cylinder5", EntityType.BODY),qCreatedBy(id+"cylinder6", EntityType.BODY),qCreatedBy(id+"cylinder7", EntityType.BODY),qCreatedBy(id+"cylinder8", EntityType.BODY),qCreatedBy(id+"cylinder9", EntityType.BODY),qCreatedBy(id+"cylinder10", EntityType.BODY),qCreatedBy(id+"cylinder11", EntityType.BODY),qCreatedBy(id+"cylinder12", EntityType.BODY)]);

     

    opBoolean(context, id + "cell", { "tools" : cyls, "operationType" : BooleanOperationType.UNION });

     

    after that when i do the opPattern as you said, it worked perfectly:

     

    opPattern(context, id + "pattern", {

    "entities" : qCreatedBy(id+"cylinder1", EntityType.BODY),

    "transforms" : transforms,

    "instanceNames" : instanceNames });

    first, i dont get why it patterns everything if in entities is selected only first one. is it because the id of the "cylinder1" is inherit to the body that is created by opBoolean (so basically: Q1) "cylinder1" becomes the howl thing and not only the cylinder made by the first fcylinder?) as after doing the opPattern (Q2) why i cant use qCreatedBy(id+"cell",EntityType.BODY) (from the opBoolean)? )

    Q3_
    , i do a opDeleteBodies to delate the original body, so this time i use:

                                opDeleteBodies(context, id + "deleteBodies", {

                            "entities" : qCreatedBy(id+"cylinder1", EntityType.BODY)

                        });
    i re use qCreatedBy(id+"cylinder1", EntityType.BODY) because opPatterns doesnt modify the body, it creates another one so, it has another id,is that so?

    So now if i want to work with the results bodies created from the opPatterns, i should use

    qCreatedBy(id+”pattern”,Entity.BODY) no?

     

    Q4_

    I re scaled and copy a body (with your help in another post…),

    opPattern(context, id + "scaled_body", {

            "entities" : definition.entities,

            "transforms" : [scaleNonuniformly(scaleX,scaleY,scaleZ)],

            "instanceNames" : ["scaled_body"]

    });

     

    So to call the orginal one would be,

    definition.entities (it is a query from the UI)

     

    and for the scaled one:

    qCreatedBy(id+” scaled_body”,Entity.BODY)

     

    I am correct?

     

    Q5_ how can i understand if a operation creates a new id for the body or keeps the same one? (as simple as if it creates a new bodie?)

     

    Q6_(and last! Sorry for the long post!)

    how can i divide a query in equal parts? I am having the issue that i create voxelyse an object and as the voxel goes down in size (creating more and more voxels…) if in the FS i do a opBoolean directly from the pattern (all the objects in one time Boolean) the document gives error (variating and i had needed to go down in the version to solve it… or contact the support (thanks guys ^^), but i realized that if i don’t do the Boolean at all with the FS, the FS doesn’t give any error and it only takes a lot of time, (normal….) and after that i do small Booleans in sections of the parts created…. That way it works, but it tedious post treatment of the FS. I thought about a loop, but I don’t know how to “cut” the query from the pattern in small parts…

     

    thanks and sorry for bothering so much,


  • NeilCookeNeilCooke Moderator, Onshape Employees Posts: 5,310
    edited January 2020
    OK, here goes. Before I get into your questions, the qUnion should not be hardcoded. Here are some options:

    You can either loop through cylinder creation and add it to a query as you go, or loop the query afterwards:

    var cyls = qNothing(); // sets variable to be of type query
    
    for(var i = 1; i < 13; i += 1)
    {
       fCylinder(context, id + ("cylinder" ~ i), {
       ...
       }
       cyls = qUnion([cyls, qCreatedBy(id + ("cylinder" ~ i), EntityType.BODY)]);
    }
    
    Senior Director, Technical Services, EMEAI
  • NeilCookeNeilCooke Moderator, Onshape Employees Posts: 5,310
    Another option is to add an extra level to your id. However, id's can only be created contiguously, so no other operation can be carried out on the cylinders until all cylinders have been created. You can try to follow along here: https://cad.onshape.com/FsDoc/library.html#Id

    for(var i = 1; i < 13; i +=1)
    {
       fCylinder(context, id + "cylinder" + i, {
       ...
       }
       // no other operations that create a new id can be added here
    }
    var cyls = qCreatedBy(id + "cylinder", EntityType.BODY); // this will get cylinder plus all its children

    Senior Director, Technical Services, EMEAI
  • NeilCookeNeilCooke Moderator, Onshape Employees Posts: 5,310
    Q1: An id is a unique identifier for the operation, not the solid body. opBoolean uses the first body in the list as the parent - this keeps body internal id's (not the same as operation id's) consistent so that part names and other references don't change. 

    Q2: Same as Q1?

    Q3: Correct & Correct

    Q4: Correct & Correct

    Q5: If a body has only been modified (boolean / transform) you query the original body.

    Q6: Loop is a bad idea for opBoolean - the script would be very slow. Do the voxels overlap? We talked about this here: https://forum.onshape.com/discussion/comment/56573#Comment_56573
    Senior Director, Technical Services, EMEAI
  • otaolafrotaolafr Member Posts: 113 EDU
    edited January 2020
    NeilCooke said:
    Q1: An id is a unique identifier for the operation, not the solid body. opBoolean uses the first body in the list as the parent - this keeps body internal id's (not the same as operation id's) consistent so that part names and other references don't change. 

    Q2: Same as Q1?

    Q3: Correct & Correct

    Q4: Correct & Correct

    Q5: If a body has only been modified (boolean / transform) you query the original body.

    Q6: Loop is a bad idea for opBoolean - the script would be very slow. Do the voxels overlap? We talked about this here: https://forum.onshape.com/discussion/comment/56573#Comment_56573
    Q6.yes they overlap, well I am trying to finish the project of that original post.... what i have donne to solve the not precise method at the end of the post is to scale the body only to be sure that it contains another line of voxels, and then intersect the voxels created with the original body(not scaled) (that i am intersecting.... Q7)
    in the post you recommend me or at least kept it like that from the other user sugestion,
    to use
                opBoolean(context, id + "boolean", {
                            "tools" : qCreatedBy(id + "pattern", EntityType.BODY),
                            "operationType" : BooleanOperationType.UNION
                        });
    my issue is that when i was working even if the bodies were intersecting, when they were too many, the FS was not working, without editing anything else, and erasing the opboolean, the FS worked.... so after that i was boolean them manually after the FS in the part studio. 
    Q7 i found the issue for this one :)

    when i intersect the bodies with opBoolean i get all the bodies that a part of them is inside but it keeps the exterior part of it. for example if i intersect A with B and A is the tool, and part of it is inside B after the boolean op i get A and B not the small part of A inside B
    opBoolean(context, id + "boolean12", {
            "tools" : qUnion([qCreatedBy(id+"cylinder1", EntityType.BODY),definition.entities]),
           "operationType" : BooleanOperationType.INTERSECTION,
           "keepTools" : true,
    });  
  • MBartlett21MBartlett21 Member, OS Professional, Developers Posts: 2,034 EDU
    NeilCooke said:
    Another option is to add an extra level to your id. However, id's can only be created contiguously, so no other operation can be carried out on the cylinders until all cylinders have been created. You can try to follow along here: https://cad.onshape.com/FsDoc/library.html#Id

    for(var i = 1; i < 13; i +=1)
    {
       fCylinder(context, id + "cylinder" + i, {
       ...
       }
       // no other operations that create a new id can be added here
    }
    var cyls = qCreatedBy(id + "cylinder", EntityType.BODY); // this will get cylinder plus all its children

    If you add the extra level before the "cylinder", like id + i + "cylinder", you then can do other operations on the cylinder, using other ids in the same format: e.g. id + i + "doStuff" You can then query for all the cylinders by querying qCreatedBy(id + ANY_ID + "cylinder", EntityType.BODY);
    mb - draftsman - also FS author: View FeatureScripts
    IR for AS/NZS 1100
Sign In or Register to comment.