#-----------------------------------------------------------------------
#                   Primitive tsxPython sample script
#                                  fan
# 
# $Id: fan1c.py 82 2019-04-27 13:48:59Z 3DfromNULL $
#-----------------------------------------------------------------------
import ptsxpy as p
import ptsxgp
import math

# radius of frame for fornt and rear grills 
r1 = 4.0

# fineness
f1 = 128

org    = Vec3f( 0., 0., 0. )
x_axis = Vec3f( 1., 0., 0. )
y_axis = Vec3f( 0., 1., 0. )
z_axis = Vec3f( 0., 0., 1. )

nblade = 4
nlongi = 60

# relative z-coordinate of neck cover and pedestal from grill frame
z1 = -0.5 * r1

# Save boolean operation options
boolopt_bk = p.BooleanGetOptions()
print( "boolopt_bk=", boolopt_bk )
# set keep_drill=off, delete_edges=on
p.BooleanSetOptions( ( boolopt_bk & ~tsxBOOLEAN_KEEP_DRILL ) | tsxBOOLEAN_DELETE_EDGES )

def ending():
    pass

def bevel_cylinder( cyl, sw_top, sw_btm, r ):
    nface = p.PolyhGetNbrFaces( cyl )
    print( "nface=", nface )
    wkp = p.PolyhGetFaceptrArray( cyl )
    wk1 = ptsxgp.alloc_long( 2 )
    done_cnt = 0
    btmtop = 0
    for i in range( nface ):
        fp1 = Face_p( ptsxgp.loadptr( wkp + i * sizeof_long ) )
        if fp1.nbrVxs() > 4:
            if done_cnt >= 2:
                print( "inconsistent (1)" )
                stop ####
            btmtop = btmtop + 1
            if ( btmtop == 1 and sw_btm != 0 ) or ( btmtop == 2 and sw_top != 0 ):
                print( "i=", i, ", ", fp1.prt() )
                ptsxgp.storelong( wk1 + done_cnt * sizeof_long, i )
                done_cnt = done_cnt + 1
    print( "done_cnt=", done_cnt )
    p.PolyhSelectFaces( cyl, done_cnt, wk1 )
    #if sw_top and not sw_btm:
    #    stop #####
    n = 10
    prev = 0
    rad0 = ( math.pi / 2. ) / n
    a = r * 2. * math.sin( rad0 / 2. )
    for i in range( n ):
        rad1 = ( i + 1 ) * rad0
        p.BevelSetAngle( int( rad1 * 180. / math.pi ) )
        #p.BevelSetBevel( ( 2 * n - i ) * 0.01 * r1 )
        #a = r * 2. * math.sin( rad0 / 2. ) - prev
        p.BevelSetBevel( a )
        p.PointsBevel()
        #prev = a
    p.Free( wk1 )

#----------
# Create blades with hub
#----------
print( "Creating a blade" )
blade1 = p.CreateCone( f1, 2, 0.5 * r1, 1.0 * r1 )
p.SceneAddObject( blade1, e_tsxFALSE )
cywk1 = p.CreateCylinder( f1, f1, 1.0 * r1, 1.0 * r1, 3.0 * r1 )
p.SceneAddObject( cywk1, e_tsxFALSE )
p.GNodeRotate( cywk1, org.p, y_axis.p, -55 * math.pi / 180., e_tsxWorldFrame )
loc1 = Vec3f( 0., -r1 / 5., -0.75 * r1 )
p.GNodeSetLocation( cywk1, loc1.p )
p.SelectSobj( cywk1, e_tsxSELECT, e_tsxFALSE )
p.CurrobjCopy()
cywk2 = p.GetCurrentSelection()
loc1.set_z( loc1.z() + 0.0125 * r1 )
p.GNodeSetLocation( cywk2, loc1.p )
p.SelectSobj( blade1, e_tsxSELECT, e_tsxFALSE )
p.BooleanSubtractionFromCurrobj( cywk1 )
p.SelectSobj( blade1, e_tsxSELECT, e_tsxFALSE )
p.BooleanIntersectionWithCurrobj( cywk2 )
p.GNodeRotate( blade1, org.p, y_axis.p, 0.8 * math.pi, e_tsxWorldFrame )
p.GNodeRotate( blade1, org.p, x_axis.p, -0.2 * math.pi, e_tsxWorldFrame )
vec1 = Vec3f( 0.6 * r1, -0.1 * r1, -0.48 * r1 )
p.MNodeSetAxesPosition( blade1, vec1.p )
p.GNodeSetLocation( blade1, org.p )
# Clone the blade
print( "Increasing blades" )
b_list = [ blade1 ]
for i in range( 1, nblade ):
    p.SelectSobj( blade1, e_tsxSELECT, e_tsxFALSE )
    p.CurrobjCopy()
    blade2 = p.GetCurrentSelection()
    p.GNodeRotate( blade2, org.p, z_axis.p, i * 2. * math.pi / nblade, e_tsxWorldFrame )
    b_list.append( blade2 )
# Group them
print( "Grouping blades" )
p.SelectSobj( b_list[ 0 ], e_tsxSELECT, e_tsxFALSE )
for i in range( 1, nblade ):
    if p.CheckAbort() == e_tsxTRUE:
        print( "aborted." )
        ending() 
        stop #####
    blades = p.GroupAtCurrobj( b_list[ i ] )
# Add a hub
h_hub = 0.25 * r1
hub = p.CreateCylinder( f1, f1, 0.15 * r1, 0.15 * r1, h_hub )
p.SceneAddObject( hub, e_tsxFALSE )
p.SelectSobj( hub, e_tsxSELECT, e_tsxFALSE )
blades_with_hub = p.GroupAtCurrobj( blades )
# Adjust origin of it
#loc1 = Vec3f( 0., 0., -1.5 * r1 )
loc1 = Vec3f( 0., 0., h_hub / 2. )
p.MNodeSetAxesPosition( blades_with_hub, loc1.p )
p.GNodeSetLocation( blades_with_hub, org.p )

#----------
# Create front and rear grill
#----------
print( "Creating a wire for front grill" )
longi_wire1 = p.CreateTorus( f1, 20, 0.98 )
p.SceneAddObject( longi_wire1, e_tsxFALSE )
p.GNodeSetLocation( longi_wire1, org.p )
sz1 = Vec3f( r1, 0.35 * r1, 0.3 * r1 )
p.GNodeScale( longi_wire1, sz1.p, e_tsxWorldFrame )
p.GNodeRotate( longi_wire1, org.p, x_axis.p, 0.5 * math.pi, e_tsxWorldFrame )
cbwk1 = p.CreateCube( 1, 3. * r1, 3. * r1, 3. * r1 )
p.SceneAddObject( cbwk1, e_tsxFALSE )
loc1 = Vec3f( 0., 0., -1.5 * r1 )
p.GNodeSetLocation( cbwk1, loc1.p )
p.SelectSobj( longi_wire1, e_tsxSELECT, e_tsxFALSE )
p.BooleanSubtractionFromCurrobj( cbwk1 )
# Clone the longitude wire
print( "Increasing wires for front grill" )
#lw_list = [ longi_wire1 ]
lw_list = []
for i in range( 0, nlongi ):
    if p.CheckAbort() == e_tsxTRUE:
        print( "aborted." )
        ending() 
        stop #####
    p.SelectSobj( longi_wire1, e_tsxSELECT, e_tsxFALSE )
    p.CurrobjCopy()
    longi_wire2 = p.GetCurrentSelection()
    p.GNodeRotate( longi_wire2, org.p, z_axis.p, i * math.pi / nlongi, e_tsxWorldFrame )
    lw_list.append( longi_wire2 )
# remove the seed
p.SobjDelete( longi_wire1 )
# Group them
print( "Grouping wires as front grill" )
#p.SelectSobj( lw_list[ 0 ], e_tsxSELECT, e_tsxFALSE )
p.SelectSobj( lw_list[ 0 ], e_tsxSELECT, e_tsxTRUE )
for i in range( 1, nlongi ):
    if p.CheckAbort() == e_tsxTRUE:
        print( "aborted." )
        ending() 
        stop #####
    front_grill = p.GroupAtCurrobj( lw_list[ i ] )
# Copy it to rear grill
print( "Copying the front grill to rear and shortening its thickness" )
p.SelectSobj( front_grill, e_tsxSELECT, e_tsxFALSE )
p.CurrobjCopy()
rear_grill = p.GetCurrentSelection()
p.GNodeRotate( rear_grill, org.p, x_axis.p, math.pi, e_tsxWorldFrame )
sz1 = Vec3f( 1., 1., 0.5 )
p.GNodeScale( rear_grill, sz1.p, e_tsxWorldFrame )

#----------
# Create a frame for grills
#----------
print( "Creating frame for grills" )
gframe = p.CreateCylinder( f1, 2, r1, r1, 0.01 * r1 )
p.SceneAddObject( gframe, e_tsxFALSE )
cywk1 = p.CreateCylinder( f1, 2, 0.96 * r1, 0.96 * r1, 0.02 * r1 )
p.SceneAddObject( cywk1, e_tsxFALSE )
p.GNodeSetLocation( gframe, org.p )
p.GNodeSetLocation( cywk1, org.p )
p.SelectSobj( gframe, e_tsxSELECT, e_tsxFALSE )
p.BooleanSubtractionFromCurrobj( cywk1 )
if p.CheckAbort() == e_tsxTRUE:
    print( "aborted." )
    ending() 
    stop #####

#----------
# Create a motor assembly
#----------
print( "Creating motor assembly" )
# part 1
motor_assem1 = p.CreateCylinder( f1, 2, 0.3 * r1, 0.25 * r1, 0.6 * r1 )
p.SceneAddObject( motor_assem1, e_tsxFALSE )
bevel_cylinder( motor_assem1, 1, 1, 0.05 * r1 )
loc1 = Vec3f( 0., 0., -0.55 * r1 )
p.GNodeSetLocation( motor_assem1, loc1.p )
# part 2
motor_assem2 = p.CreateCylinder( f1, 2, 0.17 * r1, 0.17 * r1, 0.1 * r1 )
p.SceneAddObject( motor_assem2, e_tsxFALSE )
loc1 = Vec3f( 0., 0., -0.15 * r1 )
p.GNodeSetLocation( motor_assem2, loc1.p )
# neck cover
neckcover = p.CreateCylinder( int ( f1 / 2 ), 2, 0.2 * r1, 0.2 * r1, 0.3 * r1 )
p.SceneAddObject( neckcover, e_tsxFALSE )
bevel_cylinder( neckcover, 0, 1, 0.07 * r1 )
p.GNodeRotate( neckcover, org.p, x_axis.p, -math.pi / 2., e_tsxWorldFrame )
loc1 = Vec3f( 0., 0.4 * r1, z1 )
p.GNodeSetLocation( neckcover, loc1.p )
# Group them
p.SelectSobj( motor_assem1, e_tsxSELECT, e_tsxFALSE )
motor_assem = p.GroupAtCurrobj( motor_assem2 )
p.SelectSobj( motor_assem, e_tsxSELECT, e_tsxFALSE )
motor_assem = p.GroupAtCurrobj( neckcover )
if p.CheckAbort() == e_tsxTRUE:
    print( "aborted." )
    ending() 
    stop #####

#----------
# Create a pedestal
#----------
print( "Creating pedestal" )
# Higher (inner) tube
tube_h = p.CreateCylinder( int ( f1 / 2 ), 2, 0.07 * r1, 0.07 * r1, 1.0 * r1 )
p.SceneAddObject( tube_h, e_tsxFALSE )
p.GNodeRotate( tube_h, org.p, x_axis.p, -math.pi / 2., e_tsxWorldFrame )
loc1 = Vec3f( 0., 0.9 * r1, z1 )
p.GNodeSetLocation( tube_h, loc1.p )
# Lower (outer) tube
tube_l = p.CreateCylinder( int ( f1 / 2 ), 2, 0.1 * r1, 0.1 * r1, 1.1 * r1 )
p.SceneAddObject( tube_l, e_tsxFALSE )
p.GNodeRotate( tube_l, org.p, x_axis.p, -math.pi / 2., e_tsxWorldFrame )
loc1 = Vec3f( 0., 1.5 * r1, z1 )
p.GNodeSetLocation( tube_l, loc1.p )
# base
h_base = 0.15 * r1
d_base = 2.0 * r1
base = p.CreateCylinder( int ( f1 / 2 ), 2, 0.9 * r1, 0.9 * r1, h_base )
p.SceneAddObject( base, e_tsxFALSE )
bevel_cylinder( base, 1, 0, 0.03 * r1 )
p.GNodeRotate( base, org.p, x_axis.p, -math.pi / 2., e_tsxWorldFrame )
loc1 = Vec3f( 0., d_base, 0.6 * z1 )
p.GNodeSetLocation( base, loc1.p )
# Group lower tube and base
p.SelectSobj( tube_l, e_tsxSELECT, e_tsxFALSE )
pedestal2 = p.GroupAtCurrobj( base )
if p.CheckAbort() == e_tsxTRUE:
    print( "aborted." )
    ending() 
    stop #####


#----------
# Group all
#----------
print( "Grouping to some blocks" )
# create a dummy object to avoid one group becomes a child of other group
plwk1 = p.CreatePlane( 1, 1 )
p.SceneAddObject( plwk1, e_tsxFALSE )
#----
# upper portion
p.SelectSobj( plwk1, e_tsxSELECT, e_tsxFALSE )
fan_u = p.GroupAtCurrobj( front_grill )
p.SelectSobj( fan_u, e_tsxSELECT, e_tsxFALSE )
fan_u = p.GroupAtCurrobj( rear_grill )
p.SelectSobj( fan_u, e_tsxSELECT, e_tsxFALSE )
fan_u = p.GroupAtCurrobj( gframe )
p.SelectSobj( fan_u, e_tsxSELECT, e_tsxFALSE )
fan_u = p.GroupAtCurrobj( blades_with_hub )
p.SelectSobj( fan_u, e_tsxSELECT, e_tsxFALSE )
fan_u = p.GroupAtCurrobj( motor_assem )
# ungroup the dummy object
p.SelectSobj( plwk1, e_tsxSELECT, e_tsxFALSE )
p.GroupRemoveCurrobj()
if p.CheckAbort() == e_tsxTRUE:
    print( "aborted." )
    ending() 
    stop #####
#----
# middle portion
fan_m = tube_h
#----
# lower portion
fan_l = pedestal2
#----
# whole
print( "Grouping whole" )
p.SelectSobj( plwk1, e_tsxSELECT, e_tsxFALSE )
fan = p.GroupAtCurrobj( fan_u )
p.SelectSobj( fan, e_tsxSELECT, e_tsxFALSE )
fan = p.GroupAtCurrobj( fan_m )
p.SelectSobj( fan, e_tsxSELECT, e_tsxFALSE )
fan = p.GroupAtCurrobj( fan_l )
# ungroup the dummy object
p.SelectSobj( plwk1, e_tsxSELECT, e_tsxFALSE )
p.GroupRemoveCurrobj()
# remove it
p.SobjDelete( plwk1 )
if p.CheckAbort() == e_tsxTRUE:
    print( "aborted." )
    ending() 
    stop #####

print( "Setting names" )
p.GNodeSetName( front_grill,     "Front_grill" )
p.GNodeSetName( rear_grill,      "Rear_grill" )
p.GNodeSetName( gframe,          "Grill_frame" )
p.GNodeSetName( blades_with_hub, "Blades_with_hub" )
p.GNodeSetName( motor_assem,     "Motor_assembly" )
p.GNodeSetName( pedestal2,       "Pedestal2" )
p.GNodeSetName( neckcover,       "Neck_cover" )
p.GNodeSetName( tube_h,          "Higher_tube" )
p.GNodeSetName( tube_l,          "Lower_tube" )
p.GNodeSetName( base,            "Base" )
p.GNodeSetName( fan_u,           "Upper_of_fan" )
p.GNodeSetName( fan_m,           "Middle_of_fan" )
p.GNodeSetName( fan_l,           "Lower_of_fan" )
p.GNodeSetName( fan,             "fan" )
if p.CheckAbort() == e_tsxTRUE:
    print( "aborted." )
    ending() 
    stop #####

# Move axel position of fan_u
print( "Adjusting axle and orientation" )
vec1 = Vec3f()
vec2 = Vec3f()
p.GNodeGetAxesPosition( blades_with_hub, vec1.p )
p.GNodeGetAxesPosition( tube_h, vec2.p )
vec1.set_z( vec2.z() )
p.MNodeSetAxesPosition( fan_u, vec1.p )

# Change axes orientation of upper portion of the fan
#ax1 = Axes3f((1.,0.,0.),(0.,1.,0.),(0.,0.,1.))
#p.MNodeSetAxesOrientation( fan_u, ax1.p )

# Correct orientation of fan
p.SelectSobj( fan, e_tsxSELECT, e_tsxFALSE )
p.GNodeRotate( fan, org.p, x_axis.p, -math.pi / 2., e_tsxWorldFrame )
p.GNodeGetAxesPosition( base, vec1.p )
print( "Vec1=", vec1.prt() )
vec1.set_z( vec1.z() - h_base / 2. )
p.MNodeSetAxesPosition( fan, vec1.p )
p.GNodeSetLocation( fan, org.p )

# End of modeling
p.SceneDraw()
# restore options
p.BooleanSetOptions( boolopt_bk )

if p.CheckAbort() == e_tsxTRUE:
    print( "aborted." )
    ending() 
    stop #####

#----------
# Create an animation
#----------
print( "Initializing animation" )
simtime_still1    =  15.   # (frames)
simtime_extending =  30.   # (frames)
simtime_still2    =  15.   # (frames)
simtime_rotating  = 450.   # (frames)
simtime_still3    =  30.   # (frames)

freq_rotating     =   4.   # (frames)
freq_head_shaking =  90.   # (frames)

#-----
# Create a keyframe
tm = 0.
p.AnimSetActiveTime( tm )

#-----
# Create a keyframe
tm = tm + simtime_still1
p.AnimSetActiveTime( tm )

p.SobjSetFrame( fan_u, e_tsxKFT_MOVE )
p.SobjSetFrame( fan_m, e_tsxKFT_MOVE )

print( "Creating extension animation" )
#-----
# Create a keyframe
tm = tm + simtime_extending
p.AnimSetActiveTime( tm )

vec1 = Vec3f( 0., 0., 0.4 * r1 )
p.GNodeTranslate( fan_u, vec1.p, e_tsxWorldFrame )
p.GNodeTranslate( fan_m, vec1.p, e_tsxWorldFrame )
p.SobjSetFrame( fan_u, e_tsxKFT_MOVE )
p.SobjSetFrame( fan_m, e_tsxKFT_MOVE )

#-----
# Create a keyframe
tm = tm + simtime_still1
p.AnimSetActiveTime( tm )

p.SobjSetFrame( blades_with_hub, e_tsxKFT_ROTATE )
p.SobjSetFrame( fan_u, e_tsxKFT_ROTATE )

print( "Creating blades rotation animation" )
print( "tm=", tm )
tm1 = tm
for i in range( int( simtime_rotating / freq_rotating ) ):
    if p.CheckAbort() == e_tsxTRUE:
        print( "aborted." )
        ending() 
        stop #####
    # Create a keyframe
    tm1 = tm1 + freq_rotating
    p.AnimSetActiveTime( tm1 )
    p.GNodeRotate( blades_with_hub, org.p, z_axis.p, -math.pi * 2. / 3., e_tsxModelFrame )
    p.SobjSetFrame( blades_with_hub, e_tsxKFT_ROTATE )
print( "tm1=", tm1, ", i=", i )

print( "Creating head-shaking animation" )
tm1 = tm
for i in range( int( simtime_rotating / freq_head_shaking ) ):
    if p.CheckAbort() == e_tsxTRUE:
        print( "aborted." )
        ending() 
        stop #####
    # Create a keyframe
    tm1 = tm1 + freq_head_shaking
    p.AnimSetActiveTime( tm1 )
    sign1 = 1 if i % 4 == 0 or i % 4 == 3 else -1
    p.GNodeRotate( fan_u, org.p, y_axis.p, sign1 * 0.4 * math.pi, e_tsxModelFrame )
    p.SobjSetFrame( fan_u, e_tsxKFT_ROTATE )
print( "tm1=", tm1, ", i=", i )

#-----
# Create a keyframe
tm = tm1 + simtime_still3
p.AnimSetActiveTime( tm )

p.SobjSetFrame( blades_with_hub, e_tsxKFT_ROTATE )
p.SobjSetFrame( fan_u, e_tsxKFT_ROTATE )

