Fun with asymptote

Multiplication table

Discussing about a possible virtual material for a Montessori school, I got the idea that I could use it to learn some Asymptote. Thus, I present below an asymptote code that produces a partial multiplication table, step by step, forming a nice pyramid, using the Montessori color scheme for the floors.

//texpreamble("\usepackage{mathptmx}");
//texpreamble("\usepackage{helvet}");
//texpreamble("\usepackage{avant}");
import three;
currentprojection=orthographic(5,4,3,center=true);
currentlight=light(background=white,specularfactor=0,specular=white,(0,10,20));
size(30cm);
defaultpen(AvantGarde());
//size3(6cm,5cm,8cm);
pen c[] ={black, red, green, pink, yellow, lightblue, purple, white, brown, mediumblue, orange};
defaultpen(AvantGarde());
int N=10;
real f=1/N;
for(int i=N; i>0; --i){
  for(int j=0;j<i;++j){
    draw(scale3(f)*shift(j,i-1,N-i)*unitcube, c[i]);
    draw(scale3(f)*shift(i-1,j,N-i)*unitcube, c[i]);
  }
}
for(int i=N; i>0; --i){
  for(int j=0;j<i;++j){
    draw(scale3(f)*shift(i-1,j,N-i)*unitbox, white+linewidth(2));
    draw(scale3(f)*shift(j,i-1,N-i)*unitbox, white+linewidth(2));
  }
}
for(int i=N; i>0; --i){
  for(int j=0;j<i;++j){
    draw(scale3(f)*shift(.5,.5,1.05)*shift(i-1,j,N-i)
	 *scale3(.05)*rotate(90,Z)
	 *surface(texpath((string)(i*(j+1)))),
	 white, nolight);
    draw(scale3(f)*shift(.5,.5,1.05)*shift(j,i-1,N-i)
	 *scale3(.05)*rotate(90,Z)
	 *surface(texpath((string)(i*(j+1)))),
	 white, nolight);
    draw(scale3(f)*shift(1.05,.5,0.5)*shift(i-1,j,N-i)
	 *scale3(.05)*rotate(90,Y)*rotate(90,Z)
	 *surface(texpath((string)(i*(j+1)))),
	 white, nolight);
    draw(scale3(f)*shift(.5,1.05,0.5)*shift(j,i-1,N-i)
	 *scale3(.05)*rotate(90,Z)*rotate(90,Y)*rotate(90,3Z)
	 *surface(texpath((string)(i*(j+1)))),
	 white,nolight);
  }
}

img

The following code separates vertically the planes so you can peek beneath them. The problem is that drawing so many cubes (10*11*21/6=385) is too much work for Asymptote (the heap is depleted). I could have drawn each plane as a square prism, but I just added a second row to each plane.

//texpreamble("\usepackage{mathptmx}");
//texpreamble("\usepackage{helvet}");
//texpreamble("\usepackage{avant}");
import three;
currentprojection=orthographic(5,4,3,center=true);
currentlight=light(background=white,specularfactor=0,specular=white,(0,10,20));
size(30cm);
defaultpen(AvantGarde());
//size3(6cm,5cm,8cm);
pen c[] ={black, red, green, pink, yellow, lightblue, purple, white, brown, mediumblue, orange};
defaultpen(AvantGarde());
int N=10;
real f=1/N;
for(int i=N; i>0; --i){
  for(int j=0;j<i;++j){
    draw(scale3(f)*shift(j,i-1,(N-i)*1.45)*unitcube, c[i]);
    draw(scale3(f)*shift(i-1,j,(N-i)*1.45)*unitcube, c[i]);
    if(i>1){
      draw(scale3(f)*shift(j,i-2,(N-i)*1.45)*unitcube, c[i]);
      draw(scale3(f)*shift(i-2,j,(N-i)*1.45)*unitcube, c[i]);
    }
  }
}
for(int i=N; i>0; --i){
  for(int j=0;j<i;++j){
    draw(scale3(f)*shift(i-1,j,(N-i)*1.45)*unitbox, white+linewidth(2));
    draw(scale3(f)*shift(j,i-1,(N-i)*1.45)*unitbox, white+linewidth(2));
    if(i>1){
      draw(scale3(f)*shift(i-2,j,(N-i)*1.45)*unitbox, white+linewidth(2));
      draw(scale3(f)*shift(j,i-2,(N-i)*1.45)*unitbox, white+linewidth(2));
    }
  }
}
for(int i=N; i>0; --i){
  for(int j=0;j<i;++j){
    draw(scale3(f)*shift(.5,.5,1.05)*shift(i-1,j,(N-i)*1.45)
	 *scale3(.05)*rotate(90,Z)
	 *surface(texpath((string)(i*(j+1)))),
	 white, nolight);
    draw(scale3(f)*shift(.5,.5,1.05)*shift(j,i-1,(N-i)*1.45)
	 *scale3(.05)*rotate(90,Z)
	 *surface(texpath((string)(i*(j+1)))),
	 white, nolight);
    draw(scale3(f)*shift(1.05,.5,0.5)*shift(i-1,j,(N-i)*1.45)
	 *scale3(.05)*rotate(90,Y)*rotate(90,Z)
	 *surface(texpath((string)(i*(j+1)))),
	 white, nolight);
    draw(scale3(f)*shift(.5,1.05,0.5)*shift(j,i-1,(N-i)*1.45)
	 *scale3(.05)*rotate(90,Z)*rotate(90,Y)*rotate(90,3Z)
	 *surface(texpath((string)(i*(j+1)))),
	 white,nolight);
    if(i>1){
      draw(scale3(f)*shift(.5,.5,1.05)*shift(i-2,j,(N-i)*1.45)
	   *scale3(.05)*rotate(90,Z)
	   *surface(texpath((string)((i-1)*(j+1)))),
	   white, nolight);
      draw(scale3(f)*shift(.5,.5,1.05)*shift(j,i-2,(N-i)*1.45)
	   *scale3(.05)*rotate(90,Z)
	   *surface(texpath((string)((i-1)*(j+1)))),
	   white, nolight);
    }
  }
}

img

Written on January 23, 2021