import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle, Polygon, Circle, Arc
B="#1f4e8c";GP="#16365f";V="#f2f2f2";G="#555555";A="#c47a12";T="#222222";DF="#7fc4ea"
fig=plt.figure(figsize=(17,11),dpi=110)
fig.patch.set_facecolor("white")
ax=fig.add_axes([0.01,0.27,0.60,0.62]);ax2=fig.add_axes([0.62,0.27,0.37,0.62])
for a in (ax,ax2):
    a.set_aspect("equal");a.axis("off")
ax.set_xlim(-12.5,12.5);ax.set_ylim(-1.8,13.6)
ax2.set_xlim(-6.2,6.2);ax2.set_ylim(-1.8,13.6)
fig.text(0.5,0.955,"Panneau hybride Muhleisen, version industrielle : schéma de principe",ha="center",fontsize=19,color=T,weight="bold")
fig.text(0.31,0.905,"Vue de face, volets dépliés (rotor verrouillé)",ha="center",fontsize=13,color=G)
fig.text(0.805,0.905,"Vue de profil (dans l'axe), mode vent",ha="center",fontsize=13,color=G)
def prism(a,cx,cy,s=1.0,arrow=False):
    th=np.linspace(np.radians(250),np.radians(130),14)
    nose=[(-2.45+0.22*np.cos(t_),-1.28+0.22*np.sin(t_)) for t_ in th]
    ang=np.linspace(np.radians(183.3),np.radians(244.3),14);rr=np.linspace(1.753,1.84,14)
    arc=[(r_*np.cos(t_),r_*np.sin(t_)) for r_,t_ in zip(rr,ang)]
    pts=np.array([(-0.8,-1.66),(-2.3,-1.48)]+nose+arc)*s+np.array([cx,cy])
    a.add_patch(Polygon(pts,closed=True,facecolor="#4a4a4a",edgecolor="#2a2a2a",lw=1.2,zorder=4))
    ar=np.array(arc)*s+np.array([cx,cy])
    a.plot(ar[:,0],ar[:,1],color="#888888",lw=4.5,solid_capstyle="butt",zorder=5)
    a.plot(ar[:,0],ar[:,1],color="white",lw=3,solid_capstyle="butt",zorder=6)
    if arrow:
        p0=np.array([-2.95,-1.15])*s+np.array([cx,cy]);p1=np.array([-1.95,0.25])*s+np.array([cx,cy])
        a.annotate("",xy=p1,xytext=p0,arrowprops=dict(arrowstyle="-|>",color="#4a90c2",lw=2,connectionstyle="arc3,rad=-0.15"),zorder=8)
def num(a,x,y,k,r=0.42):
    a.add_patch(Circle((x,y),r,facecolor="white",edgecolor=T,lw=1.3,zorder=20))
    a.text(x,y,str(k),ha="center",va="center",fontsize=10,weight="bold",color=T,zorder=21)
def lead(a,x0,y0,x1,y1):
    a.plot([x0,x1],[y0,y1],color="#666666",lw=0.9,zorder=19)
hy=9.0;R=3.0;rs=1.86
ax.add_patch(Rectangle((-12,-0.6),24,0.6,color="#d9d9d9"))
ax.add_patch(Rectangle((-1.2,-1.2),2.4,1.2,facecolor="#bdbdbd",edgecolor=G))
ax.add_patch(Polygon([[-0.45,0],[0.45,0],[0.3,5.0],[-0.3,5.0]],facecolor="#9a9a9a",edgecolor=G,zorder=2))
ax.add_patch(Rectangle((-0.7,5.0),1.4,0.45,facecolor="#7a7a7a",edgecolor=T,zorder=3))
ax.add_patch(Rectangle((-9.6,5.45),19.2,0.35,facecolor="#8c8c8c",edgecolor=T,zorder=3))
for xa in (-9.3,-3.1,3.1,9.3):
    ax.plot([xa,xa],[5.8,hy],color=G,lw=4,zorder=6)
    ax.add_patch(Circle((xa,hy),0.18,facecolor="#dddddd",edgecolor=T,zorder=8))
segs=[(-9.15,-3.25),(-2.95,2.95),(3.25,9.15)]
for x0,x1 in segs:
    ax.add_patch(Rectangle((x0,hy-rs),x1-x0,2*rs,facecolor=B,edgecolor="#555555",lw=2,zorder=4))
    for i in range(1,12):
        ax.plot([x0+(x1-x0)*i/12]*2,[hy-rs,hy+rs],color="#3d6fb0",lw=0.5,zorder=5)
    for j in range(1,8):
        ax.plot([x0,x1],[hy-rs+2*rs*j/8]*2,color="#3d6fb0",lw=0.5,zorder=5)
    for ya,yb in ((hy+rs,hy+R),(hy-R,hy-rs)):
        ax.add_patch(Rectangle((x0,ya),x1-x0,yb-ya,facecolor="#cfe8f3",alpha=0.75,edgecolor=G,lw=1.2,zorder=4))
    for yh in (hy+rs,hy-rs):
        ax.plot([x0,x1],[yh,yh],color=A,lw=2,ls=(0,(6,3)),zorder=6)
ax.plot([-10.2,10.2],[hy,hy],color=T,lw=3,zorder=7)
ax.add_patch(Rectangle((9.6,hy-0.5),1.3,1.0,facecolor="#6a6a6a",edgecolor=T,zorder=8))
ax.add_patch(Rectangle((-10.9,hy-0.5),1.3,1.0,facecolor="#6a6a6a",edgecolor=T,zorder=8))
ax.plot([0.0,0.0],[hy+R,hy+R+1.2],color=T,lw=1.5)
ax.add_patch(Polygon([[-0.5,hy+R+1.2],[0,hy+R+1.35],[1.0,hy+R+1.3],[1.0,hy+R+1.1],[0,hy+R+1.05]],facecolor="#cccccc",edgecolor=T))
ax.annotate("",xy=(9.15,-1.5),xytext=(-9.15,-1.5),arrowprops=dict(arrowstyle="<->",color=G))
ax.text(0,-1.75,"18 m de rotor en 3 segments de 6 m, diamètre 6 m, axe à ~9 m",ha="center",va="top",fontsize=10,color=G)
lead(ax,-6.2,8.6,-11.6,11.2);num(ax,-11.6,11.2,1)
lead(ax,-1.0,11.4,-1.0,12.9);num(ax,-1.0,12.9,2)
lead(ax,1.5,hy+rs,2.6,12.9);num(ax,2.6,12.9,3)
lead(ax,-3.1,7.2,-11.6,8.2);num(ax,-11.6,8.2,4)
lead(ax,10.9,hy,11.8,10.4);num(ax,11.8,10.4,5)
lead(ax,6.0,5.62,11.8,6.6);num(ax,11.8,6.6,6)
lead(ax,0.7,5.2,-11.6,5.0);num(ax,-11.6,5.0,7)
lead(ax,0.3,2.5,11.8,2.6);num(ax,11.8,2.6,8)
lead(ax,1.0,hy+R+1.2,4.5,13.2);num(ax,4.5,13.2,9)
lead(ax,-1.0,-0.6,-11.6,0.8);num(ax,-11.6,0.8,11)
for x_ in np.arange(-9.4,9.0,0.95):
    if abs(x_+0.4)<1.7:continue
    ax.add_patch(Polygon([[x_,0.12],[x_+0.85,0.12],[x_+0.85,0.42],[x_,0.28]],facecolor=GP,edgecolor="#0b2a52",lw=0.6,zorder=2))
lead(ax,8.0,0.3,11.8,0.9);num(ax,11.8,0.9,12)
c=np.array([0,hy])
ax2.add_patch(Rectangle((-6,-0.6),12,0.6,color="#d9d9d9"))
ax2.add_patch(Rectangle((-1.2,-1.2),2.4,1.2,facecolor="#bdbdbd",edgecolor=G))
for x_ in np.arange(-5.9,5.6,0.95):
    if abs(x_+0.4)<1.7:continue
    ax2.add_patch(Polygon([[x_,0.12],[x_+0.85,0.12],[x_+0.85,0.42],[x_,0.28]],facecolor=GP,edgecolor="#0b2a52",lw=0.6,zorder=2))
ax2.add_patch(Polygon([[-0.45,0],[0.45,0],[0.3,5.0],[-0.3,5.0]],facecolor="#9a9a9a",edgecolor=G,zorder=2))
ax2.add_patch(Rectangle((-0.7,5.0),1.4,0.45,facecolor="#7a7a7a",edgecolor=T,zorder=3))
ax2.add_patch(Rectangle((-0.6,5.45),1.2,0.35,facecolor="#8c8c8c",edgecolor=T,zorder=3))
ax2.plot([0,0],[5.8,hy],color="#9a9a9a",lw=4,zorder=1)
ax2.add_patch(Circle(c,R,fill=False,ls=(0,(4,4)),color="#999999",lw=0.8))
th=np.radians(35);u=np.array([np.cos(th),np.sin(th)]);n=np.array([-np.sin(th),np.cos(th)])
ax2.plot(*zip(c-rs*u,c+rs*u),color=B,lw=7,solid_capstyle="butt",zorder=5)
def cseg(p0,d,Ln,bend):
    pe=np.array([-d[1],d[0]]);t=np.linspace(0,1,30)
    pts=np.array([(1-tt)**2*p0+2*(1-tt)*tt*(p0+d*Ln/2+pe*bend)+tt**2*(p0+d*Ln) for tt in t])
    ax2.plot(pts[:,0],pts[:,1],color="#7fb6cc",lw=5,solid_capstyle="butt",zorder=5)
cseg(c+rs*u,u,R-rs,0.14)
cseg(c-rs*u,-n,R-rs,0.14)
ax2.add_patch(Circle(c,0.2,facecolor="#7a7a7a",edgecolor=T,zorder=7))
prism(ax2,0,hy,1.875,True)
lead(ax2,-3.0,6.6,-4.9,4.2);num(ax2,-4.9,4.2,10)
ax2.add_patch(Arc(c,6.9,6.9,theta1=40,theta2=100,color=A,lw=2))
e0=c+3.45*np.array([np.cos(np.radians(46)),np.sin(np.radians(46))]);e1=c+3.45*np.array([np.cos(np.radians(36)),np.sin(np.radians(36))])
ax2.annotate("",xy=e1,xytext=e0,arrowprops=dict(arrowstyle="-|>",color=A,lw=2))
for yy in (9.5,10.5,11.5):
    ax2.annotate("",xy=(-3.3,yy),xytext=(-6.0,yy),arrowprops=dict(arrowstyle="-|>",color="#4a90c2",lw=2.2))
ax2.text(-6.0,12.1,"Vent",fontsize=12,color="#4a90c2",weight="bold")
pt=c+(rs+0.8)*u
ax2.plot([pt[0],3.0],[pt[1],12.8],color="#666666",lw=0.9)
ax2.text(3.0,13.05,"Volet cambré ouvert :\npoussé par le vent",fontsize=10,color=T,va="center")
lead(ax2,0.4,7.0,3.4,6.6);num(ax2,3.4,6.6,4)
lead(ax2,0.4,5.2,3.4,4.6);num(ax2,3.4,4.6,7)
ax2.text(0,-1.75,"Rotor Ø 6 m : 1,86 m de panneau + 1,14 m de volet de chaque côté",ha="center",va="top",fontsize=10,color=G)
items=["1  Panneaux verre-verre bifaces (~67 m², ~14 kWc)","2  Volets cambrés en polycarbonate transparent, repliés en mode solaire","3  Charnières à ressort, vérins, butées amorties","4  Bras porteurs entre les segments, roulements","5  Génératrices industrielles + réducteurs (~10 kW éolien)","6  Poutre-berceau en treillis","7  Couronne d'orientation au sommet du mât","8  Mât de ~5 m (surélévation optimale)","9  Girouette électronique","10  Déflecteur en prisme, nez arrondi, face arrière blanche","11  Fondation, armoire de commande et raccordement","12  Champ au sol fixe sous la machine, ~230 m², ~48 kWc"]
for k,t in enumerate(items):
    col=k//4;row=k%4
    fig.text(0.03+col*0.33,0.22-row*0.033,t,fontsize=11,color=T)
fig.text(0.5,0.025,"Proportions approximatives. Vent 5,5 m/s à 10 m : rotor seul ~35 644 kWh/an à ~0,073 €/kWh, avec le champ au sol ~83 251 kWh/an à ~0,061 €/kWh ; côte très ventée : ~91 720 kWh/an, ~0,055 €/kWh. www.mulo.world",ha="center",fontsize=10.5,color=G)
plt.savefig("schema_panneau_solaire_hybride_muhleisen_industriel.png",dpi=110,facecolor="white")
