bool ON_PolyEdgeCurve::EvSrfTangent( 
        double t,
        bool bIsoDir,
        ON_3dPoint& srfpoint,
        ON_3dVector& srftangent,
        ON_3dVector& srfnormal
        ) const
{
  ON_3dPoint srfpt;
  ON_3dVector du, dv, duu, duv, dvv;
  bool rc = EvSrfDerivatives(t,srfpoint,du,dv,duu,duv,dvv);
  if (rc )
    rc = ON_EvNormal( 0, du, dv, duu, duv, dvv, srfnormal ) ? true : false;
  if (rc)
  {
    int segment_index = SegmentIndex(t);
    ON_PolyEdgeSegment* seg = SegmentCurve(segment_index);
    if ( seg )
    {
      if ( bIsoDir && seg->IsoType() == ON_Surface::not_iso )
        bIsoDir = false;
      
      ON_3dVector crvtangent = TangentAt(t);
      ON_3dVector binormal = ON_CrossProduct(crvtangent,srfnormal);
      binormal.Unitize();
      if ( seg->ReversedTrimDir() )
        binormal.Reverse();
      // at this point, binormal points "out" and is tangent
      // to the surface.
      if ( bIsoDir )
      {
        du.Unitize();
        dv.Unitize();
        double B_dot_du = binormal*du;
        double B_dot_dv = binormal*dv;
        if ( fabs(B_dot_dv) > fabs(B_dot_du) )
        {
          if (B_dot_dv < 0.0)
            dv.Reverse();
          srftangent = dv;
        }
        else
        {
          if (B_dot_du < 0.0)
            du.Reverse();
          srftangent = du;
        }
      }
      else
        srftangent = binormal;

      if ( seg && seg->m_face && seg->m_face->m_bRev )
        srfnormal.Reverse();
    }
    else
      rc = false;
  }
  return rc;
}
ON_2dPoint ON_PolyEdgeCurve::SurfaceParameter(double t) const
{
  ON_2dPoint srf_uv(ON_UNSET_VALUE,ON_UNSET_VALUE);
  int segment_index = SegmentIndex(t);
  ON_PolyEdgeSegment* seg = SegmentCurve( segment_index );
  if ( seg )
  {
    ON_Interval pdom = SegmentDomain(segment_index);
    ON_Interval sdom = seg->Domain();
    if ( sdom != pdom )
    {
      double s = pdom.NormalizedParameterAt(t);
      t = sdom.ParameterAt(s);
    }
    srf_uv = seg->SurfaceParameter(t);
  }
  return srf_uv;
}
double ON_PolyEdgeCurve::TrimParameter(double t) const
{
  double trim_t = ON_UNSET_VALUE;
  int segment_index = SegmentIndex(t);
  ON_PolyEdgeSegment* seg = SegmentCurve( segment_index );
  if ( seg )
  {
    ON_Interval pdom = SegmentDomain(segment_index);
    ON_Interval sdom = seg->Domain();
    if ( sdom != pdom )
    {
      double s = pdom.NormalizedParameterAt(t);
      t = sdom.ParameterAt(s);
    }
    trim_t = seg->TrimParameter(t);
  }
  return trim_t;
}
  template <> DLL_HEADER Ng_Element Ng_GetElement<1> (int nr)
  {
    const Segment & el = mesh->LineSegment (SegmentIndex(nr));

    Ng_Element ret;
    ret.type = NG_ELEMENT_TYPE(el.GetType());

    ret.points.num = el.GetNP();
    ret.points.ptr = (int*)&(el[0]);

    ret.vertices.num = 2;
    ret.vertices.ptr = (int*)&(el[0]);

    ret.edges.num = 1;
    ret.edges.ptr = mesh->GetTopology().GetSegmentElementEdgesPtr (nr);

    ret.faces.num = 0;
    ret.faces.ptr = NULL;

    return ret;
  }
NGX_INLINE DLL_HEADER Ng_Element Ngx_Mesh :: GetElement<1> (int nr) const
{
    const Segment & el = mesh->LineSegment (SegmentIndex(nr));

    Ng_Element ret;
    ret.type = NG_ELEMENT_TYPE(el.GetType());
    ret.index = el.si;
    ret.points.num = el.GetNP();
    ret.points.ptr = (int*)&(el[0]);

    ret.vertices.num = 2;
    ret.vertices.ptr = (int*)&(el[0]);

    ret.edges.num = 1;
    ret.edges.ptr = (T_EDGE2*)mesh->GetTopology().GetSegmentElementEdgesPtr (nr);

    ret.faces.num = 0;
    ret.faces.ptr = NULL;

    return ret;
}
NGX_INLINE DLL_HEADER int Ngx_Mesh :: GetElementIndex<1> (int nr) const
{
  return (*mesh)[SegmentIndex(nr)].si;
}
 DLL_HEADER int Ng_GetElementIndex<1> (int nr)
 {
   return (*mesh)[SegmentIndex(nr)].si;
 }
ON_Surface::ISO ON_PolyEdgeCurve::IsoType( double t) const
{
  ON_PolyEdgeSegment* seg = SegmentCurve( SegmentIndex(t) );
  return seg ? seg->IsoType() : ON_Surface::not_iso;
}
const ON_Surface*  ON_PolyEdgeCurve::SurfaceAt(double t) const
{
  ON_PolyEdgeSegment* seg = SegmentCurve( SegmentIndex(t) );
  return seg ? seg->Surface() : 0;
}
const ON_Brep*     ON_PolyEdgeCurve::BrepAt(double t) const
{
  ON_PolyEdgeSegment* seg = SegmentCurve( SegmentIndex(t) );
  return seg ? seg->Brep() : 0;
}
const ON_BrepTrim* ON_PolyEdgeCurve::TrimAt(double t) const
{
  ON_PolyEdgeSegment* seg = SegmentCurve( SegmentIndex(t) );
  return seg ? seg->Trim() : 0;
}
const ON_BrepEdge* ON_PolyEdgeCurve::EdgeAt(double t) const
{
  ON_PolyEdgeSegment* seg = SegmentCurve( SegmentIndex(t) );
  return seg ? seg->Edge() : 0;
}
bool ON_PolyEdgeCurve::EvSrfDerivatives(
        double t,
        ON_3dPoint& srfpoint,
        ON_3dVector& du,
        ON_3dVector& dv,
        ON_3dVector& duu,
        ON_3dVector& duv,
        ON_3dVector& dvv
        ) const
{
  bool rc = false;
  int segment_index = SegmentIndex(t);
  ON_PolyEdgeSegment* seg = SegmentCurve( segment_index );
  if ( seg )
  {
    ON_Interval pdom = SegmentDomain(segment_index);
    ON_Interval sdom = seg->Domain();
    double s = t;
    if ( sdom != pdom )
    {
      double x = pdom.NormalizedParameterAt(t);
      s = sdom.ParameterAt(x);
    }
    // s is the segment parameter at the polyedge parameter t
    // Get the corresponding surfaces parameters
    ON_2dPoint srf_uv = seg->SurfaceParameter(s);
    if ( ON_IsValid(srf_uv.x) )
    {
      if ( srf_uv.x == seg->m_evsrf_uv[0] && srf_uv.y == seg->m_evsrf_uv[1] )
      {
        rc = true;
        srfpoint = seg->m_evsrf_pt;
        du = seg->m_evsrf_du;
        dv = seg->m_evsrf_dv;
        duu = seg->m_evsrf_duu;
        duv = seg->m_evsrf_duv;
        dvv = seg->m_evsrf_dvv;
      }
      else if ( seg->m_surface )
      {
        rc = seg->m_surface->Ev2Der( 
                  srf_uv.x, srf_uv.y, 
                  srfpoint, 
                  du, dv, 
                  duu, duv, dvv, 
                  0, seg->m_evsrf_hint 
                  ) ? true : false;
        if ( rc )
        {
          CookDerivativesHelper( du, dv, duu, duv, dvv);
          seg->m_evsrf_uv[0] = srf_uv.x;
          seg->m_evsrf_uv[1] = srf_uv.y;
          seg->m_evsrf_pt = srfpoint;
          seg->m_evsrf_du = du;
          seg->m_evsrf_dv = dv;
          seg->m_evsrf_duu = duu;
          seg->m_evsrf_duv = duv;
          seg->m_evsrf_dvv = dvv;
        }
      }
    }
  }
  return rc;
}