//**************************************************************************
/*
 *
 * Copyright (C) 2015 CADCAM-Services Franz Reiter (franz.reiter@cadcam.co.at)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 *
-----------------------------------------------------
TODO:
  ..

-----------------------------------------------------
Modifications:
2017-11-30 new, rewritten ../gr/tess_su.c (tess. with GLU). RF.

-----------------------------------------------------
*/
#ifdef globTag
void SUR(){}
#endif
/*!
\file  ../ut/ut_sur1.c
\brief Surface functions (tesselate, ..)
\code
=====================================================
List_functions_start:

SUR_dbo_ib_oSur       get dbo of surface-subObject from surface-ogx

List_functions_end:
=====================================================



=====================================================
*/


#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../ut/ut_geo.h"              // Point ...
#include "../ut/ut_geo_const.h"        // _UT3D_VECTOR_NUL
#include "../ut/ut_memTab.h"           // MemTab_..
#include "../ut/ut_itmsh.h"            // MSHIG_EDGLN_.. typedef_MemTab.. Fac3
// #include "../ut/ut_face.h"              // UFA
#include "../ut/ut_ox_base.h"          // OGX_SET_INDEX
#include "../ut/ut_os.h"               // OS_get_tmp_dir
#include "../ut/msh2d.h"               // MSH2D TessStru
#include "../ut/ut_sur.h"              // SurStru

#include "../db/ut_DB.h"               // DB_get_..

#include "../xa/xa_mem.h"              // memspc51, mem_cbuf1
#include "../xa/xa_msg.h"              // MSG_*

// #include "../xa/xa_ato.h"              // ATO_getSpc_tmp__



// Externals aus ../xa/xa.c:
// extern char      AP_mod_fnam[128];
// extern Plane     WC_sur_act;            // die aktive Plane
extern int       WC_modact_ind;         // -1=primary Model is active;
                                        // else subModel is being created


//----------------------------------------------------------------
// local vars:
static MSH2D_STRU (MSH__);            // define MSH2D_STRU in ../ut/msh2d.h

// static char SUR_DAT__[128];
// static SUR_DAT_pln *SUR_dat_pln;
// static SUR_DAT_bsp *SUR_dat_bsp;
union {SUR_DAT_pln pln;
       SUR_DAT_bsp bsp;
      } SUR_DAT__;


#ifdef _MSC_VER
static SurStru SUR__;

#else
  // C99
static SurStru SUR__ = {
                   .vcz = _UT3D_VECTOR_NUL, // normalvector - only for planar
                   .col = _ColRGB_NUL};     // color|texture
#endif





//================================================================
  int SUR_view__ (long dbi) {
//================================================================
// display surface in structs SUR__/MSH__
// MSHIG_view__ 
// ../xa/tst_glDrawElements1.c tst_glDrawElements1.mak
// GL_Disp_ipatch GL_Disp_nifac UFA_view_nifac

 
  int    ii, sTyp;

  printf("SUR_view__ %ld\n",dbi);


// TODO: compare dbi - SUR__.ssdbi ?

  // get planar or not
  ii = MEMTAB_IND (&MSH__.vc3);
  if(ii == 1) sTyp = Typ_SURPLN;
  else        sTyp = Typ_SUR;


    UFA_view_nifac (MEMTAB_IND (&MSH__.fac),
                    MEMTAB_DAT (&MSH__.fac),
                    MEMTAB_DAT (&MSH__.ipa),
                    MEMTAB_DAT (&MSH__.pa3),
                    MEMTAB_DAT (&MSH__.vc3),
                    dbi,
                    sTyp);


  return 0;

}


//================================================================
  int SUR_init__ () {
//================================================================
// init 
// get SUR__ = static space for active surface;
// get MSH__ = static space for 2D-tesselation of active surface;


  printf("SUR_init__ \n");


  return 0;

}
 

//================================================================
  int SUR_stps_oxs (ObjGX *ox_stps, ObjGX *ox_sur, Memspc *wrkSpc) {
//================================================================
// get TPS-surface from complex-surface
// Input:
//   ox_sur       surface to handle
// Output:
//   ox_stps     trimmed-perforated-supported from ox_sur


  int     irc;
  long    dbob;
  ObjGX   *oxTab;


  UT3D_stru_dump (Typ_ObjGX, ox_sur, "SUR_stps_oxs");

/*
   //================================================================
  // Typ_SURTPS = already surface-trimmed-perforated-supported; OK.
  // see APT_decode_su_pln ..
  if((ox_sur->typ == Typ_SURTPS) ||
     (ox_sur->typ == Typ_SURBSP))   {
    *ox_stps = *ox_sur;
    return 0;
  }

  //================================================================
  // Typ_SURBSP = supportsurface untrimmed unperforated , B_Spline_Surf (SurBSpl)
  // create boundary ..  was TSU_DrawSurBsp GL_sSym_sbsp
  if(ox_sur->typ == Typ_SURBSP) {

    // get space for 2 ObjGX
    oxTab = UME_reserve (wrkSpc, sizeof(ObjGX) * 2);
    if(oxTab == NULL) return -1;

    // ox[0] = supporting-surface Typ_SURBSP (SurBSpl)
    OGX_SET_INDEX (&oxTab[0], Typ_SURBSP, dbi);

    // get outer-boundary CurvCCV = 4 x CurvBSpl
    irc = TSU_cv_sbsp (&dbob, ox_sur);
    if(irc < 0) return -1;
    OGX_SET_INDEX (&oxTab[1], Typ_CVTRM, dbob);
    // ox[1] = outer-boundary
    // oxTab[1] = .;

    ox_stps->typ    = Typ_SURTPS;
    ox_stps->form   = Typ_ObjGX;
    ox_stps->siz    = 2;
    ox_stps->data   = oxTab;
    return 0;
  }

*/


  //================================================================
  TX_Error("SUR_stps_oxs sur NYI form=%d",ox_sur->form);
  return -1;

}


//================================================================
  int SUR_rdf__ (long dbi) {
//================================================================
// load binary-mesh from file
// see test_MSH_rdf__ TSU_rdf__ MSHIG_rdf__

static char cTyp='A';   // surf

  FILE      *fp1;
  char      ofid[128];
  TessStru  *ts1;


  printf("SUR_rdf__ \n");


  // init ts1
  ts1 = &MSH__;
  MSH2D_memspc_init (ts1, SUR_NR_PTS);


  // if(ts1->mdli >= 0) {           // 0-n = sind in Submodel; -1=main
    // sprintf(ofid,"%sM%d_%c%ld.odat",OS_get_tmp_dir(),cTyp,ts1->mdli,ts1->dbi);
  // } else {
    sprintf(ofid,"%s%c%ld.test_odat",OS_get_tmp_dir(),cTyp,dbi);
  // }
    printf(" ofid=|%s|\n",ofid);


  if((fp1=fopen(ofid,"rb")) == NULL) {
    // TX_Print("test_MSH_rdf__ E001 |%s|",ofid);
    MSG_STD_ERR (ERR_file_open, "'%s'", ofid);
    return -1;
  }


  // get data
  MemTab_rdf (fp1, &ts1->tab);
  MemTab_rdf (fp1, &ts1->ipa);
  MemTab_rdf (fp1, &ts1->pa3);
  MemTab_rdf (fp1, &ts1->pa2);
  MemTab_rdf (fp1, &ts1->vc3);
  MemTab_rdf (fp1, &ts1->fac);
  MemTab_rdf (fp1, &ts1->fnb);

  fread(&ts1->gbx, sizeof(GridBox), 1, fp1);
  fread(&ts1->tol, sizeof(double), 1, fp1);

  fclose(fp1);

    // TESTBLOCK
    UT3D_stru_dump (Typ_MemTab, &ts1->tab, ".tab-rdf");
    UT3D_stru_dump (Typ_MemTab, &ts1->ipa, ".ipa-rdf");
    UT3D_stru_dump (Typ_MemTab, &ts1->pa3, ".pa3-rdf");
    UT3D_stru_dump (Typ_MemTab, &ts1->pa2, ".pa2-rdf");
    UT3D_stru_dump (Typ_MemTab, &ts1->vc3, ".vc3-rdf");
    UT3D_stru_dump (Typ_MemTab, &ts1->fac, ".fac-rdf");
    UT3D_stru_dump (Typ_MemTab, &ts1->fnb, ".fnb-rdf");
    UT3D_stru_dump (Typ_GridBox, &ts1->gbx, ".gbx-rdf");
    printf(" tol=%f\n",ts1->tol);
    MemTab_dump (&ts1->tab, ".tab-rdf");
    // END TESTBLOCK


  return 0;

}
  

//================================================================
  int SUR_wrf__ (long dbi) {
//================================================================
// store binary-mesh into file
// see test_MSH_wrf__ MSH_bsav_fTab 


static char cTyp='A';   // surf

  FILE      *fp1;
  char      ofid[128];
  TessStru  *ts1;



  ts1 = &MSH__;


  // if(ts1->mdli >= 0) {           // 0-n = sind in Submodel; -1=main
    // sprintf(ofid,"%sM%d_%c%ld.odat",OS_get_tmp_dir(),cTyp,ts1->mdli,ts1->dbi);
  // } else {
  // get filename; see MSHIG_fnam TSU_wrf__
  sprintf(ofid,"%s%c%ld.test_odat",OS_get_tmp_dir(),cTyp,dbi);


    printf("SUR_wrf__ |%s|\n",ofid);
    UT3D_stru_dump (Typ_MemTab, &ts1->tab, ".tab-wrf");
    UT3D_stru_dump (Typ_MemTab, &ts1->ipa, ".ipa-wrf");
    UT3D_stru_dump (Typ_MemTab, &ts1->pa3, ".pa3-wrf");
    UT3D_stru_dump (Typ_MemTab, &ts1->pa2, ".pa2-wrf");
    UT3D_stru_dump (Typ_MemTab, &ts1->fac, ".fac-wrf");
    UT3D_stru_dump (Typ_MemTab, &ts1->fnb, ".fnb-wrf");
    UT3D_stru_dump (Typ_GridBox, &ts1->gbx, ".gbx-wrf");
    printf(" tol=%f\n",ts1->tol);
    MemTab_dump (&ts1->tab, ".tab-rdf");


  if((fp1=fopen(ofid,"wb")) == NULL) {
    TX_Print("SUR_wrf__ E001 |%s|",ofid);
    return -1;
  }

  // write tab,pst,ipa,pa..
  MemTab_wrf (fp1, &ts1->tab);
  MemTab_wrf (fp1, &ts1->ipa);
  MemTab_wrf (fp1, &ts1->pa3);
  MemTab_wrf (fp1, &ts1->pa2);
  MemTab_wrf (fp1, &ts1->vc3);
  MemTab_wrf (fp1, &ts1->fac);
  MemTab_wrf (fp1, &ts1->fnb);

  // write gbx, tol
  fwrite(&ts1->gbx, sizeof(GridBox), 1, fp1);
  fwrite(&ts1->tol, sizeof(double), 1, fp1);

  fclose(fp1);

  return 0;

}


//================================================================
  int SUR_tess_dbo__ (long dbiSur) {
//================================================================
// load surface from db into SUR-surface SUR__/MSH__
// see TSU_stps_sur
// see MSHIG_init_sur


  int         irc, fNr;
  long        l1;
  ObjGX       *ox_sur, ox_tps;
  Memspc      wrkSpcT1;


  printf("SUR_tess_dbo__ %ld\n", dbiSur);


  // init|reset tess-struct TessStru MSH__
  MSH2D_memspc_init (&MSH__, SUR_NR_PTS);


  // init|reset SurStru SUR__
  SUR__.dbi  = dbiSur;
  SUR__.mdli = WC_modact_ind;


  // get SUR__ = surf out of DB                   see INF_???
  SUR__.oxs = DB_GetSur (dbiSur, 1);
  if(!SUR__.oxs->typ) return -1;
    UT3D_stru_dump (Typ_ObjGX, SUR__.oxs, "ox_sur-tess_dbo__");


  // SUR_stps_oxs nicht mehr erforderlich, da alle boundaries schon von
  // der APT_decode-funktion als curves erzeugt werden ?
  // // get TPS-surface from surface dbiSur
  // UME_init (&wrkSpcT1, memspc201, sizeof(memspc201));
  // irc = SUR_stps_oxs (&ox_tps, ox_sur, &wrkSpcT1);
  // if(irc < 0) return irc;


  //----------------------------------------------------------------
  // analyze support-surface:
  //   get ssTyp = surfacetype of support-surface; 
  //   get ssDbi = dbi of support-surface; (not for planar)
  irc = UTO_surfTyp_sur (&SUR__.ssTyp, &SUR__.ssDbi, &SUR__.ssDat, SUR__.oxs);
  if(irc < 0) return -1;
    printf(" ssTyp=%d ssDbi=%ld\n",SUR__.ssTyp,SUR__.ssDbi);


  //----------------------------------------------------------------
  // get 3D-points of boundary-curves -> MSH__
  // add all boundaries as indexed-points-curves to MSH__.tab,ipa,pa3
  // see MSH2D_bnd_add_dbo (ts1, Typ_CV, 21L, MSH_EDGLN_OB);
  // see test_SUR_bnd__
  irc = SUR_bnd_add_dbo ();
  if(irc < 0) return irc;


  //----------------------------------------------------------------
  // analyze support-surface, set functions tr_2D_3D, tr_3D_2D
  // store surface-specific-data in SUR__.td
  irc = SUR_ini__ ();
  if(irc < 0) return irc;


  //----------------------------------------------------------------
  // get 2D-points of boundary-curves;
  MSH2D_bnd_2D_3D (&MSH__, SUR__.tr_2D_3D);

     // TESTBLOCK
     // return -99;
     // END TESTBLOCK


  //----------------------------------------------------------------
  // get tolerances and grid for TPS-surface
  // define gridbox gbx from (uMin, uMax, vMin, vMax, uNr, vNr)
  // MSH2D_tess_grid (&ts1->gbx, 0.,   1.,   0.,   1.,   25,   25);
  // see test_MSH2D_ini ?
  irc = SUR_ini_gbx (&MSH__, &SUR__);
  if(irc < 0) return irc;



  //----------------------------------------------------------------
  // query additional necessary memspc for faces (fac, fnb) for gridbox
  fNr = MSH2D_facNrMax (&MSH__);
    // fNr = MSH2D_NR_PTS * 4;   // see UFA_fNr_max

  // prepare necessary memspc for faces
  MemTab_add (&MSH__.fac, &l1, NULL, fNr, 2);
  MemTab_add (&MSH__.fnb, &l1, NULL, fNr, 2);



  //================================================================
  // mesh (tesselate 2D)
  irc = MSH2D_tess__ (&MSH__,
                      0,             // 0=keep unused gridpoints, 1=delete
                      0);            // 0=do-NOT-optimize; 1=optimize.

    // TESTBLOCK
    printf("ex-_tess__-irc=%d pNr=%d\n",irc,MEMTAB_IND (&MSH__.pa2));
    // MemTab_dump (&MSH__.tab, ".tab-t");
    // MemTab_dump (&MSH__.pa2, ".pa2-t");
    // MSH2D_view_nfac ("pn", 0, -1, "---");
    // MSH2D_view_nfac (&MSH__, "pnbvfs", 0, -1, "---");
    // MSH2D_dump__ ("tess-exit");
    // DL_Redraw ();
    // END TESTBLOCK


  if(irc < -90) return irc;


  // get 3D-points and 3D-vectors for new created 2D-gridpoints
  if(SUR__.ssTyp != Typ_SURPLN) SUR_3D_2D_add ();


  return 0;

}
 

//================================================================
  int SUR_3D_2D_add () {
//================================================================
// get 3D-points and 3D-vectors for new created 2D-gridpoints
// Planar does not have grid-points
 
  int          i1, i2, ii, *ia;
  char         *pstat;
  Point2       *pa2;
  Point        *pa3;



  // get ia=list-gridpoints and status
  MSH2D_pgb_get (&ii, &ia, &pstat);

  // get data-blocks for points
  pa2 = MEMTAB_DAT (&MSH__.pa2);
  pa3 = MEMTAB_DAT (&MSH__.pa3);


  for(i1=0; i1<ii; ++i1) {
    if(pstat[i1] == 0) continue;          // skip stat=0 (point unused)
    i2 = ia[i1];                          // get index into pa2 & pa3 & vc3

    // get 3D-point from 2D-point
    SUR__.tr_3D_2D (&pa3[i2], &pa2[i2]);
    // get 3D-vector for 2D-gridpoint ..
    // test_MSH2D_vc_pt (&vc3[i2], &pa3[i2], NULL);
  }

    // TESTBLOCK
    // GL_att_pt (ATT_PT_YELLOW);
    // UFA_view_nifac (&tessDat, -1L, Typ_SUR);
    // vcf1.dx = 0.;
    // vcf1.dy = 0.;
    // vcf1.dz = 1.;
    // MemTab_add (&tessDat.vc3, &l1, &vcf1, 1, 0);
      // // MemTab_dump (&tessDat.vc3, "tessDat.vc3");
    // UFA_view_nifac (MEMTAB_IND (&tessDat.fac),
                    // MEMTAB_DAT (&tessDat.fac),
                    // MEMTAB_DAT (&tessDat.ipa),
                    // MEMTAB_DAT (&tessDat.pa3),
                    // MEMTAB_DAT (&tessDat.vc3), -1L, Typ_PLN);
    // END TESTBLOCK


  return 0;

}


//================================================================
  int SUR_ini__ () {
//================================================================
// analyze support-surface, set functions tr_2D_3D, tr_3D_2D
// store surface-specific-data in SUR__.td
// see TSU_test_tess__

  int  irc;


  printf("SUR_ini__ %d\n",SUR__.ssTyp);


  //----------------------------------------------------------------
  switch(SUR__.ssTyp) {

    case Typ_SURPLN:
      irc = SUR_pln_ini__ (&SUR__, &MSH__);
      break;


    default:
      TX_Error("SUR_ini__ E1-%d",SUR__.ssTyp);
      return -1;
  }




  return irc;

}


//================================================================
  int SUR_ini_gbx (TessStru *td, SurStru *sd) {
//================================================================
// set tolerances and grid

  printf("SUR_ini_gbx \n");


  //----------------------------------------------------------------
  switch(sd->ssTyp) {

    case Typ_SURPLN:
      SUR_pln_ini_gbx (td);
      break;


    default:
      TX_Error("SUR_ini_gbx_ E1-%d",sd->ssTyp);
      return -1;
  }


  return 0;

}


//================================================================
  int SUR_bnd_add_dbo () {
//================================================================
// add all boundaries as indexed-points-curves to MSH__.tab,ipa,pa3
// Input:
//   SUR__.oxs            surface ObjGX             see INF_OGX_SUR_TPS
// get 3D-points of boundary-curves;
// see MSH2D_bnd_add_dbo (ts1, Typ_CV, 21L, MSH_EDGLN_OB);
// see test_SUR_bnd__


  int     irc, bTyp, iBnd, eTyp;
  long    bDbi;


  printf("SUR_bnd_add_dbo \n");


  // loop tru boundaries of surface
  iBnd = 1;
  eTyp = MSH_EDGLN_OB;

  L_nxt_bnd:
    // get dbo (typ, DB-index) of boundary iBnd out of surf. SUR__.oxs
    // iBnd=1 = outer-boundary = second subObj of complex-obj oSur
    // iBnd>1 = inner-boundaries = following subObj's of complex-obj oSur
    irc = SUR_dbo_ib_oSur (&bTyp, &bDbi, iBnd, SUR__.oxs);
    if(irc < 0) return -1;

      // TESTBLOCK
      printf(" _add_dbo iBnd=%d bTyp=%d bDbi=%ld\n",iBnd,bTyp,bDbi);
      // irc = GR_Disp_dbo (bTyp, bDbi, 8, 0); DL_Redraw (); 
      // END TESTBLOCK




    // add boundary bTyp,bDbi as indexed-points-curve to MSH__.tab,ipa,pa3
    MSH2D_bnd_3D_add_dbo (&MSH__, bTyp, bDbi, eTyp);


    // if(mshTyp == MSH_EDGLN_OB) and if (surTyp == Typ_SURPLN) compute Z-Vektor
// aus SUR__.ssTyp = Typ_SURPLN !
    // only for outer-boundary
    // if(cTyp == MSH_EDGLN_OB) {
      // irc = UT3D_pl_pta (&pl1, ptNr, pa);
      // if(irc < 0) return irc;
      // ts1->vcz = pl1.vz;
        // UT3D_stru_dump (Typ_VC, &ts1->vcz, "  vcz");
    // }





    ++iBnd;
    eTyp = MSH_EDGLN_IB;
    if(iBnd < SUR__.oxs->siz) goto L_nxt_bnd;


  //----------------------------------------------------------------
    // TESTBLOCK
    MemTab_dump (&MSH__.tab, ".tab-0");
    // MemTab_dump (&MSH__.ipa, ".ipa-0");
    // MemTab_dump (&MSH__.pa2, ".pa2-0");
    // return -99;
    // END TESTBLOCK



  return 0;

}


//===================================================================
  int SUR_dbo_ib_oSur (int *bTyp, long *bDbi, int iBnd, ObjGX *oxSur) {
//===================================================================
// get dbo of surface-subObject from surface-ogx
// surface has a table of DB-objects (support-surf, boundaries)
// Input:
//   oxSur is top-obj of a surface; its data is a group of DB-links (typ ObjGX);
//   iBnd  0=support-surface, 1=outer-boundary, 2=first-inner-boundary ..
// Output:
//   bTyp,bDbi     dbo of support-surface|boundary


  int     irc;
  ObjGX   *oTab, *oBnd;
  void    *odOB;


  printf("SUR_dbo_ib_oSur iBnd=%d\n",iBnd);


  // get oxOB = outer-boundary = second obj
  oTab = oxSur->data;
  oBnd = &oTab[iBnd];
    UT3D_stru_dump (Typ_ObjGX, oBnd, " oBnd[%d]",iBnd);

  // obj must be a link
  if(oBnd->form != Typ_Index) {TX_Error("SUR_dbo_ib_oSur E1");return -1;}

  // resolv link
  OGX_GET_INDEX (bTyp, bDbi, oBnd);
    printf(" bTyp=%d bDbi=%ld\n",*bTyp,*bDbi);


  // // oxOB must be a CCV (Typ_CVTRM)|CI|CV
  // if(oxOB->typ != Typ_CVTRM) {
    // TX_Error("TSU_oOB_oSur E2");
    // return -1;
  // }
  // // Link to CCV:
  // // OB must be a DB-link; get data of DB-link
  // return DB_GetLinkDat (form, data, oNr, oxOB);

}


//================================================================
  int SUR_int_pln (MemTab(Line) *lna, long dbi) {
//================================================================
// SUR_int_dbo     intersect active surface with plane
// see TSU_test_read TSU_test_intersect INT_nln_nfac_pln
// see tst_tess_int
// Output:
//   lna           intersecting linesegments; MUST BE FREED


  int          lNr, fNr;
  long         l1;
  Plane        *pl1;

  printf("SUR_int_dbo %ld\n",dbi);


  // get plane
  pl1 = DB_get_PLN (dbi);


  // get space for (fNr) linesegments in lna
  fNr = MEMTAB_IND (&MSH__.fac);
  lNr = fNr + 16;

  // get space for lNr free records
  MemTab_ini (lna, sizeof(Line), Typ_LN, 100);
  MemTab_add (lna, &l1, NULL, lNr, 2);


  // lna = intersect Indexed-faces ifa with plane pl1; eg S20=INT A20 R20
  INT_nln_nifac_pln (lna, fNr,
                     MEMTAB_DAT (&MSH__.fac),
                     MEMTAB_DAT (&MSH__.ipa),
                     MEMTAB_DAT (&MSH__.pa3), pl1);

  return 0;

}

 
// EOF
