CUT OUT HEXAGONS

Canvas, 113 112 bytes

«/*α_×-/═↔⁸3+ *-╶R⇵{;X:«w╷/###/*Kky┤_×+-y#×/×-y_×-/═ŗ∙ #⟳#¶#╋# ⟳_╋↔x“kyv╴e┌/i┴⁰U<alissfr↖;,imFE!↷qB╪²-‟#ŗ}#∙ ╋↔║

Try it here!

A part of the answer is literally evaluating the JavaScript p.p.overlap(p.p,0,p.p,(a,b)=>b==0?a:b)..


Charcoal, 80 bytes

F⮌…·¹N«→↘F²«M⁺³×⁴ι↑P×_⊗ι↙F⊗ι«FκP× ⁴↙¹»→Fι«FκP× ⁴↘¹»F⊖ι«FκP× ⁻׳ιλ↘¹»\P×_⊗ι»»‖BO²

Try it online! Link is to verbose version of code. Explanation:

F⮌…·¹N«

Loop from the largest to the smallest hexagon.

→↘F²«M⁺³×⁴ι↑

Draw each hexagon twice in the desired location.

P×_⊗ι

Draw half of the top line of the hexagon.

↙F⊗ι«FκP× ⁴↙¹»

Draw the top left diagonal, but for each row erase 4 spaces first if this is the second hexagon.

→Fι«FκP× ⁴↘¹»

Draw half of the bottom left diagonal, still erasing 4 spaces first if this is the second hexagon.

F⊖ι«FκP× ⁻׳ιλ↘¹»

Draw almost all of the rest of the bottom left diagonal, erasing until the middle of the hexagon if this is the second hexagon.

\P×_⊗ι

Finish the bottom left diagonal and draw half of the bottom line of the hexagon.

»»‖BO²

Mirror everything at the end.

Alternative approach, also 80 bytes:

F⮌…·¹N«→↘F²«M⁺³×⁴ι↑FκG→⊗ι↓³←⊖⊗ι↙⊖⊗ι↘⊖⊗ι→⊖⊗ι↓³←⊗ι↖⊕⊗ι↗⊕⊗ι P×_⊗ι↙↙⊗ι→↘⊗ι↑P×_⊗ι»»‖M

Try it online! Link is to verbose version of code. Explanation:

F⮌…·¹N«

Loop from the largest to the smallest hexagon.

→↘F²«M⁺³×⁴ι↑

Draw each hexagon twice in the desired location.

FκG→⊗ι↓³←⊖⊗ι↙⊖⊗ι↘⊖⊗ι→⊖⊗ι↓³←⊗ι↖⊕⊗ι↗⊕⊗ι 

Before drawing the second hexagon, erase the area between it and the next smaller hexagon.

P×_⊗ι↙↙⊗ι→↘⊗ι↑P×_⊗ι»»‖M

Draw the left half of each hexagon, and then mirror everything at the end.


C (clang), 374 bytes

#define F(X,R)*d=*(d=o+x*(l*3+35-g)+x/2+X+R)-32?*d:R?
i,z,x,l,w,r,g,m;f(n){int*d,o[i=z=(x=n*8+1)*(n*5+4)],*c=o;for(;l=i--;)*c++=i%x?32:10;for(;l++<n;)for(g=35;i=g-29;g-=3){for(r=m+=m=w=l*2;r--;F(~-w*x-w,r)g:g)F(w*~x,r)95:95,F(w*x-w,r)95:95;for(;w--;)for(r=4;r--;F(m-~w*~-x,-r)g:47)F(w-m-w*x,r)g:47,F(w-m-~w*x,r)g:92,F(m+~w-w*x,-r)g:92;}for(;i<z;++i)printf(o[i]-35?o+i:" ");}

Try it online!

-33 more saved by @ceilingcat improvement

C (clang), 433 412 407 bytes

#define F(Y,X,W,R)*d=*(d=c-Y+X+W+R)-32?*d:R?
i,z,x,l,w,r,d,G,g,m;f(n){int*c,*d,o[i=z=(x=n*8+1)*(n*5+4)];for(c=o;l=i--;)*c++=i%x?32:10;for(;l++<n;)for(G=0;i=G<4;G+=3){g=35-G;c=o+x*l*3+G*x+x/2;for(r=m+=m=w=l*2;r--;F(x-w*x,-w,0,r)g:g)F(w*x,-w,0,r)95:95,F(-w*x,-w,0,r)95:95;for(;w--;)for(r=4;r--;F(~w*x,m,~w,-r)g:47)F(w*x,-m,w,r)g:47,F(~w*x,-m,w,r)g:92,F(w*x,m,~w,-r)g:92;}for(;i<z;)i+=printf(o[i]-35?o+i:" ");}

Try it online!

-21 thanks to @ceilingcat -5 @ceilingcat + y removed

   ###\  
    ###\   <= we  draw only on spaces ' '  
\###     
 \###        first time we draw '#' for collisions

 /####\  
/######\ 
\######/  
 \####/ 

  ____
 /####\        then we move our drawing pointer
/######\     3 lines below
\######/
 \____/         and we draw spaces 
/      \       instead of # 
\      /
 \____/


      ____
    _/####\
   //######\     and we repeat for bigger donuts
  /#\######/   moving our drawing pointer 
 /###\____/      
/###/      \ 
\###\      /
 \###\____/
  \####??####/
   \________/