Size of this preview: 600 × 600 pixels. Other resolutions: 240 × 240 pixels | 480 × 480 pixels | 768 × 768 pixels | 1,024 × 1,024 pixels | 1,417 × 1,417 pixels.
Original file (1,417 × 1,417 pixels, file size: 143 KB, MIME type: image/png)
This is a file from the Wikimedia Commons. Information from its description page there is shown below. Commons is a freely licensed media file repository. You can help. |
Contents
Summary
DescriptionShrub model of Mandelbrot set 60 10 labelled.png |
English: Shrub model of Mandelbrot set, dMax = 60, circle level max = 10, labelled. Based on the paper M. Romera et al, Int. J. Bifurcation Chaos 13, 2279 (2003).
Shrubs in the Mandelbrot Set Ordering www.tic.itefi.csic.es/gerardo/publica/Romera03.pdf. See also gitlab repo |
Date | |
Source | Own work |
Author | Adam majewski |
Other versions |
|
Licensing
I, the copyright holder of this work, hereby publish it under the following license:
This file is licensed under the Creative Commons Attribution-Share Alike 4.0 International license.
- You are free:
- to share – to copy, distribute and transmit the work
- to remix – to adapt the work
- Under the following conditions:
- attribution – You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
- share alike – If you remix, transform, or build upon the material, you must distribute your contributions under the same or compatible license as the original.
See also:
- ascii graphics From the Mandelbrot Set Glossary and Encyclopedia, by Robert Munafo, (c) 1987-2017 "is a graphical image rendered entirely out of characters from the ASCII character set ...to permit sending the articles to email users."
- From the Mandelbrot Set Glossary and Encyclopedia, by Robert Munafo, (c) 1987-2017analytical naming system
- math.stackexchange question: is-there-a-koch-circle ?
to do
- minimal font size : https://www.imarc.com/blog/best-font-size-for-any-device
Summary
Program creates 2 files:
- svg fiele without labels
- text file containing text group = labels
old C source code
/*
gcc d.c -Wall -lm
./a.out
program creates 2 files
- svg file ( without labels which are in the text files)
- text file with text group ( labela)
one can copy content of the text fil into svg file to have file with labels
It is manual optimisation ( file size is smaller)
Draw a model of Mandelbrot set.
Based on the paper M. Romera et al, Int. J. Bifurcation Chaos 13, 2279 (2003).
Shrubs in the Mandelbrot Set Ordering
www.tic.itefi.csic.es/gerardo/publica/Romera03.pdf
compare with :
[[:File:Cactus_model_of_Mandelbrot_set.svg]]
angle is measured :
* in turns
* counterclockwise
https://en.wikipedia.org/wiki/Turn_(geometry)
angle can be :
* global ( 0 = 1 is on horizontal = x axis )
* local, where 0 is internal angle of parent
CircleLevel :
0 = main circle (main cardioid) = period 1 cycle
1 = circles on the main circles
2 =
stroke_width : A number without units is rendered the same as a percentage
https://css-tricks.com/almanac/properties/s/stroke-width/
Its default value is 1.
If a <percentage> is used, the value represents a percentage of the current viewport.
If a value of 0 is used the outline will never be drawn.
mutually and externally tangent circles
http://mathworld.wolfram.com/TangentCircles.html
Two circles are mutually and externally tangent if distance between their centers is equal to the sum of their radii
svg check
https://validator.w3.org/check
http://jsfiddle.net/j5ykdtgc/
cd existing_folder
git init
git remote add origin git@gitlab.com:adammajewski/mandelbrot-shrub-model.git
git add d.c
git commit -m "Initial commit"
git push -u origin master
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //strncat
#include <math.h> // sin, M_PI
/* - ------------------------- global variables ----------------------------- */
// limits and main parameters of the program ~ detailes of the image
// what is efficient relation between limits ?
#define CircleLevelMax 10 //
const int dMax = 60; // maximal denominator of internal angle
// svg
// viewBox
double Xmax = 1000.0;
double Ymax = 1000.0;
double stroke_width; // = 0.5;
double minimal_radius; /* radius of minimal circle to draw */
double min_font_size;
double min_length;
// RGB colors = 24 bit
// http://www.december.com/html/spec/color4.html
char *black = "#000000"; /* hexadecimal number as a string for svg color*/
char *white = "#FFFFFF";
char *burgundy = "#9E0508";
char *SeaGreen = "#068481";
char *turquoise= "#40E0D0";
char *red = "#FF0000";
char *navy = "#000080";
char *blue = "#0000FF";
// ----------- svg file -----------------------------
FILE * svg_fp;
#define BUFSIZE 11 // 6+4+1 = name + .svg + eof
char svg_name [BUFSIZE]; /* name of file */
char *svg_file_name; //="shrub.svg";
// text file
FILE * txt_fp;
char txt_name [BUFSIZE]; /* name of file */
char *txt_file_name; //
// ----------- svg parameters -----------------
char *comment = "<!-- sample comment in SVG file \n can be multi-line -->";
char *stroke_color ;
char *fill_color ;
const double main_angle = 0.5; // angle in turns ; if 0.5 then main antenna is horizontal
int n1 = 1;
int d1 = 1;
int NoOfDrawnCircles = 0;
int NoOfAllCircles = 0;
int NoOfDrawnShrubs = 0;
int NoOfAllShrubs = 0;
// type for saving info about circle ( hyperbolic component of Mandelbrot set )
typedef struct {
int CircleLevel;
// global (internal) angle in turns T = N/D
double T;
// local (internal) angle in turns t = n/d
int n; // numerator
int d; // denominator
// ------- circle parameters -------
// center of the circle c = cx + cy*I
double cx;
double cy;
double radius;
// ------ shrub parameters -----------------
// internal angle of the wake / limb / shrub
int N;
int D;
// apex = end point, it simulates M-Feigenbaum ponit, here shrub starts
// tangency point for n/d = 1/2
double ax;
double ay;
//
double length; // of the shrub
} DataType;
DataType Data = {0, 0.5,1,1 }; // declare and initialize the structure Data
DataType *DataP ;//= &Data = pointer to Data
// --------------------------- functions -------------------------------===============
// GiveNewRadius(old,_p,_q):=old*abs(sin(%pi*_p/_q)/(_q*_q))
double GiveNewRadius(double OldRadius, int num, int den ){
//double t = (double)num / den;
double d2 = den*den;
//printf( "t = %f ; d2 = %f ",t, d2);
//double temp =(num*num)/d2;
//printf( "temp = %f ; ",temp);
return 1.3*OldRadius/d2; //
}
//GiveGlobalAngle(old,new):=mod(old-(1/2-new),1);
double GiveNewAngle (double old, double n, double d) {
double t =old-(main_angle-n/d);
if (t > 1.0) t = t - 1.0;
return t;
}
// pass the struct by reference. This means that your function can access the struct outside of the function and modify its values. You do this by passing a pointer to the structure to the function.
// https://stackoverflow.com/questions/10370047/passing-struct-to-function
void SetData(DataType *w, int CircleLevel, double T, int n, int d, double cx, double cy, double radius, double ax, double ay, double length ){
w->CircleLevel = CircleLevel;
w->T = T;
w->n = n;
w->d = d;
w->cx = cx;
w->cy = cy;
w->radius = radius;
w->N = 1;
w->D = 1;
w->ax = ax;
w->ay = ay;
w->length = length; }
void PrintData(DataType w){
printf("CircleLevel = %d \n", w.CircleLevel);
printf("global angle = T = %f \n", w.T);
printf("local angle = n/d = %d/%d \n", w.n, w.d);
printf("center = (%f;%f) radius = %f \n", w.cx, w.cy, w.radius);
printf("wake angle = N/D = %d/%d \n", w.N, w.D);
printf("apex = (%f;%f) \n", w.ax,w.ay);
printf("length = %f\n", w.length);
}
/*
w_new is changed and then it is used to draw = output
w_old is is an input
it is the longest procedure !!!!
maybe some changes ?
*/
int UpdateData(DataType *w_new, DataType w_old, int n, int d){
double distance ; // distance between centers of tangent circles
double angle;
// global angle
w_new->T = GiveNewAngle(w_old.T, n, d);
angle = 2.0*M_PI*w_new->T;
w_new->radius = GiveNewRadius(w_old.radius, n, d );
distance = w_old.radius + w_new->radius; // distance between centers of tangent circles
// new center
w_new->cx = w_old.cx + distance* cos(angle);
w_new->cy = w_old.cy + distance* sin(angle);
if (w_old.CircleLevel < CircleLevelMax)
{w_new->CircleLevel = w_old.CircleLevel +1; // next circle
}
else w_new->CircleLevel = w_old.CircleLevel; // go to the shrub not next circle
// local angle in turns t = n/d
w_new->n = n;
w_new->d = d;
NoOfAllCircles += 1;
/* ------- shrub parameters -------------- */
switch(w_old.CircleLevel) {
case 0 : // w_new->CircleLevel = 1
w_new->length = 2.0*w_new->radius;
w_new->N = n;
w_new->D = d;
break; /* */
default : /* w_old.CircleLevel>0 && w_new->CircleLevel > 1 */
// length
if (w_new->n ==1 && w_new->d ==2)
w_new->length = w_old.length + 2.0 * w_new->radius; // limb
else w_new->length = 2.0 * w_new->radius; // sublimb
// N/D
// if new angle = 1/2
if (n ==1 && d ==2) {
// save old angle
w_new->N = w_old.N;
w_new->D = w_old.D;
}
else { // use new values
w_new->N = n;
w_new->D = d;
}
} // switch
// when shrub is drawn then no circle is drawn, so use previous circle parameters
// apex of the last circle aproximates MF point
angle = 2.0*M_PI*w_old.T;
w_new->ax = w_old.cx + w_old.radius * cos(angle); //
w_new->ay = w_old.cy + w_old.radius * sin(angle); //
//if ( w_new->D > dMax)
// {printf("w_new->D = %d > dMax for CircleLevel = %d d= %d \n",w_new->D, w_new->CircleLevel, d);
// return 1; }
return 0;
}
double min(double a, double b) {
return a < b ? a : b;
}
void beginSVG(){ //
snprintf(svg_name, 6, "%02d_%02d", dMax, CircleLevelMax ); /*nn_nn + \0 = 5+1 */
svg_file_name = strncat(svg_name,".svg",9 ); // 5+4 = length(name) + length(.ext)
//
svg_fp = fopen( svg_file_name,"w");
if( svg_fp == NULL ) {printf (" svg file open error \n"); return ; }
// SVG
fprintf(svg_fp,
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
"%s \n "
"<svg width=\"40cm\" height=\"40cm\" viewBox=\"0 0 %.0f %.0f\"\n"
" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n",
comment,Xmax,Ymax);
fprintf(svg_fp,"<g stroke=\"%s\" stroke-width=\"%f\" fill=\"%s\">\n", stroke_color, stroke_width, fill_color); // group open
printf(" beginSVG done \n");
}
int BeginTextFile(){
snprintf(txt_name, 6, "%02d_%02d", dMax, CircleLevelMax ); /*nn_nn + \0 = 5+1 */
txt_file_name = strncat(txt_name,".txt",9 ); // 5+4 = length(name) + length(.ext)
//
txt_fp = fopen( txt_file_name,"w");
if( txt_fp == NULL ) {printf (" txt file open error \n"); return 1; }
fprintf(txt_fp,"<g text-anchor=\"middle\" fill=\"black\" stroke =\"none\">\n"); // group open
return 0;
};
void Begin(){
// main circle = period 1
double R1; // radius
// center = x1 + y1*I;
double X1;
double Y1;
// period 1 circle
// center
X1 = Xmax - Xmax/3.5;
Y1 = Ymax/2.0;
R1 = min(X1, Y1)- min(X1, Y1)*0.5; // radius
//
DataP = &Data;
SetData(DataP, 0, main_angle, n1, d1, X1, Y1, R1, X1-R1, Y1, 0.0 );
stroke_color = black; // stroke
fill_color = white; // fill
// set limits : all depends on the stroke_width !!!!
stroke_width = 0.5; // a percentage of the current viewport
minimal_radius = stroke_width/10.0; /* radius of minimal circle to draw */
min_font_size = minimal_radius/2.0;
min_length = minimal_radius;
BeginTextFile();
beginSVG();
}
void EndTxt(void){
fprintf(txt_fp,"</g>\n"); // group close
fclose(txt_fp); // file close
printf("EndTxt done,\n file %s saved \n",txt_file_name );
}
void EndSVG(void){
fprintf(svg_fp,"</g>\n"); // group close
fprintf(svg_fp,"</svg>\n"); // svg close
fclose(svg_fp); // file close
printf("endSVG done\n file %s saved \n",svg_file_name );
}
/*
draw text to the file in the svg format
<text x="0" y="35" font-family="Verdana" font-size="35">
Hello, out there
</text>
https://stackoverflow.com/questions/8865458/how-do-i-vertically-center-text-with-css?rq=1
https://stackoverflow.com/questions/12250403/vertical-alignment-of-text-element-in-svg?rq=1
https://www.w3.org/TR/SVG/text.html#TextElementDYAttribute
*/
void draw_txt(double x, double y, double font_size, int n, int d ){
double dy; // vertical alligment inside a circle
if ( font_size > min_font_size){
dy = font_size/3.0; // vertical alligment inside a circle
fprintf(txt_fp,"<text x=\"%.1f\" y=\"%.1f\" dy=\"%.2f\" font-size=\"%.2f\">%d/%d</text>\n", x, y, dy, font_size, n,d);
// font-family = \"serif\" font-weight=\"normal\" font-style=\"normal\"
}
}
// draw circle to svg file
void draw_circle(double x, double y, double radius ){
if (radius > minimal_radius){
fprintf(svg_fp,"<circle cx=\"%.1f\" cy=\"%.1f\" r=\"%.1f\" />\n", x, y, radius);
// else printf ("radius < minimal_radius\n");
NoOfDrawnCircles += 1; // count the number of drawn circles
}
}
// draw circle to svg file
void draw_labeled_circle(DataType w){
int n;
double font_size;
if (w.n==1 && w.d==1)
n=1 ;
else n= w.d-w.n ; /* reverse y axis
because in svg the initial coordinate system has the origin at the top/left
with the x-axis pointing to the right and the y-axis pointing down
https://www.w3.org/TR/SVGTiny12/coords.html#InitialViewport
*/
draw_circle(w.cx, w.cy, w.radius);
font_size = w.radius/2.0;
if (font_size > min_font_size)
draw_txt (w.cx, w.cy, font_size, n, w.d );
}
/*
<line x1="0" y1="0" x2="200" y2="200" style="stroke:rgb(255,0,0);stroke-width:2" />
*/
// draw line to svg file
void draw_line(double x1, double y1, double T, double length ){
double x2;
double y2;
double angle;
angle = 2.0*M_PI*T;
x2 = x1 + length * cos(angle);
y2 = y1 + length * sin(angle);
fprintf(svg_fp,"<line x1=\"%.1f\" y1=\"%.1f\" x2=\"%.1f\" y2=\"%.1f\"/>\n", x1, y1, x2, y2);
}
void draw_line_from_points(double x1, double y1, double x2, double y2 ){
fprintf(svg_fp,"<line x1=\"%.1f\" y1=\"%.1f\" x2=\"%.1f\" y2=\"%.1f\"/>\n", x1, y1, x2, y2);
}
/*
[[:File:N-th_arm_stars.svg]]
not working properly
--- bugs --------------
"Though there are some bugs (see lower side of 1/1->1/2, for
example)." Claude
*/
void DrawStar(DataType w){
double cx,cy; // center of the star
double length; // of the arms
double angle; // between arms
double T; // global angle in turns
int n;
length = w.length/3.0;
T = 2.0*M_PI*w.T;
cx = w.ax + length * cos(T);
cy = w.ay + length * sin(T);
angle = 1.0 / w.D; // angle in turns between w.D arms
// draw w.D arms = the star
// set up starting angle
T = w.T + 0.5;
if (T > 1.0) T -= 1.0; // modulo 1
for(n=0; n<w.D; n++) {
draw_line(cx, cy, T, length);
T = T + angle;
if (T> 1.0) T -= 1.0; // modulo 1
}
}
/*
. The part of the Mandelbrot set connected to the main cardioid at this bifurcation point c_{p/q} is called the p/q-limb.
*/
// shrub is a part of the limb after Myrberg-Feigenbaum point ( end of period doubling cascade )
void DrawShrub(DataType w){
// to do
//PrintAddress(w);
NoOfAllShrubs += 1;
//(w.n == 1 && w.d == 2 &&
if( w.length > min_length)
{
NoOfDrawnShrubs += 1;
DrawStar(w);
//else PrintData(w);
}
}
/*
https://stackoverflow.com/questions/19738919/gcd-function-for-c
The GCD function uses Euclid's Algorithm.
It computes A mod B, then swaps A and B with an XOR swap.
*/
int gcd(int a, int b)
{
int temp;
while (b != 0)
{
temp = a % b;
a = b;
b = temp;
}
return a;
}
/*
main drawing procedure
surprisingly short, but recurrent so maybe inefficient
it differs from paper algorithm
where first main cardioid is drawn then all n/d limbs ( families )
here all 1/2-"limb" with sublimbs ( approx)
*/
int drawSVG(DataType w)
{
// internal angle = n/d
int n; // numerator
int d; // denominator
//
DataType w_new; //
DataType *w_newP = &w_new; // to change w in a function (UpdateData) one must pass it by reference not value
if (w.CircleLevel > CircleLevelMax || w.radius < minimal_radius) /* when to stop the recursion,
if || w.radius < minimal_radius is removed then error */
{
DrawShrub(w); // chaotic part of the set
return 0;} // end of the recursion
// periodic part of the set
draw_labeled_circle(w); // draw one circle
// and smaller mutually and externally tangent circles
// n/d = local angle in turns
for (d = 2; d <= dMax; ++d )
for (n = 1; n < d; ++n )
if (gcd(n,d)==1 )// irreducible fraction
{
UpdateData(w_newP, w, n, d);
drawSVG(w_new); // recurence
} // if(gcd
return 0;
}
void PrintInfo(DataType w){
PrintData(w);
printf("limits \n");
printf("Maximal Circle level = %d \n", CircleLevelMax);
printf("Maximal denominator = %d \n", dMax);
printf("width of the circle stroke = %f\n", stroke_width);
printf("minimal radius of the circle = %f\n", minimal_radius);
printf("min_font_size = %f\n", min_font_size);
printf("min_length = %f\n", min_length);
printf("\n");
printf("there are %d circles drawn from all %d possible \n", NoOfDrawnCircles, NoOfAllCircles);
printf("there are %d shrubs drawn from all %d possible \n", NoOfDrawnShrubs, NoOfAllShrubs);
}
void End(DataType w){
EndTxt();
EndSVG();
PrintInfo(Data);
}
// ------------------------------------- main ---------------------------------------------------
int main(){
Begin();
drawSVG(Data);
End(Data);
return 0;
}
new c source code
/*
gcc e.c -Wall -lm
./a.out
program creates 2 files
- svg file ( without labels which are in the text files)
- text file with text group ( labela)
one can copy content of the text fil into svg file to have file with labels
It is manual optimisation ( file size is smaller)
Draw a model of Mandelbrot set.
Based on the paper M. Romera et al, Int. J. Bifurcation Chaos 13, 2279 (2003).
Shrubs in the Mandelbrot Set Ordering
www.tic.itefi.csic.es/gerardo/publica/Romera03.pdf
image:
[[:File:Shrub_model_of_Mandelbrot_set_60_10_labelled.png]]
compare with :
[[:File:Cactus_model_of_Mandelbrot_set.svg]]
angle is measured :
* in turns
* counterclockwise
https://en.wikipedia.org/wiki/Turn_(geometry)
angle can be :
* global ( 0 = 1 is on horizontal = x axis )
* local, where 0 is internal angle of parent
CircleLevel :
0 = main circle (main cardioid) = period 1 cycle
1 = circles on the main circles
2 =
stroke_width : A number without units is rendered the same as a percentage
https://css-tricks.com/almanac/properties/s/stroke-width/
Its default value is 1.
If a <percentage> is used, the value represents a percentage of the current viewport.
If a value of 0 is used the outline will never be drawn.
mutually and externally tangent circles
http://mathworld.wolfram.com/TangentCircles.html
Two circles are mutually and externally tangent if distance between their centers is equal to the sum of their radii
svg check
https://validator.w3.org/check
svg test
http://jsfiddle.net/j5ykdtgc/
cd existing_folder
git init
git remote add origin git@gitlab.com:adammajewski/mandelbrot-shrub-model.git
git add d.c
git commit -m "Initial commit"
git push -u origin master
----------------
file 06_02.txt saved (dMax_CircleLevelMax.txt)
file 06_02.svg saved (dMax_CircleLevelMax.svg)
w:
circle parameters :
CircleLevel = 0
global angle = T = 0.500000
local angle = n/d = 1/1
center = (714.285714;500.000000) radius = 250.000000
wake angle = N/D = 1/1
shrub/star parameters :
apex of the last circle = (464.285714;500.000000) = end point , it simulates M-Feigenbaum ponit, here shrub starts (base of the shrub/star))
length of the shrub = 0.000000
limits
Maximal Circle level = 2
Maximal denominator = 6
width of the circle stroke = 0.500000
minimal radius of the circle = 0.050000
min_font_size = 0.025000
min_length of the shrub= 0.050000
there are 2754 circles drawn from all 30294 possible
there are 4235 shrubs drawn from all 27541 possible
------------
limb = 1/2
limb = 1/3
limb = 2/3
limb = 1/4
limb = 3/4
limb = 1/5
limb = 2/5
limb = 3/5
limb = 4/5
limb = 1/6
limb = 5/6
limb = 1/7
limb = 2/7
limb = 3/7
limb = 4/7
limb = 5/7
limb = 6/7
limb = 1/8
limb = 3/8
limb = 5/8
limb = 7/8
limb = 1/9
limb = 2/9
limb = 4/9
limb = 5/9
limb = 7/9
limb = 8/9
limb = 1/10
limb = 3/10
limb = 7/10
limb = 9/10
limb = 1/11
limb = 2/11
limb = 3/11
limb = 4/11
limb = 5/11
limb = 6/11
limb = 7/11
limb = 8/11
limb = 9/11
limb = 10/11
limb = 1/12
limb = 5/12
limb = 7/12
limb = 11/12
limb = 1/13
limb = 2/13
limb = 3/13
limb = 4/13
limb = 5/13
limb = 6/13
limb = 7/13
limb = 8/13
limb = 9/13
limb = 10/13
limb = 11/13
limb = 12/13
limb = 1/14
limb = 3/14
limb = 5/14
limb = 9/14
limb = 11/14
limb = 13/14
limb = 1/15
limb = 2/15
limb = 4/15
limb = 7/15
limb = 8/15
limb = 11/15
limb = 13/15
limb = 14/15
limb = 1/16
limb = 3/16
limb = 5/16
limb = 7/16
limb = 9/16
limb = 11/16
limb = 13/16
limb = 15/16
limb = 1/17
limb = 2/17
limb = 3/17
limb = 4/17
limb = 5/17
limb = 6/17
limb = 7/17
limb = 8/17
limb = 9/17
limb = 10/17
limb = 11/17
limb = 12/17
limb = 13/17
limb = 14/17
limb = 15/17
limb = 16/17
limb = 1/18
limb = 5/18
limb = 7/18
limb = 11/18
limb = 13/18
limb = 17/18
limb = 1/19
limb = 2/19
limb = 3/19
limb = 4/19
limb = 5/19
limb = 6/19
limb = 7/19
limb = 8/19
limb = 9/19
limb = 10/19
limb = 11/19
limb = 12/19
limb = 13/19
limb = 14/19
limb = 15/19
limb = 16/19
limb = 17/19
limb = 18/19
limb = 1/20
limb = 3/20
limb = 7/20
limb = 9/20
limb = 11/20
limb = 13/20
limb = 17/20
limb = 19/20
file 20_04.txt saved (dMax_CircleLevelMax.txt)
file 20_04.svg saved (dMax_CircleLevelMax.svg)
level 0 parameters from w data structure:
component/circle parameters :
CircleLevel = 0
global angle = T = 0.500000
local angle = n/d = 1/1
center = (714.285714;500.000000) radius = 250.000000
wake angle = N/D = 1/1
shrub/star parameters :
apex of the last circle = (464.285714;500.000000) = end point , it simulates M-Feigenbaum ponit, here shrub starts (base of the shrub/star))
length of the shrub = 0.000000
limits
Maximal Circle level = 4
Maximal denominator = 20
width of the circle stroke = 0.500000
minimal radius of the circle = 0.050000
min_font_size = 0.025000
min_length of the shrub= 0.050000
summary
there are 9768 circles drawn from all 262518652 possible
there are 23537 shrubs drawn from all 260451577 possible
real 0m41,573s
user 0m41,561s
sys 0m0,009s
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //strncat
#include <math.h> // sin, M_PI
/* - ------------------------- global variables ----------------------------- */
// limits and main parameters of the program ~ detailes of the image
// what is efficient relation between limits ?
const int dMax = 20; // 60 maximal denominator of internal angle
#define CircleLevelMax 4// 10 //
// svg
// viewBox
double Xmax = 1000.0;
double Ymax = 1000.0;
double stroke_width; // = 0.5;
double minimal_radius; /* radius of minimal circle to draw */
double min_font_size;
double min_length;
// RGB colors = 24 bit
// http://www.december.com/html/spec/color4.html
char *black = "#000000"; /* hexadecimal number as a string for svg color*/
char *white = "#FFFFFF";
char *burgundy = "#9E0508";
char *SeaGreen = "#068481";
char *turquoise= "#40E0D0";
char *red = "#FF0000";
char *navy = "#000080";
char *blue = "#0000FF";
// ----------- svg file -----------------------------
FILE * svg_fp;
#define BUFSIZE 11 // 6+4+1 = name + .svg + eof
char svg_name [BUFSIZE]; /* name of file */
char *svg_file_name; //="shrub.svg";
// text file
FILE * txt_fp;
char txt_name [BUFSIZE]; /* name of file */
char *txt_file_name; //
// ----------- svg parameters -----------------
char *comment = "<!-- sample comment in SVG file \n can be multi-line -->";
char *stroke_color ;
char *fill_color ;
const double main_angle = 0.5; // angle in turns ; if 0.5 then main antenna is horizontal
int n1 = 1;
int d1 = 1;
int NoOfDrawnCircles = 0;
int NoOfAllCircles = 0;
int NoOfDrawnShrubs = 0;
int NoOfAllShrubs = 0;
// type for saving info about circle ( hyperbolic component of Mandelbrot set )
typedef struct {
int CircleLevel;
// global (internal) angle in turns T = N/D
double T;
// local (internal) angle in turns t = n/d
int n; // numerator
int d; // denominator
// ------- circle parameters -------
// center of the circle c = cx + cy*I
double cx;
double cy;
double radius;
// ------ shrub parameters -----------------
// internal angle of the wake / limb / shrub
int N;
int D;
// apex = end point, it simulates M-Feigenbaum ponit, here shrub starts
// tangency point for n/d = 1/2
double ax;
double ay;
//
double length; // of the shrub
} DataType;
DataType Data = {0, 0.5,1,1 }; // declare and initialize the structure Data
DataType *DataP ;//= &Data = pointer to Data
// --------------------------- functions -------------------------------===============
// GiveNewRadius(old,_p,_q):=old*abs(sin(%pi*_p/_q)/(_q*_q))
double GiveNewRadius(double OldRadius, int num, int den ){
//double t = (double)num / den;
double d2 = den*den;
//printf( "t = %f ; d2 = %f ",t, d2);
//double temp =(num*num)/d2;
//printf( "temp = %f ; ",temp);
return 1.3*OldRadius/d2; //
}
//GiveGlobalAngle(old,new):=mod(old-(1/2-new),1);
double GiveNewAngle (double old, double n, double d) {
double t =old-(main_angle-n/d);
if (t > 1.0) t = t - 1.0;
return t;
}
// pass the struct by reference. This means that your function can access the struct outside of the function and modify its values. You do this by passing a pointer to the structure to the function.
// https://stackoverflow.com/questions/10370047/passing-struct-to-function
void SetData(DataType *w, int CircleLevel, double T, int n, int d, double cx, double cy, double radius, double ax, double ay, double length ){
w->CircleLevel = CircleLevel;
w->T = T;
w->n = n;
w->d = d;
w->cx = cx;
w->cy = cy;
w->radius = radius;
w->N = 1;
w->D = 1;
w->ax = ax;
w->ay = ay;
w->length = length; }
void PrintData(DataType w){
printf("\nlevel 0 parameters from w data structure:\n\n");
printf("component/circle parameters : \n");
printf("\tCircleLevel = %d \n", w.CircleLevel);
printf("\tglobal angle = T = %f \n", w.T);
printf("\tlocal angle = n/d = %d/%d \n", w.n, w.d);
printf("\tcenter = (%f;%f) radius = %f \n", w.cx, w.cy, w.radius);
printf("\twake angle = N/D = %d/%d \n", w.N, w.D);
printf("\nshrub/star parameters : \n");
printf("\tapex of the last circle = (%f;%f) = end point , it simulates M-Feigenbaum ponit, here shrub starts (base of the shrub/star))\n", w.ax,w.ay);
printf("\tlength of the shrub = %f\n", w.length);
printf("\n");
}
/*
w_new is changed and then it is used to draw = output
w_old is is an input
it is the longest procedure !!!!
maybe some changes ?
*/
int UpdateData(DataType *w_new, DataType w_old, int n, int d){
double distance ; // distance between centers of tangent circles
double angle;
// global angle
w_new->T = GiveNewAngle(w_old.T, n, d);
angle = 2.0*M_PI*w_new->T;
w_new->radius = GiveNewRadius(w_old.radius, n, d );
distance = w_old.radius + w_new->radius; // distance between centers of tangent circles
// new center
w_new->cx = w_old.cx + distance* cos(angle);
w_new->cy = w_old.cy + distance* sin(angle);
if (w_old.CircleLevel < CircleLevelMax)
{w_new->CircleLevel = w_old.CircleLevel +1; // next circle
}
else w_new->CircleLevel = w_old.CircleLevel; // go to the shrub not next circle
// local angle in turns t = n/d
w_new->n = n;
w_new->d = d;
NoOfAllCircles += 1;
/* ------- shrub parameters -------------- */
switch(w_old.CircleLevel) {
case 0 : // w_new->CircleLevel = 1
w_new->length = 2.0*w_new->radius;
w_new->N = n;
w_new->D = d;
break; /* */
default : /* w_old.CircleLevel>0 && w_new->CircleLevel > 1 */
// length
if (w_new->n ==1 && w_new->d ==2)
w_new->length = w_old.length + 2.0 * w_new->radius; // limb
else w_new->length = 2.0 * w_new->radius; // sublimb
// N/D
// if new angle = 1/2
if (n ==1 && d ==2) {
// save old angle
w_new->N = w_old.N;
w_new->D = w_old.D;
}
else { // use new values
w_new->N = n;
w_new->D = d;
}
} // switch
// when shrub is drawn then no circle is drawn, so use previous circle parameters
// apex of the last circle aproximates MF point
angle = 2.0*M_PI*w_old.T;
w_new->ax = w_old.cx + w_old.radius * cos(angle); //
w_new->ay = w_old.cy + w_old.radius * sin(angle); //
//if ( w_new->D > dMax)
// {printf("w_new->D = %d > dMax for CircleLevel = %d d= %d \n",w_new->D, w_new->CircleLevel, d);
// return 1; }
return 0;
}
double min(double a, double b) {
return a < b ? a : b;
}
void beginSVG(){ //
snprintf(svg_name, 6, "%02d_%02d", dMax, CircleLevelMax ); /*nn_nn + \0 = 5+1 */
svg_file_name = strncat(svg_name,".svg",9 ); // 5+4 = length(name) + length(.ext)
//
svg_fp = fopen( svg_file_name,"w");
if( svg_fp == NULL ) {printf (" svg file open error \n"); return ; }
// SVG
fprintf(svg_fp,
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
"%s \n "
"<svg width=\"40cm\" height=\"40cm\" viewBox=\"0 0 %.0f %.0f\"\n"
" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n",
comment,Xmax,Ymax);
fprintf(svg_fp,"<g stroke=\"%s\" stroke-width=\"%f\" fill=\"%s\">\n", stroke_color, stroke_width, fill_color); // group open
//printf(" beginSVG done \n");
}
int BeginTextFile(){
snprintf(txt_name, 6, "%02d_%02d", dMax, CircleLevelMax ); /*nn_nn + \0 = 5+1 */
txt_file_name = strncat(txt_name,".txt",9 ); // 5+4 = length(name) + length(.ext)
//
txt_fp = fopen( txt_file_name,"w");
if( txt_fp == NULL ) {printf (" txt file open error \n"); return 1; }
fprintf(txt_fp,"<g text-anchor=\"middle\" fill=\"black\" stroke =\"none\">\n"); // group open
return 0;
};
void Begin(){
// main circle = period 1
double R1; // radius
// center = x1 + y1*I;
double X1;
double Y1;
// period 1 circle
// center
X1 = Xmax - Xmax/3.5;
Y1 = Ymax/2.0;
R1 = min(X1, Y1)- min(X1, Y1)*0.5; // radius
//
DataP = &Data;
SetData(DataP, 0, main_angle, n1, d1, X1, Y1, R1, X1-R1, Y1, 0.0 );
stroke_color = black; // stroke
fill_color = white; // fill
// set limits : all depends on the stroke_width !!!!
stroke_width = 0.5; // a percentage of the current viewport
minimal_radius = stroke_width/10.0; /* radius of minimal circle to draw */
min_font_size = minimal_radius/2.0;
min_length = minimal_radius;
BeginTextFile();
beginSVG();
}
void EndTxt(void){
fprintf(txt_fp,"</g>\n"); // group close
fclose(txt_fp); // file close
printf("file %s saved (dMax_CircleLevelMax.txt)\n",txt_file_name );
}
void EndSVG(void){
fprintf(svg_fp,"</g>\n"); // group close
fprintf(svg_fp,"</svg>\n"); // svg close
fclose(svg_fp); // file close
printf("file %s saved (dMax_CircleLevelMax.svg)\n",svg_file_name );
}
/*
draw text to the file in the svg format
<text x="0" y="35" font-family="Verdana" font-size="35">
Hello, out there
</text>
https://stackoverflow.com/questions/8865458/how-do-i-vertically-center-text-with-css?rq=1
https://stackoverflow.com/questions/12250403/vertical-alignment-of-text-element-in-svg?rq=1
https://www.w3.org/TR/SVG/text.html#TextElementDYAttribute
*/
void draw_txt(DataType w ){
double x = w.cx;
double y = w.cy;
double font_size = w.radius/2.0;
double dy; // vertical alligment inside a circle
int n ;
int d = w.d;
if (w.n==1 && w.d==1)
n=1 ;
else n= w.d-w.n ; /* reverse y axis
because in svg the initial coordinate system has the origin at the top/left
with the x-axis pointing to the right and the y-axis pointing down
https://www.w3.org/TR/SVGTiny12/coords.html#InitialViewport
*/
if ( font_size > min_font_size){
dy = font_size/3.0; // vertical alligment inside a circle
fprintf(txt_fp,"<text x=\"%.1f\" y=\"%.1f\" dy=\"%.2f\" font-size=\"%.2f\">%d/%d</text>\n", x, y, dy, font_size, n,d);
// font-family = \"serif\" font-weight=\"normal\" font-style=\"normal\"
}
}
// draw circle to svg file
void draw_circle(DataType w ){
double x = w.cx;
double y = w.cy;
double radius = w.radius;
if (radius > minimal_radius){
// inf about progres
if (w.CircleLevel == 1)
printf("limb = %d/%d \n", w.n, w.d);
fprintf(svg_fp,"<circle cx=\"%.1f\" cy=\"%.1f\" r=\"%.1f\" />\n", x, y, radius);
// else printf ("radius < minimal_radius\n");
NoOfDrawnCircles += 1; // count the number of drawn circles
}
}
// https://www.w3.org/TR/SVG/paths.html#PathElement
/*
smooth curves in svg:
* Bezier curves, cubic ( C) and quadratic (Q)
* arc = sections of circles or ellipses ( A)
* path
*/
/*
https://en.wikipedia.org/wiki/Cardioid
cusp at 0.0,
x(t) = 2a (1 - cos(t))* cos(t)
y(t) = 2a (1 - cos(t))* sin(t)
*/
// compute points of the cardioid
// save points as a svg path :
// <path id="cardioid" d="M 100 100 L 300 100 L 200 300 z" fill="orange" stroke="black" stroke-width="3" />
// fprintf(svg_fp,"<circle cx=\"%.1f\" cy=\"%.1f\" r=\"%.1f\" />\n", x, y, radius);
/*
void draw_cardioid(DataType w){
draw_circle(w); // temporary solition
}
*/
// draw circle to svg file
void draw_labeled_component(DataType w){
draw_circle(w);// component
draw_txt ( w ); // label
}
/*
<line x1="0" y1="0" x2="200" y2="200" style="stroke:rgb(255,0,0);stroke-width:2" />
*/
// draw line to svg file
void draw_line(double x1, double y1, double T, double length ){
double x2;
double y2;
double angle;
angle = 2.0*M_PI*T;
x2 = x1 + length * cos(angle);
y2 = y1 + length * sin(angle);
fprintf(svg_fp,"<line x1=\"%.1f\" y1=\"%.1f\" x2=\"%.1f\" y2=\"%.1f\"/>\n", x1, y1, x2, y2);
}
void draw_line_from_points(double x1, double y1, double x2, double y2 ){
fprintf(svg_fp,"<line x1=\"%.1f\" y1=\"%.1f\" x2=\"%.1f\" y2=\"%.1f\"/>\n", x1, y1, x2, y2);
}
/*
[[:File:N-th_arm_stars.svg]]
not working properly
--- bugs --------------
"Though there are some bugs (see lower side of 1/1->1/2, for
example)." Claude
*/
void DrawStar(DataType w){
double cx,cy; // center of the star
double length; // of the arms
double angle; // between arms
double T; // global angle in turns
int n;
length = w.length/3.0;
T = 2.0*M_PI*w.T;
cx = w.ax + length * cos(T);
cy = w.ay + length * sin(T);
angle = 1.0 / w.D; // angle in turns between w.D arms
// draw w.D arms = the star
// set up starting angle
T = w.T + 0.5;
if (T > 1.0) T -= 1.0; // modulo 1
for(n=0; n<w.D; n++) {
draw_line(cx, cy, T, length);
T = T + angle;
if (T> 1.0) T -= 1.0; // modulo 1
}
}
/*
. The part of the Mandelbrot set connected to the main cardioid at this bifurcation point c_{p/q} is called the p/q-limb.
*/
// shrub is a part of the limb after Myrberg-Feigenbaum point ( end of period doubling cascade )
void DrawShrub(DataType w){
// to do
//PrintAddress(w);
NoOfAllShrubs += 1;
//(w.n == 1 && w.d == 2 &&
if( w.length > min_length)
{
NoOfDrawnShrubs += 1;
DrawStar(w);
//else PrintData(w);
}
}
/*
https://stackoverflow.com/questions/19738919/gcd-function-for-c
The GCD function uses Euclid's Algorithm.
It computes A mod B, then swaps A and B with an XOR swap.
*/
int gcd(int a, int b)
{
int temp;
while (b != 0)
{
temp = a % b;
a = b;
b = temp;
}
return a;
}
/*
main drawing procedure
surprisingly short, but recurrent so maybe inefficient
it differs from paper algorithm
where first main cardioid is drawn then all n/d limbs ( families )
here all 1/2-"limb" with sublimbs ( approx)
*/
int drawSVG(DataType w)
{
// internal angle = n/d
int n; // numerator
int d; // denominator
//
DataType w_new; //
DataType *w_newP = &w_new; // to change w in a function (UpdateData) one must pass it by reference not value
if (w.CircleLevel < CircleLevelMax || w.radius > minimal_radius) /* when to stop the recursion, if it is removed then error */
{
// periodic part of the set
draw_labeled_component(w); // draw one base component
// and smaller mutually and externally tangent circles
// n/d = local angle in turns
for (d = 2; d <= dMax; ++d )
for (n = 1; n < d; ++n )
if (gcd(n,d)==1 )// irreducible fraction
{
UpdateData(w_newP, w, n, d);
drawSVG(w_new); // recurence
} // if(gcd
}
// stop
else {
DrawShrub(w); // chaotic part of the set
return 0;} // end of the recursion
return 0;
}
void PrintInfo(DataType w){
PrintData(w);
printf("limits \n");
printf("\tMaximal Circle level = %d \n", CircleLevelMax);
printf("\tMaximal denominator = %d \n", dMax);
printf("\twidth of the circle stroke = %f\n", stroke_width);
printf("\tminimal radius of the circle = %f\n", minimal_radius);
printf("\tmin_font_size = %f\n", min_font_size);
printf("\tmin_length of the shrub= %f\n", min_length);
printf("summary \n");
printf("\tthere are %d circles drawn from all %d possible \n", NoOfDrawnCircles, NoOfAllCircles);
printf("\tthere are %d shrubs drawn from all %d possible \n", NoOfDrawnShrubs, NoOfAllShrubs);
}
void End(DataType w){
EndTxt();
EndSVG();
PrintInfo(Data);
}
// ------------------------------------- main ---------------------------------------------------
int main(){
Begin();
drawSVG(Data); //
End(Data);
return 0;
}
Haskell source code
-- cabal install diagrams-cairo
-- Haskell program by Claude Heiland-Allen
-- http://mathr.co.uk/blog/
-- to compile :
-- ghc Romero03.hs
-- to run :
-- ./Romera03 -o out.png -w 1000
import Diagrams.Prelude hiding (star) -- circle
import Diagrams.Backend.Cairo.CmdLine (B, defaultMain)
import Data.Ratio ((%))
{-|
:info B
type B = Diagrams.Backend.Cairo.Internal.Cairo
-- Defined in ‘Diagrams.Backend.Cairo.Internal’
:info defaultMain
defaultMain ::
QDiagram Diagrams.Backend.Cairo.Internal.Cairo V2 Double Any
-> IO ()
-- Defined in ‘Diagrams.Backend.Cairo.CmdLine’
:info Diagram
type Diagram b = QDiagram b (V b) (N b) Any
-- Defined in ‘Diagrams.Core.Types’
http://projects.haskell.org/diagrams/haddock/Diagrams-Combinators.html
:info atop
atop ::
(OrderedField n, Metric v, Semigroup m) =>
QDiagram b v n m -> QDiagram b v n m -> QDiagram b v n m
-- Defined in ‘Diagrams.Core.Types’
infixl 6 `atop`
:info circle
circle ::
(TrailLike t, V t ~ V2, N t ~ n, Transformable t) => n -> t
-- Defined in ‘Diagrams.TwoD.Ellipse’
-}
--
star :: [Integer] -> Diagram B
star [] = p2(0,0) ~~ p2(0,1)
star (q:qs) = scale (1 / fromInteger q) $ p2(0,0) ~~ p2(0,1) `atop` mconcat
[ star qs
# rotate (fromRational (p % q - 1/2) @@ turn)
# translateY 1
| p <- [ 1 .. q - 1 ]
]
-- https://en.wikipedia.org/wiki/Currying
shrub :: Integer -> Integer -> [Integer] -> Diagram B
shrub maxPeriod period decorations =
circle 1 `atop`
(if null children
then star (filter (/= 2) decorations) # scale s # translateY (4/3)
else mempty) `atop`
mconcat children
where
s =
2 *
fromInteger (product (take 1 (reverse (dropWhile (== 2) decorations)))) *
fromInteger (product decorations) ^ 2 /
fromInteger (product $ dropWhile (== 2) decorations) ^ 2
children =
[ shrub maxPeriod (q * period) (q : decorations)
# scale r
# translateY (1 + r)
# rotate (fromRational (t - 1/2) @@ turn)
| q <- [ 2 .. (maxPeriod + period - 1) `div` period ]
, p <- [ 1 .. q - 1 ]
, p `gcd` q == 1
, let t = p % q
, let r = 1 / fromInteger q ^ 2
]
-- https://hackage.haskell.org/package/diagrams-cairo-0.7/docs/Diagrams-Backend-Cairo-CmdLine.html
main = defaultMain
( shrub 60 1 []
# rotate (1/4 @@ turn)
# centerXY
# frame 0.1
# bg white
# lw veryThin
# lineCap LineCapRound
)
It creates png file without labells
Algorithm
Algorithm by https://chatgpt.org/chat :
- Define a function named "star" that takes a list of integers and returns a Diagram.
- If the input list is empty, create a line from (0,0) to (0,1) and return it.
- Otherwise, scale down the diagram by the reciprocal of the first integer in the list.
- Create a line from (0,0) to (0,1) and place it at the original position.
- Repeat step 4 for each p in the range [1, q-1] where q is the first integer in the list.
- Rotate each line by angle (p/q - 1/2) * 2π and translate it vertically by 1.
- Combine the lines using "atop".
- Recursively call "star" with the remaining integers in the list and combine the result with the current diagram using "atop".
- Define a function named "shrub" that takes an integer "maxPeriod", an integer "period", a list of integers "decorations", and returns a Diagram.
- Create a circle with radius 1.
- If the input list is empty, create a star diagram by calling the "star" function with the remaining input list and scale it by a computed factor.
- Otherwise, create an empty diagram.
- Create a list of children diagrams by recursively calling "shrub" with different parameters based on the current input and some conditions.
- Scale down each child diagram by a computed factor.
- Translate each child diagram vertically by a factor of 1 plus its scale factor.
- Rotate each child diagram by a computed angle.
- Combine all the child diagrams using "mconcat".
- Combine all the created diagrams using "atop".
- Call the defaultMain function with the final diagram as input.
text output of the c program
beginSVG done
EndTxt done,
file 60_10.txt saved
endSVG done
file 60_10.svg saved
CircleLevel = 0
global angle = T = 0.500000
local angle = n/d = 1/1
center = (714.285714;500.000000) radius = 250.000000
wake angle = N/D = 1/1
apex = (464.285714;500.000000)
length = 0.000000
limits
Maximal Circle level = 10
Maximal denominator = 60
width of the circle stroke = 0.500000
minimal radius of the circle = 0.050000
min_font_size = 0.025000
min_length = 0.050000
there are 12682 circles drawn from all 13962882 possible
there are 24249 shrubs drawn from all 13950201 possible
Postprocessing
- copy text file ( text group = labels) into svg file manually = add labels
- convert svg ( 16.4 MB) to png image ( 146 kB)
convert 60_10_l.svg 60_10_l.png
Items portrayed in this file
depicts
some value
14 August 2017
146,049 byte
1,417 pixel
1,417 pixel
image/png
fe5eea41acf88f349e943067cf5d08a6fbd1521e
File history
Click on a date/time to view the file as it appeared at that time.
Date/Time | Thumbnail | Dimensions | User | Comment | |
---|---|---|---|---|---|
current | 20:03, 14 August 2017 | 1,417 × 1,417 (143 KB) | Soul windsurfer | User created page with UploadWizard |
File usage
No pages on the English Wikipedia use this file (pages on other projects are not listed).
Global file usage
The following other wikis use this file:
- Usage on en.wikibooks.org
- Usage on pl.wikibooks.org
Metadata
This file contains additional information, probably added from the digital camera or scanner used to create or digitize it.
If the file has been modified from its original state, some details may not fully reflect the modified file.
File change date and time | 19:58, 14 August 2017 |
---|