K="#141414"; FF="Avenir Next, Avenir, Helvetica Neue, Helvetica" C={"y":("#ffe680","#ffd84d","#e8b81f"),"g":("#a8e3c1","#7fd4a3","#3da96f"), "r":("#fbbfae","#f79b83","#e0563a"),"n":("#f2f0ea","#e8e6df","#b3b0a6"), "b":("#bcd9ef","#8fc4e6","#4a90c2")} DX,DY=58,42 def slab(x,y,w,t,c,dx=DX,dy=DY,sw=4): top,fr,sd=C[c] return (f'' f'' f'') def prism(x,y,w,h,c,d1=12,d2=10,sw=3.5): top,fr,sd=C[c] return (f'' f'' f'') def card(x,y,w,h,c,sw=4): top,fr,sd=C[c]; d1,d2=26,20 return (f'' f'' f'') def txt(x,y,s,sz=19,w=600,f=K,a="start"): return f'{s}' def arrow(x1,y1,x2,y2,c=K,sw=6): import math ang=math.atan2(y2-y1,x2-x1); L=17; sp=0.42 ax=x2-L*math.cos(ang-sp); ay=y2-L*math.sin(ang-sp) bx=x2-L*math.cos(ang+sp); by=y2-L*math.sin(ang+sp) return (f'' f'') def callout(x,y,lines,ax,ay,side="bottom",c=K,fill="#ffffff",sz=17,pad=16): """Globo con línea de llamada y punto de ancla. (x,y)=esquina sup-izq de la caja.""" wmax=max(len(l) for l in lines)*sz*0.52 w=wmax+pad*2; h=len(lines)*(sz+8)+pad*1.4 o=[f''] for i,l in enumerate(lines): o.append(txt(x+w/2,y+pad+sz*0.85+i*(sz+8),l,sz,600 if i==0 else 500,c,"middle")) if side=="bottom": sx,sy=x+w/2,y+h elif side=="top": sx,sy=x+w/2,y elif side=="left": sx,sy=x,y+h/2 else: sx,sy=x+w,y+h/2 o.append(f'') o.append(f'') return "".join(o) def step(x,y,n,label,c="n",w=150,h=96): """Caja de etapa de proceso, numerada.""" o=[card(x,y,w,h,c)] o.append(f'') o.append(txt(x+w+26,y-13,str(n),18,600,"#ffffff","middle")) o.append(txt(x+w/2,y+h+34,label,18,600,K,"middle")) return "".join(o) def chains(x,y,w,mode,col=K,dx=DX,dy=DY,sw=3): o=[] if mode in("long","mesh"): for k in (0.22,0.42,0.62,0.82): o.append(f'') if mode in("cross","mesh"): n=int(w/44) for j in range(1,n+1): px=x+j*w/(n+1) o.append(f'') if mode=="tangle": for k in (0.32,0.5,0.68): bx=x+k*dx; by=y-k*dy; seg=[] for i in range(9): px=bx+i*w/8; py=by+(8 if i%2 else -8) seg.append(f'{"M" if i==0 else "L"}{px:.0f} {py:.0f}') o.append(f'') if mode=="wavy": for k in (0.32,0.5,0.68): bx=x+k*dx; by=y-k*dy; seg=[] for i in range(9): px=bx+i*w/8; py=by+(3 if i%2 else -3) seg.append(f'{"M" if i==0 else "L"}{px:.0f} {py:.0f}') o.append(f'') return "".join(o) def cota(x1,y1,x2,y2,label,c="#4a90c2",off=0,sz=16): """Línea de cota con topes y etiqueta.""" import math o=[f''] if abs(y2-y1)') o.append(f'') o.append(txt((x1+x2)/2,y1-14+off,label,sz,600,c,"middle")) else: o.append(f'') o.append(f'') o.append(txt(x1-16+off,(y1+y2)/2+5,label,sz,600,c,"end")) return "".join(o) def bubble(cx,base,top,rw,nw,c="y",sw=4): """Burbuja simple: cuello nw abajo, ancho rw arriba.""" tp,fr,sd=C[c] ry=int(rw*0.25) p=(f'') p+=(f'') p+=(f'') p+=(f'') p+=f'' return p def bagfig(x,y,w,h,c="g",sw=4): """Bolsa isométrica simple.""" tp,fr,sd=C[c]; d=22 return (f'' f'' f'') def tablefig(x,y,cols,rows,cw,rh=42,head="#e8e6df",sz=16): """Tabla dibujada con trazo grueso.""" o=[]; W=sum(cw) o.append(f'') cx=x for i,c in enumerate(cols): o.append(txt(cx+cw[i]/2,y+rh*0.64,c,sz,600,K,"middle")); cx+=cw[i] if i') for r,row in enumerate(rows): ry=y+rh*(r+1) o.append(f'') cx=x for i,cell in enumerate(row): col=K if i==0 else "#5f5e5a" o.append(txt(cx+cw[i]/2,ry+rh*0.64,cell,sz-1,600 if i==0 else 500,col,"middle")); cx+=cw[i] o.append(f'') return "".join(o) def molec(x,y,w,tipo,col=K,sw=4.5,amp=16,n=10): """Cadena de polietileno en zigzag con ramificación según tipo.""" pts=[]; stepx=w/n for i in range(n+1): pts.append((x+i*stepx, y-amp if i%2 else y+amp)) d="".join(f'{"M" if i==0 else "L"}{px:.0f} {py:.0f} ' for i,(px,py) in enumerate(pts)) o=[f''] def rama(i,l,sub=False,up=True): if i>len(pts)-1: return px,py=pts[i]; dy=-l if up else l o.append(f'') if sub: o.append(f'') o.append(f'') if tipo=="ldpe": rama(1,42,True,True); rama(4,38,True,False); rama(7,44,True,True); rama(min(9,n-1),30,False,False) elif tipo=="lldpe": for i in (1,3,5,7,9): if i<=n: rama(i,20,False,i%4==1) elif tipo=="mdpe": rama(2,18,False,True); rama(6,18,False,False) return "".join(o) def scalebar(x,y,w,marks,lo,hi,h=26,c="#e8e6df"): """Barra de escala horizontal con marcadores.""" o=[f''] for val,lab,col,side in marks: px=x+(val-lo)/(hi-lo)*w o.append(f'') o.append(f'') if side=="up": o.append(txt(px,y-26,lab,18,600,col,"middle")) else: o.append(txt(px,y+h+42,lab,18,600,col,"middle")) o.append(txt(x,y+h+70,str(lo),16,500,"#a8a8a8","start")) o.append(txt(x+w,y+h+70,str(hi),16,500,"#a8a8a8","end")) return "".join(o) def stackchains(x,y,w,n,gap,tipo,col=K,sw=4,amp=10,seg=9,jitter=0): """Varias cadenas apiladas para mostrar empaquetamiento.""" import random random.seed(11) o=[] for i in range(n): yy=y+i*gap+(random.randint(-jitter,jitter) if jitter else 0) xx=x+(random.randint(-jitter*2,jitter*2) if jitter else 0) o.append(molec(xx,yy,w,tipo,col,sw,amp,seg)) return "".join(o) def upicon(x,y,c="#1d6b3e",s=1.0): return (f'') def downicon(x,y,c="#e0563a",s=1.0): return (f'')