// -------------------------------------------------------------------------- // // Adapted from https://femto-physique.fr/simulations/courbes-de-poursuite.php // Written in "Processing" (https://processing.org/) // // Pursuit curve // https://en.wikipedia.org/wiki/Pursuit_curve // // -------------------------------------------------------------------------- #version 3.7; // -------------------------------------------------------------------------- // --- CHECK IMAGE RATIO ---------------------------------------------------- // -------------------------------------------------------------------------- #if(image_width!=image_height) #error "Set image aspect ratio to ONE !" #end // -------------------------------------------------------------------------- // --- INCLUDES ------------------------------------------------------------- // -------------------------------------------------------------------------- #include "colors.inc" // -------------------------------------------------------------------------- // --- VARS ----------------------------------------------------------------- // -------------------------------------------------------------------------- #declare displayAxis = false; #declare displayPlane = false; #declare AxisLen = 16; // Scale = AxisLen/image_width #declare Scale = AxisLen/image_width; // -------------------------------------------------------------------------- // --- SETTINGS ------------------------------------------------------------- // -------------------------------------------------------------------------- global_settings { assumed_gamma 1.80 max_trace_level 5 } #default { finish { ambient 0.00 emission 0.40 diffuse 0.60 } } // -------------------------------------------------------------------------- // --- SCENE ---------------------------------------------------------------- // -------------------------------------------------------------------------- camera { orthographic location <0, 0, -26> up y right x*image_width/image_height look_at <0, 0, 0> angle 36 } light_source { <0, 0, -100> color White } background { color White*0 } #if(displayPlane) plane { z,0 pigment { checker White,White*0.80 } } #end //#if (displayAxis) // drawAxis (AxisLen, 0.02) //#end // -------------------------------------------------------------------------- // --- MACROS --------------------------------------------------------------- // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- // --- Draw line from two points -------------------------------------------- // -------------------------------------------------------------------------- #macro DrawLine(x1, y1, x2, y2, r, c) #if ( !(x1=x2 & y1=y2)) cylinder { , , r pigment { color c transmit c.transmit } } #end #end // -------------------------------------------------------------------------- // https://www.rapidtables.com/convert/color/hsv-to-rgb.html // HSV is the same thing as HSB ! // -------------------------------------------------------------------------- #macro hsb2rgb ( _Hue, _Saturation, _Brightness, _Transmit) #local C = _Brightness*_Saturation; #local X = C - (1 - abs(mod(_Hue/60,2) - 1)); #local m = _Brightness-C; #if ( _Hue>=0 & _Hue<60) #local RED = C; #local GREEN = X; #local BLUE = 0; #elseif ( _Hue>=60 & _Hue<120) #local RED = X; #local GREEN = C; #local BLUE = 0; #elseif ( _Hue>=120 & _Hue<180) #local RED = 0; #local GREEN = C; #local BLUE = X; #elseif ( _Hue>=180 & _Hue<240) #local RED = 0; #local GREEN = X; #local BLUE = C; #elseif ( _Hue>=240 & _Hue<300) #local RED = X; #local GREEN = 0; #local BLUE = C; #elseif ( _Hue>=300 & _Hue<360) #local RED = C; #local GREEN = 0; #local BLUE = x; #else #error "_Hue out of range in convertion ! " #end #end // -------------------------------------------------------------------------- // --- RANDOM LISTE --------------------------------------------------------- // -------------------------------------------------------------------------- // I wasn't able to transpose/make the original function work properly. // So I wrote my own routine. // Shuffle one dimension array in place #macro ShuffleArray(ThisArray, Alea) #local dim = dimension_size(ThisArray, 1); #local i = dim-1; #while ( i > 2 ) #local j = 1+int(rand(Alea)*dim-1); #local tmp = ThisArray[i]; #local ThisArray[i] = ThisArray[j]; #local ThisArray[j] = tmp; #local i = i - 1; #end #end // Create random liste of integer from 0..(ArraySize-1) #macro randomListe(ArraySize, Alea) #local LocalArray = array[ArraySize]; #local i = 0; #while ( i < ArraySize) #local LocalArray[i] = i; #local i = i + 1; #end // Here, the list is sorted ShuffleArray(LocalArray, Alea) // and now, it's a mess. LocalArray #end // -------------------------------------------------------------------------- // --- SETUP ---------------------------------------------------------------- // -------------------------------------------------------------------------- #macro SetUp() // radius of polygon #declare r = image_width/2; // angel between each polygon vertex #declare theta = 2*pi/n; // Compute points of polygon #local i = 0; #while ( i < n) #declare pos[i][0] = r*cos(theta/2+i*theta)*Scale; #declare pos[i][1] = r*sin(theta/2+i*theta)*Scale; #local i = i + 1; #end // Draw Polygon #local m = 1; #while( m <= n) #local mg = mod(m,n)+1; #local Color = rgb 0.25; DrawLine(pos[m-1][0], pos[m-1][1], pos[mg-1][0], pos[mg-1][1], rLine, Color) #local m = m + 1; #end #end // -------------------------------------------------------------------------- // --- INITIALISATION ------------------------------------------------------- // -------------------------------------------------------------------------- #macro Initialisation(Alea) #local il = randomListe(n, Alea); #local i = 0; #while ( i < n ) // random numbering of pursuers #local ir = il[i]; // positions #declare pos[i][0] = r*cos(theta/2+ir*theta)*Scale; #declare pos[i][1] = r*sin(theta/2+ir*theta)*Scale; #local i = i + 1; #end #end // -------------------------------------------------------------------------- // --- DRAW ----------------------------------------------------------------- // -------------------------------------------------------------------------- #macro Draw() #local m = 1; #while ( m <= n ) #local mg = 1 + mod(m,n); #local Color = CHSV2RGB(); DrawLine(pos[m-1][0], pos[m-1][1], pos[mg-1][0], pos[mg-1][1], rLine, Color) #local m = m + 1; #end #local m = 1; #while ( m <= n ) #declare pos[m-1][0] = pos[m-1][0] + h*(pos[mod(m,n)][0]-pos[m-1][0]); #declare pos[m-1][1] = pos[m-1][1] + h*(pos[mod(m,n)][1]-pos[m-1][1]); #local m = m + 1; #end #declare compteur = compteur+1; #end // -------------------------------------------------------------------------- // --- VARIABLES ------------------------------------------------------------ // -------------------------------------------------------------------------- // --- have fun with these variables ---------------------------------------- // Initializes a pseudo-random stream #declare alea = seed(1023); // Play with it // Number of pursuers #declare n = 8; // Play with it. 3 is a minium // Max number of lines to draw #declare MaxLines = 150; // Play with it // --- Others variables ----------------------------------------------------- // Mapping Color Hue : 0 -> 0, n -> 360 #declare ColorHue = 360/n; // Steep #declare h = 0.04; // Counter #declare compteur = 1; // Array of positions // ... yes, I know, i can make an array of vectors directly. #declare pos = array[n][2]; // Line width / Cylinder radius #declare rLine = 0.010; // -------------------------------------------------------------------------- // --- LET'S GO ------------------------------------------------------------- // -------------------------------------------------------------------------- SetUp() Initialisation(alea) #while ( compteur < MaxLines) Draw() #end