/*----------------------------------------------------------------------*/
/*                                                                      */
/*  File        :       scribner.c                                      */
/*                                                                      */
/*  Programmer  :       Peter Isensee                                   */
/*  Project     :       Modoc Lumber Scaler Program                     */
/*  Compiler    :       Borland Turbo C V2.0                            */
/*  Date        :       1/90                                            */
/*                                                                      */
/*  Description :       scribner functions used to compute log volumes  */
/*                                                                      */


/*----------------------------------------------------------------------*/
/*                                                                      */
/*  Function    :       gross                                           */
/*                                                                      */
/*  Description :       computes the gross volume of a log based on the */
/*                      Scribner Decimal C Rule                         */
/*                                                                      */
/*  Arguments   :       length          log total length                */
/*                      dia1            one end diameter                */
/*                      dia2            other end diameter              */
/*                      butt            butt log marker                 */
/*                                                                      */
/*  Returns     :       the volume of a given log based on its end      */
/*                      diameters.  This volume is computed according   */
/*                      to the Scribner Decimal C Rule                  */
/*                                                                      */
/*  Algorithm   :                                                       */
/*                                                                      */
/*      if neither diameter has been entered or                         */
/*      length has not been entered or                                  */
/*      length is too large                                             */
/*              return (0)                                              */
/*                                                                      */
/*      if log length is less than or equal to the max. scaling length  */
/*              return volume based on length and MIN(dia1, dia2)       */
/*                                                                      */
/*      if log length is less than or equal to 2*max. scaling length    */
/*              divide log into two segments                            */
/*              compute taper = MAX(dia1, dia2) - MIN(dia1, dia2)       */
/*              if taper is not divisible by two then add an inch       */
/*              if log is a butt log then taper is assigned according   */
/*              to log length                                           */
/*              return the sum of the volumes of the top and bottom     */
/*              segments based on length, the small diameter, and the   */
/*              taper                                                   */
/*                                                                      */
/*      if log length is greater than 2*max. scaling length             */
/*              divide log into three segments                          */
/*              compute taper                                           */
/*              raise the total taper to a number divisible by 3 and    */
/*              divide.  Assign this to the top seg.  Distribute        */
/*              remainder of taper as in a two seg. log.                */
/*              if log is a butt log then taper is assigned according   */
/*              to log length                                           */
/*              return the sum of the volumes of the top, middle and    */
/*              bottom segments                                         */
/*                                                                      */

int gross(int length, int dia1, int dia2, char *butt)
{
   int taper,                   /* total log taper                      */
       top_taper,               /* taper assigned in 3 seg. logs        */
       sm_dia,                  /* small end diameter                   */
       lg_dia,                  /* large end diameter                   */
       top_seg,                 /* top segment length                   */
       mid_seg,                 /* middle segment length                */
       btm_seg;                 /* bottom segment length                */

   /* if neither diameter has been entered or length field is too large */
   /* or length field has not been entered then return zero             */
   if (dia1 == 0 && dia2 == 0 || length > MAX_LENGTH || length == 0)
      return (0);

   /* determine large and small diameters */
   sm_dia = MIN(dia1, dia2);
   lg_dia = MAX(dia1, dia2);

   /* --- SINGLE SEGMENT LOG --- */
   if (length <= MAX_SCALING_LENGTH)
      return (vol(length, lg_dia));

   /* --- TWO SEGMENT LOG --- */
   else if (length <= 2*MAX_SCALING_LENGTH) {

      /* divide log into two segments */
      btm_seg = logdivision[length-(MAX_SCALING_LENGTH+1)][0];
      top_seg = logdivision[length-(MAX_SCALING_LENGTH+1)][1];

      if (*butt != SPACE && *butt != NULLCHAR) {
         /* butt log */
         taper = (length < 27) ? 2 : 4;
         sm_dia = lg_dia;
      }
      else {
         /* non-butt log */
         taper = lg_dia - sm_dia;
         if (taper % 2 == 1) taper++;
      }

      /* return the sum of the volumes of the top and bottom segments */
      return (vol(top_seg, sm_dia) +
              vol(btm_seg, sm_dia + taper/2));
   }

   /* --- THREE SEGMENT LOG --- */
   else {

      /* divide log into three segments */
      btm_seg = logdivision[length-(MAX_SCALING_LENGTH+1)][0];
      mid_seg = logdivision[length-(MAX_SCALING_LENGTH+1)][1];
      top_seg = logdivision[length-(MAX_SCALING_LENGTH+1)][2];

      if (*butt != SPACE && *butt != NULLCHAR) {
         /* butt log */
         taper = (length < 47) ? 4 : 6;
         sm_dia = lg_dia;
      }
      else {
         /* non-butt log */
         taper = lg_dia - sm_dia;
      }

      /* raise the total taper to a number divisible by 3 and divide.  */
      /* This is the amount of taper assigned to the top segment.      */
      /* Distribute the remainder of the taper as in a two-segment log */
      top_taper = taper;
      while (top_taper % 3 != 0) top_taper++;
      taper -= top_taper/3;
      if (taper % 2 == 1) taper++;

      /* return the sum of the volumes of the top, middle, */
      /* and bottom segments                               */
      return (vol(top_seg, sm_dia) +
              vol(mid_seg, sm_dia + top_taper/3) +
              vol(btm_seg, sm_dia + top_taper/3 + taper/2));

   }  /* end else */

}  /* end gross */


/*----------------------------------------------------------------------*/
/*                                                                      */
/*  Function    :       vol                                             */
/*                                                                      */
/*  Description :       computes the volume of a single log segment     */
/*                      based on the segment length and diameter        */
/*                                                                      */
/*  Arguments   :       length          segment length                  */
/*                      dia             segment diameter                */
/*                                                                      */
/*  Returns     :       the volume of a log segment                     */
/*                                                                      */
/*  Notes       :       this function utilizes an array of Scribner     */
/*                      table factors to compute volumes.  Before       */
/*                      returning the volume it is rounded to the       */
/*                      nearest tens place.                             */
/*                                                                      */

int vol(int length, int dia)
{
   /* logs having diameters 6" through 11" have a separate diameter */
   /* factor for lengths 1' thru 15' and 16' thru 20'               */

   if ((length > 15 && length < 32) && (dia > 5 && dia < 12))
      return (ROUND((int)(length * factor16[dia-6])));
   else
      return (ROUND((int)(length * factor[dia-1])));
}


/*----------------------------------------------------------------------*/
/*                                                                      */
/*  Function    :       net                                             */
/*                                                                      */
/*  Description :       computes the net volume of a log based on the   */
/*                      Scribner Decimal C Rule                         */
/*                                                                      */
/*  Arguments   :       gross           gross volume of the log         */
/*                      length          log total length                */
/*                      dia1            one end diameter                */
/*                      dia2            other end diameter              */
/*                      butt            butt log marker                 */
/*                      seg#_l          seg. # length defect            */
/*                      seg#_d          seg. # diameter defect          */
/*                      seg#_s          seg. # square defect            */
/*                      seg#_g          seg. # grade                    */
/*                                                                      */
/*  Returns     :       the net volume of a given log based on its end  */
/*                      diameters.  This volume is computed according   */
/*                      to the Scribner Decimal C Rule                  */
/*                                                                      */
/*  Algorithm   :                                                       */
/*                                                                      */
/*      if gross volume equals zero                                     */
/*              return (0)                                              */
/*                                                                      */
/*      if none of the defect fields has been entered and none of the   */
/*      log segments are cull                                           */
/*              return (0);                                             */
/*                                                                      */
/*      if log length is less than or equal to the max. scaling length  */
/*              return volume based on length - length defect and       */
/*              MAX(dia1, dia2) - diameter defect and square defect     */
/*                                                                      */
/*      if log length is less than or equal to 2*max. scaling length    */
/*              divide log into two segments                            */
/*              compute taper = MAX(dia1, dia2) - MIN(dia1, dia2)       */
/*              if taper is not divisible by two then add an inch       */
/*              if log is a butt log then taper is assigned according   */
/*              to log length                                           */
/*              return the sum of the volumes of the top and bottom     */
/*              segments based on length, the small diameter, the       */
/*              taper, and the defects of the segment                   */
/*                                                                      */
/*      if log length is greater than 2*max. scaling length             */
/*              divide log into three segments                          */
/*              compute taper                                           */
/*              raise the total taper to a number divisible by 3 and    */
/*              divide.  Assign this to the top seg.  Distribute        */
/*              remainder of taper as in a two seg. log.                */
/*              if log is a butt log then taper is assigned according   */
/*              to log length                                           */
/*              return the sum of the volumes of the top, middle and    */
/*              bottom segments                                         */
/*                                                                      */

int net(int gross, int length, int dia1, int dia2, char *butt,
        int seg1_l, int seg1_d, int seg1_s, char *seg1_g,
        int seg2_l, int seg2_d, int seg2_s, char *seg2_g,
        int seg3_l, int seg3_d, int seg3_s, char *seg3_g)
{
   int taper,                   /* total log taper                      */
       top_taper,               /* taper assigned in 3 seg. logs        */
       sm_dia,                  /* small end diameter                   */
       lg_dia,                  /* large end diameter                   */
       top_seg,                 /* top segment length                   */
       mid_seg,                 /* middle segment length                */
       btm_seg,                 /* bottom segment length                */
       top_vol,                 /* top segment volume                   */
       mid_vol,                 /* middle segment volume                */
       btm_vol;                 /* bottom segment volume                */

   /* if the gross volume is zero then net volume is zero */
   if (gross == 0)
      return(0);

   /* if none of the defect fields has been entered and no segments are */
   /* CULL logs, then the net volume is the same as the gross volume    */
   if (seg1_l==0 && seg1_d==0 && seg1_s==0 && strcmpi(seg1_g, CULL)!=0 &&
       seg2_l==0 && seg2_d==0 && seg2_s==0 && strcmpi(seg2_g, CULL)!=0 &&
       seg3_l==0 && seg3_d==0 && seg3_s==0 && strcmpi(seg3_g, CULL)!=0)
      return(gross);

   /* determine large and small diameters */
   sm_dia = MIN(dia1, dia2);
   lg_dia = MAX(dia1, dia2);

   /* --- SINGLE SEGMENT LOG --- */
   if (length <= MAX_SCALING_LENGTH)
      if (strcmpi(seg1_g, CULL) == 0)
         return (0);
      else {
         top_vol = vol(length-seg1_l, lg_dia-seg1_d) - 10*seg1_s;
         if (top_vol > 0)
            return (top_vol);
         else
            return (0);
      }

   /* --- TWO SEGMENT LOG --- */
   else if (length <= 2*MAX_SCALING_LENGTH) {

      /* divide log into two segments */
      btm_seg = logdivision[length-(MAX_SCALING_LENGTH+1)][0];
      top_seg = logdivision[length-(MAX_SCALING_LENGTH+1)][1];

      if (*butt != SPACE && *butt != NULLCHAR) {
         /* butt log */
         taper = (length < 27) ? 2 : 4;
         sm_dia = lg_dia;
      }
      else {
         /* non-butt log */
         taper = lg_dia - sm_dia;
         if (taper % 2 == 1) taper++;
      }

      /* compute volume of bottom segment */
      if (strcmpi(seg1_g, CULL) == 0)
         btm_vol = 0;
      else
         btm_vol = vol(btm_seg-seg1_l, sm_dia + taper/2 - seg1_d) - 10*seg1_s;

      /* compute volume of top segment */
      if (strcmpi(seg2_g, CULL) == 0)
         top_vol = 0;
      else
         top_vol = vol(top_seg-seg2_l, sm_dia - seg2_d) - 10*seg2_s;

      /* return the sum of the volumes of the top and bottom segments */
      if (top_vol + btm_vol > 0)
         return (top_vol + btm_vol);
      else
         return (0);
   }

   /* --- THREE SEGMENT LOG --- */
   else {

      /* divide log into three segments */
      btm_seg = logdivision[length-(MAX_SCALING_LENGTH+1)][0];
      mid_seg = logdivision[length-(MAX_SCALING_LENGTH+1)][1];
      top_seg = logdivision[length-(MAX_SCALING_LENGTH+1)][2];

      if (*butt != SPACE && *butt != NULLCHAR) {
         /* butt log */
         taper = (length < 47) ? 4 : 6;
         sm_dia = lg_dia;
      }
      else {
         /* non-butt log */
         taper = lg_dia - sm_dia;
      }

      /* raise the total taper to a number divisible by 3 and divide.  */
      /* This is the amount of taper assigned to the top segment.      */
      /* Distribute the remainder of the taper as in a two-segment log */
      top_taper = taper;
      while (top_taper % 3 != 0) top_taper++;
      taper -= top_taper/3;
      if (taper % 2 == 1) taper++;

      /* compute volume of bottom segment */
      if (strcmpi(seg1_g, CULL) == 0)
         btm_vol = 0;
      else
         btm_vol = vol(btm_seg-seg1_l, sm_dia+top_taper/3+taper/2-seg1_d)
                      - 10*seg1_s;

      /* compute volume of middle segment */
      if (strcmpi(seg2_g, CULL) == 0)
         mid_vol = 0;
      else
         mid_vol = vol(mid_seg-seg2_l, sm_dia + top_taper/3 - seg2_d)
                      - 10*seg2_s;

      /* compute volume of top segment */
      if (strcmpi(seg3_g, CULL) == 0)
         top_vol = 0;
      else
         top_vol = vol(top_seg-seg3_l, sm_dia - seg3_d) - 10*seg3_s;

      /* return the sum of the volumes of the top, middle, */
      /* and bottom segments                               */
      if (top_vol + mid_vol + btm_vol > 0)
         return (top_vol + mid_vol + btm_vol);
      else
         return (0);

   }  /* end else */

}  /* end net */