Skip to content

Instantly share code, notes, and snippets.

@Gro-Tsen
Last active January 10, 2026 18:21
Show Gist options
  • Select an option

  • Save Gro-Tsen/6bdb99090c41705b5ba64ab0fb7a3590 to your computer and use it in GitHub Desktop.

Select an option

Save Gro-Tsen/6bdb99090c41705b5ba64ab0fb7a3590 to your computer and use it in GitHub Desktop.
Fourier transform of a decagon and related images
gcc -o d10fourier d10fourier.c -O6 -Wall -std=c99 -pedantic -Wextra -lm -DTEN=10 -DPIC_WIDTH=1920 -DPIC_HEIGHT=1080 -DFRAME_COUNT=1440
parallel -j 8 ./d10fourier {} ::: $(seq 0 719)
ffmpeg -framerate 24 -i d10fourier-%04d.png -video_size 1920x1080 -c:v libx265 -preset slower -crf 27 -pix_fmt yuv420p d10fourier.mp4
gcc -o d14fourier d10fourier.c -O6 -Wall -std=c99 -pedantic -Wextra -lm -DTEN=14 -DPIC_WIDTH=1920 -DPIC_HEIGHT=1080 -DFRAME_COUNT=1440
parallel -j 8 ./d14fourier {} ::: $(seq 0 719)
ffmpeg -framerate 24 -i d14fourier-%04d.png -video_size 1920x1080 -c:v libx265 -preset slower -crf 27 -pix_fmt yuv420p d14fourier.mp4
// d10fourier.c - compute the Fourier transform of a regular decagon
// David A. Madore <http://www.madore.org/~david/>
// Initially written 2018-04-22 (based on an earlier e8fourier program)
// This version 2026-01-10
/* This program is in the Public Domain. However, I would appreciate
* being credited if significant parts of it are being used
* somewhere. */
/* The author of this program disclaims all warranties with regard to
* this software, including all implied warranties of merchantability
* and fitness for a particular purpose: in no event shall the author
* be liable for any damages arising out of or in connection with the
* use or performance of this software. If you need this sort of
* legalese, you are an idiot and you should not use a computer. */
/* Compile with something like
gcc -o d10fourier d10fourier.c -O6 -Wall -std=c99 -Wextra -lm
* The "convert" program from ImageMagick is used to convert .ppm to
* .png (this should be easy to change, search for "convert" in
* main()). Various compile-time adjustable parameters are below. */
#ifndef PIC_WIDTH
#define PIC_WIDTH 1920 // Image width
#endif
#ifndef PIC_HEIGHT
#define PIC_HEIGHT 1080 // Image height
#endif
#ifndef PIC_SCALE
#define PIC_SCALE 16 // Pixels per unit distance
#endif
#ifndef FRAME_COUNT
#define FRAME_COUNT 1440 // Frame count for a full cycle
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#ifndef TEN
#define TEN 10
#endif
#define DIM 2
#ifndef M_PI
// Stupid <math.h> does not define this by order of the assholes who
// removed this from the C99 standard.
#define M_PI 3.141592653589793238462643383279502884
#endif
double vecs[TEN][DIM];
int
main (int argc, char *argv[])
{
int frameno = 0;
char havearg = 0;
if ( argc >= 2 )
{
havearg = 1;
sscanf (argv[1], "%d", &frameno);
}
double phaseshift = (double)frameno / FRAME_COUNT;
for ( int k=0 ; k<TEN ; k++ )
{
vecs[k][0] = cos(M_PI*2*k/TEN);
vecs[k][1] = sin(M_PI*2*k/TEN);
}
char buf[255];
if ( havearg )
snprintf (buf, sizeof(buf), "d%02dfourier-%04d.ppm", TEN, frameno);
else
snprintf (buf, sizeof(buf), "d%02dfourier.ppm", TEN);
FILE *ppmf = fopen (buf, "w");
if ( ! ppmf )
{
fprintf (stderr, "Failed to open %s for writing: %s\n",
buf, strerror(errno));
exit (EXIT_FAILURE);
}
fprintf (ppmf, "P3\n%d %d 255\n", PIC_WIDTH, PIC_HEIGHT);
for ( int l=0 ; l<PIC_HEIGHT ; l++ )
{
for ( int k=0 ; k<PIC_WIDTH ; k++ )
{
double v[DIM];
v[0] = ((k-PIC_WIDTH/2-0.5)/PIC_SCALE);
v[1] = ((PIC_HEIGHT/2-0.5-l)/PIC_SCALE);
double val = 0;
for ( int r=0 ; r<TEN/2 ; r++ )
{
double dot = 0;
for ( int i=0 ; i<DIM ; i++ )
dot += vecs[r][i] * v[i];
dot += ((r%2) ? -2*phaseshift : 2*phaseshift);
val += 2*cos(M_PI*dot);
}
// Fourier transform takes values between -10 and 10.
assert (val >= -TEN && val <= TEN);
#if 0 // Color gradient (blue for negative, black for zero, white for positive)
if ( val < 0. )
{
int i = (int)((val+TEN)*255/(TEN+0.));
fprintf (ppmf, " %d %d %d", 0, 0, 255-i);
}
else
{
int i = (int)((val)*255/(TEN+0.));
fprintf (ppmf, " %d %d %d", i, i, i);
}
#elif 0 // Black for negative, white for positive
if ( val < -0.3 )
fprintf (ppmf, " %d %d %d", 0, 0, 0);
else if ( val > 0.3 )
fprintf (ppmf, " %d %d %d", 255, 255, 255);
else
{
int i = (int)((val+0.3)*425.);
assert (i>=0 && i<=255);
fprintf (ppmf, " %d %d %d", i, i, i);
}
#else // White for [-1,1], black outside of [-1.5,1.5]
if ( val >= -1 && val <= 1 )
fprintf (ppmf, " %d %d %d", 255, 255, 255);
else if ( val > 1.5 || val < -1.5 )
fprintf (ppmf, " %d %d %d", 0, 0, 0);
else
{
int i = (int)(255-(fabs(val)-1.)*510.);
assert (i>=0 && i<=255);
fprintf (ppmf, " %d %d %d", i, i, i);
}
#endif
}
fprintf (ppmf, "\n");
}
fclose (ppmf);
// Now convert PPM image to PNG.
pid_t convpid = fork ();
if ( convpid < 0 )
{
fprintf (stderr, "Failed to fork: %s\n", strerror(errno));
exit (EXIT_FAILURE);
}
if ( convpid == 0 )
{
char buf2[255];
if ( havearg )
snprintf (buf2, sizeof(buf2), "d%02dfourier-%04d.png", TEN, frameno);
else
snprintf (buf2, sizeof(buf2), "d%02dfourier.png", TEN);
execlp ("convert", "convert", buf, buf2, (char *)NULL);
fprintf (stderr, "Failed to execlp: %s\n", strerror(errno));
exit (EXIT_FAILURE);
}
else
{
waitpid (convpid, NULL, 0);
unlink (buf);
}
exit (EXIT_SUCCESS);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment