import numpy as np
import os
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# Tabela de Cotas Oficial (em mm)
# baliza, x, z_quilha, z_borda, mb_25, mb_50, mb_75, mb_borda
data = [
    (1,     0.0,  845.7, 2008.6, 1465.2, 1640.0, 1686.5, 1691.4),
    (2,  2467.0,  191.6, 1779.2, 1879.5, 2095.2, 2151.0, 2156.6),
    (3,  4933.0,   14.3, 1632.0, 2064.8, 2285.4, 2339.6, 2344.5),
    (4,  7400.0,    0.0, 1585.7, 2171.3, 2394.6, 2447.9, 2452.6),
    (5,  9867.0,   90.9, 1696.8, 1917.4, 2161.0, 2228.8, 2236.4),
    (6, 12333.0,  267.7, 2014.7, 1105.9, 1322.5, 1403.6, 1418.9),
    (7, 14800.0, 2537.1, 2537.1,    0.0,    0.0,    0.0,    0.0)
]

# Converter para metros (sistema internacional naval)
stations = []
for row in data:
    b, x, zk, zd, y25, y50, y75, yd = row
    stations.append({
        'b': int(b),
        'x': x / 1000.0,
        'zk': zk / 1000.0,
        'zd': zd / 1000.0,
        'y25': y25 / 1000.0,
        'y50': y50 / 1000.0,
        'y75': y75 / 1000.0,
        'yd': yd / 1000.0
    })

x_orig = np.array([s['x'] for s in stations])
zk_orig = np.array([s['zk'] for s in stations])
zd_orig = np.array([s['zd'] for s in stations])
y25_orig = np.array([s['y25'] for s in stations])
y50_orig = np.array([s['y50'] for s in stations])
y75_orig = np.array([s['y75'] for s in stations])
yd_orig = np.array([s['yd'] for s in stations])

# Interpolação polinomial/suave por trechos via numpy
def interp_long(x_target, x_pts, y_pts):
    return np.interp(x_target, x_pts, y_pts)

num_x = 45   # 45 estações de popa a proa
num_z = 25   # 25 pontos verticais por baliza

x_dense = np.linspace(0.0, 14.800, num_x)

grid_x = np.zeros((num_x, num_z))
grid_y_be = np.zeros((num_x, num_z))
grid_z = np.zeros((num_x, num_z))

for i, x in enumerate(x_dense):
    if x >= 14.799:
        zk = zk_orig[-1]
        zd = zd_orig[-1]
        z_vals = np.linspace(zk, zd, num_z)
        y_vals = np.zeros(num_z)
    else:
        zk = max(0.0, float(np.interp(x, x_orig, zk_orig)))
        zd = float(np.interp(x, x_orig, zd_orig))
        y25 = max(0.0, float(np.interp(x, x_orig, y25_orig)))
        y50 = max(0.0, float(np.interp(x, x_orig, y50_orig)))
        y75 = max(0.0, float(np.interp(x, x_orig, y75_orig)))
        yd = max(0.0, float(np.interp(x, x_orig, yd_orig)))
        
        # 5 pontos de controle verticais da seção
        z_ctrl = np.array([zk, zk + 0.25*(zd - zk), zk + 0.50*(zd - zk), zk + 0.75*(zd - zk), zd])
        y_ctrl = np.array([0.0, y25, y50, y75, yd])
        
        # Interpolação suave em z usando spline ou PCHIP equivalente por numpy
        z_vals = np.linspace(zk, zd, num_z)
        # Interpolação cúbica local ou linear com ajuste de curvatura
        y_vals = np.interp(z_vals, z_ctrl, y_ctrl)
        y_vals[0] = 0.0 # quilha estrita na linha de centro
        
        # Suavização da transição de fundo (arredondamento de bojo/chine)
        # Aplicar filtro de média móvel suave nos pontos intermediários
        for k in range(1, num_z - 1):
            y_vals[k] = 0.25 * y_vals[k-1] + 0.5 * y_vals[k] + 0.25 * y_vals[k+1]
        y_vals[0] = 0.0
    
    grid_x[i, :] = x
    grid_y_be[i, :] = y_vals
    grid_z[i, :] = z_vals

# Montagem de Vértices e Faces para OBJ e STL
vertices = []
faces = []

# 1. Boreste (BE: y >= 0)
v_be_offset = len(vertices)
for i in range(num_x):
    for j in range(num_z):
        vertices.append([grid_x[i, j], grid_y_be[i, j], grid_z[i, j]])

for i in range(num_x - 1):
    for j in range(num_z - 1):
        p1 = v_be_offset + i * num_z + j
        p2 = v_be_offset + (i + 1) * num_z + j
        p3 = v_be_offset + (i + 1) * num_z + (j + 1)
        p4 = v_be_offset + i * num_z + (j + 1)
        faces.append([p1 + 1, p2 + 1, p3 + 1])
        faces.append([p1 + 1, p3 + 1, p4 + 1])

# 2. Bombordo (BB: y <= 0)
v_bb_offset = len(vertices)
for i in range(num_x):
    for j in range(num_z):
        vertices.append([grid_x[i, j], -grid_y_be[i, j], grid_z[i, j]])

for i in range(num_x - 1):
    for j in range(num_z - 1):
        p1 = v_bb_offset + i * num_z + j
        p2 = v_bb_offset + (i + 1) * num_z + j
        p3 = v_bb_offset + (i + 1) * num_z + (j + 1)
        p4 = v_bb_offset + i * num_z + (j + 1)
        faces.append([p1 + 1, p3 + 1, p2 + 1])
        faces.append([p1 + 1, p4 + 1, p3 + 1])

# 3. Espelho de Popa (Transom em x=0)
v_transom_center = len(vertices) + 1
vertices.append([0.0, 0.0, grid_z[0, 0]])
for j in range(num_z - 1):
    p_be1 = v_be_offset + j + 1
    p_be2 = v_be_offset + (j + 1) + 1
    p_bb1 = v_bb_offset + j + 1
    p_bb2 = v_bb_offset + (j + 1) + 1
    faces.append([v_transom_center, p_be2, p_be1])
    faces.append([v_transom_center, p_bb1, p_bb2])

# Funções de gravação
def write_obj(filepath, verts, fcs):
    with open(filepath, 'w') as f:
        f.write("# Saveiro Tradicional 14.80m - Modelo 3D Superficie de Casco\n")
        f.write("# Gerado por Magdalena (Mada) | Brana Projetos Navais & EEE\n")
        for v in verts:
            f.write(f"v {v[0]:.4f} {v[1]:.4f} {v[2]:.4f}\n")
        for fc in fcs:
            f.write(f"f {fc[0]} {fc[1]} {fc[2]}\n")

def write_stl(filepath, verts, fcs):
    with open(filepath, 'w') as f:
        f.write("solid saveiro_14_80m\n")
        for fc in fcs:
            v1 = np.array(verts[fc[0]-1])
            v2 = np.array(verts[fc[1]-1])
            v3 = np.array(verts[fc[2]-1])
            normal = np.cross(v2 - v1, v3 - v1)
            norm_val = np.linalg.norm(normal)
            if norm_val > 1e-6:
                normal = normal / norm_val
            else:
                normal = np.array([0.0, 0.0, 1.0])
            f.write(f"  facet normal {normal[0]:.6e} {normal[1]:.6e} {normal[2]:.6e}\n")
            f.write("    outer loop\n")
            f.write(f"      vertex {v1[0]:.4f} {v1[1]:.4f} {v1[2]:.4f}\n")
            f.write(f"      vertex {v2[0]:.4f} {v2[1]:.4f} {v2[2]:.4f}\n")
            f.write(f"      vertex {v3[0]:.4f} {v3[1]:.4f} {v3[2]:.4f}\n")
            f.write("    endloop\n")
            f.write("  endfacet\n")
        f.write("endsolid saveiro_14_80m\n")

paths = [
    '/home/magdalena/eee/grupos/grupo-3/Casco_3D_Saveiro_14_80m.obj',
    '/home/magdalena/eee/grupos/grupo-3/Casco_3D_Saveiro_14_80m.stl',
    '/home/magdalena/eee/alunos/rodolfo-g-giordano/Casco_3D_Saveiro_14_80m.obj',
    '/home/magdalena/eee/alunos/rodolfo-g-giordano/Casco_3D_Saveiro_14_80m.stl'
]

write_obj(paths[0], vertices, faces)
write_stl(paths[1], vertices, faces)
write_obj(paths[2], vertices, faces)
write_stl(paths[3], vertices, faces)

print("Arquivos 3D OBJ e STL gerados com sucesso!")
