//
// shaping.cpp
//
// Written by John A deLaubenfels, https://www.adaptune.com/steg.htm .
// Permission granted to use freely in any non-fraudulent way.
//
//
// NOTE: known weakness as of 10-07-02: if two guys with the exact same
// input value, bad things happen:
//
//     . the guys can't be ordered properly: there is ambiguity.
//     . did I mention that the program will blow up if you try to extract that value?  Or will it?
//
//
//



#ifdef NEED_PCH
   #include "pch.h"
#else
   #include "stdafx.h"
#endif // !NEED_PCH

#include <stdio.h>
#include <string.h>
#include <assert.h>

#include <math.h>
#include <sys/stat.h>
#include <time.h>
#include "globs.h"
#include "bufin.h"
#include "randd.h"
#include "shaping.h"

#ifdef _WIN32
#include <conio.h>
#endif // _WIN32

// qxShaping()

Shaping::Shaping(double dIn, double dOut) 

: m_next(NULL)
, m_myValIn(dIn)
, m_myValOut(dOut)

{
}




Shaping::Shaping(const Shaping& rs) {  // copy constructor...
   m_next     = NULL;         // till set.
   m_myValIn  = rs.myValIn();
   m_myValOut = rs.myValOut();
}




Shaping::~Shaping() {
}




//
//
//
//
//
// qxShaping::operator=()
//

const Shaping& Shaping::operator=(const Shaping& rs) {

   if(&rs != this) {
      m_myValIn  = rs.myValIn();
      m_myValOut = rs.myValOut();
   } // if(&rs != this)

   return *this;
} // end of Shaping::operator=()...



// qxShaping::memoryUnderMySway()
//

int Shaping::memoryUnderMySway() const {

   return sizeof(Shaping);
}





// qxShapingAnch()

ShapingAnch::ShapingAnch() {
   m_shapeName = NULL;
   m_shapeBone = NULL;
   m_nBone     = NADA;
   m_sillyLin  = 0;               // 10-07-02
}




ShapingAnch::ShapingAnch(const ShapingAnch& rs) {  // copy constructor...
   m_next     = NULL;         // till set.
   m_myValIn  = rs.myValIn();
   m_myValOut = rs.myValOut();
   m_sillyLin = rs.sillyLin();     // 10-07-02

   m_shapeName = NULL;
   m_shapeBone = NULL;
   m_nBone     = NADA;

   if(rs.shapeName() != NULL) this->shapeName(rs.shapeName());

   const Shaping *shp;

   for(shp=rs.next(); shp!=NULL; shp=shp->next()) {
      this->dlinkMe(shp);
   } // for(shp=rs.next(); shp!=NULL; shp=shp->next())

   if(rs.shapeBone() != NULL) this->make_bone();

}




ShapingAnch::~ShapingAnch() {
   // if(m_shapeName != NULL) delete [] m_shapeName;  // will be done by free_list(), and if WE wanted to do it, we need to set m_shapeName to NULL!!!

   this->free_list();  // frees shapeName and shapeBone as well...
}





//
//
//
//
//
// qxShapingAnch::operator=()
//

const ShapingAnch& ShapingAnch::operator=(const ShapingAnch& rs) {

   if(&rs != this) {
      this->free_list();

      m_myValIn  = rs.myValIn();
      m_myValOut = rs.myValOut();
      m_sillyLin = rs.sillyLin();     // 10-07-02

      this->shapeName(rs.shapeName());

      const Shaping *shp;

      for(shp=rs.next(); shp!=NULL; shp=shp->next()) {
         this->dlinkMe(shp);
      } // for(shp=rs.next(); shp!=NULL; shp=shp->next())

      if(rs.shapeBone() != NULL) this->make_bone();

   } // if(&rs != this)

   return *this;
} // end of ShapingAnch::operator=()...





// qxShapingAnch::memoryUnderMySway()
//

int ShapingAnch::memoryUnderMySway() const {
   int myMem = sizeof(ShapingAnch);

   if(m_shapeName != NULL) {
      myMem += (int)strlen(m_shapeName) + 1;
   } // if(m_shapeName != NULL)

   if(m_shapeBone != NULL) {
      myMem += m_nBone * sizeof(Shaping *);
   } // if(m_shapeName != NULL)

   Shaping *shp;

   for(shp=this->m_next; shp!=NULL; shp=shp->next()) {
      myMem += shp->memoryUnderMySway();
   } // for(shp=this->m_next; shp!=NULL; shp=shp_next) {

   return myMem;
}




//
// New 05-06-02
//
//
//
//
// qxshapeName()
//

const char *ShapingAnch::shapeName(const char *newName) {
   if(m_shapeName != NULL) {
      delete [] m_shapeName;
      m_shapeName = NULL;
   } // if(m_shapeName != NULL)

   if(newName == NULL) return NULL;

   m_shapeName = new char[strlen(newName) + 1];
   
#ifdef _WIN32   
   strcpy_s(m_shapeName, strlen(newName)+1, newName);
#else   
   strcpy(m_shapeName, newName);   
#endif // !_WIN32   

   return m_shapeName;
} // end of shapeName()...




// qxfree_bone()

int ShapingAnch::free_bone() {
   if(shapeBone() != NULL) {
      delete [] m_shapeBone;
      m_shapeBone=NULL;
   }
   m_nBone = NADA;
   return 0;
} // end of free_bone()...






// qxmake_bone()

int ShapingAnch::make_bone() {
   int i;

   // if one exists, get rid of it:
   this->free_bone();

   int ict = this->subCt();
   if(ict <= 0) return NADA;

   m_nBone     = ict;
   m_shapeBone = new const Shaping *[m_nBone];

   Shaping *shp;

   for(i=0, shp=this->next(); shp!=NULL; i++, shp=shp->next()) {
      m_shapeBone[i] = shp;
   } // for(shp=this->m_next; shp!=NULL; shp=shp_next) {

   JASSERT(i == m_nBone);

   return 0;
} // end of make_bone()...





//
//
//
//
//
//
//
//
// 08-19-17 (jdl): check for backbone; if present, don't scan.
//
// qxShapingAnch::subCt()
//

int ShapingAnch::subCt() const {
   int ict = 0;

   const Shaping **shpp = this->shapeBone();
   if(shpp == NULL) {
      const Shaping *shp;

      for(shp=this->next(); shp!=NULL; shp=shp->next())
         ict++;
   } else {
      ict = m_nBone;
   } // !if(shpp == NULL)

   return ict;
} // end of ShapingAnch::subCt()...






//
//
// qxShapingAnch::free_list()
//

int ShapingAnch::free_list() {
   int ict = 0;

   this->free_bone();       // 05-07-02
   this->shapeName(NULL);   // 05-06-02

   Shaping *shp, *shp_next;

   for(shp=this->m_next; shp!=NULL; shp=shp_next) {
      shp_next = shp->m_next;
      delete shp;
      ict++;
   } // for(shp=this->m_next; shp!=NULL; shp=shp_next) {

   this->m_next = NULL;

   return ict;
} // end of ShapingAnch::free_list()...




//
//
//
//
//
//
// 08-01-17 (jdl): fp_inf (default NULL)
// 06-16-22 (jdl): cut line into tokens.
//
// qxShapingAnch::read_list()
// qxread_list()
//

int ShapingAnch::read_list(const char *fileName, FILE *fp_inf) {

   this->free_list();    // start fresh

   Bufin *bip = new Bufin(fileName);

   if(!bip->is_active()) {
      delete bip;
      return NADA;
   } // if(!bip->is_active())

   this->shapeName(fileName);   // 05-06-02

   const char *cp_buf;

   while((cp_buf=bip->get_line()) != NULL) {
      // hmmm, just something really simple:
      std::vector<std::string> vcToks;
      int nTok = cutLineIntoTokens(cp_buf, vcToks);
      if(nTok < 2)
         continue;

      double      val1 = atof(vcToks[0].c_str());
      double      val2 = atof(vcToks[1].c_str());

      Shaping *shp_nuu = new Shaping(val1, val2);

      this->linkMe(shp_nuu);
   } // while((cp_buf=bip->get_line()) != NULL)

   delete bip;

   this->make_bone();

   if(fp_inf != NULL) {
      fprintf(fp_inf, "\nContents of shaping file %s:\n", fileName);
      this->write_list(fp_inf);
      fprintf(fp_inf, "[eof]\n\n");
   } // if(fp_inf != NULL)

   return 0;
} // end of read_list()




//
// new 05-07-02
//
//
//
//
// qxShapingAnch::write_list()
// qxwrite_list()
//

int ShapingAnch::write_list(const char *fileName) const {
   FILE *fp_out;

   if(fileName == NULL) return NADA;
   arcMeSimple(fileName);              // 10-19-16

   // if(fopen_s(&fp_out, fileName, "w") != 0) return NADA;
#ifdef _WIN32
   if(fopen_s(&fp_out, fileName, "w") != 0) return NADA;
#else   
   if((fp_out = fopen(fileName, "w")) == NULL) return NADA;   
#endif // !_WIN32   

   int iRet = this->write_list(fp_out);

   fclose(fp_out); fp_out=NULL;

   return iRet;
} // end of write_list()...






//
// new 05-07-02
//
//
//
//
// qxShapingAnch::write_list()
// qxwrite_list()
//

int ShapingAnch::write_list(const char *fileName) {
   FILE *fp_out;

   if(fileName == NULL) return NADA;
   arcMeSimple(fileName);              // 10-19-16

#ifdef _WIN32
   if(fopen_s(&fp_out, fileName, "w") != 0) return NADA;
#else   
   if((fp_out = fopen(fileName, "w")) == NULL) return NADA;   
#endif // !_WIN32   

   int iRet = this->write_list(fp_out);

   fclose(fp_out); fp_out=NULL;

   if(iRet == 0) {
      this->shapeName(fileName);  // why not?
   } // if(iRet == 0)

   return iRet;
} // end of write_list()...





//
// qxformatDouble()
//

static const char *formatDouble(double dval, int maxWidth, int maxPrec, char *cval=NULL) {
	static char cLocalBuf[256];
	static char *cbuffer;
	if(cval!=NULL) {
		cbuffer = cval;
   } else {
		cbuffer = cLocalBuf;
   }

#ifdef _WIN32
	sprintf_s(cbuffer, 256, "%*.*f", maxWidth, maxPrec, dval);
#else	
	sprintf(cbuffer, "%*.*f", maxWidth, maxPrec, dval);	
#endif // !_WIN32	

	// just chop off anything that goes too far.
	cbuffer[maxWidth] = '\0';


	return cbuffer;
}//formatDouble()




//
// new 05-07-02
//
//
//
//
//
//
// 01-02-12 (jdl): try to be smarter about formatting, to get maximum precision in the first value.
//
// qxShapingAnch::write_list()
// qxwrite_list()
//

int ShapingAnch::write_list(FILE *fp_out) const {
   const Shaping *shp, *shp_next;

   if(fp_out == NULL)       return NADA;
   if(this->m_next == NULL) return NADA;

   int ict = 0;

   for(shp=this->m_next; shp!=NULL; shp=shp_next) {
      shp_next = shp->m_next;

      // fprintf(fp_out, "%9.5f %9.5f\n", shp->myValIn(), shp->myValOut());
      fprintf(fp_out, "%10s %.8f\n", formatDouble(shp->myValIn(), 10, 8), shp->myValOut());  // we claim one more column.
      ict++;
   } // for(shp=this->m_next; shp!=NULL; shp=shp_next) {

   return 0;
} // end of write_list()...





//
// new 10-07-02
//
//
//
//
// qxaddPair()
//

int ShapingAnch::addPair(double valIn, double valOut) {
   Shaping ash;
   ash.myValIn(valIn);
   ash.myValOut(valOut);

   int iRet = this->dlinkMe(&ash);

   return iRet;
} // end of addPair()






//
//
//
//
//
//
// qxShapingAnch::linkMe()
//

int ShapingAnch::linkMe(Shaping *shpAdd) {
   Shaping *shp, *shp_next;

   if(shpAdd == NULL) return NADA;

   this->free_bone();

   // we start with the anchor itself, though we won't accumulate to it:
   for(shp=this; shp!=NULL; shp=shp_next) {
      shp_next = shp->m_next;

      // do we need to insert before the next guy???
      int insert = 0;
      // int merge  = 0;

      if(shp_next == NULL) {
         insert = 1;
      } else {
         // as soon as the next is higher than us, jump in!
         if(shp_next->myValIn() > shpAdd->myValIn()) {
            insert = 1;
         } // if(shp_next->myValIn() > shpAdd->myValIn())
      } // shp_next != NULL

      if(insert) {
         // Shaping *shp_nuu = new Shaping(*shpAdd);  // copy constr.
         Shaping *shp_nuu = shpAdd;
         shp->m_next     = shp_nuu;
         shp_nuu->m_next = shp_next;  // maybe NULL, maybe not.
         return 0;
      } // if(insert)
   } // for(shp=this->m_next; shp!=NULL; shp=shp_next) {

   // we should never get here:
   JASSERT(false);
   return NADA;
} // end of linkMe()




//
//
//
//
//
//
// qxShapingAnch::dlinkMe()
//

int ShapingAnch::dlinkMe(const Shaping *shpAdd) {

   Shaping *shp_nuu = new Shaping(*shpAdd);  // copy constr.

   int iRet = this->linkMe(shp_nuu);

   return iRet;
} // end of dlinkMe()...




//
// this function assumes an ordered linked list, which will always
// happen when the approved linkMe() and dlinkMe() functions have
// been used.
//
//
//
//
// 11-08-02: change extrapolation method.  Well, just patch a <=...
// 04-08-19: verySmall to avoid division by zero.
//
// qxinToOut()
//

double ShapingAnch::inToOut(double valIn) const {
   double valOut;
   const double verySmall = 1.0E-100;
   const Shaping *shp, *shp_next;

   int iDoDbg = 0;

   // sanity check: do we even have ANYTHING?
   if(this->next() == NULL) return valIn;

   // new check 11-08-02: do we have just ONE???
   if(this->next()->next() == NULL) {
      if(this->sillyLin()) {
         // new option 10-07-02:
         valOut = this->next()->myValOut() + (valIn - this->next()->myValIn());
      } else {
         // always, before 10-07-02:
         double divisor = this->next()->myValIn();
         if(divisor == 0.0) divisor = .0001;         // crude...
         valOut = this->next()->myValOut() * (valIn / divisor);
      } // !if(this->sillyLin())
      return valOut;
   } // if(this->next()->next() == NULL)

   const Shaping **shpp = this->shapeBone();
   if(shpp == NULL) {
      // always before 05-07-02: linear walk thru sorted guys:
      // extrapolation on the low side:
      if(this->next()->myValIn() > valIn) {
         // wow!  We're lower than the lowest guy!
         if(this->sillyLin()) {
            // new option 10-07-02:
            // valOut = shpp[0]->myValOut() + (valIn - shpp[0]->myValIn());
            valOut = this->next()->myValOut() + (valIn - this->next()->myValIn());  // last term negative
         } else {
            // always, before 10-07-02:
            // valOut = shpp[0]->myValOut() * (valIn / shpp[0]->myValIn());
            valOut = this->next()->myValOut() * (valIn / this->next()->myValIn());
         } // !if(this->sillyLin())
         return valOut;
      } // if(this->next()->myValIn() > valIn)

      // interpolate while watching for extrapolation on the high side:
      // we start with the anchor itself, though we won't really use it:
      for(shp=this; shp!=NULL; shp=shp_next) {
         shp_next = shp->m_next;

         // extrapolation on the high side:
         if(shp_next == NULL) {
            // wow!  We're higher than the highest guy!

            if(this->sillyLin()) {
               // new option 10-07-02:
               // valOut = shpp[m_nBone-1]->myValOut() + (valIn - shpp[m_nBone-1]->myValIn());
               valOut = shp->myValOut() + (valIn - shp->myValIn());
            } else {
               // always, before 10-07-02:
               // valOut = shpp[m_nBone-1]->myValOut() * (valIn / shpp[m_nBone-1]->myValIn());
               valOut = shp->myValOut() * (valIn / shp->myValIn());
            } // !if(this->sillyLin())

            return valOut;
         } // if(shp_next == NULL)

         // interpolate?
         if(shp_next->myValIn() >= valIn) {
            double dRat = (valIn - shp->myValIn()) / MAX(verySmall, (shp_next->myValIn() - shp->myValIn()));  // how far along the line; expect range 0.0 .. 1.0

            if(this->sillyLin()) {
               // new option 10-07-02:
               if(dRat >= 0.5) {
                  // come down from the upper value:
                  // valOut = shpp[iHii]->myValOut() + (valIn - shpp[iHii]->myValIn());  // last term is negative.
                  valOut = shp_next->myValOut() + (valIn - shp_next->myValIn());  // last term is negative.
               } else {
                  // go up from the lower value:
                  // valOut = shpp[iLow]->myValOut() + (valIn - shpp[iLow]->myValIn());
                  valOut = shp->myValOut() + (valIn - shp->myValIn());
               } // !if(dRat >= 0.5)
            } else {
               // always, before 10-07-02:
               // valOut = shpp[iLow]->myValOut() + dRat * (shpp[iHii]->myValOut() - shpp[iLow]->myValOut());
               valOut = shp->myValOut() + dRat * (shp_next->myValOut() - shp->myValOut());
            } // !if(thisi->sillyLin())

            return valOut;
         } // if(shp_next->myValIn() >= valIn)
      } // for(shp=this; shp!=NULL; shp=shp_next)
   } else {
      // new shapeBone 05-07-02: binary search:

      // extrapolation on the low side:
      // if(shpp[0]->myValIn() >= valIn) {  // out 11-08-02
      if(shpp[0]->myValIn() > valIn) {
         // wow!  We're lower than the lowest guy!
         if(this->sillyLin()) {
            // new option 10-07-02:
            valOut = shpp[0]->myValOut() + (valIn - shpp[0]->myValIn());
         } else {
            // always, before 10-07-02:
            valOut = shpp[0]->myValOut() * (valIn / shpp[0]->myValIn());
         } // !if(this->sillyLin())
         return valOut;
      } // if(shpp[0]->myValIn() >= valIn)

      // extrapolation on the high side:
      // if(shpp[m_nBone-1]->myValIn() <= valIn) {  // out 11-08-02
      if(shpp[m_nBone-1]->myValIn() < valIn) {
         // wow!  We're higher than the highest guy!
         if(this->sillyLin()) {
            // new option 10-07-02:
            valOut = shpp[m_nBone-1]->myValOut() + (valIn - shpp[m_nBone-1]->myValIn());
         } else {
            // always, before 10-07-02:
            valOut = shpp[m_nBone-1]->myValOut() * (valIn / shpp[m_nBone-1]->myValIn());
         } // !if(this->sillyLin())
         return valOut;
      } // if(shpp[m_nBone-1]->myValIn() <= valIn)

      // play the binary game:
      JASSERT(m_nBone >= 2);    // or else we'd kick about above, and barf below.
      int iLow = 0;
      int iHii = m_nBone-1;
      int tRue = 1;

      if(iDoDbg) qprintf(fp_dbg, "m_nBone %d\n", m_nBone);

      while(tRue) {
         if(iHii == (iLow+1)) break;

         int iMid = (iHii + iLow) / 2;
         if(shpp[iMid]->myValIn() < valIn) {  // or >=, either ok.
            iLow = iMid;
            if(iDoDbg) qprintf(fp_dbg, "iLow    %d\n", iLow);
         } else {
            iHii = iMid;
            if(iDoDbg) qprintf(fp_dbg, "iHii    %d\n", iHii);
         } // !if(shpp[iMid]->myValIn() < valIn)
      } // while(tRue)

      double dRat = (valIn - shpp[iLow]->myValIn()) / MAX(verySmall, (shpp[iHii]->myValIn() - shpp[iLow]->myValIn()));  // how far along the line; expect range 0.0 .. 1.0
      if(this->sillyLin()) {
         // new option 10-07-02:
         if(dRat >= 0.5) {
            // come down from the upper value:
            valOut = shpp[iHii]->myValOut() + (valIn - shpp[iHii]->myValIn());  // last term is negative.
         } else {
            // go up from the lower value:
            valOut = shpp[iLow]->myValOut() + (valIn - shpp[iLow]->myValIn());
         } // !if(dRat >= 0.5)
      } else {
         // always, before 10-07-02:
         valOut = shpp[iLow]->myValOut() + dRat * (shpp[iHii]->myValOut() - shpp[iLow]->myValOut());
      } // !if(thisi->sillyLin())
      if(iDoDbg) {
         qprintf(fp_dbg, "Low in, out %8.4f %8.4f; Hii in, out %8.4f %8.4f; actual in, out %8.4f %8.4f\n", shpp[iLow]->myValIn(), shpp[iLow]->myValOut(), shpp[iHii]->myValIn(), shpp[iHii]->myValOut(), valIn, valOut); // qxtemp!!!
      } // if(iDoDbg)
      return valOut;

   } // !if(shpp == NULL)

   // should never get here!
   JASSERT(false);
   return DADA;
} // end of inToOut()...






//
// new 08-19-17
//
//
//
//
//
// qxbIsInRange()
//

bool ShapingAnch::bIsInRange(double valIn) const {
   // double valOut;
   const Shaping *shp, *shp_next;

   int iDoDbg = 0;

   // sanity check: do we even have ANYTHING?
   if(this->next() == NULL) return false;


   const Shaping **shpp = this->shapeBone();
   if(shpp == NULL) {
      if(this->next()->myValIn() > valIn) {
         // wow!  We're lower than the lowest guy!
         return false;
      } // if(this->next()->myValIn() > valIn)

      // interpolate while watching for extrapolation on the high side:
      // we start with the anchor itself, though we won't really use it:
      for(shp=this; shp!=NULL; shp=shp_next) {
         shp_next = shp->m_next;

         // extrapolation on the high side:
         if(shp_next == NULL) {
            // wow!  We're higher than the highest guy!
            return false;
         } // if(shp_next == NULL)

         // are we done?
         if(shp_next->myValIn() >= valIn)
            return true;
      } // for(shp=this; shp!=NULL; shp=shp_next)
   } else {
      if(shpp[0]->myValIn() > valIn) {
         // wow!  We're lower than the lowest guy!
         return false;
      } // if(shpp[0]->myValIn() >= valIn)

      // extrapolation on the high side:
      // if(shpp[m_nBone-1]->myValIn() <= valIn) {  // out 11-08-02
      if(shpp[m_nBone-1]->myValIn() < valIn) {
         // wow!  We're higher than the highest guy!
         return false;
      } // if(shpp[m_nBone-1]->myValIn() <= valIn)

      return true;

   } // !if(shpp == NULL)

   // should never get here!
   return false;
} // end of bIsInRange()...






//
// new 11-16-04.  Assumes usual sorted list.
//
//
//
//
//
//
//
// qxmaxIn()
//

double ShapingAnch::maxIn() const {
   const Shaping *shp;

   // sanity check: do we even have ANYTHING?
   if(this->next() == NULL) return DADA;

   for(shp=this; ; shp=shp->m_next) {
      if(shp->m_next == NULL) break;
   } // for(shp=this; ; shp=shp->m_next)


   double dRet = shp->myValIn();

   return dRet;
} // end of maxIn()...



//
// new 07-20-18
//
//
//
//
//
// qxgetIth()
//

int ShapingAnch::getIth(int i, double &dFirstOut, double &dSecondOut) const {
   dFirstOut = dSecondOut = -1.0;   // error return (plus, we'll return NADA).

   const Shaping **shpp = this->shapeBone();
   if(shpp == NULL) {
      const Shaping *shp;
      int ict = 0;

      for(shp=this->next(); shp!=NULL; shp=shp->next()) {
         if(ict == i) {
            dFirstOut  = shp->myValIn();
            dSecondOut = shp->myValOut();

            return 0;
         } // if(ict == i)

         ict++;
      } // for(shp=this->next(); shp!=NULL; shp=shp->next())
   } else {
      if((i < 0) || (i >= m_nBone)) {
         // fall through and return NADA;
      } else {
         const Shaping *shp = shpp[i];
         dFirstOut  = shp->myValIn();
         dSecondOut = shp->myValOut();

         return 0;
      } // !if((i < 0) || (i >= m_nBone))
   } // !if(shpp == NULL)

   return NADA;   // out of range.
} // int ShapingAnch::getIth(int i, double &dFirstOut, double &dSecondOut) const




//
// new 06-24-22
//
// Input:
//    factr (default 1.0)
//    offst (default 0.0)
//
// Output:
//    return value: 0
//    "X" (aka "In") values modified if factr != 1.0 or offst != 0.0 .
//
//
//
// qxtransformIn()
//

int ShapingAnch::transformIn(double factr, double offst) {
   if((factr == 1.0) && (offst == 0.0))
      return 0;

   for(Shaping *psh=this->next(); psh!=NULL; psh=psh->next())
      psh->myValIn(offst   +   factr * psh->myValIn());

   return 0;
} // int ShapingAnch::transformIn(double factr, double offst)





//
// new 06-24-22
//
// Input:
//    factr (default 1.0)
//    offst (default 0.0)
//
// Output:
//    return value: 0
//    "Y" (aka "Out") values modified if factr != 1.0 or offst != 0.0 .
//
//
//
// qxtransformOut()
//

int ShapingAnch::transformOut(double factr, double offst) {
   if((factr == 1.0) && (offst == 0.0))
      return 0;

   for(Shaping *psh=this->next(); psh!=NULL; psh=psh->next())
      psh->myValOut(offst   +   factr * psh->myValOut());

   return 0;
} // int ShapingAnch::transformOut(double factr, double offst)






