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.

Feature script: Circular pattern + Torrodial rotation by steps around secondary axis.

Code by clause on preplexity, I helped .

Screenshot 2025-09-18 113611.png


import(path : "onshape/std/common.fs", version : "2752.0");

// Define custom angle bounds
export const CUSTOM_ANGLE_BOUNDS = {
(degree) : [0, 15, 360] // [min, default, max] in degrees
} as AngleBoundSpec;

export const TOTAL_ANGLE_BOUNDS = {
(degree) : [1, 360, 1080] // [min, default, max] - allows up to 2 full rotations
} as AngleBoundSpec;

annotation { "Feature Type Name" : "Dual Axis Pattern" }
export const dualAxisPattern = defineFeature(function(context is Context, id is Id, definition is map)
precondition
{
annotation { "Name" : "Bodies to pattern", "Filter" : EntityType.BODY }
definition.entities is Query;

    annotation { "Name" : "Circular pattern axis", "Filter" : GeometryType.LINE }
    definition.circularAxis is Query;
    
    annotation { "Name" : "Step rotation axis", "Filter" : GeometryType.LINE }
    definition.stepAxis is Query;
    
    annotation { "Name" : "Number of instances" }
    isInteger(definition.instanceCount, POSITIVE_COUNT_BOUNDS);
    
    annotation { "Name" : "Total rotation around main axis" }
    isAngle(definition.totalRotation, TOTAL_ANGLE_BOUNDS);
    
    annotation { "Name" : "Step angle per instance" }
    isAngle(definition.stepAngle, CUSTOM_ANGLE_BOUNDS);
}
{
    var circularAxisLine = evAxis(context, { "axis" : definition.circularAxis });
    var stepAxisLine = evAxis(context, { "axis" : definition.stepAxis });
    
    // Calculate angle between instances: totalRotation / instanceCount
    var anglePerInstance = definition.totalRotation / definition.instanceCount;
    
    var transforms = [];
    var instanceNames = [];
    
    for (var i = 1; i < definition.instanceCount; i += 1)
    {
        // Step 1: rotate around secondary axis by stepAngle * i
        var stepRotation = rotationAround(stepAxisLine, definition.stepAngle * i);
        
        // Step 2: rotate around main axis by anglePerInstance * i 
        var circularRotation = rotationAround(circularAxisLine, anglePerInstance * i);
        
        // Combine: main rotation AFTER step rotation
        var combinedTransform = circularRotation * stepRotation;
        
        transforms = append(transforms, combinedTransform);
        instanceNames = append(instanceNames, "instance_" ~ i);
    }
    
    if (size(transforms) > 0)
    {
        opPattern(context, id, {
            "entities" : definition.entities,
            "transforms" : transforms,
            "instanceNames" : instanceNames
        });
    }
}

);

Comments

Sign In or Register to comment.