/* See mtv_cup.h */
/* Last edited on 2016-04-22 17:12:46 by stolfilocal */

#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>

#include <bool.h>
#include <r3.h>
#include <affirm.h>
#include <ppv_array.h>

#include <voxm_obj.h>
#include <voxm_splat.h>
#include <voxm_splat_tube.h>

#include <mtv_cup.h>

void mtv_cup_make
  ( ppv_array_t *a, 
    r3_t *ctr, 
    double cupbotZ, 
    double cuptopZ, 
    double cupR, 
    double cupT, 
    double fuzzR
  )
  {
    /* !!! Select plain or threaded !!! */
    double cupF = 3*cupT;    /* Radius of base filet. */
    mtv_cup_plain_make(a, ctr, cupbotZ, cuptopZ, cupR, cupT, cupF, fuzzR);
  }

void mtv_cup_plain_make
  ( ppv_array_t *a, 
    r3_t *ctr, 
    double cupbotZ, 
    double cuptopZ, 
    double cupR, 
    double cupT, 
    double cupF,
    double fuzzR
  )
  {
    bool_t debug = FALSE;
    
    /* Derived cup parameters: */
    double cupmidZ = (cupbotZ + cuptopZ)/2;    /* {Z} coordinate of cup center. */
    double cupH = fabs(cuptopZ - cupbotZ)/2;  /* Half-height of cup. */
    
    if (debug)
      { fprintf(stderr, "calling {%s}:", __FUNCTION__);
        fprintf(stderr, " cupmidZ = %.2f  halfH = %.2f  cupR = %.2f", cupmidZ, cupH, cupR);
        fprintf(stderr, "  cupT = %.2f  fillR = %.2f\n", cupT, cupF);
      }
    
    /* Position and orientation of cup: */
    r3_path_state_t state;
    state.p = (*ctr); state.p.c[2] = cupmidZ;
    r3x3_ident(&(state.M));
    if (cuptopZ < cupbotZ) { /* Upside-down: */ state.M.c[2][2] = -1; }
    
    auto double fuzzy_cup(r3_t *p);
      /* Indicator function for the cup. */
       
    voxm_splat_object(a, fuzzy_cup, &state, hypot(cupH, cupR) + fuzzR, FALSE);
    
    return;
      
    double fuzzy_cup(r3_t *p)
      { return voxm_obj_round_cup(p, cupH, cupR, cupT, cupF, fuzzR); }
  }

void mtv_cup_threaded_make
  ( ppv_array_t *a, 
    r3_t *ctr, 
    double cupbotZ, 
    double cuptopZ,
    double cupT,
    double fuzzR,
    double vsz
  )
  {
    bool_t debug = FALSE;
    if (debug) { fprintf(stderr, "enter %s\n", __FUNCTION__); }

    if (debug) { fprintf(stderr, "  Z from %.2f vx to %.2f vx  thickness = %.2f vx\n", cupbotZ, cuptopZ, cupT); }
    demand(cupT > fuzzR, "cup wall thickness is too small"); 

    /* Main cup: */
    double inR = 13.8/vsz;    /* Inner radius of cup. */
    double otR = inR + cupT;  /* Outer radius of cup. */
    double cupF = 1.2*cupT;   /* Radius of base filet. */
    if (debug) { fprintf(stderr, "  inR = %.2f vx  otR = %.2f vx  fillet R = %.2f vx\n", inR, otR, cupF); }

    mtv_cup_plain_make(a, ctr, cupbotZ, cuptopZ, otR, cupT, cupF, fuzzR);
    
    /* Threads: */
    double thrH = 2.5/vsz; /* Threads rise per turn. */
    double thrR = inR;     /* Radius of midline of threads helix. */
    double thrN = 2.0;     /* Number of helix turns. */
    double thrZ0 = cupT + 3.5/vsz; /* Distance from cup bottom to start of thread. */
    int dirZ = (cuptopZ > cupbotZ ? +1 : -1);  /* {Z}-direction of cup. */
    double thrbotZ = cupbotZ + dirZ*thrZ0;    /* Bottom of thread. */

    mtv_cup_thread_make(a, ctr, thrbotZ,dirZ, thrR,thrH,thrN, fuzzR);

    /* Inner cuplet defining the gasket seat: */
    double hgt2 = cupT + 4.5/vsz;  /* Total height of cuplet. */
    double cupT2 = 1.5/vsz;        /* Thickness of cuplet. */
    double otR2 = 10.8/vsz;       /* Outer radius of cuplet. */
    double cupF2 = 1.2*cupT2;      /* Fillet radius of cuplet. */
    double cupbotZ2 = cupbotZ;    /* Bottom of cuplet. */
    double cuptopZ2 = cupbotZ + dirZ*hgt2; /* Top of cuplet. */

    mtv_cup_plain_make(a, ctr, cupbotZ2, cuptopZ2, otR2,cupT2,cupF2, fuzzR);

    if (debug) { fprintf(stderr, "exit %s\n", __FUNCTION__); }
    return;
  }
  
void mtv_cup_thread_make
  ( ppv_array_t *a, 
    r3_t *ctr, 
    double thrbotZ, 
    int dirZ,
    double thrR,
    double thrH,
    double thrN,
    double fuzzR
  )
  {
    /* Reference state at mid-thread: */
    r3_path_state_t midS;
    midS.p = (*ctr); 
    midS.p.c[0] += thrR;
    midS.p.c[2] = thrbotZ + dirZ*thrN*thrH/2;
    r3_t midU, midV, midW; /* Basis vectors. */
    r3_axis(1, &midU);
    r3_axis(0, &midV); r3_neg(&midV,&midV);
    r3_axis(2, &midW); 
    r3x3_ident(&(midS.M));
    if (dirZ < 0)
      { /* Upside-down; invert {U} and {W} axes to keep the trhead right-handed:  */ 
        r3_neg(&midU, &midU);
        r3_neg(&midW, &midW);
      }
    r3x3_from_rows(&midU, &midV, &midW, &(midS.M));

    double otR = thrH/4;      /* Radius of thread wire. */
    double thrA = 2*M_PI;     /* Angle swept in unit time. */
    double thrL = thrA*thrR;  /* Projected length traversed in unit time. */
      
    voxm_splat_tube_round_helix
      ( a, -1.00, +1.00, &midS,
        thrL,thrA,thrH, 0.0, otR, fuzzR, FALSE, NULL, NULL
      );
  }
