Last active
February 20, 2026 17:40
-
-
Save jpfaraco/84f37530916c33466cb4597ae995459b to your computer and use it in GitHub Desktop.
Onshape feature - Sine wave
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| FeatureScript 2780; | |
| import(path : "onshape/std/common.fs", version : "2780.0"); | |
| annotation { "Feature Type Name" : "Sine wave" } | |
| export const sineWave = defineFeature(function(context is Context, id is Id, definition is map) | |
| precondition | |
| { | |
| annotation { "Name" : "Edge", "Filter" : EntityType.EDGE, "MaxNumberOfPicks" : 1 } | |
| definition.edge is Query; | |
| annotation { "Name" : "Reference face", "Filter" : EntityType.FACE && GeometryType.PLANE, "MaxNumberOfPicks" : 1 } | |
| definition.referenceFace is Query; | |
| annotation { "Name" : "Amplitude" } | |
| isLength(definition.amplitude, { (millimeter) : [0.1, 5, 100] } as LengthBoundSpec); | |
| annotation { "Name" : "Number of cycles" } | |
| isReal(definition.cycles, { (unitless) : [0.1, 5, 100] } as RealBoundSpec); | |
| annotation { "Name" : "Phase offset" } | |
| isAngle(definition.phase, { (degree) : [0, 0, 360] } as AngleBoundSpec); | |
| annotation { "Name" : "Points per cycle" } | |
| isInteger(definition.pointsPerCycle, { (unitless) : [8, 32, 100] } as IntegerBoundSpec); | |
| annotation { "Name" : "Flip direction" } | |
| definition.flip is boolean; | |
| } | |
| { | |
| var amplitude = definition.amplitude; | |
| if (definition.flip) | |
| amplitude = -amplitude; | |
| var cycles = definition.cycles; | |
| var phase = definition.phase; | |
| var pointsPerCycle = definition.pointsPerCycle; | |
| var totalPoints = cycles * pointsPerCycle + 1; | |
| // The reference face normal defines which direction the wave oscillates in. | |
| // At each point along the edge, we project this normal onto the plane | |
| // perpendicular to the tangent, so the wave always goes "sideways" relative | |
| // to the edge direction. | |
| var refPlane = evPlane(context, { "face" : definition.referenceFace }); | |
| var waveDir = refPlane.normal; | |
| var points = []; | |
| for (var i = 0; i < totalPoints; i += 1) | |
| { | |
| var t = i / (totalPoints - 1); | |
| var tangentLine = evEdgeTangentLine(context, { | |
| "edge" : definition.edge, | |
| "parameter" : t | |
| }); | |
| var pos = tangentLine.origin; | |
| var tan = tangentLine.direction; | |
| // Project wave direction onto the plane perpendicular to the tangent | |
| var perp = waveDir - dot(waveDir, tan) * tan; | |
| var len = norm(perp); | |
| if (len < 1e-10) | |
| throw regenError("The reference face normal is parallel to the edge. Pick a different face.", ["referenceFace"]); | |
| perp = perp / len; | |
| // Compute sine offset at this parameter | |
| var angle = t * cycles * 2 * PI * radian + phase; | |
| var offset = sin(angle) * amplitude; | |
| points = append(points, pos + perp * offset); | |
| } | |
| opFitSpline(context, id + "sineWave", { | |
| "points" : points | |
| }); | |
| }); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment