/* ../ut/mshig.c
//      irregular-grid-mesh  Functions        2017-06-20      RF
 *
 *
 * 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:
  ..

-----------------------------------------------------
*/
#ifdef globTag
void MSHIG(){}
#endif
/*!
\file  ../ut/mshig.c
\brief aux. functions init tesselation using GLU 
\code

=====================================================
List_functions_start:

MSHIG_init_ts
MSHIG_init_sur
MSHIG_load_sur
MSHIG_clear_sur       delete meshfile
MSHIG_clear_ts        reset MSHIG_ts
MSHIG_init_PLN__
MSHIG_init_BSP__

MSHIG_init_bnd__      add all boundaries
MSHIG_init_bnd_add    add contour pa to ts1.ipa,pa3,pst,tab
MSHIG_init_ipa_add    add <ptNr> links into ts1->ipa;
MSHIG_init_bnd_orient orient contours to CCW

MSHIG_facNr_ipatch    get nr of triangles of indexed-patches using TessStru
MSHIG_nfac_ipatch     get indexed-triangles from indexed-patches
MSHIG_wrf__           write mesh into file
MSHIG_rdf__
                  
List_functions_end:
=====================================================

\endcode *//*----------------------------------------



tesselation with outer-boundary, holes and a rectangular grid.

Tesselate active surface into MSHIG_ts (MSHIG_init_sur);
  save MSHIG_ts into file (MSHIG_wrf__)
  or load into MSHIG_ts (MSHIG_rdf__)


a surface has -
  - a color or texture  (.col)
  - outer-boundary      (.tab - MSH_EDGLN_OB -record)
  - n inner-boundaries  (.tab - MSH_EDGLN_IB -records)
  - n patches           (.tab - MSH_PATCH -records)

  a patch has:
    - n faces
    - a normalvector (vcZ) or array of normalvectors (vc3)



*/


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

#include <GL/gl.h>                     // GL_TRIANGLES ..

#include "../ut/ut_geo.h"              // Point ...
#include "../ut/ut_geo_const.h"        // UT3D_CCV_NUL
#include "../ut/ut_ox_base.h"          // OGX_SET_INDEX
#include "../ut/ut_memTab.h"           // MemTab_..
#include "../ut/ut_itmsh.h"            // MSHIG_EDGLN_.. typedef_MemTab..
#include "../ut/ut_face.h"             // UFA_..
#include "../ut/ut_os.h"               // OS_get_bas_dir ..

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

#include "../xa/xa_mem.h"              // memspc51, mem_cbuf1
// #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




// ex ../gr/ut_tess_su.c
#define TessDatSiz 256   // TessDat_SWP
// Typ_PLN   unused; 0
//// Typ_SURSWP TessDat_SWP


// tesselation-data for surfaces
// oxs      ObjGX of surface (support, boundaries)
// ssTyp    form of support-surface; Typ_PLN|Typ_SURSWP
// ssDbi    DB-index of support-surface
// ssDat    data of support-surface (was TSU_sbsp ..)
// tr_*     functions 3D to 2D and retour
// vc_pt    function to get vector for 3d-point on surface
// rx, ry   2D-range
// dx, dy   2D-increment (grid)
// tol      2D-tol
// td       individual for surface-type;
//          TessDat_SWP if typ = Typ_SURSWP
typedef struct {ObjGX *oxs; int ssTyp; long ssDbi; void *ssDat;
                int (*tr_2D_3D)(); int (*tr_3D_2D)(); int (*VC3D_PT3D)();
                double rx, ry, dx, dy, tol;
                char td[TessDatSiz];}                                TessDat;



typedef struct {long dbi; int mdli;
                MemTab(IndTab) tab;
                MemTab(char)   pst;
                MemTab(int)    ipa;
                MemTab(Point)  pa3;
                MemTab(Point)  pa2;
                MemTab(Vector) vc3;
                GridBox        gbx;
                Vector         vcz;
                ColRGB         col;}                                TessStru;

//----------------------------------------------------------------
//   vcz        NULL: surface not planar; vc3 set.
//              else normalvector of planar surface; vc3 not set.
//              if planar surf has n patches: all patches have same normalvector
//----------------------------------------------------------------
// Boundaries: tab + ipa + pta;
//   tab        one IndTab-record in .tab = one boundary;
//   tab.ibeg   index of first point in ipa; 
//   tab.inr    nr of points of contour; last point must be same as first
//              last pointindex is (tab.ibeg + tab.inr - 1)
//   tab.typi   MSH_EDGLN_OB MSH_EDGLN_IB 
//   ipa        index into pta
//
//----------------------------------------------------------------
// Faces: tab + ipa + pta + pst
//   tab        one IndTab-record in .tab = one patch;
//   tab.ibeg   index of first point of patch in ipa;
//   tab.inr    nr of points of patch;
//              last pointindex is (tab.ibeg + tab.inr - 1)
//   tab.typi   MSH_PATCH  // indexed-openGl-patch
//   tab.typd   Typ_PLN (planar) or (0=Typ_Error) not-planar
//   tab.aux    GL_TRIANGLES|GL_TRIANGLE_STRIP|GL_TRIANGLE_FAN  (4-6)
//   
//   pst        boundary-flags for pmt-points
//              bitVal 8 point is used in tab
//              bitVal 1 is in tab and on boundary (added point)
//              bitVal 2 is used in tab (is on primary boundary)
//              bitVal 4 is used in gridbox
//
//----------------------------------------------------------------

#ifdef _MSC_VER

static TessDat MSHIG_td;
static TessStru MSHIG_ts;


#else
  // C99
static TessDat MSHIG_td;
static TessStru MSHIG_ts = {
                   .tab = _MEMTAB_NUL,     // boundaries, tesselated patches
                   .pst = _MEMTAB_NUL,     // status of points
                   .ipa = _MEMTAB_NUL,     // index to points
                   .pa2 = _MEMTAB_NUL,     // 2D-points
                   .pa3 = _MEMTAB_NUL,     // 3D-points
                   .vc3 = _MEMTAB_NUL,     // normalVectors
                   .gbx = _GRIDBOX_NUL,
                   .vcz = _UT3D_VECTOR_NUL, // normalvector - only for planar
                   .col = _ColRGB_NUL};     // color|texture
#endif






//================================================================
  int MSHIG_init_ts () {
//================================================================
// TODO: must be added into GL_Init1 ()
// see MSHIG_init__ MSHIG_exit
 
#ifdef _MSC_VER
const MemTab(void) MEMTAB_NUL = { NULL, 0, 0, 0 }; //_MEMTAB_NUL;
#endif

// defaultNr contours for a single surf
#define MSHIG_NR_CNTS 50
// defaultsize points for a single surf
#define MSHIG_NR_PTS 1000


  printf("MSHIG_init_ts \n");

#ifdef _MSC_VER
  MSHIG_ts.tab = *((MemTab_IndTab*)&MEMTAB_NUL);    // IndTab
  MSHIG_ts.pst = *((MemTab_char*)&MEMTAB_NUL);      // char
  MSHIG_ts.ipa = *((MemTab_int*)&MEMTAB_NUL);       // int
  MSHIG_ts.pa2 = *((MemTab_Point*)&MEMTAB_NUL);
  MSHIG_ts.pa3 = *((MemTab_Point*)&MEMTAB_NUL);
  MSHIG_ts.vc3 = *((MemTab_Vector*)&MEMTAB_NUL);    // Vector
  MSHIG_ts.gbx = GRIDBOX_NUL;
  MSHIG_ts.vcz = UT3D_VECTOR_NUL;
  // MSHIG_ts.col = ?
#endif


  // init OpenGL-GLU-tesselation
  GLT_init_tess ();


  return MSHIG_clear_ts ();

}


//================================================================
  int MSHIG_clear_ts () {
//================================================================
 

  MemTab_ini (&MSHIG_ts.tab, sizeof(IndTab), Typ_IndTab, MSHIG_NR_PTS/2);
  MemTab_ini (&MSHIG_ts.pst, sizeof(char), Typ_Int1, MSHIG_NR_PTS);
  MemTab_ini (&MSHIG_ts.ipa, sizeof(int), Typ_Int4, MSHIG_NR_PTS * 2);
  MemTab_ini (&MSHIG_ts.pa2, sizeof(Point), Typ_PT, MSHIG_NR_PTS);
  MemTab_ini (&MSHIG_ts.pa3, sizeof(Point), Typ_PT, MSHIG_NR_PTS);
  MemTab_ini (&MSHIG_ts.vc3, sizeof(Vector), Typ_VC, MSHIG_NR_PTS);


  return 0;

}


//================================================================
  int MSHIG_fnam (char *fnam, int mdli, long dbi) {
//================================================================

static char cTyp='A';

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

  return 0;

}


//================================================================
  int MSHIG_clear_sur (int mdli, long dbi) {
//================================================================
// MSHIG_clear_sur       delete meshfile

  char      ofid[128];


  MSHIG_fnam (ofid, mdli, dbi);

  return OS_file_delete (ofid);

}


//================================================================
  int MSHIG_load_sur (long dbi, Memspc *tbuf1) {
//================================================================
// load mesh for surf <dbi> from file or create (MSHIG_init_sur)
// Output: mesh in MSHIG_ts
//   

  int       irc;


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


  irc = MSHIG_rdf__ (WC_modact_ind, dbi);
  if(!irc) goto L_exit;


  // tesselate into MSHIG_ts, save into file
  irc = MSHIG_init_sur (dbi, tbuf1);



  //----------------------------------------------------------------
  L_exit:
    // TESTBLOCK
    // MemTab_dump (&MSHIG_ts.tab, "tab-2");
    // MSHIG_view__ (5);  // display MSHIG_ts
    // END TESTBLOCK


  return irc;

}


//================================================================
  int MSHIG_init_sur (long dbi, Memspc *tbuf1) {
//================================================================
// init = create mesh; get mesh <- file. If not yet exists:
//   load outer-boundary and inner-boundaries as indexed 2D-points
//   compute grid-values (range,dx,dy..); create grid-points and vectors.
//   tesselate; create indexed-faces; add vectors for new points
//   save mesh -> file.

// load tesselation-grid

// see TSU_test_tess__

  int    irc, i1, ii, cNr, ptNr;



  printf("============================================ \n");
  printf("MSHIG_init_sur dbi=%ld\n",dbi);


  // init|reset ts
  MSHIG_clear_ts ();


  // get surf out of DB 
  MSHIG_td.oxs = DB_GetSur (dbi, 1);
  if(!MSHIG_td.oxs->typ) return -1;
    UTO_dump_s_ (MSHIG_td.oxs, "n-DB_GetSur");


  MSHIG_ts.dbi  = dbi;
  MSHIG_ts.mdli = WC_modact_ind;

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


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

    //----- supportSurfaces ------------------------------------------
    // supportSurfaces are not trimmed, not perforated;
    // tesselate as stripes or fan manually
    case Typ_SURBSP:
      // supportSurface only; tesselate as stripes or fan manually
      irc = MSHIG_init_BSP__ (&MSHIG_ts, &MSHIG_td);
      break;

    case Typ_SURSWP:
      irc = TODO ("MSHIG_init_SWP__", &MSHIG_ts, &MSHIG_td, tbuf1);
      break;


    // case Typ_SURRBSP:
    // case Typ_SURRV:
// Typ_SURRV  (SurRev*) RevolvedSurface
    // case Typ_SURRU:
// Typ_SURRU  contour + contour|vector|point; (Ruled)
      // break;


    //----- trimmed-supported-surfaces ------------------------------------------
    case Typ_SURPLN:
      // planar, with outer-boundary, optionally holes, no supportSurface
      irc = MSHIG_init_PLN__ (&MSHIG_ts, &MSHIG_td);
      break;

    case Typ_SURTPS:
      TX_Error("TODO MSHIG_init_sur Typ_SURTPS"); return -1;
      // TSU_test_tess_TPS
      // break;

    default:
      TX_Error("MSHIG_init_sur E1-%d",MSHIG_td.ssTyp);
      return -1;
  }
  if(irc < 0) goto L_exit;


  //----------------------------------------------------------------
    // TESTBLOCK
    // MemTab_dump (&MSHIG_ts.tab, "tab-2");
    // MemTab_dump (&MSHIG_ts.ipa, "ipa-2");
    // MemTab_dump (&MSHIG_ts.pa2, "pa2-2");
    // testDisp
    // MSHIG_view__ (5);
    // END TESTBLOCK



  //----------------------------------------------------------------
  // save into file binary
  irc = MSHIG_wrf__ ();
  if(irc < 0) goto L_exit;



  //----------------------------------------------------------------
  L_exit:

  return irc;

}





/*
  //================================================================
  // load outer-boundary
  // add points -> pa, indices -> ia, boundary -> ba
  // ii = sizeof(paOB)/sizeof(Point);
  // irc = TSU_init_bnd_add (paOB, ii, MSH_EDGLN_OB, &MSHIG_ts);
  // if(irc < 0) goto L_exit;

  //================================================================
  // load inner-boundaries
  // add points -> pa, indices -> ia, boundary -> ba
  // ii = sizeof(paIB)/sizeof(Point);
  // irc = TSU_init_bnd_add (paIB, ii, MSH_EDGLN_IB, &MSHIG_ts);
  // if(irc < 0) goto L_exit;

  //================================================================
  // define gridbox

  //================================================================
  // tesselate (get faces)
  // irc = MSHIG_TESS (&MSHIG_ts.tab,&MSHIG_ts.ipa,&MSHIG_ts.pa2,&MSHIG_ts.pst,&gb,&MSHIG_ts.vcz);
  // if(irc < 0) goto L_exit;

  // display faces
}
*/


//================================================================
  int MSHIG_init_BSP__ (TessStru *ts1, TessDat *td1) {
//================================================================
// Typ_SURBSP (SurBSpl*) B-Spline-Surface (Loft)
// Input:
//   ts1->dbi,mdli  
//   td1->oxs            surf-obj
//   td1->ssTyp,ssDbi    suppSurf  NOT for planar-surf
// was TSU_test_tess_SS_BSP_s


  int       irc, i1, iip, iu, iv, ptNr, ips, iis, *ia;
  long      ld;
  double    du, dv, d1, d2;
  Point     *pa3, *pa2, *p2Gbx, *p3Gbx, pt1;
  Vector    *va, *vGbx, vc1;
  SurBSpl   *sbsp;
  Memspc    wrkSpc;
  IndTab    itGbx;


  printf("MSHIG_init_BSP__ td1->ssTyp=%d\n",td1->ssTyp);


  //----------------------------------------------------------------
  // add all boundary-points into ts1->ipa,pa3 
  // add outer-boundary-records -> ts1->tab
  // add all links into ts1->ipa
  irc = MSHIG_init_bnd__ (ts1, td1);
  if(irc < 0) return irc;

  // get ips = nr of points for all boundary-points -> ts1->vc3
  ips = MEMTAB_IND (&ts1->pa3);

  // reserve space for ips 2D-points in .pa2
  irc = MemTab_add (&ts1->pa2, &ld, NULL, ips, 1);
  if(irc < 0) return irc;

  // reserve space for ips vectors in vc3
  irc = MemTab_add (&ts1->vc3, &ld, NULL, ips, 1);
  if(irc < 0) return irc;


  //----------------------------------------------------------------
  // find 2D-tolerance, parameter-offsets in u and v
  // get parameter-offsets in u and v
  UME_init (&wrkSpc, memspc53, sizeof(memspc53));
  sbsp = td1->ssDat;
  // get nr of rows,columns for grid of points with tolerance < UT_DISP_cv
  UT3D_uvNr_sbsp (&iu, &iv, sbsp, &wrkSpc);
  ptNr = iu * iv;
  ts1->gbx.ix = iu;
  ts1->gbx.iy = iv;
    printf("  ptNr=%d iu=%d iv=%d\n",ptNr,iu,iv);


  //----------------------------------------------------------------
  // add all gridpoints and its vectors to ts1
  // get normalvectors for all boundary-points -> ts1->vc3
  // add all links into ipa

  // reserve space for ptNr 3D-points in pa3
  irc = MemTab_add (&ts1->pa3, &ld, NULL, ptNr, 1);
  if(irc < 0) return irc;

  // reserve space for ptNr 2D-points in pa2
  irc = MemTab_add (&ts1->pa2, &ld, NULL, ptNr, 1);
  if(irc < 0) return irc;

  // reserve space for ptNr vectors in pa3
  irc = MemTab_add (&ts1->vc3, &ld, NULL, ptNr, 1);
  if(irc < 0) return irc;

  // get startPosition for 3D-poingts and normalvectors
  p3Gbx = MEMTAB__ (&ts1->pa3, ips);
  p2Gbx = MEMTAB__ (&ts1->pa2, ips);
  vGbx = MEMTAB__ (&ts1->vc3, ips);

  // create 3D-gridBox with all points
  UME_init (&wrkSpc, memspc53, sizeof(memspc53));  // tempspace
  irc = UT3D_ptgrid_sbsp (p3Gbx, p2Gbx, vGbx, &du, &dv, sbsp, iu, iv, &wrkSpc);
  if(irc < 0) return -1;

  // add links to gridPoints in ipa
  iis = MSHIG_init_ipa_add (ptNr, ips, ts1);
  if(iis < 0) return -1;

  // create/add itGbx = the IndTab for the gridbox-points
  itGbx.ibeg = iis;    // startindex in ipa
  itGbx.iNr  = ptNr;   // nr of points
  itGbx.typi = MSH_GRIDBOX;
  itGbx.aux  = 0;      // unused
  irc = MemTab_add (&ts1->tab, &ld, &itGbx, 1, 0);
  if(irc < 0) return irc;


      // TESTBLOCK
      printf("  du=%f dv=%f iu=%d iv=%d\n",du,dv,iu,iv);
      GR_Disp_pTab (ptNr, p3Gbx, SYM_STAR_S, ATT_COL_RED);
      GR_Disp_pTab (ptNr, p2Gbx, SYM_STAR_S, ATT_COL_BLUE);
      for(i1=0; i1<ptNr; ++i1) GR_Disp_vc (&vGbx[i1], &p3Gbx[i1], 11, 0);
      // MemTab_dump (&ts1->ipa, "ipa-1");
      // END TESTBLOCK


  //----------------------------------------------------------------
  // get normalvectors for all boundary-points -> ts1->vc3
  // get 2D-points for all boundary-points -> ts1->pa2

  // create normalvectors for all boundary-points -> ts1->vc3
  pa3 = MEMTAB_DAT (&ts1->pa3);
  pa2 = MEMTAB_DAT (&ts1->pa2);
  ia = MEMTAB_DAT (&ts1->ipa);
  va = MEMTAB_DAT (&ts1->vc3);
  for(i1=0; i1<ips; ++i1) {
    iip = ia[i1];
    // get 2D-point
    UME_init (&wrkSpc, memspc53, sizeof(memspc53));
// see UTO_vc_perp_sur
    irc = UT3D_parsbsp_pt (&d1, &d2, &pa3[iip],
                         p3Gbx, du, dv, iu, iv, sbsp, &wrkSpc);
    if(irc < 0) return irc;

    // set 2D-point
    pa2[iip].x = d1;
    pa2[iip].y = d2;
    pa2[iip].z = 0.;

    // set normalvector
    UME_init (&wrkSpc, memspc53, sizeof(memspc53));
    UT3D_ptvc_evparsbsp  (NULL, &va[iip], 2, 0, sbsp, d1, d2, &wrkSpc);

      // TESTBLOCK
      GR_Disp_vc (&va[iip], &pa3[iip], 11, 0);
      APT_disp_SymB (SYM_STAR_S, ATT_COL_YELLOW, &pa2[iip]);
      // END TESTBLOCK
  }



  //----------------------------------------------------------------
  // tesselate; create faces from gridpoints;

  irc = GLT_TESS__ (&ts1->tab, &ts1->ipa, &ts1->pa2, &ts1->pst,
                    &ts1->gbx, NULL);
  if(irc) {
    TX_Print ("**** GLT_TESS__ error %d A%ld", irc, ts1->dbi);
    return -1;
  }


  //----------------------------------------------------------------
  // compute normalvectors for all points created by GLT_TESS__




  return 0;

}


//================================================================
  int MSHIG_init_PLN__ (TessStru *ts1, TessDat *td1) {
//================================================================
// planar, with outer-boundary, optionally holes, no supportSurface
// Input:
//   ts1->dbi,mdli  
//   td1->oxs            surf-obj
//   td1->ssTyp,ssDbi    suppSurf  NOT for planar-surf
// was TSU_init_pln

  int    irc, cNr, cAct, cTyp, bTyp, ptNr, ips, iis;
  long   bDbi, ld;
  char   c1;
  Point  *pa;
  Plane  pl1;
  ObjGX  *oxa, *oxb;
  IndTab cnt1;


  printf("MSHIG_init_PLN__ td1->ssTyp=%d\n",td1->ssTyp);


  //----------------------------------------------------------------
  // add all boundaries into ts1->ipa,pa3 and get normalvector -> ts1->vcz
  // add outer-boundary-records -> ts1->tab
  // add all links into ts1->ipa
  irc = MSHIG_init_bnd__ (ts1, td1);
  if(irc < 0) return irc;


  //----------------------------------------------------------------
  // orient all ts1-contours CCW
  irc = MSHIG_init_bnd_orient (&ts1->tab, ts1->pa3.data, &ts1->vcz);
  if(irc < 0) return -1;


  //----------------------------------------------------------------
  // tesselate, using GLU_tess__
  // get patches in .tab
  // vcz: only for planar; else NULL.
  irc = GLT_TESS__ (&ts1->tab, &ts1->ipa, &ts1->pa3, &ts1->pst,
                    NULL, &ts1->vcz);
  if(irc) {
    TX_Print ("**** GLT_TESS__ error %d A%ld", irc, ts1->dbi);
    return -1;
  }



}


//=====================================================================
  int MSHIG_init_bnd__ (TessStru *ts1, TessDat *td1) {
//=====================================================================
// Input:
//   cTyp         MSH_EDGLN_OB|MSH_EDGLN_IB
// add contour pa to ts1.ipa,pa3,pst,tab


  int    irc, cNr, cAct, cTyp, bTyp, ptNr;
  long   bDbi, ld;
  Point  *pa;
  Plane  pl1;
  ObjGX  *oxa, *oxb;


  //----------------------------------------------------------------
  // add all boundary-points into ts1->ipa,pa3 
  // add outer-boundary-records -> ts1->tab
  // add all links into ts1->ipa

  oxa = td1->oxs->data;   // table of surface-objects (supp,OB,IB's)
  cNr = td1->oxs->siz;    // nr of contours
  cAct = 1;               // 1=OB
  cTyp = MSH_EDGLN_OB;



  //----------------------------------------------------------------
  L_nxt_cnt:
    // get oxb = next boundary
    oxb = &oxa[cAct];

    // get bDbi = dbi for outer-boundary
    if(oxb->form == Typ_Index) {
      OGX_GET_INDEX (&bTyp, &bDbi, oxb);
    } else {
      TX_Error("MSHIG_init_bnd__ E1");
      return -1;
    }
      printf("--- cAct=%d  bTyp=%d bDbi=%ld\n",cAct,bTyp,bDbi);

    
    // get points ..
    irc = PRCV_npt_dbo__ (&pa, &ptNr, bTyp, bDbi, WC_modact_ind);
    if(irc < 0) {TX_Error("MSHIG_init_bnd__ E2");return -1;}
      // printf(" _npt_dbo__ %d %d\n",irc,ptNr);
      // GR_Disp_pTab (ptNr, pa, SYM_STAR_S, 2);


    //----------------------------------------------------------------
    // only fro planar: compute Z-Vektor for planar (normal-vector to boundary)
    if(cAct == 1) { // 0=SS; 1=OB
      if(td1->ssTyp == Typ_SURPLN) {
        irc = UT3D_pl_pta (&pl1, ptNr, pa);
        if(irc < 0) return irc;
        ts1->vcz = pl1.vz;
          UT3D_stru_dump (Typ_VC, &ts1->vcz, "  vcz");
      }
    }


    //----------------------------------------------------------------
    // add contour to ts1.ipa,pa3,pst,tab
    irc = MSHIG_init_bnd_add (pa, ptNr, cTyp, ts1);
    if(irc < 0) return irc;

    ++cAct;
    cTyp = MSH_EDGLN_IB;
    if(cAct < cNr) goto L_nxt_cnt;


  //----------------------------------------------------------------
      // TESTBLOCK
      // MemTab_dump (&ts1->tab, "init_bnd__");
      // MemTab_dump (&ts1->pst, "pst-1");
      // GR_Disp_pTab (ts1->pa2.rNr, ts1->pa2.data, SYM_STAR_S, 2);
      // printf(" -MSHIG_init_bnd__-0\n");
      // END TESTBLOCK


  return 0;

}



//=====================================================================
  int MSHIG_init_bnd_add (Point *pa, int ptNr, int cTyp, TessStru *ts1) {
//=====================================================================
// Input:
//   cTyp         MSH_EDGLN_OB|MSH_EDGLN_IB
// add contour pa to ts1.ipa,pa3,pst,tab

  int     irc, ips, iis;
  long    ld;
  char    c1;
  IndTab  cnt1;


  // get startpos in pa3
  ips = MEMTAB_IND (&ts1->pa3);
    printf(" TSU_init_bnd_add  ptNr=%d ips=%d\n",ptNr,ips);


  // add boundary-point to pa3
  irc = MemTab_add (&ts1->pa3, &ld, pa, ptNr, 0);
  if(irc < 0) return irc;

  // add all links into ipa
  iis = MSHIG_init_ipa_add (ptNr, ips, ts1);
  if(iis < 0) return -1;

  // add point-status 2 to pst
  c1 = 2;
  irc = MemTab_add (&ts1->pst, &ld, &c1, ptNr, 4);
  if(irc < 0) return irc;

  // add boundary-record -> ts1->tab
  cnt1.ibeg = iis;    // startindex in ipa
  cnt1.iNr  = ptNr;   // nr of points
  cnt1.typi = cTyp;   // MSH_EDGLN_OB|MSH_EDGLN_IB
  cnt1.aux  = 0;      // unused
  irc = MemTab_add (&ts1->tab, &ld, &cnt1, 1, 0);
  if(irc < 0) return irc;

    // MemTab_dump (&ts1->tab, "tab-2");
    // MemTab_dump (&ts1->ipa, "ipa-2");
    // MemTab_dump (&ts1->pa2, "pa2-2");

  return 0;

}


//================================================================
 int MSHIG_init_ipa_add (int ptNr, int ips, TessStru *ts1) {
//================================================================
// add <ptNr> links into ts1->ipa;
// first link is <ips>
// returns startIndex in ipa
// TODO: see MemTabI_add_s


  int     irc, i1, *ia, iis, ip1, ii1;
  long    ld;


  printf("MSHIG_init_ipa_add ptNr=%d ips=%d\n",ptNr,ips);


  // iis = next free position in ipa
  iis = MEMTAB_IND (&ts1->ipa);
    printf(" iis=%d\n",iis);

  // reserve ptNr links in ipa
  irc = MemTab_add (&ts1->ipa, &ld, NULL, ptNr, 1);
  if(irc < 0) {TX_Error("MSHIG_init_ipa_add E1");return -1;}

  // add all links into ipa 
  ia = MEMTAB_DAT (&ts1->ipa);   // get int-table
  if(irc < 0) {TX_Error("MSHIG_init_ipa_add E2");return -1;}

  ip1 = ips;
  ii1 = iis;

  for(i1=0; i1<ptNr; ++i1) {
    ia[ii1] = ip1;
    ++ip1;
    ++ii1;
  }

     // MemTab_dump (&ts1->ipa, "ex-MSHIG_init_ipa_add-ipa");

  return iis;

}


//================================================================
 int MSHIG_init_bnd_orient (MemTab(IndTab) *ncnt, Point *pTab, Vector *vcz) {
//================================================================
// orient contour to CCW
// was SUP_cvcnt_orient__ SUP_orient

  int    i1, idir, ipa, iNr, cNr, plMain;
  IndTab *iTab;
  Point  *pta;


  MemTab_dump (ncnt, " MSHIG_init_bnd_orient");
  // UT3D_stru_dump (Typ_VC, vcz, " vcz");

  cNr = ncnt->rNr;

  // get main-BackPlaneNr
  plMain = UT3D_bp_vcz (vcz); // Berechnungsebene definieren
    // printf(" plMain=%d\n",plMain);



  for(i1=0; i1<cNr; ++i1) {

    iTab = MEMTAB__ (ncnt, i1);
      // UT3D_stru_dump (Typ_IndTab, iTab, " iTab[%d]",i1);

    iNr = iTab->iNr - 1;  // Anzahl Punkte ohne den letzten == ersten Punkt !
    // ipa = cTab[i1].ipa;
    pta = &pTab[iTab->ibeg];

    // // wenn keine Kontur vorhanden:
    // if(pta == NULL) continue;

    // get direction
    idir = UT3D_sr_polc (iNr, pta, vcz, plMain);
      // printf(" cnt %d dir %d\n",i1,idir);

    // all boundaries must be CCW
      if(idir < 0) {
          // printf(" ++++inv con %d\n",i1);
        UT3D_cv_inv (iNr+1, pta);
      }
  }


  return 0;

}


//================================================================
  int MSHIG_wrf__ () {
//================================================================
// write mesh into file "[M<subModelNr>]A<surf#>.odat"
// Fileformat: recordNr's, recordSizes, MemTabs.
// was TSU_wrf__
// see also PRCV_wrf__

static char cTyp='A';

  FILE      *fp1;
  char      ofid[128];
  TessStru  *ts1 = &MSHIG_ts;


  printf("MSHIG_wrf__ %ld\n",ts1->dbi);


  MSHIG_fnam (ofid, ts1->mdli,ts1->dbi);


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

  // write nr of records of tab,pst,ipa,pta
  fwrite(&ts1->tab.rNr, sizeof(int), 1, fp1);
  fwrite(&ts1->pst.rNr, sizeof(int), 1, fp1);
  fwrite(&ts1->ipa.rNr, sizeof(int), 1, fp1);
  fwrite(&ts1->pa3.rNr, sizeof(int), 1, fp1);
  fwrite(&ts1->pa2.rNr, sizeof(int), 1, fp1);
  fwrite(&ts1->vc3.rNr, sizeof(int), 1, fp1);

/*
  // write size of records of tab,pst,ipa,pta,bnd
  fwrite(&ts1->tab.rSiz, sizeof(int), 1, fp1);
  fwrite(&ts1->pst.rSiz, sizeof(int), 1, fp1);
  fwrite(&ts1->ipa.rSiz, sizeof(int), 1, fp1);
  fwrite(&ts1->pa3.rSiz, sizeof(int), 1, fp1);
  fwrite(&ts1->pa2.rSiz, sizeof(int), 1, fp1);
  fwrite(&ts1->bnd.rSiz, sizeof(int), 1, fp1);
  fwrite(&ts1->vc3.rSiz, sizeof(int), 1, fp1);
*/

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

  // write gbx, vcz, col
  fwrite(&ts1->gbx, sizeof(GridBox), 1, fp1);
  fwrite(&ts1->vcz, sizeof(Vector), 1, fp1);
  fwrite(&ts1->col, sizeof(ColRGB), 1, fp1);

  fclose(fp1);



  return 0;

}


//================================================================
  int MSHIG_rdf__ (int mdli, long dbi) {
//================================================================
/// Input:
///   ts1->dbi
///   ts1->mdli
/// Retcod:
///    0            surface is already loaded in MSHIG_ts
///   -1            no meshfile exists for this surface
// was TSU_rdf__
// see TSU_wrf__ PRCV_rdf__

static char cTyp='A';

  int       rNr;
  long      l1;
  char      ofid[128];
  char      *vp1;
  FILE      *fp1;
  TessStru  *ts1 = &MSHIG_ts;

  printf("MSHIG_rdf__ %d %ld\n",mdli,dbi);




  //----------------------------------------------------------------
  // test if surface already in MSHIG_ts
  if(dbi != ts1->dbi) goto L_load;
  if(mdli != ts1->mdli) goto L_load;

  // ok.
  return 0;



  //----------------------------------------------------------------
  L_load:
  MSHIG_fnam (ofid, mdli, dbi);

  if((fp1=fopen(ofid,"rb")) == NULL) {
    printf(" MSHIG_rdf__ I001 |%s|\n",ofid);
    return -1;
  }



  //----------------------------------------------------------------
  // get nr-of-records of tab,pst,ipa,pta  then check size
  fread(&rNr, sizeof(int), 1, fp1); MemTab_add (&ts1->tab, &l1, NULL, rNr, 2);
  fread(&rNr, sizeof(int), 1, fp1); MemTab_add (&ts1->pst, &l1, NULL, rNr, 2);
  fread(&rNr, sizeof(int), 1, fp1); MemTab_add (&ts1->ipa, &l1, NULL, rNr, 2);
  fread(&rNr, sizeof(int), 1, fp1); MemTab_add (&ts1->pa3, &l1, NULL, rNr, 2);
  fread(&rNr, sizeof(int), 1, fp1); MemTab_add (&ts1->pa2, &l1, NULL, rNr, 2);
  fread(&rNr, sizeof(int), 1, fp1); MemTab_add (&ts1->vc3, &l1, NULL, rNr, 2);


/*
  // get size-of-records of tab,pst,ipa,pta,bnd
  fread(&ts1->tab.rSiz, sizeof(int), 1, fp1);
  fread(&ts1->pst.rSiz, sizeof(int), 1, fp1);
  fread(&ts1->ipa.rSiz, sizeof(int), 1, fp1);
  fread(&ts1->pa3.rSiz, sizeof(int), 1, fp1);
  fread(&ts1->pa2.rSiz, sizeof(int), 1, fp1);
  fread(&ts1->bnd.rSiz, sizeof(int), 1, fp1);
  fread(&ts1->vc3.rSiz, sizeof(int), 1, fp1);
    printf(" size-of-records %d %d %d %d %d %d %d\n",ts1->tab.rSiz,ts1->pst.rSiz,
           ts1->ipa.rSiz,ts1->pa3.rSiz,ts1->pa2.rSiz,ts1->bnd.rSiz,ts1->vc3.rSiz);

  // compute totalsize bSiz
  bSiz = 0L;
  bSiz += ts1->tab.rNr * ts1->tab.rSiz;
  bSiz += ts1->pst.rNr * ts1->pst.rSiz;
  bSiz += ts1->ipa.rNr * ts1->ipa.rSiz;
  bSiz += ts1->pa3.rNr * ts1->pa3.rSiz;
  bSiz += ts1->pa2.rNr * ts1->pa2.rSiz;
  bSiz += ts1->bnd.rNr * ts1->bnd.rSiz;
  bSiz += ts1->vc3.rNr * ts1->vc3.rSiz;
  bSiz += sizeof(GridBox);
  bSiz += sizeof(Vector);
  bSiz += sizeof(ColRGB);
  bSiz += 256;
    printf(" bSiz=%ld\n",bSiz);
  // get memspc
  // ts1->ts1Spc = malloc(bSiz);
  // set data-space for tab,pst,ipa,pta,bnd
  // vp1 = ts1->ts1Spc;
  ts1->tab.data = (void*)vp1;
  ts1->tab.rMax = ts1->tab.rNr;
  vp1 += ts1->tab.rNr * ts1->tab.rSiz;
  ts1->pst.data = vp1;
  ts1->pst.rMax = ts1->pst.rNr;
  vp1 += ts1->pst.rNr * ts1->pst.rSiz;
  ts1->ipa.data = (void*)vp1;
  ts1->ipa.rMax = ts1->ipa.rNr;
  vp1 += ts1->ipa.rNr * ts1->ipa.rSiz;
  ts1->pa3.data = (void*)vp1;
  ts1->pa3.rMax = ts1->pa3.rNr;
  vp1 += ts1->pa3.rNr * ts1->pa3.rSiz;
  ts1->pa2.data = (void*)vp1;
  ts1->pa2.rMax = ts1->pa2.rNr;
  vp1 += ts1->pa2.rNr * ts1->pa2.rSiz;
  ts1->bnd.data = (void*)vp1;
  ts1->bnd.rMax = ts1->bnd.rNr;
  vp1 += ts1->bnd.rNr * ts1->bnd.rSiz;
  ts1->vc3.data = (void*)vp1;
  ts1->vc3.rMax = ts1->vc3.rNr;
*/


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

  fread(&ts1->gbx, sizeof(GridBox), 1, fp1);
  fread(&ts1->vcz, sizeof(Vector), 1, fp1);
  fread(&ts1->col, sizeof(ColRGB), 1, fp1);

  fclose(fp1);

    printf("ex MSHIG_rdf__\n");

  return 0;

}


//================================================================
  int MSHIG_view__ (int iatt) {
//================================================================
// display content of MSHIG_ts

  int       i1, rNr, *ipa;
  TessStru  *ts1 = &MSHIG_ts;
  IndTab    *itAct, *itTab;
  Point     *pta;

 
  printf("MSHIG_view__ %d\n",iatt);


  // loop tru MSHIG_ts.tab
  itTab = MEMTAB_DAT (&ts1->tab);
  pta = MEMTAB_DAT(&ts1->pa3);
  rNr = ts1->tab.rNr;

  for(i1=0; i1<rNr; ++i1) {
    itAct = &itTab[i1];
    ipa = MEMTAB__(&ts1->ipa, itAct->ibeg);
      printf(" _view__ %d\n",i1);

    // display opengl-patch
    if(itAct->typi == MSH_PATCH) {
// TODO: use GL_Disp_nifac
      // GL_view_ipatch_2 (itAct->aux, itAct->iNr, ipa, pta, NULL,
                        // &ts1->vcz, -1L);
      continue;
    }

    // display boundary (typi = MSH_EDGLN_OB|MSH_EDGLN_IB)
    if(itAct->typi == MSH_EDGLN_OB) {
      GL_view_inpt (itAct->iNr, ipa, pta, iatt);
    }

  }



  return 0;

}


//=======================================================================
  int MSHIG_nfac_ipatch (MemTab(Fac3) *ifa, Point **pta,
                         Memspc *tbuf1, long dbiSur) {
//=======================================================================
// get indexed-triangles from indexed-patches (fmt + ipa + pa3)
// Output:
//   ifa
//   pTab
// see also TSU_ntria_bMsh_p


  int       irc, i1, i2, ii, fNr, *iTab;
  long      l1;
  IndTab    *itAct, *itTab;
  Fac3      *fTab;
  TessStru  *ts1 = &MSHIG_ts;


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


  // load mesh of DB-obj typ1,dbi1 into MSHIG_ts
  irc = MSHIG_load_sur (dbiSur, tbuf1);
  if(irc) return -1;


  // estimate nr of triangles (for memspc)
  fNr = MSHIG_facNr_ipatch (ts1);
    printf(" fNr=%d\n",fNr);



  // get space for fNr triangles
  MemTab_ini (ifa, sizeof(Fac3), Typ_Fac3, fNr / 3);
  irc = MemTab_add (ifa, &l1, NULL, fNr, 1);
  if(irc < 0) return irc;
    // MemTab_dump (ifa, "_facNr_ipatch-ifa-1");

  // out
  fTab = MEMTAB_DAT (ifa);

  // in
  iTab = MEMTAB_DAT (&ts1->ipa);  // ts1->ipa.data;
  itTab = MEMTAB_DAT (&ts1->tab);
  *pta = MEMTAB_DAT (&ts1->pa3);  // ts1->pa3.data;


  // add indexed-triangles from patches
  // loop tru all patches of ts1
  ii = 0;
  for(i1=0; i1<ts1->tab.rNr; ++i1) {

    // get next patch
    itAct = &itTab[i1];
    if(itAct->typi != MSH_PATCH) continue;
      // printf(" glTyp=%d inr=%d\n",patAct->aux,patAct->iNr);

    // i2 = max nr of faces
    i2 = ifa->rMax - ii;

    // add triangles of patch
    irc = TSU_nfac_ipatch__ (&fTab[ii], &i2, itAct, iTab);
    if(irc < 0) return -1;

    // ii = nr of faces now
    ii += i2;
  }


    // TESTBLOCK
    // display indexed-triangles
    // MemTab_dump (ifa, "_facNr_ipatch-ifa-2");
    // if(ii != ifa->rNr) printf("**** TSU_nfac_ipatch_ts1 E1\n");
    // MSH_test_disp_fb1
    { Point     *pTab = ts1->pa3.data;
    for(i1=0;i1<ii;++i1) UFA_disp_fb1 (i1, fTab, pTab);
    }
    // END TESTBLOCK



  return 0;

}



//================================================================
  int MSHIG_facNr_ipatch (TessStru *ts1) {
//================================================================
// get nr of triangles of indexed-patches using TessStru
// see UTRI_triaNr_patch

  int    i1, fNr;
  IndTab *itAct, *itTab;


  printf("MSHIG_facNr_ipatch \n");
  // MemTab_dump (&ts1->fmt, "_facNr_ipatch-fmt");


  itTab = MEMTAB_DAT (&ts1->tab);
  fNr = 0;

  // loop tru all patches of ts1
  for(i1=0; i1<ts1->tab.rNr; ++i1) {
    // get next patch
    itAct = &itTab[i1];
    if(itAct->typi != MSH_PATCH) continue;
      // printf(" glTyp=%d inr=%d\n",itAct->aux,itAct->iNr);

    switch (itAct->aux) {

      case GL_TRIANGLES:
        fNr += itAct->iNr / 3;
        break;

      case GL_TRIANGLE_STRIP:
      case GL_FAC_PLANAR:
      case GL_TRIANGLE_FAN:
      case GL_QUAD_STRIP:
        fNr += itAct->iNr - 2;
        break;

      default:
        TX_Error("MSHIG_facNr_ipatch NYI typ=%d",itAct->aux);
        return -1;
    }

  }

    // printf("ex MSHIG_facNr_ipatch %d\n",fNr);


  return fNr;

}


// EOF
