Sine heart
A simple sine heart graph with multiple frequencies.
Log in to post a comment.
// Little sine wave heart generator
// Originality disclosure:
// Sine wave heart equation was found on the internet a while ago (not sure what the original source is)
// Was being lazy and used an LLM to change the sine wave heart function, but cleaned
// it up afterwards, so it's fairly decent now (but the interpolation "idea" came from the LLM,
// comments and current set up are mine).
// TODO: Make offsets and scalars constants. Some DRY refinement.
Canvas.setpenopacity(1);
// Detail level
const xStep = 0.001; // min = 0.001 max = 10 step=0.001
// // Original sine wave heart function
// function sine_heart_old(x, a) {
// return Math.abs(x)**(2/3) + Math.sqrt(3.3 - x**2) * Math.sin(a * Math.PI * x);
// }
function sine_heart(x, a) {
// (semi-)Circular envelope
const circle_envelope = Math.sqrt(3.3 - x**2);
// Sine wave in circular envelope
const wave = circle_envelope * Math.sin(a * Math.PI * x);
// Rounded heart envelope (like a ⋎, rounded v)
const heart_envelope = Math.abs(x)**(2/3)
// Blending constant. Only affects <1 "a"s
// that were having a C^1 discontinuity at x=0
const blend = Math.min(1, Math.abs(a))**4;
// Average height of the heart term. Calculated via:
// (\int_{xMin}^{xMax} sine_heart(x, 16) dx)/(xMax-xMin)
// This may be the wrong way to calculate it
// TODO: fix this calculation to properly align low "a" value hearts
const baseline = 0.893283331772;
// Interpolate between a constant and the heart envelope to smooth
// the x=0 kink caused by the heart envelope & noticable in low "a"s
const offset = baseline + blend * (heart_envelope - baseline);
// Final heart: circular sine + interpolated heart swoop
return wave + offset;
}
// Main code
const turtle = new Turtle();
// Boundary of our heart. Decided by sine_heart()
const xMin = -Math.sqrt(3.3);
const xMax = Math.sqrt(3.3);
// Arbitrary scale by to fill the space nicely
const scale_by = 5;
// frequency values for the row of hearts
var a_vals = [0.5, 1, 2, 4, 8, 16];
// Distance between the start of each heart
var xshift=5*scale_by;
// Loop over frequency values
for (let i=0; i<a_vals.length; i++) {
var a = a_vals[i];
var x=xMin;
var y=sine_heart(x,a);
turtle.penup();
turtle.goto(x*scale_by+(i*xshift-65),-y*scale_by);
turtle.pendown();
// Step through heart function
for (let j=0; x<xMax; j++) {
x = xMin + (j*xStep);
if(x>xMax) {
break;
}
y = sine_heart(x,a);
turtle.goto(x*scale_by+(i*xshift-65),-y*scale_by);
}
turtle.penup();
}