second step: JSL

Names Default To Here( 1 );
// Parameters
r_inner = 1; // Radius of the inner circle
r_outer = 3; // Radius of the outer circle
a = 1; // Amplitude factor
// Function for the deltoid curve
deltoid = Function( {t, r_inner, r_outer, a},
{default local},
x = (r_outer - r_inner) * Cos( t ) + a * Cos( (r_outer - r_inner) / r_inner * t );
y = (r_outer - r_inner) * Sin( t ) - a * Sin( (r_outer - r_inner) / r_inner * t );
Return( Eval List( {x, y} ) );
);
deltoid_coordinates = Transform Each( {i}, As List( Transpose( 1 :: 999 ) ),
t = 2 * Pi() * (i - 1) / 999;
deltoid( t, r_inner, r_outer, a );
);
nr = N Items( deltoid_coordinates );
nsplit = Round( nr / 3 );
splits = Eval List( {deltoid_coordinates[1 :: nsplit], deltoid_coordinates[nsplit + 1 :: 2 * nsplit], deltoid_coordinates[2 * nsplit + 1 :: nr]} );
// Function for the outer circle
myCircle = Function( {t, r},
{default local},
x = r * Cos( t );
y = r * Sin( t );
Return( Eval List( {x, y} ) );
);
// Compute the tangent
compute_tangent = Function( {t0, r_inner, r_outer, a},
{default local},
point = deltoid( t0, r_inner, r_outer, a );
x0 = point[1];
y0 = point[2];
h = 1e-5;
dx_dt = deltoid( t0 + h, r_inner, r_outer, a )[1] - deltoid( t0, r_inner, r_outer, a )[1];
dy_dt = deltoid( t0 + h, r_inner, r_outer, a )[2] - deltoid( t0, r_inner, r_outer, a )[2];
slope = dy_dt / dx_dt;
intercept = y0 - slope * x0;
Return( Eval List( {x0, y0, slope, intercept} ) );
);
// Function to compute the distance between a point and a line
distance_to_line = Function( {point, slope, intercept},
{default local},
x = point[1];
y = point[2];
Return( Abs( slope * x - y + intercept ) / Sqrt( slope ^ 2 + 1 ) );
);
// Function to compute intersection points
find_closest_points = Function( {slope, intercept, splits},
{default local},
// Split the deltoid coordinates into three sections
// Compute the minimum distance for each section
min_distances = Transform Each( {split}, Eval List( splits ),
Min( Transform Each( {point}, split, distance_to_line( point, slope, intercept ) ) )
);
split_to_remove = Loc Min( Matrix( min_distances ) );
// Select remaining valid sections
valid_splits = Remove( Eval List( splits ), split_to_remove );
// Find the closest point with the smallest distance
closest_points = {};
For Each( {split}, valid_splits,
min_pos = Loc Min( Matrix( Transform Each( {point}, split, distance_to_line( point, slope, intercept ) ) ) );
Insert Into( closest_points, split[min_pos] );
);
Return( closest_points );
);
// Create a new table
dt = New Table( "Deltoid Data",
Add Rows( 999 ),
// Create columns for the table
New Column( "angle", Numeric ),
New Column( "x_deltoid", Numeric ),
New Column( "y_deltoid", Numeric ),
New Column( "x_inner", Numeric ),
New Column( "y_inner", Numeric ),
New Column( "x_outer", Numeric ),
New Column( "y_outer", Numeric ),
New Column( "x_0", Numeric ),
New Column( "y_0", Numeric ),
New Column( "x_1", Numeric ),
New Column( "y_1", Numeric ),
New Column( "x_2", Numeric ),
New Column( "y_2", Numeric ),
New Column( "x_center", Numeric ),
New Column( "y_center", Numeric )
);
angles = 2 * Pi() * (As List( Transpose( 1 :: 999 ) ) - 1) / 999;
dt[0, "angle"] = angles;
dt[0, {"x_deltoid", "y_deltoid"}] = deltoid_coordinates;
dt[0, {"x_inner", "y_inner"}] = Transform Each( {t}, angles, myCircle( t, r_inner ) );
dt[0, {"x_outer", "y_outer"}] = Transform Each( {t}, angles, myCircle( t, r_outer ) );
dt[0, {"x_0", "y_0"}] = Transform Each( {t}, angles, compute_tangent( t, r_inner, r_outer, a )[{1, 2}] );
dt[0, {"x_1", "y_1", "x_2", "y_2"}] = Transform Each( {t}, angles,
{slope, intersect} = compute_tangent( t, r_inner, r_outer, a )[{3, 4}];
find_closest_points( slope, intersect, splits );
);
dt[0, "x_center"] = (dt[0, "x_1"] + dt[0, "x_2"]) / 2;
dt[0, "y_center"] = (dt[0, "y_1"] + dt[0, "y_2"]) / 2;
::myrow = 1;
New Window( "deltoid",
V List Box(
gb = Graph Builder(
Size( 466, 471 ),
Show Control Panel( 0 ),
Summary Statistic( "Median" ),
Graph Spacing( 4 ),
Variables(
X( :x_0 ),
X( :x_1, Position( 1 ) ),
X( :x_center, Position( 1 ) ),
X( :x_2, Position( 1 ) ),
Y( :y_0 ),
Y( :y_1, Position( 1 ) ),
Y( :y_center, Position( 1 ) ),
Y( :y_2, Position( 1 ) )
),
Elements(
Line(
X( 1 ),
X( 2 ),
X( 4 ),
Y( 1 ),
Y( 2 ),
Y( 4 ),
Legend( 33 ),
Ordering( "Within Row" ),
Connection( "Arrow" ),
Summary Statistic( "Mean" )
),
Points( X( 1 ), Y( 1 ), Legend( 34 ) ),
Points( X( 2 ), Y( 2 ), Legend( 35 ) ),
Points( X( 4 ), Y( 4 ), Legend( 36 ) ),
Points( X( 3 ), Y( 3 ), Legend( 37 ) )
),
SendToReport(
Dispatch( {}, {:x_0}, ScaleBox, {Min( -2.96728319980322 ), Max( 3.31428686472806 ), Inc( 1 ), Minor Ticks( 4 )} ),
Dispatch( {}, {:y_0}, ScaleBox, {Min( -3.05132715458842 ), Max( 3.20702958989834 ), Inc( 1 ), Minor Ticks( 1 )} ),
Dispatch( {}, "400", ScaleBox,
{Legend Model( 34, Properties( 0, {Marker Size( 12 )}, Item ID( "y_0", 1 ) ) ), Legend Model(
35,
Properties( 0, {Marker Size( 12 )}, Item ID( "y_1", 1 ) )
), Legend Model( 36, Properties( 0, {Marker Size( 12 )}, Item ID( "y_2", 1 ) ) ), Legend Model(
37,
Properties( 0, {Marker Size( 12 )}, Item ID( "y_center", 1 ) )
)}
),
Dispatch( {}, "Graph Builder", FrameBox,
{Marker Drawing Mode( "Outlined" ), Reference Line Order( 3 ), Add Graphics Script(
2,
Description( "" ),
Pen Color( "black" );
Line( :x_deltoid << get values(), :y_deltoid << get values() );
Pen Color( "red" );
XY Function( Cos( x ), Sin( x ), x, Min( 0 ), Max( 2 * Pi() ), inc( 0.001 ) );
XY Function( 3 * Cos( x ), 3 * Sin( x ), x, Min( 0 ), Max( 2 * Pi() ), inc( 0.001 ) );
Pen Color( "blue" );
Pen Size( 3 );
Line( {:x_1[::myrow], :y_1[::myrow]}, {:x_2[::myrow], :y_2[::myrow]} );
)}
)
)
)
)
);
ldf = gb << Local Data Filter( Add Filter( columns( :angle ), Modeling Type( :angle, Nominal ), Where( :angle == 0 ) ) );
f = Function( {a},
::myrow = Try( (ldf << Get Filtered Rows())[1], 1 )
);
fch = ldf << make filter change handler( f );