######################################
###  DM2_w25 # AGruber@tugraz.at   ###
### hu_08 Mary Poppins Regenschirm ###
######################################

import rhinoscriptsyntax as rs
import random, time, sys, math
sys.path.append("P:/")
sys.path.append("P:/WWW/dx6419/dm2/")
import DM_lib as dm
import scriptcontext as sc

rs.UnitSystem(4)  # Meter
rs.ShowGrid(None, False)
rs.ShowGridAxes(None, False)
rs.ViewDisplayMode(rs.CurrentView(), "wireframe")
rs.Command("cplane w t enter", False)  # World Top

dm.PointRadius(displayModeX=0, rad=3, styl=3)
dm.PointRadius(displayModeX=1, rad=4, styl=1)
dm.PointRadius(displayModeX=2, rad=2, styl=0)
dm.printDisplay(state=False)

rs.EnableRedraw(False)

def drawSockelPanel(panel, sockel=10):
    if not panel or len(panel) < 4:
        return []

    for pt in panel:
        if pt is None or any(c is None for c in pt):
            return []

    p0, p1, p2, p3 = panel
    created_objs = []

    # Sockelpanelle (niedrig)
    if p0[2] < 2*sockel:
        mid0 = [(p0[i]+p2[i])/2 for i in range(3)]
        if None not in mid0:
            l1 = rs.AddLine(p0, p2)
            l2 = rs.AddLine(p1, p3)
            created_objs += [l1,l2]
        return created_objs


    colors = [[200,50,100],[50,200,100],[100,100,200],[200,200,50]]
    color = random.choice(colors)

    # Mittelpunkt berechnen
    center = [(p0[i]+p1[i]+p2[i]+p3[i])/4 for i in range(3)]
    if None in center:
        return created_objs

    # Linien vom Zentrum zu den Ecken
    for pt in [p0,p1,p2,p3]:
        if pt is not None:
            line = rs.AddLine(pt, center)
            if line:
                rs.ObjectColor(line, color)
                created_objs.append(line)
    return created_objs

# -------------------------
# Funktion zum Erzeugen des Schirms mit Segmenten
# -------------------------
def create_umbrella_with_panels(position=[0,0,0], radius=0.5, pole_height=20, num_ribs=8,
                                circle_drop=0.8, rib_drop=0.1, pole_length=0.6, num_segments=3, sockel=10):
    pos3d = rs.coerce3dpoint(position)
    pos3d = rs.PointAdd(pos3d, [0,0,-pole_height])
    top = rs.VectorAdd(pos3d, [0,0,pole_height])

    # Schirmkreis Punkte
    circle_z = pole_height * circle_drop
    circle_points = []
    for i in range(num_ribs):
        angle = 2*math.pi*i/num_ribs
        x = radius * math.cos(angle)
        y = radius * math.sin(angle)
        z = circle_z
        cor = [x, y, z]
        cor = rs.VectorAdd(cor, pos3d)
        circle_points.append(cor)

    # Streben erzeugen und Segmente berechnen
    streben_segments = []
    for pt_coords in circle_points:
        mid = dm.pntInbetween(top, pt_coords)
        mid[2] += pole_height * rib_drop
        strebe = rs.AddCurve([top, mid, pt_coords], degree=2)
        params = [rs.CurveParameter(strebe, t/num_segments) for t in range(num_segments+1)]
        points_on_strebe = [rs.EvaluateCurve(strebe, p) for p in params]
        streben_segments.append(points_on_strebe)

    # Schirmkante verbinden
    circle_points.append(circle_points[0])
    rs.AddCurve(circle_points, 1)

    # Querlinien zwischen Segmentpunkten
    for seg_idx in range(1, num_segments):
        for rib in range(num_ribs):
            start_pt = streben_segments[rib][seg_idx]
            next_rib = (rib + 1) % num_ribs
            end_pt = streben_segments[next_rib][seg_idx]
            rs.AddLine(start_pt, end_pt)

    # Panels zwischen Streben und Querlinien
    for rib in range(num_ribs):
        next_rib = (rib + 1) % num_ribs
        for seg_idx in range(num_segments):
            panel_pts = [
                streben_segments[rib][seg_idx],
                streben_segments[next_rib][seg_idx],
                streben_segments[next_rib][seg_idx+1],
                streben_segments[rib][seg_idx+1]
            ]
            drawSockelPanel(panel_pts, sockel=sockel)

    # Stab
    bottom = rs.PointAdd(top, [0,0,-pole_length])
    rs.AddLine(top, bottom)

    return bottom

# -------------------------
# Flugbahn und Parameter
# -------------------------
flugbahn = rs.ObjectsByName("flugbahn")[0]
anzahl = 20
positions = rs.DivideCurve(flugbahn, anzahl, False)

dm.newEmptyLayer("PROJECT::umbrellas", [0,100,200])
rs.Redraw()

delta_circle_drop = dC = (0.9 - 0.1)/anzahl
delta_rib_drop    = dR = (0.6 - 0.2)/anzahl
delta_radius      = dRad = (20.0 - 0.1)/anzahl
pole_start = 0.8
pole_end   = 20.0
delta_pole = (pole_end - pole_start) / anzahl

# Blockinstanz
layer_name = "Mary popins"
objs_on_layer = rs.ObjectsByLayer(layer_name)
block_instance = None
for obj in objs_on_layer:
    if rs.IsBlockInstance(obj):
        block_instance = obj
        break
if not block_instance:
    raise Exception("Keine Blockinstanz auf Layer '{}' gefunden.".format(layer_name))

block_def_name = rs.BlockInstanceName(block_instance)
block_def_objs = rs.BlockObjects(block_def_name)
block_def_point = None
for obj in block_def_objs:
    if rs.IsPoint(obj):
        block_def_point = rs.PointCoordinates(obj)
        break
if not block_def_point:
    raise Exception("Kein Punkt innerhalb der Blockdefinition gefunden!")
xform = rs.BlockInstanceXform(block_instance)
block_point_inst = rs.PointTransform(block_def_point, xform)

stop_distance = 200
end_pos = positions[-1]

# Animation: immer nur aktueller Schirm + Block
last_umbrella_objs = []
last_block = None
block_stop = False

for i, pos in enumerate(positions):
    if sc.escape_test():
        print("Animation abgebrochen!")
        break

    if last_umbrella_objs:
        rs.DeleteObjects(last_umbrella_objs)
        last_umbrella_objs = []

    if last_block and not block_stop:
        rs.DeleteObject(last_block)
        last_block = None

    # Schirm erzeugen
    objs_before = set(rs.AllObjects())
    bottom = create_umbrella_with_panels(
        position=pos,
        radius=0.1 + dRad*i,
        num_ribs=8 + i,
        circle_drop=0.9 - dC*i,
        rib_drop=0.2 + dR*i,
        pole_length=pole_start + delta_pole*i,
        num_segments=3,
        sockel=10
    )
    objs_after = set(rs.AllObjects())
    last_umbrella_objs = list(objs_after - objs_before)

    # Block erzeugen
    dist_to_end = rs.Distance(bottom, end_pos)
    if not block_stop:
        target_point_on_stab = bottom
        new_block = rs.CopyObject(block_instance)
        translation = rs.VectorCreate(target_point_on_stab, block_point_inst)
        rs.MoveObject(new_block, translation)
        last_block = new_block
        if dist_to_end <= stop_distance:
            block_stop = True

    rs.Redraw()
    rs.Sleep(100)

rs.EnableRedraw(True)
dm.printDisplay(state=True, scale=1000)
dm.newEmptyLayer("Default")
print("done")
