// Duplicate surface curve
proc string[] dup_surf_curves(string $uv, float $from, float $to, int $step, int $dup_first_curve, string $obj_name)
{
    if ($uv == "u" || $uv == "v")
    {
        string $curve_name[];
        int $flag = 0;
        int $count = 0;
        if ($dup_first_curve == 0) $flag = 1;
        for ($i = $flag; $i <= $step; $i++)
        {
            string $dup_curve[] = `duplicateCurve -ch 1 -rn 0 -local 0  ($obj_name + "." + $uv + "[" + ($from + ($to - $from)/$step*$i) + "]")` ;
            $curve_name[$count] = $dup_curve[0];
            $count++;
        }
    return $curve_name;
    }
    else error("Invailed valuable!: select u or v.");
}
  
// This proc returns distance of two objects
proc float distance(string $obj1, string $obj2)
{
    float $obj1_center[] = `xform -q -sp $obj1`;
    float $obj2_center[] = `xform -q -sp $obj2`;
    float $dif_x = $obj1_center[0] - $obj2_center[0];
    float $dif_y = $obj1_center[1] - $obj2_center[1];
    float $dif_z = $obj1_center[2] - $obj2_center[2];
    float $dist = sqrt($dif_x*$dif_x + $dif_y*$dif_y + $dif_z*$dif_z);
    return $dist;
}
  
// Tweak curve scale by time
proc tweak_curve_scale(string $obj_name, float $curve_scale, float $dist)
{
    float $a = 10.0;
    float $b = 2.0;
    float $wich_of_agnesi = ($b*$b*$b/(($a*$dist)*($a*$dist) + $b*$b))/$b;
    float $scale_value = 1 - (1 - $curve_scale)*$wich_of_agnesi;
    scale -a $scale_value $scale_value $scale_value $obj_name;
}
  
global proc string[] cell_division(string $cell_name[], int $curve_step, float $div_time)
{
    // Duplicate curves on two spheres
    string $cell_1_curve[] = dup_surf_curves("u", 0.0, 0.5, $curve_step, 1, $cell_name[0]);
    string $cell_2_curve[] = dup_surf_curves("u", 0.5, 1.0, $curve_step, 1, $cell_name[1]);
  
    // Exitract boundary curve from two cell spheres
    string $boundary_curve[] = `intersect  -ch 0 -fs 1 -cos 0 -tol 0.01 $cell_name[0] $cell_name[1]`;
    xform -cp $boundary_curve[0];
    
    // Get a radius of the boundary curve
    float $boundary_curve_bb[] = `xform -q -bb $boundary_curve[0]`;
    float $max_y = $boundary_curve_bb[4];
    
    // Get radiuses of two cells
    float $cell_1_radius = `sphere -q -r $cell_name[0]`;
    float $cell_1_scale = `getAttr ($cell_name[0] + ".sy")`;
    $cell_1_radius *= $cell_1_scale;
    float $cell_2_radius = `sphere -q -r $cell_name[1]`;
    float $cell_2_scale = `getAttr ($cell_name[1] + ".sy")`;
    $cell_2_radius *= $cell_2_scale;
  
    // Find out the UV range where surface curves need to be duplicated
    float $boundary_uv_range_1 = ((acosd(($max_y/$cell_1_radius))) / 90.0) * 0.5;
    float $boundary_uv_range_2 = ((acosd(($max_y/$cell_2_radius))) / 90.0) * 0.5;
    float $general_curve_space = 0.5/$curve_step;
    
    // Duplicate curves around the boundary of two cells
    int $boundary_uv_step_1 = $boundary_uv_range_1 / $general_curve_space;
    int $boundary_uv_step_2 = $boundary_uv_range_2 / $general_curve_space;
    string $cell_1_b_curve[];
    string $cell_2_b_curve[];
    if($boundary_uv_step_1 != 0) 
        $cell_1_b_curve = dup_surf_curves("u", 0.5, (0.5 + ($boundary_uv_range_1*(1.0 - 1.0/$boundary_uv_step_1))), ($boundary_uv_step_1 - 1), 0, $cell_name[0]);
    if($boundary_uv_step_2 != 0)
        $cell_2_b_curve = dup_surf_curves("u", (0.5 - $boundary_uv_range_2), (0.5 - ($boundary_uv_range_2/$boundary_uv_step_2)), ($boundary_uv_step_2 - 1), 0, $cell_name[1]);
    xform -cp $cell_1_curve $cell_2_curve $cell_1_b_curve $cell_2_b_curve;
  
    // Tweak curve scale by time
    float $current_time = `currentTime -q`;
    float $curve_scale;
    if($current_time <= $div_time)
        $curve_scale = 1 - `pow ($current_time/$div_time) 2`;
    else $curve_scale = 0.0;
    // Put all curve names into one array
    string $curves[];
    appendStringArray($curves, $cell_1_curve, `size($cell_1_curve)`);
    appendStringArray($curves, $cell_1_b_curve, `size($cell_1_b_curve)`);
    appendStringArray($curves, $boundary_curve, 1);
    appendStringArray($curves, $cell_2_b_curve, `size($cell_2_b_curve)`);
    appendStringArray($curves, $cell_2_curve, `size($cell_2_curve)`);
  
    // Tweak all curves' scale
    string $scaled_curve;    
    for($scaled_curve in $curves)
    {
        float $dist = distance($boundary_curve[0], $scaled_curve);
        tweak_curve_scale($scaled_curve, $curve_scale, $dist);
    }
    
    
    string $cell[];
    if ($curve_scale > 0)
    {
        string $cell_temp[] = `loft $curves`;
        $cell[0] = $cell_temp[0];
        delete $curves;
    }
    else
    {
        string $cell_1_last_curve[];
        string $cell_2_first_curve[];
        // Duplicate last curve of cell 1 to be used to close loft surface
        if((size($cell_1_b_curve)) != 0)
            $cell_1_last_curve = `duplicate -rr $cell_1_b_curve[(size($cell_1_b_curve) - 1)]`;
        else
            $cell_1_last_curve = `duplicate -rr $cell_1_curve[(size($cell_1_curve) - 1)]`;
        scale -a 0 0 0 $cell_1_last_curve;
        move -r 0.25 0 0 $cell_1_last_curve;
        // Duplicate fist curve of cell 2 to be used to close loft surface
        if((size($cell_2_b_curve)) != 0)
            $cell_2_first_curve = `duplicate -rr $cell_2_b_curve[0]`;
        else
            $cell_2_first_curve = `duplicate -rr $cell_2_curve[0]`;
        scale -a 0 0 0 $cell_2_first_curve;
        move -r -0.25 0 0 $cell_2_first_curve;
        
        // Loft cell 1 surface
        string $cell_1[];
        appendStringArray($cell_1, $cell_1_curve, `size($cell_1_curve)`);
        appendStringArray($cell_1, $cell_1_b_curve, `size($cell_1_b_curve)`);
        appendStringArray($cell_1, $cell_1_last_curve, 1);
        string $cell_temp[] = `loft $cell_1`;
        $cell[0] = $cell_temp[0];
        
        // Loft cell 2 surface
        string $cell_2[];
        appendStringArray($cell_2, $cell_2_first_curve, 1);
        appendStringArray($cell_2, $cell_2_b_curve, `size($cell_2_b_curve)`);
        appendStringArray($cell_2, $cell_2_curve, `size($cell_2_curve)`);
        $cell_temp = `loft $cell_2`;
        $cell[1] = $cell_temp[0];
        
        delete $cell_1;
        delete $cell_2;
        delete $boundary_curve[0];
    }
    return $cell;
}
  
global proc cell_div_seq()
{
    int $end_frame = 120;
    int $frame_count = 1;
    int $curve_step = 8;
    float $div_time = 60.0;
        
    // Keep the names of cell spheres
    string $cell_name[] = `ls -sl`;
    
    //  To make each UV span 0 to 1
    rebuildSurface -ch 1 -rpo 1 -rt 0 -end 1 -kr 0 -kcp 0 -kc 0 -su 8 -du 3 -sv 8 -dv 3 -tol 0.01 -fr 0  -dir 2 $cell_name[0];
    rebuildSurface -ch 1 -rpo 1 -rt 0 -end 1 -kr 0 -kcp 0 -kc 0 -su 8 -du 3 -sv 8 -dv 3 -tol 0.01 -fr 0  -dir 2 $cell_name[1];
    
    for($frame_count = 1; $frame_count <= $end_frame; $frame_count++)
    {
        currentTime $frame_count;
        string $new_cells[] = cell_division($cell_name, $curve_step, $div_time);
        string $temp;
        for($temp in $new_cells)
        {
            setAttr ($temp + ".v") 1;
            setKeyframe ($temp + ".v");
        }
        currentTime ($frame_count - 1);
        for($temp in $new_cells)
        {
            setAttr ($temp + ".v") 0;
            setKeyframe ($temp + ".v");
        }
        currentTime ($frame_count + 1);
        for($temp in $new_cells)
        {
            setAttr ($temp + ".v") 0;
            setKeyframe ($temp + ".v");
        }
    }
    select -r $cell_name[0] ;
    select -tgl $cell_name[1] ;
    HideSelectedObjects;
    currentTime 1 ;
}
  
cell_div_seq;