#-----------------------------------------------------------------------
#                 Primitive tsxPython sample script
#                           Water ripple
# 
# $Id: wave1a.py 92 2021-04-12 09:48:31Z 3DfromNULL $
#-----------------------------------------------------------------------
import ptsxpy as p
import ptsxgp

from math import *

#--
# Make a surface like spider's web using NURBS cylinder that has very short
# height (almost zero), a large bottom, and a small top. We use its latitude
# for a ring wave.
#--
r1 = 80.      # radius of the outmost circle
long_div = 4  # longitude division of the mesh
lat_div = 3   # latitude  division of the mesh
cap_div = 1   # cap       division of the mesh
ncy1 = p.NURBSCylinderCreate( e_tsxTRUE, r1, 0.01, 0.001, 0., 360., e_tsxTRUE, lat_div, long_div, cap_div, e_tsxFALSE, e_tsxTRUE )
p.SceneAddObject( ncy1, e_tsxFALSE )
print( "lat_div=", lat_div, ", long_div=", long_div, ", cap_div=", cap_div )

# True NURBS patch is the cylinder's child.
print( "ncy1=", ncy1 )
ch1 = p.GNodeGetFirstChild( ncy1 )

#sz1 = 0.1

# Get number of control points about U (longitude) and V (latitude) directions.
nu = p.NPatchGetNumUCntlPts( ch1 ) # 3 * long_div + 1
nv = p.NPatchGetNumVCntlPts( ch1 ) # 3 * lat_div  + 4

# Get an array of control points ( nu * nv elements)
cps1 = p.NPatchGetCntlPts( ch1 )
print( "nu=", nu, "nv=", nv, "cps1=", cps1 )
cps2 = cps1
a = 6  # index of a latitude for "wave" (0 is outermost, nv - 1 is innermost)
b = 10. / r1  # magnifier to shrink wave length
for j in range( nv ):
    for i in range( nu ):
        vp1 = Vec3f_p( cps2 )
        # Shrink the distance from the center for 9 latitudes
        if j >= a - 4 and j <= a - 2: # outer flat surface
            vp1.set_x( b * 0.15 * vp1.x() ) 
            vp1.set_y( b * 0.15 * vp1.y() )
            #p.NPatchMarkCntlPointChange( ncy1, i, j )
        if j >= a - 1 and j <= a + 1: # wave
            vp1.set_x( b * 0.15 * vp1.x() )
            vp1.set_y( b * 0.15 * vp1.y() )
            #p.NPatchMarkCntlPointChange( ncy1, i, j )
        if j >= a + 2 and j <= a + 4: # inner flat surface
            vp1.set_x( b * 0.2 * vp1.x() )
            vp1.set_y( b * 0.2 * vp1.y() )
            #p.NPatchMarkCntlPointChange( ncy1, i, j )
        ## for debug
        #cb1 = p.CreateCube( 1, sz1, sz1, sz1 )
        #p.SceneAddObject( cb1, e_tsxFALSE )
        #p.GNodeSetLocation( cb1, vp1.p )
        #
        cps2 = cps2 + sizeof_CtsxVector3f

tm = 0.
dt = 5.
p.AnimSetActiveTime( tm )
p.SobjSetFrame( ch1, e_tsxKFT_NURBSPATCH )

tm = tm + 3 * dt
p.AnimSetActiveTime( tm )
p.SobjSetFrame( ch1, e_tsxKFT_NURBSPATCH )

cps2 = cps1
for j in range( nv ):
    for i in range( nu ):
        vp1 = Vec3f_p( cps2 )
        if j >= a - 1 and j <= a + 1: # wave
            vp1.set_z( vp1.z() + 0.20 ) # lift it up
        cps2 = cps2 + sizeof_CtsxVector3f

# 
#ret = p.NPatchBuildVisRepAuto( ch1, tsxNPATCH_VR_DRAG )
#print( "NPatchBuildVisRepAuto() ret=", ret )

tm = tm + dt

va1 = Vec3fArray_p( cps1 )
b = sqrt( va1[ 1 ][ 0 ] ** 2 + va1[ 1 ][ 1 ] ** 2 ) / va1[ 1 ][ 0 ]
print( "b=", b )
dr = 2.5
nfrm = 15
for k in range( nfrm ):
    # Create a keyframe
    p.AnimSetActiveTime( tm )
    p.SobjSetFrame( ch1, e_tsxKFT_NURBSPATCH )
    #
    cps2 = cps1
    for j in range( nv ):
        #if j != 2:
        #    continue
        for i in range( nu ):
            vp1 = Vec3f_p( cps2 )
            if j >= 2 and j <= 10: # 5-7 are high, 2-4 and 8-10 are low.
                rad1 = atan2( vp1.y(), vp1.x() )
                c = 1. if i % 3 == 0 else b
                vp1.set_x( vp1.x() + c * dr * cos( rad1 ) )
                vp1.set_y( vp1.y() + c * dr * sin( rad1 ) )
                p.NPatchMarkCntlPointChange( ncy1, i, j )
                print( "%3d (%2d, %2d) %5.2f, %5.2f, %5.2f" % ( k, i, j, vp1.x(), vp1.y(), vp1.z() ) )
            ## for debug
            #if k == nfrm - 1:
            #    cb1 = p.CreateCube( 1, sz1, sz1, sz1 )
            #    p.SceneAddObject( cb1, e_tsxFALSE )
            #    p.GNodeSetLocation( cb1, vp1.p )
            cps2 = cps2 + sizeof_CtsxVector3f
    tm += dt
ret = p.NPatchBuildVisRepAuto( ch1, tsxNPATCH_VR_DRAG )
print( "NPatchBuildVisRepAuto() ret=", ret )

# Rewind the time to zero.
tm = 0.
p.AnimSetActiveTime( tm )

#--
# Clone the wave
#--
wk1 = Ulong()
clones = []
for i in range( 7 ):
    p.GNodeCopy( ncy1, wk1.p )
    ncy2 = wk1.get()
    p.SceneAddObject( ncy2, e_tsxFALSE )
    loc1 = Vec3f( 3. * ( ( i + 1 ) * 0.2 ) * ( 2 * ( ( i + 1 ) % 5 ) - 1 ), 3 * ( 2 * ( i % 2 ) - 1 ), -0.01 * ( i + 1 ) ) # a crude random for x,y. shifting z to avoid from "flickering".
    p.GNodeTranslate( ncy2, loc1.p, e_tsxWorldFrame )
    ch1 = p.GNodeGetFirstChild( ncy2 )
    print( "ch1=", ch1 )
    a = 20. + ( 2 * i + 1 ) - 5 * ( i % 3 ) + i % 5  # a crude random
    for seg1 in range( nu * nv ):
        fr1 = p.SobjGetLastFrame( ch1, e_tsxKFT_NURBSPATCH, seg1 )
        if fr1 <= 0:
            continue;
        for j in range( 10000 ):  # there should be nfrm1 plus a few frames (set before loop of nfrm1 above)
            if fr1 <= 0:
                break;
            #print( "i=%2d, j=%2d, fr1=0x%08x" % ( i, j, fr1 ) )
            t1 = p.FrameGetTime( fr1 )
            print( "t1=", t1 )
            p.SobjInsertFrame( ch1, fr1, seg1, t1 + a )
            fr1 = p.FrameGetPrevFrame( fr1 )
    clones.append( ncy2 )

p.SceneDraw()

