// UT2D_
// UTP_
/*
=====================================================
List_functions_start:

UTP_sorta_nval_nint         sort ascending parameters, ints

UT2D_par_nor_2vc            parameter height to lenght
UT2D_2pt_ck_int_2pt         check if 2 linesegments intersect with tol
UT2D_is_convex_inpt3        check if indexed contour is convex | concave
UT2D_ck_pt_in_tria_tol      check if point is inside triangle with tol

UT2D_box_inpt3              2D-bounding-box for 3D-points
UT23D_box_addTol            add tolerance to box

UT2D_box_2pt__              2D-bounding-box for 2 2D-points
UT2D_box_2pt_tol            2D-bounding-box for 2 2D-points with tol

// ../ut/ut_npt.c
UT3D_npt_inpt2              3D-points from indexed-2D-points

GR_Disp_inpt                display indexed polygon

UT2D_test_..

List_functions_end:
=====================================================
*/


#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_memTab.h"           // MemTab_..
#include "../xa/tst_new.h"
#include "../ut/ut_txt.h"              // fnam_del UTX_find_chr


#include "../ut/ut_itmsh.h"            // MSHIG_EDGLN_.. typedef_MemTab.. Fac3
#include "../ut/msh2d.h"



/*
//================================================================
  int _MemTab_wrf (FILE *fp1, MemTab *mt) {
//================================================================
// write MemTab to file


  fwrite(mt, sizeof(MemTab), 1, fp1);
  
  if(mt->rNr > 0)
  fwrite(mt->data, mt->rSiz, mt->rNr, fp1);
  
  
  return 0;
}
  

//================================================================
  int _MemTab_rdf (FILE *fp1, MemTab *mt1) {
//================================================================
// read MemTab from file
// mt1 must already have rSiz

  int     rNr;
  long    l1;
  MemTab  mt2;


  printf("MemTab_rdf rNr=%d rMax=%d rSiz=%d\n",
             mt1->rNr,mt1->rMax,mt1->rSiz);

  // copy mt1
  mt2 = *mt1;

  // overwrite mt1
  fread(mt1, sizeof(MemTab), 1, fp1);

     printf("        in rNr=%d rMax=%d rSiz=%d\n",
             mt1->rNr, mt1->rMax, mt2.rSiz);
     // UT3D_stru_dump (Typ_MemTab, mt2, "MemTab_dump");

  // keep old dataPos and size
  mt1->data = mt2.data;
  mt1->rMax = mt2.rMax;

  // add space if necessary
  if(mt1->rNr > mt2.rMax) {
    rNr = mt1->rNr - mt2.rMax + 4;
    MemTab_add (mt1, &l1, NULL, rNr, 2);
  }

  // overwrite data
  if(mt1->rNr > 0)
  fread(mt1->data, mt1->rSiz, mt1->rNr, fp1);


  return 0;
}
*/


/* UU
//================================================================
  int UFA_Disp_nEdg2 (int eNr, int *fa, int *ea,
                     Fac3 *fTab, Point *p2a,
                     char *opts, int grAtt, double zVal) {
//================================================================
// display 2D-edges 
// Input:
//   eNr      nr of edges
//   fa,ea    edges to display
//   fTab     table of (all) faces
//   p2a      table of (all) points
//   opts     s-disp.faces-shaded; b-disp.curve-faceBound
// TODO: Disp sollte eigentlich das Init & Exit nicht selbst machen, damit
//       mehrere Disp-functions into 1 dispList gepckt weden können ..

  int     i1;
  long    dbi = -1l, dli;  // dynam.
  Point2  pta[2];


  printf("UFA_Disp_nEdg2 eNr=%d opts=|%s| grAtt=%d zVal=%f\n",
         eNr,opts,grAtt,zVal);

   // boundary
  dli = DL_StoreObj (Typ_CVPOL, dbi, grAtt);
  GL_Draw_Ini (&dli, Typ_Att_Fac1);  // init cv/surf, glNewList < GL_fix_DL_ind


  //----------------------------------------------------------------
  // Must display surface before boundary.
  if(!strchr(opts, 's') ) goto L_bvi;
    // display shaded triangles
    GL_att_su (ATT_COL_GREEN);

    for(i1=0; i1 < eNr; ++i1) {
      // if(fa[ii].st < 0) continue;   // skip deleted faces
      UFA_Disp_fac2 (&fTab[fa[i1]], p2a, zVal);
    }


  //----------------------------------------------------------------
  L_bvi:
  if(!strchr(opts, 'b') ) goto L_end;

  // GL_DrawLn_Ini (&dli, grAtt);
  // GR_Disp_ln2
  // GL_Draw_Ini (&dli, grTyp);  // init cv/surf, glNewList < GL_fix_DL_ind
  GL_att_cv (grAtt);   // INF_COL_CV

  for(i1=0; i1 < eNr; ++i1) {
    // get the points of edge cf1a[i1],ce1a[i1]
    UFA_2pt2_fac_esn (&pta[0], &pta[1], ea[i1], &fTab[fa[i1]], p2a);
      // UT3D_stru_dump (Typ_PT2, &pta[0], " ps");
      // UT3D_stru_dump (Typ_PT2, &pta[1], " pe");
    GL_Disp_cv2z (2, pta, zVal);
  }


  //----------------------------------------------------------------
  L_end:
  GL_EndList1 (0);     // glEndList


  return 0;

}
*/


/* UU
//================================================================
  int UFA_view2__ (Fac3 *fa, int ifs, int fNr, Point2 *pa, int pNr,
                  char *opts, long dbi, double zVal) {
//================================================================
// UFA_view__   display indexed faces
//   fa       table of faces
//   ifs      index of first face to display
//   fNr      nr of faces to display
//   pa       table of points
//   pNr      only for opts "pn"
//   opts v   disp normalvector in gravity-centerPoint
//        b   disp bounds of faces
//        s   disp triangle shaded
//        f   disp faceNr in gravity-centerPoint
//        P   disp all points as (SYM_STAR_S,ATT_COL_BLUE)
//        n   disp all point-numbers
//   dbi    0L   do not use DispList (write into open DispList)
//         -1L   use dynamic DispList
//         >=1   use/overwrite existing DispList
//
// see MSH_test_disp_f1 UPAT_ipatch_disp_opts
// TODO: only s works ..


  int      irc, i1, ii, iBnd, iVc, iTx, iVT, iNr, *ia, ife;
  long     dli;
  char     s1[40];
  Point2   ptt[4], *pgca;
  Point    pg3;
  Vector   vcn;
  Fac3     *fAct;
  Triangle *ta;


  ife = ifs + fNr;

  printf("UFA_view2__ ifs=%d fNr=%d dbi=%ld pNr=%d opts=|%s|\n",
                      ifs, fNr, dbi, pNr, opts);




  //----------------------------------------------------------------
  if(dbi) {
    if(dbi > 0) {
      DL_SetInd (dbi);
    }
    dli = DL_StoreObj (Typ_GL_Sur, dbi, Typ_Att_Fac1);
    GL_Draw_Ini (&dli, Typ_Att_Fac1);  // init cv/surf, glNewList < GL_fix_DL_ind
  }



  //----------------------------------------------------------------
  // Must display surface before boundary.
  if(!strchr(opts, 's') ) goto L_bvi;
    // display shaded triangles
    GL_att_su (ATT_COL_GREEN);

    for(ii=ifs; ii<ife; ++ii) {
      if(fa[ii].st < 0) continue;   // skip deleted faces
      UFA_Disp_fac2 (&fa[ii], pa, zVal);
    }


  //----------------------------------------------------------------
  L_bvi:

  iBnd = UTX_find_chr(opts, 'b');  // find character in string; 0=no, 1=yes
  iVc = UTX_find_chr(opts, 'v');
  iTx = UTX_find_chr(opts, 'f');
  // iTx = (iOff >= 0) ? 1 : 0; // (opts, 'i');
  iVT = iVc + iTx;
    printf(" iBnd=%d iVc=%d iTx=%d\n",iBnd,iVc,iTx);




  //----------------------------------------------------------------
  // display boundary as polygon
  if(iBnd) {
      GL_att_cv (9);
    for(ii=ifs; ii<ife; ++ii) {
      if(fa[ii].st < 0) continue;   // skip deleted faces
      // set display-attributes for curves
      ptt[0] = pa[fa[ii].i1];
      ptt[1] = pa[fa[ii].i2];
      ptt[2] = pa[fa[ii].i3];
      ptt[3] = pa[fa[ii].i1];
      GL_Disp_cv2z (4, ptt, zVal);
    }
  }


  //----------------------------------------------------------------
  if(!iVT) goto L_points;


  // get space for pgca = gravity-centerPoints
  ii = ife - ifs;
  pgca = (Point2*) MEM_alloc_tmp (ii * sizeof(Point2));


  // set all gravity-centerPoints
  i1 = 0;
  for(ii=ifs; ii<ife; ++ii) {
    if(fa[ii].st < 0) continue;   // skip deleted faces
    UT2D_pt_gcp_3pt (&pgca[i1], &pa[fa[ii].i1], &pa[fa[ii].i2], &pa[fa[ii].i3]);
    ++i1;
  }


  // disp faceNr in gravity-centerPoint
  if(iTx) {
    GL_att_cv (Typ_Att_def);
    i1 = 0;
    for(ii=ifs; ii<ife; ++ii) {
      if(fa[ii].st < 0) continue;   // skip deleted faces
      // sprintf(s1,"%d",iOff + ii);
      sprintf(s1,"%d",ii);
      pg3 = UT3D_pt_pt2z (&pgca[i1], zVal);
      GL_Disp_txtA (&pg3, s1);
      ++i1;
    }
  }


  // disp normalvector in gravity-centerPoint
  if(iVc) {
    GL_att_cv (Typ_Att_def);
    i1 = 0;
    for(ii=ifs; ii<ife; ++ii) {
      UT3D_vc_perp3pt (&vcn, &pa[fa[ii].i1], &pa[fa[ii].i2], &pa[fa[ii].i3]);
      // UT3D_vc_setLength (&vcn, &vcn, 1.);
        // UT3D_stru_dump (Typ_VC, &vcn, " vcn: ");
      // GL_Disp_vSym (SYM_ARROW, &pg3, &vcn, 10., 0); //ATT_COL_HILI);
      GL_Disp_vc (&vcn, &pgca[i1], ATT_COL_CYAN);
      ++i1;
    }
  }


  //----------------------------------------------------------------
  L_points:
  if(strchr(opts, 'p')) {
    //  p   disp points as (SYM_STAR_S,ATT_COL_BLUE)
    GL_att_sym (ATT_COL_BLUE);
    for(i1=0; i1<pNr; ++i1) {
        GL_Disp_symB (SYM_TRI_S, &pa[i1]);
    }
  }


  //----------------------------------------------------------------
  if(strchr(opts, 'n')) {
    //  n   disp point-numbers
    GL_att_cv (Typ_Att_Symb);
    for(i1=0; i1<pNr; ++i1) {
      sprintf(s1,"%d",i1);
      GL_Disp_txtA (&pa[i1], s1);  // Typ_Att_Symb = 7 = yellow thick3
    }
  }


  //----------------------------------------------------------------
  L_done:
  if(dbi) {
    GL_EndList ();     // glEndList
  }

  return 0;

}
*/

//=====================================================================
  int UT3D_npt_inpt2 (Point *pta,
                      int ptNr, int *ipta, Point2 *pt2a, double zVal) {
//=====================================================================
// UT3D_npt_inpt2              3D-points from indexed-2D-points

  int   i1;

  for(i1=0; i1<ptNr; ++i1) {
    memcpy (&pta[i1], &pt2a[ipta[i1]], sizeof(Point2));
    pta[i1].z = zVal;
  }


  return 0;

}


/*
//============================================================================
  int UFA_if_nf_2ip (int *if1, int *en1, int ifNr, int *ifa, int ips, int ipe,
                     Fac3 *fa) {
//============================================================================
// UFA_if_nf_2ip    find edge from 2 oriented points in list of faces
// see also UFA_ifac_ck_edgo
// Input:
//   ips,ipe    2 points - oriented edge (find this edge)
//   ifa        list of <ifNr> faces
// Output:
//   if1        face index
//   en1        edge ips-ipe
//   retCod     0  OK; 
//              -1 edge ips-ipe not found

  int    i1, iif;


  printf("UFA_if_nf_2ip iips=%d ipe=%d\n",ips,ipe);
  for(i1=0;i1<ifNr;++i1) printf(" fa[%d]=%d\n",i1,ifa[i1]);


  for(i1=0; i1<ifNr; ++i1) {
    iif = ifa[i1];

    if(fa[iif].i1 == ips) {
      if(fa[iif].i2 == ipe) {*en1 = 1; goto L_fnd;}
      continue;
    }

    if(fa[iif].i2 == ips) {
      if(fa[iif].i3 == ipe) {*en1 = 2; goto L_fnd;}
      continue;
    }

    if(fa[iif].i3 == ips) {
      if(fa[iif].i1 == ipe) {*en1 = 3; goto L_fnd;}
      continue;
    }
  }

    // TX_Error("UFA_if_nf_2ip E1_%d_%d",ips,ipe);
  return -1;


  L_fnd:
  *if1 = iif;

    printf("ex-UFA_if_nf_2ip f%d e%d\n",*if1,*en1);

  return 0;

}


//================================================================
  int UTP_sorta_nval_nint (int iNr, double *da, int *ia) {
//================================================================
// UTP_sorta_nval_nint         sort indexed values ascending 

  int     i1, i2;

  L_sort1:
  i1 = 0;

  for(i2=1; i2<iNr; ++i2) {
    if(da[i1] > da[i2]) {
        // printf(" _nval_npt swap %d %d\n",i1,i2);
      // swap value and int
      MEM_swap_2db (&da[i1], &da[i2]);
      MEM_swap__ (&ia[i1], &ia[i2], sizeof(int));
      goto L_sort1;
    }
    ++i1;
  }

    // for(i1=0;i1<iNr;++i1) printf(" sort-%d-%lf\n",i1,da[i1]);

  return 0;

}

 
//================================================================
  int UT2D_box_2pt__ (Point2 *pb1, Point2 *pb2,
                      Point2 *pt1, Point2 *pt2) {
//================================================================
// see UT3D_box_2pt


  if(pt1->x < pt2->x) {
    pb1->x = pt1->x;
    pb2->x = pt2->x;
  } else {
    pb1->x = pt2->x;
    pb2->x = pt1->x;
  }

  if(pt1->y < pt2->y) {
    pb1->y = pt1->y;
    pb2->y = pt2->y;
  } else {
    pb1->y = pt2->y;
    pb2->y = pt1->y;
  }

  // GR_Disp_box (pb1, pb2, 2);

  return 0;

}



//================================================================
  int UT2D_box_2pt_tol (Point2 *pb1, Point2 *pb2,
                        Point2 *pt1, Point2 *pt2, double *tol) {
//================================================================
// see UT3D_box_2pt


  if(pt1->x < pt2->x) {
    pb1->x = pt1->x - *tol;
    pb2->x = pt2->x + *tol;
  } else {
    pb1->x = pt2->x - *tol;
    pb2->x = pt1->x + *tol;
  }

  if(pt1->y < pt2->y) {
    pb1->y = pt1->y - *tol;
    pb2->y = pt2->y + *tol;
  } else {
    pb1->y = pt2->y - *tol;
    pb2->y = pt1->y + *tol;
  }

  // GR_Disp_box (pb1, pb2, 2);

  return 0;

}
*/



//=======================================================================
  int GR_Disp_inpt2 (int ptNr, int *ipa, Point2 *pa, int iClo, int iatt)  {
//=======================================================================
// display indexed polygon
// TODO: MISMATCH pa §D - 2D !

  return GL_view_inpt (ptNr, ipa, pa, iClo, iatt);

}


/*
//================================================================
  int _UT2D_sid_3pt (Point2 *pt,  Point2 *p1, Point2 *p2) {
//================================================================
/// \code
/// UT2D_sid_3pt               compare if pt is on, above or below line (p1-p2)
///
///                 . X
///            vp.     pt    1
///        . 
///   p1------------vl--------p2->
///            
///                         -1
/// 
/// RetCode:
///   0   pt is on vector vl
///   1   pt is above vector vl (left side)
///  -1   pt is below vector vl (right side)
///
/// side before,behind: UT2D_sidPerp_3pt
/// \endcode

  int      irc;
  double   d1;
  Vector2  vl, vp;


  UT2D_vc_2pt (&vl, p1, p2);
    UT3D_stru_dump (Typ_VC2, &vl, "  vl");

  UT2D_vc_2pt (&vp, p1, pt);
    UT3D_stru_dump (Typ_VC2, &vp, "  vp");

  d1 = vl.dx * vp.dy - vp.dx * vl.dy;  // - vl.dx * vp.dy;
    printf(" d1=%f\n",d1);


  return DSIGTOL (d1, UT_TOL_min2);

}


//======================================================================
  int UT2D_sid_ptvc____ (Point2 *pt,  Point2 *pl, Vector2 *vl) {
//======================================================================
/// \code
/// UT2D_sid_ptvc____           compare if pt is on, above or below line (pl+vl)
///
///                 X pt      1
///           pl
/// ----------X-------vl--->  0
///            
///                 X pt     -1
/// 
/// retcode:
///   0   pt is on vector vl
///   1   pt is above vector vl (left side)
///  -1   pt is below vector vl (right side)
/// \endcode

  double   d1;
  Vector2  vp;

  // UT3D_stru_dump (Typ_PT2, pt, "UT2D_sid_ptvc__ pt");
  // UT3D_stru_dump (Typ_PT2, pl, "  pl");
  // UT3D_stru_dump (Typ_VC2, vl, "  vl");

  UT2D_vc_2pt (&vp, pl, pt);
    // UT3D_stru_dump (Typ_VC2, &vp, "  vp");

  d1 = vp.dx * vl->dy - vl->dx * vp.dy;
    // printf(" d1=%f\n",d1);

  return DSIGTOL (d1, UT_TOL_min2);  // 2017-10-04 was UT_TOL_min1

}


//===========================================================================
  int UT2D_sid_ptvc__tol (Point2 *pt,  Point2 *pl, Vector2 *vl, double *tol) {
//===========================================================================
/// \code
/// UT2D_sid_ptvc__tol         compare if pt is on, above or below line with tol
///
///                 X pt      1
///           pl
/// ----------X-------vl--->  0
///            
///                 X pt     -1
/// 
/// retcode:
///   0   pt is on vector vl
///   1   pt is above vector vl (left side)
///  -1   pt is below vector vl (right side)
/// \endcode
// see also UT2D_sid_2vc_tol

  Vector2  vp;

  // UT3D_stru_dump (Typ_PT2, pt, "UT2D_sid_ptvc__ pt");
  // UT3D_stru_dump (Typ_PT2, pl, "  pl");
  // UT3D_stru_dump (Typ_VC2, vl, "  vl");

  UT2D_vc_2pt (&vp, pl, pt);
    // UT3D_stru_dump (Typ_VC2, &vp, "  vp");

  return UT2D_sid_2vc_tol (vl, &vp, tol);

}


//================================================================
  int UT2D_sid_2vc__ (Vector2 *v1, Vector2 *v2) {
//================================================================
/// TODO: replace with UT2D_sid_2vc_tol (see UT2D_ck_pt_in_tria_tol UT2D_2pt_ck_int_2pt
/// \code
/// UT2D_sid_2vc         check vc for left (CCW, above) or right (CW, below)
/// vectors must not be normalized
/// RC   1   v2 is above v1  (pos. angle)
/// RC   0   v1-v2 are parallel
/// RC  -1   v2 is below v1  (neg. angle)
/// 
///              X
///           v2/          1
///            /
/// ----------X---v1----------->  0
///            
///                       -1
/// 
/// was UT2D_sid_2vc
/// see also UT2D_sidPerp_2vc UT2D_sar_2vc
/// \endcode

  int    irc;
  double sk;


  // UT3D_stru_dump (Typ_VC, v1, "UT3D_sid_2vc__");
  // UT3D_stru_dump (Typ_VC, v2, "              ");

  // see UT2D_sar_2vc
  sk = v1->dx * v2->dy - v2->dx * v1->dy;

  return DSIGTOL (sk, UT_TOL_min2);

}
*/

/*
//================================================================
  int UT2D_sid_2vc_tol (Vector2 *v1, Vector2 *v2, double *tol) {
//================================================================
/// \code
/// UT2D_sid_2vc_tol     check vc for left (CCW, above) or right (CW, below)
/// vectors must not be normalized
/// RC   1   v2 is above v1  (pos. angle)
/// RC   0   v1-v2 are within tolerance (parallel)
/// RC  -1   v2 is below v1  (neg. angle)
/// 
///              X
///           v2/          1
///            /
/// ----------X---v1----------->  0
///            
///                       -1
/// 
/// see also UT2D_sidPerp_2vc UT2D_sar_2vc
/// \endcode


  int     isl, isr;
  double  rTol;
  Vector2 vl, v2l, vr, v2r;


  // UT3D_stru_dump (Typ_VC2, v1, "UT2D_sid_2vc_tol");
  // UT3D_stru_dump (Typ_VC2, v2, "              ");

  // get vector for tolerance above (left-side)
  UT2D_vcPerpAppr_vc_len (&vl, v1, tol);
    // printf(" vl.dx=%f dy=%f\n", vl.dx, vl.dy);

  // move endPt of v2 <tol> up
  UT2D_vc_add2vc (&v2l, v2, &vl);
    // printf(" v2l.dx=%f dy=%f\n", v2l.dx, v2l.dy);

  // see UT2D_sar_2vc
  isr = DSIGN (v1->dx * v2l.dy - v2l.dx * v1->dy);
    // printf(" isr=%d\n",isr);

  // -1 = below tolerance
  if(isr < 0) return isr;

  // get vector for tolerance above (left-side) - invert vr
  UT2D_vc_invert (&vr, &vl);
    // printf(" vr.dx=%f dy=%f\n", vr.dx, vr.dy);

  // move endPt of v2 <tol> down
  UT2D_vc_add2vc (&v2r, v2, &vr);
    // printf(" v2r.dx=%f dy=%f\n", v2r.dx, v2r.dy);

  // see UT2D_sar_2vc
  isl = DSIGN (v1->dx * v2r.dy - v2r.dx * v1->dy);
    // printf(" isl=%d\n",isl);

  // 1 = above tolerance
  if(isl > 0) return isl;

  // within tolerance
  return 0;

}


/// UT2D_vcPerpAppr_vc_len create vector with fixed length normal to vector
/// approximation (not precise)
/// Vector2 vp, vc={ 0.5, -1.}; double dd = 0.1;
/// UT2D_vcPerpAppr_vc_len (&vp, &vc, &dd); printf(" dx=%f dy=%f\n",vp.dx,vp.dy);
void UT2D_vcPerpAppr_vc_len (Vector2 *vco, Vector2 *vci, double *len);
#define UT2D_vcPerpAppr_vc_len(vco,vci,len){\
 if(fabs((vci)->dx) > fabs((vci)->dy))\
 {(vco)->dy = 0.; (vco)->dx = ((vci)->dx > 0.) ? *len : -*len;}\
 else\
 {(vco)->dx = 0.; (vco)->dy = ((vci)->dy > 0.) ? *len : -*len;}}


*/


//================================================================
//================================================================
// Liste_TESTFUNKTIONEN:
//================================================================
//================================================================

#ifdef DEB




//================================================================
  int tst_tst__ () {
//================================================================

  int       id, in, ir;
  double    dd, dr;

  printf("tst_tst__ \n");

  // UT2D_test_sid__ ();
  // UT2D_test_ck_pt_in_tria_tol ();
  // UT2D_test_2pt_ck_int_2pt ();
  MemTab_test_I_add_s ();


  printf("ex-tst_tst__\n");

  return 0;

}


#endif


// EOF
