////////////////////////////////////////////////////////////////////////////////
//
//    
//
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"

#include "LibObj.h"
#include "events\DocumentFrameEvent.h"
#include <Math.h>
#include <SArray.h>
#include <SSArray.h>

#include <GL\gl.h>

#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "glaux.lib")


#define   LENGTH_EPSILON    1E-10 //  


extern IApplicationPtr newKompasAPI; //    

PArray<LibObj> m_libObjects;
LibObj * LibObj::editObj = NULL;


#define SELECT    "SELECT" 
#define ROOT      "ROOT" 
#define FORCES    "FORCES" 
#define FOLDER    "FOLDER"
#define EXPAND    "EXPAND"
#define GRIDEDGES "GRIDEDGES"
#define STRAINS   "STRAINS"  
#define FORCES_TREE _T("FORCES TREE") 

#define ARROW_M3D  _T("\\Models\\ .m3d") 
#define STRAIN_M3D _T("\\Models\\ _def.m3d")

#define LIBVERSION 1l

//-----------------------------------------------------------------------------
//
// ---
LibObj * FindOrCreateLibObj( IDocumentFramePtr & docFrame, bool create )
{
  LibObj * res = NULL;
  if ( docFrame )
  {
    LibObj * next = NULL;
    for ( int i = 0, count = m_libObjects.Count(); i < count; i++ )
    {
      next = m_libObjects[i];
      if ( next && next->IsMyFrame(docFrame) )
      {
        res = next;
        break;
      }  
    }
    if ( !res && create )
    {  
      res = new LibObj( docFrame );
      m_libObjects.Add( res );
    }
  }
  return res;
}


//------------------------------------------------------------------------------
//     (by AVR)
// ---
bool GetFullName( LPCTSTR inName, LPTSTR outName, int outNameLen ) 
{
  bool     rez; //    name
  OFSTRUCT ofs;
  
  if ( ::GetModuleFileName(OneWindowDLL.hModule, outName, outNameLen) )
  {
    TCHAR * c = ::_tcsrchr( outName, _T('\\') );
    if( c )
    {
      *(c + 1) = _T('\0');
      ::_tcscat( outName, inName );
      rez = ::OpenFile( _bstr_t(outName), &ofs, OF_EXIST ) != HFILE_ERROR;
      if ( !rez ) 
      {
        *(c + 1) = _T('\0');
        ::_tcscat( outName, _T("LOAD\\") );
        ::_tcscat( outName, inName );
        rez = ::OpenFile( _bstr_t(outName), &ofs, OF_EXIST ) != HFILE_ERROR;
      }
    }
  }
  
  if ( !rez ) 
  {
    ::ksGetFullPathFromSystemPathT( (LPTSTR)inName,         //    (    )
      outName,        // ()    
      outNameLen,     //  
      sptSYSTEM_FILES //    . ksSystemPath
      );
    
    rez = ::OpenFile( _bstr_t(outName), &ofs, OF_EXIST ) != HFILE_ERROR;
  }
  
  return rez;
}


//-----------------------------------------------------------------------------
//  
// ---
void Matrix3D::Init()
{
  el[0][1] = el[0][2] = el[0][3] = 0.0;
  el[1][0] = el[1][2] = el[1][3] = 0.0;
  el[2][0] = el[2][1] = el[2][3] = 0.0;
  el[3][0] = el[3][1] = el[3][2] = 0.0;
  el[0][0] = 1.0;
  el[1][1] = 1.0;
  el[2][2] = 1.0;
  el[3][3] = 1.0;
}


//-----------------------------------------------------------------------------
// el    double[16]
// ---
Matrix3D::Matrix3D( double * el16 )
{
  el[0][0] = el16[0];
  el[0][1] = el16[1];
  el[0][2] = el16[2];
  el[0][3] = el16[3];
  el[1][0] = el16[4];
  el[1][1] = el16[5];
  el[1][2] = el16[6];
  el[1][3] = el16[7];
  el[2][0] = el16[8];
  el[2][1] = el16[9];
  el[2][2] = el16[10];
  el[2][3] = el16[11];
  el[3][0] = el16[12];
  el[3][1] = el16[13];
  el[3][2] = el16[14];
  el[3][3] = el16[15];
}

//-----------------------------------------------------------------------------
//
// ---
void Matrix3D::Init( Point3D  &original, 
                     Vector3D &normal,   
                     Vector3D &axisX, 
                     Vector3D &axisY )
{
  GetOrigin() = original;
  GetAxisX () = axisX;  //  
  GetAxisY () = axisY;  //  
  GetAxisZ () = normal; //  
}


//-----------------------------------------------------------------------------
//
// ---
void Matrix3D::Init( ISurface & surf,   //  
                     bool       isSameSense,  //         
                     double     u,      //  u 
                     double     v )     //  v;   
{
  Init();
  Point3D & original = GetOrigin();
  surf.GetPoint( u, v, &original.x, &original.y, &original.z );
  Vector3D & ax = GetAxisX ();  
  surf.GetTangentVectorU( u, v, &ax.x, &ax.y, &ax.z ); //    U

  Vector3D & ay = GetAxisY ();  
  surf.GetTangentVectorV( u, v, &ay.x, &ay.y, &ay.z ); //    V
 
  Vector3D & az = GetAxisZ ();  
  surf.GetNormal( u, v, &az.x, &az.y, &az.z ); //    uv
  if ( !isSameSense ) //    z   y   x
  {  
    //   Z
    az.x = -az.x;
    az.y = -az.y;
    az.z = -az.z;
    //   Y
    ay.x = -ay.x;
    ay.y = -ay.y;
    ay.z = -ay.z;
  }
}


//------------------------------------------------------------------------------
//    
// ---
bool Matrix3D::operator == ( const Matrix3D &m ) const {
  bool bRes = true;
  for ( int i = 0; (i < 4) && bRes; i++ ) {   
    bRes = ( (::fabs(el[i][0] - m.el[i][0]) <= LENGTH_EPSILON) &&
      (::fabs(el[i][1] - m.el[i][1]) <= LENGTH_EPSILON) &&
      (::fabs(el[i][2] - m.el[i][2]) <= LENGTH_EPSILON) &&
      (::fabs(el[i][3] - m.el[i][3]) <= LENGTH_EPSILON) );
  }
  return bRes;
}


//------------------------------------------------------------------------------
//    this = this * b;
// ---
Matrix3D staticMatrix; //   
void Matrix3D::Multiply( const Matrix3D &b ) {  
  staticMatrix.Init( b, *this );
  ::memcpy( el, staticMatrix.el, sizeof(el) );
}

//------------------------------------------------------------------------------
//   this = (B * A), Init( A, B ) != A * B !!!
// ---
void Matrix3D::Init( const Matrix3D &A, const Matrix3D &B ) {

    el[0][0] = ( A.el[0][0] * B.el[0][0] + A.el[1][0] * B.el[0][1] + A.el[2][0] * B.el[0][2] );
    el[0][1] = ( A.el[0][1] * B.el[0][0] + A.el[1][1] * B.el[0][1] + A.el[2][1] * B.el[0][2] );
    el[0][2] = ( A.el[0][2] * B.el[0][0] + A.el[1][2] * B.el[0][1] + A.el[2][2] * B.el[0][2] );

    el[1][0] = ( A.el[0][0] * B.el[1][0] + A.el[1][0] * B.el[1][1] + A.el[2][0] * B.el[1][2] );
    el[1][1] = ( A.el[0][1] * B.el[1][0] + A.el[1][1] * B.el[1][1] + A.el[2][1] * B.el[1][2] );
    el[1][2] = ( A.el[0][2] * B.el[1][0] + A.el[1][2] * B.el[1][1] + A.el[2][2] * B.el[1][2] );

    el[2][0] = ( A.el[0][0] * B.el[2][0] + A.el[1][0] * B.el[2][1] + A.el[2][0] * B.el[2][2] );
    el[2][1] = ( A.el[0][1] * B.el[2][0] + A.el[1][1] * B.el[2][1] + A.el[2][1] * B.el[2][2] );
    el[2][2] = ( A.el[0][2] * B.el[2][0] + A.el[1][2] * B.el[2][1] + A.el[2][2] * B.el[2][2] );

    el[3][0] = ( A.el[0][0] * B.el[3][0] + A.el[1][0] * B.el[3][1] + A.el[2][0] * B.el[3][2] );
    el[3][1] = ( A.el[0][1] * B.el[3][0] + A.el[1][1] * B.el[3][1] + A.el[2][1] * B.el[3][2] );
    el[3][2] = ( A.el[0][2] * B.el[3][0] + A.el[1][2] * B.el[3][1] + A.el[2][2] * B.el[3][2] );

    
    el[3][0] += ( A.el[3][0] * B.el[3][3] );
    el[3][1] += ( A.el[3][1] * B.el[3][3] );
    el[3][2] += ( A.el[3][2] * B.el[3][3] );

    el[0][3] = 0.0;
    el[1][3] = 0.0;
    el[2][3] = 0.0;

    el[3][3] = ( A.el[3][3] * B.el[3][3] );

}


//-------------------------------------------------------------------------------
//   SafeArray  double
// ---
VARIANT CreateSafeArray( SArray<Point3D> & points )
{
  VARIANT varRow;
  VariantInit(&varRow);
  
  int varsCount = points.Count() * 3; 

  SAFEARRAYBOUND sabNewArray;
  sabNewArray.cElements = varsCount;
  sabNewArray.lLbound = 0;
  
  SAFEARRAY * pSafe = ::SafeArrayCreate( VT_R8, 1, &sabNewArray );
  
  if( pSafe )
  {
    for ( long i = 0, j = 0, count = points.Count(); i < count; i++, j++ )
    {
      Point3D & point = points[i];
      ::SafeArrayPutElement( pSafe, &j, &point.x );
      j++;
      ::SafeArrayPutElement( pSafe, (long*)&j, (void*)&point.y );
      j++;
      ::SafeArrayPutElement( pSafe, (long*)&j, (void*)&point.z );
    }
    
    V_VT(&varRow) = VT_ARRAY | VT_R8;
    V_ARRAY(&varRow) = pSafe;
  }
  return varRow;
}


//-------------------------------------------------------------------------------
//   SafeArray  double
// ---
VARIANT CreateSafeArray( SArray<Matrix3D> & matrix )
{
  VARIANT varRow;
  VariantInit(&varRow);
  
  int varsCount = matrix.Count() * 16; 
  
  SAFEARRAYBOUND sabNewArray;
  sabNewArray.cElements = varsCount;
  sabNewArray.lLbound = 0;
  
  SAFEARRAY * pSafe = ::SafeArrayCreate( VT_R8, 1, &sabNewArray );
  
  if( pSafe )
  {
    for ( long i = 0, j = 0, count = matrix.Count(); i < count; i++ )
    {
      Matrix3D & m = matrix[i];
      for ( int ei = 0; ei < 4; ei++ )
      {
        for ( int ej = 0; ej < 4; ej++ )
        {
          ::SafeArrayPutElement( pSafe, &j, &m.el[ei][ej] );
          j++; 
        }
      }  
    }
    
    V_VT(&varRow) = VT_ARRAY | VT_R8;
    V_ARRAY(&varRow) = pSafe;
  }
  return varRow;
}


//-------------------------------------------------------------------------------
//   SafeArray  double
// ---
VARIANT CreateSafeArray( SArray<long> & arr )
{
  VARIANT varRow;
  
  VariantInit(&varRow);
  
  int varsCount = arr.Count(); 
  SAFEARRAYBOUND sabNewArray;
  sabNewArray.cElements = varsCount;
  sabNewArray.lLbound = 0;
  
  SAFEARRAY * pSafe = ::SafeArrayCreate( VT_I4, 1, &sabNewArray );
  
  if( pSafe )
  {
    for ( long i = 0; i < varsCount; i++ )
    {
      ::SafeArrayPutElement( pSafe, (long*)&i, (void*)&arr[i] );
    }
    
    V_VT(&varRow) = VT_ARRAY | VT_I4;
    V_ARRAY(&varRow) = pSafe;
  }
  return varRow;
}


//-------------------------------------------------------------------------------
//   SafeArray  double
// ---
BOOL SafeArrayToSArray( const VARIANT & arr, SArray<Point3D> & points )
{
  BOOL res = FALSE;
  if ( arr.vt == (VT_ARRAY | VT_R8) && arr.parray ) {
    //          
    int count = arr.parray->rgsabound[0].cElements;
    if ( arr.parray->cDims == 1 && count && !(count % 3) ) 
    {
      HRESULT hr;
      double HUGEP *pvar;
      hr = ::SafeArrayAccessData(arr.parray, (void HUGEP* FAR*)&pvar);
      if ( !FAILED(hr) && pvar ) 
      {
        count = count / 3;
        
        //      
        for ( int i = 0; i < count; i++ ) {
          Point3D point( pvar[i*3], pvar[i*3+1], pvar[i*3+2] );
          points.Add( point );
        }
        
        hr = ::SafeArrayUnaccessData(arr.parray);
        if ( !FAILED(hr) )
          res = TRUE;
      }
    }
  }
  return res;
}

//-------------------------------------------------------------------------------
//   SafeArray  double
// ---
BOOL SafeArrayToSArray( const VARIANT & arr, SArray<long> & sArr )
{
  BOOL res = FALSE;
  if ( arr.vt == (VT_ARRAY | VT_I4) && arr.parray ) {
    //          
    int count = arr.parray->rgsabound[0].cElements;
    if ( arr.parray->cDims == 1 && count ) 
    {
      HRESULT hr;
      long HUGEP *pvar;
      hr = ::SafeArrayAccessData(arr.parray, (void HUGEP* FAR*)&pvar);
      if ( !FAILED(hr) && pvar ) 
      {
        
        //      
        for ( int i = 0; i < count; i++ ) {
          sArr.Add( pvar[i] );
        }
        
        hr = ::SafeArrayUnaccessData(arr.parray);
        if ( !FAILED(hr) )
          res = TRUE;
      }
    }
  }
  else
    if ( arr.vt == VT_I4 )
      sArr.Add( arr.lVal );
  return res;
}

//-------------------------------------------------------------------------------
//   SafeArray  double
// ---
BOOL SafeArrayToSArray( const VARIANT & arr, SArray<Matrix3D> & sArr )
{
  BOOL res = FALSE;
  if ( arr.vt == (VT_ARRAY | VT_R8) && arr.parray ) {
    //          
    int count = arr.parray->rgsabound[0].cElements;
    if ( arr.parray->cDims == 1 && count && !(count % 16) ) 
    {
      HRESULT hr;
      double HUGEP *pvar;
      hr = ::SafeArrayAccessData(arr.parray, (void HUGEP* FAR*)&pvar);
      if ( !FAILED(hr) && pvar ) 
      {
        count = count / 16;
        
        //      
        for ( int i = 0; i < count; i++ ) 
        {

          Matrix3D m( &pvar[i*16] );
          sArr.Add( m );
        }
        
        hr = ::SafeArrayUnaccessData(arr.parray);
        if ( !FAILED(hr) )
          res = TRUE;
      }
    }
  }
  return res;
}

//-----------------------------------------------------------------------------
//
// ---
template < class T >
VARIANT CreateDispSafeArray( PArray<T> & objects )
{
  VARIANT res;
  ::VariantInit( &res ); //   
  
  int count = objects.Count();
  if ( count )
  {
    
    SAFEARRAYBOUND sabNewArray;
    sabNewArray.cElements = count;
    sabNewArray.lLbound   = 0;
    
    //    
    SAFEARRAY __RPC_FAR * psa = SafeArrayCreate( VT_DISPATCH, 1, &sabNewArray );
    res.vt = VT_ARRAY | VT_DISPATCH;
    res.parray = psa;
    
    for( long i = 0; i < count; i++ )        //    
    {
      //    API
      IDispatchPtr obj7( IUnknownPtr(::ksTransferInterface( *objects[i], ksAPI7Dual, 0 ), false/*AddRef*/ ) );
      //    
      ::SafeArrayPutElement( psa, &i, (void *)(LPDISPATCH)obj7 );
    }
  }  
  return res;
}

//-----------------------------------------------------------------------------
//
// ---
template < class T >
void FillObjectsDefinitions( _variant_t &varArr, PArray<T> & objects )
{
  if ( varArr.vt == (VT_ARRAY | VT_DISPATCH) && varArr.parray )
  {
    LPDISPATCH obj = NULL;     
    int count = varArr.parray->rgsabound[0].cElements;
    for( long i = 0; i < count; i++ )        //    
    {
      SafeArrayGetElement( varArr.parray, &i, &obj );
      //    API
      if ( obj )
      {
        IEntityPtr newObj( IUnknownPtr(ksTransferInterface(obj, ksAPI3DCom, o3d_entity), false/*AddRef*/) );
        if ( newObj )
        {
          IUnknownPtr def( newObj->GetDefinition(), false/*AddRef*/ );
          T tDef( def );
          if ( tDef )
            objects.Add( new T(tDef) );
        }
        obj->Release();
        obj = NULL;
      }
    }
  } 
  else if ( varArr.vt == VT_DISPATCH )
  {
    IEntityPtr newObj( IUnknownPtr(ksTransferInterface(varArr.pdispVal, ksAPI3DCom, o3d_entity), false/*AddRef*/) );
    if ( newObj )
    {
      IUnknownPtr def( newObj->GetDefinition(), false/*AddRef*/ );
      T tDef( def );
      if ( tDef )
        objects.Add( new T(tDef) );
    }
  }
}


//-----------------------------------------------------------------------------
//
// ---
struct GrridEdge
{
  long m_i1;
  long m_i2;
  GrridEdge( long i1, long i2 )
    : m_i1( i1 > i2 ? i2 : i1 ) 
    , m_i2( i1 > i2 ? i1 : i2 ) 
  {
  }
  
  bool operator==(const GrridEdge& other ) const
  {
    return ( m_i1 == other.m_i1 && m_i2 == other.m_i2 ); 
  }  

  bool operator <( const GrridEdge & other ) const  //   
  {
    return ( m_i1 < other.m_i1) || (( m_i1 == other.m_i1) && (m_i2 < other.m_i2)); 
  }  
  
  
};


#pragma warning( disable : 4786 ) 
//-----------------------------------------------------------------------------
//         
// ---
ExternalTeselationParam::ExternalTeselationParam( IEntityPtr & obj, IPartPtr & topPart )
  : color          ( 0     ) //  
  , ambient        ( 1     ) //  
  , diffuse        ( 1     ) // 
  , specularity    ( 1     ) // 
  , shininess      ( 1     ) //  
  , transparency   ( 1     ) // 
  , emission       ( 1     ) // 
  , edge           ( false ) //   
{
  if ( obj )
  {
    IUnknownPtr def( obj->GetDefinition(), false/*addRef*/ );
    if ( def )
    {
      if ( obj->GetType() == o3d_face ) 
      {
        obj->GetAdvancedColor( &color, &ambient, &diffuse, &specularity, &shininess, &transparency, &emission );
        if ( transparency > 0.001 ) //      
          InitByFace( IFaceDefinitionPtr(def) );
      }
      else if ( obj->GetType() == o3d_edge )
      {
        IEdgeDefinitionPtr edgeDef( def );
        if ( edgeDef )
        {
          IFaceDefinitionPtr face( edgeDef->GetAdjacentFace(false), false/*AddRef*/ );
          if ( face )
          {
            InitByEdge( edgeDef );
            edge         = true;
            color        = RGB( 0, 0, 0 );
          }
        }  
      }
      IPartPtr parentPart;
      if ( topPart )
      {
        parentPart.Attach( obj->GetParent(), false/*addRef*/ ); 
        if ( topPart  == parentPart )
          parentPart = NULL;
      }

      if ( parentPart )
      {
        if ( points.vt == (VT_ARRAY | VT_R8) )
          topPart->TransformPoints( &points, parentPart );
        
        if ( normals.vt == (VT_ARRAY | VT_R8) )
        {
          double x0 = 0.0, y0 = 0.0, z0 = 0.0; 
          topPart->TransformPoint( &x0, &y0, &z0, parentPart );
          if ( fabs(x0) > LENGTH_EPSILON || 
               fabs(y0) > LENGTH_EPSILON || 
               fabs(z0) > LENGTH_EPSILON )
          {
            topPart->TransformPoints( &normals, parentPart );
            SArray<Point3D> normalsArr;
            SafeArrayToSArray( normals, normalsArr );
            Point3D p0( x0, y0, z0 );
            for ( int i = 0, count = normalsArr.Count(); i < count; i++ )
            {
              normalsArr[i] -= p0;
            }  
            normals.Attach( CreateSafeArray(normalsArr) ); 
          }
        }
      }
    }
  }
}
#pragma warning( once : 4786 ) 

//-----------------------------------------------------------------------------
//       
// ---
ExternalTeselationParam::ExternalTeselationParam( PArray<ExternalTeselationParam> & params )
  : color       ( RGB(0,0,0) ) //  
  , ambient     ( 1          ) //  
  , diffuse     ( 1          ) // 
  , specularity ( 1          ) // 
  , shininess   ( 1          ) //  
  , transparency( 1          ) // 
  , emission    ( 1          ) // 
  , edge        ( true       ) //   
{
  PacEdges( params );
}


//-----------------------------------------------------------------------------
//   
// ---
void ExternalTeselationParam::InitByFace( IFaceDefinitionPtr &faceDef )
{
  if ( faceDef )
  {
    BOOL plane = faceDef->IsPlanar();
    ITessellationPtr tess( faceDef->GetTessellation(), false/*addRef*/ );
    if ( tess )
    {
      if ( plane )
      {
        float x, y, z; 
        tess->GetNormal(0, &x, &y, &z );         //        
        SArray<Point3D> norm;
        norm.Add( Point3D(x, y, z) );
        normals.Attach( CreateSafeArray(norm) );
      }
      else
        tess->GetFacetNormals( &normals );
      
      tess->GetFacetPoints( &points, &indexes );
    }
  }
}


//-----------------------------------------------------------------------------
//
// ---
void ExternalTeselationParam::InitByEdge( IEdgeDefinitionPtr &edgeDef )
{
  if ( edgeDef )
  {
    ICurve3DPtr curve( edgeDef->GetCurve3D(), false/*addRef*/ );
    if ( curve )
    {
      BOOL line = curve->IsLineSeg();  
      if ( line ) //          
      {
        SArray<Point3D> p;
        double x, y, z; 
        curve->GetPoint( curve->GetParamMin(), &x, &y, &z );
        p.Add( Point3D(x, y, z) );
        curve->GetPoint( curve->GetParamMax(), &x, &y, &z );
        p.Add( Point3D(x, y, z) );
        points.Attach( CreateSafeArray(p) );
      }
      else
        curve->CalculatePolygon( 0/*step*/, &points ); //    

      if ( points.vt == (VT_ARRAY | VT_R8) && points.parray )
      {
        SArray<long> ind;
        long count = points.parray->rgsabound[0].cElements / 3;
        ind.Add(count);
        for ( int i = 0; i < count; i ++ )
        {
          ind.Add(i);
        } 
        
        indexes.Attach( CreateSafeArray(ind) ); 
      }  
    }
  }
}


//-----------------------------------------------------------------------------
//      
// ---
void ExternalTeselationParam::PacEdges( PArray<ExternalTeselationParam> & params ) 
{
  SArray<Point3D> p;
  SArray<long>    edges;
  for ( int i = 0, count = params.Count(); i < count; i++ )
  {
    if ( params[i]->edge )
    {
      long oldCount = p.Count();
      SafeArrayToSArray( params[i]->points, p );
      long newCount = p.Count();
      edges.Add( newCount - oldCount );
      for ( int j = oldCount; j < newCount; j++ )
        edges.Add( j ); //   
    }  
  }
  points.Attach(  CreateSafeArray(p)     );
  indexes.Attach( CreateSafeArray(edges) );

}
   

//-----------------------------------------------------------------------------
//     SafeArray-
// ---
void FillParts( _variant_t & parts, PArray<IPartPtr> & partsArr )
{
  int count = parts.parray->rgsabound[0].cElements;
  if ( parts.parray->cDims == 1 && count ) 
  {
    LPDISPATCH obj = NULL;
    for ( long i = 0; i < count; i++ )
    {
      SafeArrayGetElement( parts.parray, &i, &obj ); //  AddRef
      if ( obj )
      {
        IPartPtr newPart( IUnknownPtr(ksTransferInterface(obj, ksAPI3DCom, o3d_part), false/*AddRef*/) );
        if ( newPart )
          partsArr.Add( new IPartPtr(newPart) );

        obj->Release(); //  
      }
    }  
  }
}


//-----------------------------------------------------------------------------
//    
// ---
void LoadTessellations( PArray<ExternalTeselationParam> & params, IPartPtr & topPart, IPartPtr & nextPart )
{
  if ( nextPart )
  {
    IEntityPtr pointCS( nextPart->GetDefaultEntity( o3d_pointCS ), false );
    if ( pointCS )
    {
      pointCS->SetHidden( TRUE );
      pointCS->Update();
    }
    IEntityCollectionPtr coll( nextPart->EntityCollection(o3d_face), false/*AddRef*/ );
    if ( coll )
    {
      for ( int i = 0, count = coll->GetCount(); i < count; i++ )
      {
        IEntityPtr entity( coll->GetByIndex(i), false/*AddRef*/ );
        if ( entity )
        {
          ExternalTeselationParam * param = new ExternalTeselationParam(entity, topPart);
          if ( param->IsValid() )  
            params.Add( param );
          else
            delete param;
        }
      }  
    }
    
    coll.Attach( nextPart->EntityCollection(o3d_edge), false/*AddRef*/ );
    if ( coll )
    {
      for ( int i = 0, count = coll->GetCount(); i < count; i++ )
      {
        IEntityPtr entity( coll->GetByIndex(i), false/*AddRef*/ );
        if ( entity )
        {
          ExternalTeselationParam * param = new ExternalTeselationParam(entity, topPart);
          if ( param->IsValid() )  
            params.Add( param );
          else
            delete param;
        }
      }  
    }

    if ( !nextPart->IsDetail() )
    {
      IPart7Ptr part7( IUnknownPtr( ksTransferInterface(nextPart, ksAPI7Dual, 0), false) );
      if ( part7 )
      {
        PArray<IPartPtr> partsArr;
        {
          _variant_t parts( part7->PartsEx[(long)ksAllParts] ); //          
          FillParts( parts, partsArr );
        }
        for ( int i = 0, count = partsArr.Count(); i < count; i++ )
        {
          LoadTessellations( params, topPart, *partsArr[i] );
        }  
      }
    }
  }  
}


//-----------------------------------------------------------------------------
//    
// ---
bool LoadTessellations( PArray<ExternalTeselationParam> & params, _bstr_t & fileName )
{
  //       
  if ( fileName.length() > 0 )
  {
    IDocument3DPtr doc3D( ksGet3dDocument(), false/*AddRef*/ );
    if ( (bool)doc3D && doc3D->Open( fileName, 1 ) ) 
    {
      {  //     
        IPartPtr topPart( doc3D->GetPart(pTop_Part), false/*AddRef*/ );
        if ( topPart )
          LoadTessellations( params, topPart, topPart );
      }
      doc3D->Close();
      ResultNULL(); //      
    }
  } 
  return params.Count() > 0;
}



////////////////////////////////////////////////////////////////////////////////
//
// 
//
////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------
// 
//---
LibObj::LibObj( IDocumentFramePtr & frame ) 
  : PropertyManagerObject(       )
  , m_command            ( 0     )
  , m_documentFrameEvent ( NULL  )
  , m_arrowsIndex        ( 1     ) //   
  , m_newArrow           ( NULL  ) 
  , m_treeCtrlEvent      ( NULL  )
  , m_treeViewEvent      ( NULL  )
  , m_TreeVisible        ( true  )
  , m_LoadTree           ( false ) 

{
  NOPARAM.vt    = VT_ERROR;
  NOPARAM.scode = DISP_E_PARAMNOTFOUND;
  
  m_treeMenu.LoadMenu( IDM_TREE_MENU );
  if ( frame )
  {
    m_documentFrameEvent = NewDocumentFrameEvent( frame->GetParent(), frame, *this );
    LoadTree();
  }  
}


//-----------------------------------------------------------------------------
//
// ---
LibObj::~LibObj()
{
  CloseTree();
  OffAllTessellations();
  delete m_documentFrameEvent;
}


//-----------------------------------------------------------------------------
//
// ---
void LibObj::OffAllTessellations()
{
  for ( int i = 0, count = m_arrows.Count(); i < count; i++ )
    OnOffTesselations( m_arrows[i]->m_iids,  false, m_arrows[i]->m_visible,  true );
}


//-------------------------------------------------------------------------------
//    
// ---
bool LibObj::OnChangeControlValue( /*IPropertyControl* cntrl,*/ long ctrlID, const VARIANT & newVal ) 
{
  return true;  
} 


//---------------------------------------------------------------------------------------------------- 
//   
// ---
bool LibObj::OnButtonClick( long buttonID ) 
{ 
  bool res = true; 
  if ( buttonID == pbEnter )
  {
    switch ( m_command )
    {
      case 1:
      {  
        if ( m_newArrow )
        {
          m_newArrow->m_index = m_arrowsIndex;
          AddNode( _T(FORCES), IDP_FORCE, m_arrowsIndex );
          m_arrowsIndex++;
          m_newArrow = NULL;
        }
        break;
      }
    }
    res = false; //   
  }
  else
  {
    if ( buttonID == pbEsc )
    {
      if ( m_newArrow )
      {
        OnOffTesselations( m_newArrow->m_iids, false, true, true );
        m_arrows.RemoveObj( m_newArrow );
        m_newArrow = NULL;
      }
    }  
  }  
  return res; 
}


//-----------------------------------------------------------------------------
// prControlCommand   
// ---
bool LibObj::OnControlCommand( long ctrlID, long buttonID )
{
  return false;
}


//-----------------------------------------------------------------------------
// prButtonUpdate        -    .
// ---
bool LibObj::OnButtonUpdate(long buttonID, long* check, VARIANT_BOOL* _enable)
{
  if ( buttonID == pbEnter && _enable )
  {
    switch ( m_command )
    {
      case 1: *_enable = !!m_newArrow; break;
    }
  }
  return true;
}

  
//-----------------------------------------------------------------------------
//
// ---
bool LibObj::IsMyFrame( IDocumentFramePtr & frame )
{
  return frame == GetFrame();
}

//-----------------------------------------------------------------------------
//  
// ---
IDocumentFramePtr LibObj::GetFrame()                              
{
  return IDocumentFramePtr( m_documentFrameEvent ? m_documentFrameEvent->GetContainer(FALSE/*AddRef*/) : NULL );
}


//-----------------------------------------------------------------------------
//    
// ---
void LibObj::CreateForce()
{
  m_command = 1;
  CreateTree();
  SelectFacesForForce(); 
  SaveTree();
} 
              

//-----------------------------------------------------------------------------
//      
// ---
void LibObj::CreateTree()          
{
  if ( !(bool)m_TreeCtrl && m_TreeVisible )
  {
    IDocumentFramePtr frame( GetFrame() );
    IFrameTreesManagerPtr mng( frame );
    if ( mng )
    {
      m_TreeCtrl = mng->AddTab( LoadStr(IDS_TREE_NAME), LoadStr(IDS_VCTREE_ID) );

      IImageListPtr m_treeImageList = InitTreeImageList();   //     
      FillTree( m_treeImageList );                            //  
    
      m_treeCtrlEvent = new ADVCTreeEvents( m_TreeCtrl, *this );

      //  InitToolBarImageList(); //     toolbar'a
      //  InitToolBar();          //  toolbar
    }
  }
}


//-----------------------------------------------------------------------------
//   
// ---
void LibObj::CloseTree() 
{
  if ( m_TreeCtrl )
  {
    IDocumentFramePtr frame( GetFrame() );
    IFrameTreesManagerPtr mng( frame );
    if ( mng )
    {
      mng->RemoveTab( m_TreeCtrl );
      m_TreeCtrl = NULL;
      m_TreeVeiw = NULL;
    }
  }
  delete m_treeViewEvent;
  m_treeViewEvent = NULL;
  delete m_treeCtrlEvent;
  m_treeCtrlEvent = NULL;

}


//-----------------------------------------------------------------------------
// \ 
// ---
void LibObj::OnOfTree()
{
  m_TreeVisible = (bool)m_TreeCtrl && m_TreeVisible ? false : true;
  if ( m_TreeVisible )
  {
    CreateTree();
    if ( m_TreeCtrl )
    {
      IDocumentFramePtr frame( GetFrame() );
      IFrameTreesManagerPtr mng( frame );
      if ( mng )
      {
        mng->ActiveTab = m_TreeCtrl;
      }
    }  
  }  
  else
    CloseTree(); 
}


//-----------------------------------------------------------------------------
//  
// ---
void LibObj::FillTree(  IImageListPtr & treeImageList )          
{
  if ( m_TreeCtrl )
  {
    m_TreeVeiw = m_TreeCtrl->GetTree();
    
    if ( m_TreeVeiw )
    {
      m_TreeVeiw->LineStyle   = tvwTreeLines;
      m_TreeVeiw->Style       = tvwTreelinesPlusMinusPictureText;
      m_TreeVeiw->LabelEdit   = tvwManual;
      m_TreeVeiw->Indentation = 0;

      ASSERT((bool)treeImageList); //  !!!
      // Set imageList to tree
      m_TreeVeiw->ImageList = treeImageList;
      
      
      INodesPtr nodes = m_TreeVeiw->GetNodes();
      // Add Nodes                                                          // VARIANT*
      INodePtr root = nodes->Add( &NOPARAM,                                 // Relative
                                  &NOPARAM,                                 // Relationship
                                  &_variant_t(      _T(ROOT)),              // Key
                                  &_variant_t(LoadStr(IDS_STRENGTH_TEST)),  // Text            +  
                                  &_variant_t(      _T(ROOT)),              // Image           |
                                  &_variant_t(      _T(ROOT) _T(SELECT)) ); // SelectedImage
      
      INodePtr node = nodes->Add( &_variant_t(     _T(ROOT)),               // Relative
                                  &_variant_t( (long)tvwChild ),            // Relationship
                                  &_variant_t(     _T(FORCES)),             // Key
                                  &_variant_t(LoadStr(IDS_FORCES)),         // Text            |-    
                                  &_variant_t(     _T(FOLDER) ),            // Image
                                  &_variant_t(     _T(FOLDER) _T(SELECT))); // SelectedImage
      
 
               FillTreeNodes( _T(FORCES),    IDP_FORCE,    m_arrows  );
 
               root->Expanded = true;
      m_treeViewEvent = new ATreeViewEvent( m_TreeVeiw, *this );  
    }
  }
}

//-----------------------------------------------------------------------------
///     
// ---
IImageListPtr LibObj::InitTreeImageList()
{
  IImageListPtr treeImageList  = m_TreeCtrl ? m_TreeCtrl->CreateImageList() : NULL; // 
  
  if ( treeImageList )
  {
    //  11   20*20   
    treeImageList->ImageHeight = 16;
    treeImageList->ImageWidth  = 16;

    //   10 
    CPictureHolder pict[8];
    pict[0].CreateFromBitmap( IDB_ROOT               ); //  
    pict[1].CreateFromBitmap( IDB_ROOTSELECT         ); //   
    
    pict[2].CreateFromBitmap( IDB_FOLDER             ); // 
    pict[3].CreateFromBitmap( IDB_FOLDERSELECT       ); //   
    
    pict[4].CreateFromBitmap( IDB_FOLDEREXPAND       ); //  
    pict[5].CreateFromBitmap( IDB_FOLDEREXPANDSELECT ); //   
    
    pict[6].CreateFromBitmap( IDB_FORCES             ); // 
    pict[7].CreateFromBitmap( IDB_FORCESSELECT       ); //  

    
    //   m_treeImageList
    IImagesPtr images = treeImageList->ListImages;
    images->Add(&NOPARAM, &_variant_t(     _T(ROOT)                 ), &_variant_t(pict[ 0].GetPictureDispatch())); 
    images->Add(&NOPARAM, &_variant_t(_bstr_t(ROOT SELECT)          ), &_variant_t(pict[ 1].GetPictureDispatch())); 
    images->Add(&NOPARAM, &_variant_t(     _T(FOLDER)               ), &_variant_t(pict[ 2].GetPictureDispatch())); 
    images->Add(&NOPARAM, &_variant_t(_bstr_t(FOLDER SELECT)        ), &_variant_t(pict[ 3].GetPictureDispatch())); 
    images->Add(&NOPARAM, &_variant_t(_bstr_t(FOLDER EXPAND)        ), &_variant_t(pict[ 4].GetPictureDispatch())); 
    images->Add(&NOPARAM, &_variant_t(_bstr_t(FOLDER EXPAND SELECT) ), &_variant_t(pict[ 5].GetPictureDispatch())); 
    images->Add(&NOPARAM, &_variant_t(     _T(FORCES)               ), &_variant_t(pict[ 6].GetPictureDispatch())); 
    images->Add(&NOPARAM, &_variant_t(_bstr_t(FORCES SELECT)        ), &_variant_t(pict[ 7].GetPictureDispatch())); 
  }
  return treeImageList;
}


//-----------------------------------------------------------------------------
//
// ---
BOOL LibObj::BeginPaintGL ( IDocumentFramePtr & docFrame, ksGLObjectPtr & glObj, long drawMode ) 
{ 
  bool visible = false;
  if ( visible )
  {
    //   
    ::glClearColor( 1.0f, 1.0f, 1.0f, 1.0f );    
    ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
  }

  return !visible; 
}


// DocumentFrameEventCalback #########################################################
// frAddGabarit          -   
BOOL LibObj::AddGabarit( IDocumentFramePtr & docFrame, IGabaritObjectPtr & gabObj )
{
  bool arrowsVisible  = IsArrowsVisible();
    
  if ( (bool)gabObj && (arrowsVisible ) )
  {
    double x1;
    double y1;
    double z1;
    double x2;
    double y2;
    double z2;
    VARIANT_BOOL res = gabObj->GetCurrentGabarit( 0, &x1, &y1, &z1, &x2, &y2, &z2 );
    if ( res ) {
      double delta = 100; 
      x1 -= delta;
      y1 -= delta;
      z1 -= delta;
      x2 += delta;
      y2 += delta;
      z2 += delta;
      res = gabObj->AddGabarit( x1, y1, z1, x2, y2, z2 );
    }
  }
  return TRUE;
}


//-----------------------------------------------------------------------------
// frCloseFrame          -  
// ---
BOOL LibObj::CloseFrame( IDocumentFramePtr & docFrame )
{
  //    
  m_libObjects.RemoveObj(this);
  return true;
}
// DocumentFrameEventCalback #########################################################


//------------------------------------------------------------------------------
//  
// ---
bool WINAPI LibObj::SELECTFILTERPROC( IEntity* entity ) 
{
  return entity && entity->IsIt( o3d_face ); //   
}


//------------------------------------------------------------------------------
//   
// ---
int WINAPI LibObj::SELECTCALLBACKPROC( IEntity* entity, IRequestInfo* info ) 
{ 
  BOOL res = FALSE;
  if ( editObj && entity && entity->IsIt( o3d_face ) ) //   
  {
    IFaceDefinitionPtr faceDef( IUnknownPtr(entity->GetDefinition(), false/*AddRef*/) );
    res = editObj->OnSelectFace( faceDef );
  }
  return res;
}


//-----------------------------------------------------------------------------
//
// ---
BOOL LibObj::OnSelectFace( IFaceDefinitionPtr & face )
{
  switch ( m_command )
  {
    case 1: CreateForce        ( face ); break; //   
  }
  return TRUE;
}


#pragma warning( disable : 4786 )
//-----------------------------------------------------------------------------
//          
// ---
bool GetSummMtr( IKompasDocument3DPtr & doc3D, Matrix3D & summMtr, IFaceDefinitionPtr & face )
{
  if ( (bool)doc3D && (bool)face )
  {
    IPart7Ptr part7( doc3D->TopPart );
     
    IEntityPtr parent( face->GetEntity(), false/*AddRef*/ );
    if ( (bool)part7 && (bool)parent )
    {
      IPartPtr part( parent->GetParent(), false/*AddRef*/ );
      IPartPtr topPart( IUnknownPtr(ksTransferInterface(part7, ksAPI3DCom, o3d_part), false/*AddRef*/) );
      if ( topPart != part )
      {
        _variant_t mtr;
        topPart->GetSummMatrix( &mtr, part ); //      
        SArray<Matrix3D> arrMtr;
        SafeArrayToSArray( mtr, arrMtr );
        summMtr = arrMtr[0];  
      }
    }  
  }
  return !(summMtr == Matrix3D()); 
}
#pragma warning( once : 4786 ) 


//-----------------------------------------------------------------------------
//     
// ---
void LibObj::LoadArrowParams()
{
  if ( arrowParams.Count() == 0 ) //     
  {
    TCHAR arrowFile[_MAX_PATH] = _T("");
    GetFullName( ARROW_M3D, arrowFile, _MAX_PATH ); 
    if ( arrowFile[0] )
    {
      //     
      LoadTessellations(arrowParams, _bstr_t(arrowFile) );
    }
    else
    {
      MessageT( _T("   :" ARROW_M3D) );
    }  
  }
}


//-----------------------------------------------------------------------------
//   
// ---
void LibObj::CreateForce( IFaceDefinitionPtr & face )
{
  LoadArrowParams();
  if ( arrowParams.Count() )
  {
    IDocumentFramePtr docFrame( GetFrame() );
    if ( docFrame )
    {
      if ( !m_newArrow )
      {
        m_newArrow = new ArrowParam();
        m_arrows.Add(m_newArrow);
      }

      m_newArrow->m_faces.Add( new IFaceDefinitionPtr(face) );
      
      m_newArrow->m_visible = true;

      m_newArrow->Make( face, docFrame, arrowParams );

      docFrame->SetGabaritModifying();
      docFrame->RefreshWindow();
    }
  }
} 


//-----------------------------------------------------------------------------
//     
//-----------------------------------
//     U, %  V, %
// 1     0             0
// 2     0             50
// 3     0             100
// 4     50            0
// 5     50            50
// 6     50            100
// 7     100           0
// 8     100           50
// 9     100           100
// ---
void MakeMatrixes( ISurfacePtr & surf, bool isSameSense, SArray<Matrix3D> & matrix )
{
  if ( surf )
  {
    double uMin = surf->GetParamUMin(),
           uMax = surf->GetParamUMax(),
           vMin = surf->GetParamVMin(),
           vMax = surf->GetParamVMax();
    double du   = (uMax - uMin) * 0.5; 
    double dv   = (vMax - vMin) * 0.5; 
    Matrix3D m;
    double u = uMin, v;
    for ( int i = 0; i < 3; i++, u+= du )           
    {
      v = vMin;
      for ( int j = 0; j < 3; j++, v+= dv )           
      {
        m.Init( surf, isSameSense, u, v );
        matrix.Add(m);
      } 
    }
  }  
}


//-----------------------------------------------------------------------------
//       
// ---
void LibObj::SelectFacesForForce()
{
  SelectFaces( IDP_FORCE, STR_SELECT_FACES );
}


//-----------------------------------------------------------------------------
//       
// ---
void LibObj::SelectFaces( long procID, long promtID )
{
  IDocumentFramePtr frame( GetFrame() );
  if ( frame )
  {
    IKompasDocument3DPtr komDoc3D( frame->GetParent()->GetParent() );
    IDocument3DPtr doc3D( IUnknownPtr( ksTransferInterface(komDoc3D, ksAPI3DCom, o3d_document), false) );
    if ( doc3D )
    {
      IRequestInfoPtr info( doc3D->GetRequestInfo(NULL), false/*AddRef*/  );
      if ( info )
      {
        //      
        info->SetPrompt        ( LoadStr( promtID ) );
        info->SetFilterCallBack( SELECTFILTERPROC   );
        info->SetCallBack      ( SELECTCALLBACKPROC ); 
      }
      
      if( InitProcessParam( procID, pnEnterEscHelp, procID ) )
      {
        m_procParam->AutoReduce = false;     
        info->SetProcessParam( m_procParam );            
        editObj = this;
        doc3D->UserGetPlacementAndEntity(0);
        editObj = NULL;
        EndProcess();
      }  
    }
  }     
}


//-----------------------------------------------------------------------------
//     
// ---
void  LibObj::ShowControls ()  
{
}


//-----------------------------------------------------------------------------
// \         
// ---
void LibObj::OnOffTesselations( SArray<long> & iids, bool vis, bool oldVis, bool del )
{
  if ( iids.Count() )
  {
    IDocumentFramePtr frame( GetFrame() );
    if ( frame )
    {
      IKompasDocument3DPtr komDoc3D( frame->GetParent()->GetParent() );
      IExternalTessellationManagerPtr mng( komDoc3D );
      if ( mng )
      {
        _variant_t varIids( CreateSafeArray(iids), vis );
        if ( vis != oldVis )
          mng->ObjectsVisible[varIids][frame] = vis;  // \ 
        if ( del )
        {
          mng->DeleteObjects( varIids );              // 
          iids.Flush();
        }  
        frame->SetGabaritModifying();
        frame->RefreshWindow();
      }
    }   
  }  
}


//-----------------------------------------------------------------------------
//   
// ---
bool LibObj::AddNode( LPCTSTR key, long nameID, int index )
{
  bool res = false;
  if ( m_TreeVeiw )
  {
    _bstr_t name( MakeNodeName(LoadStr(nameID), index ) );
    INodesPtr nodes = m_TreeVeiw->GetNodes();
    _bstr_t selectIndex( key );
    selectIndex+= _T(SELECT);
    // Add Nodes                                                        // VARIANT*
    INodePtr  node = nodes->Add( &_variant_t(       key          ),     // Relative
                                 &_variant_t( (long)tvwChild     ),     // Relationship
                                 &_variant_t(       name         ),     // Key
                                 &_variant_t(       name         ),     // Text                
                                 &_variant_t(       key          ),     // Image
                                 &_variant_t(       selectIndex  ) );   // SelectedImage
    if ( node )
    {
      node->PutTag( (long)index );
      
      node = node->Parent;
      if ( !node->Expanded )  
        node->Expanded = true;
      
      res = true;
    }
  } 
  return res;
} 


//-----------------------------------------------------------------------------
//
// ---
LPCTSTR LibObj::MakeNodeName( LPCTSTR name, int index )
{
  static CString nodeName;
  if ( index != 0 )
    nodeName.Format( _T("%s:%i"), name, index );
  else
    nodeName = name;
  return nodeName;
}


//-----------------------------------------------------------------------------
//
// ---
bool LibObj::IsArrowsVisible()
{
  bool res = !!m_newArrow;
  for ( int i = 0, count = m_arrows.Count(); i < count && !res; i++ )
    res = m_arrows[i]->m_visible;
  return res;
}


// ADVCTreeEventsCallBack #########################################################
//-----------------------------------------------------------------------------
//   
// ---
void LibObj::OnMenuCommand ( long Id )
{
  if ( m_TreeVeiw )
  {
    INodePtr curNode( m_TreeVeiw->SelectedItem );
    if ( curNode )
    {
      long tag = curNode->Tag;
      switch ( Id )
      {
        case 501:  // 
        {
          break;
        }
        case 502:  //  
        {
          int index = GetIndexByID( tag, m_arrows );
          if ( index >= 0 )
          {
            ArrowParam * param = m_arrows[index];
            OnOffTesselations( param->m_iids, false, param->m_visible, true ); // 
            m_arrows.RemoveInd( index );
            m_TreeVeiw->Nodes->Remove( &_variant_t( curNode->Index ) ); //     
          }
          break;
        }
        case 503: //  
        {
          int index = GetIndexByID( tag, m_arrows );
          if ( index >= 0 )
          {
            ArrowParam * param = m_arrows[index];
            OnOffTesselations( param->m_iids, !param->m_visible, param->m_visible, false ); // 
            param->m_visible = !param->m_visible;
          }
          break;
        }
      }
    }
  }  
}
// ADVCTreeEventsCallBack #########################################################


// ATreeCtrlEventCallBack #########################################################
//-----------------------------------------------------------------------------
//  
// ---
void LibObj::OnExpandOrCollapse( struct INode * Node, bool collapse )
{
  if ( Node )
  {
    _bstr_t key = Node->Key;
    //           
    if ( key == _bstr_t(_T(FORCES)    ) )
    {
      if ( collapse )
      {
        Node->Image = _T(FOLDER);
        Node->SelectedImage = _bstr_t( FOLDER SELECT );
      }  
      else
      {
        Node->Image = _bstr_t( FOLDER EXPAND );
        Node->SelectedImage = _bstr_t( FOLDER EXPAND SELECT );
      }
    } 
  }
}


//-----------------------------------------------------------------------------
//    
// ---
void LibObj::OnNodeClick( struct INode * Node )
{
  if ( (bool)m_TreeCtrl && Node )
  {
    //        
    int subMenuIndex = -1;
    INodePtr parent = Node->Parent;
    if ( parent )
    {
      _bstr_t key = parent->Key;
      if (      key == _bstr_t(_T(FORCES) )   )
        subMenuIndex = 0;
    }
    if ( subMenuIndex >= 0 )
    {
      CMenu * subMenu = m_treeMenu.GetSubMenu(subMenuIndex);
      if ( subMenu )
        m_TreeCtrl->SetContextMenu( (long)subMenu->m_hMenu );
      else
        m_TreeCtrl->SetContextMenu( 0l );
    }
    else
      m_TreeCtrl->SetContextMenu( 0l );
  }  
}
// ATreeCtrlEventCallBack #########################################################


//-----------------------------------------------------------------------------
//
// ---
template <class T>
void LibObj::FillTreeNodes( LPCTSTR key, long nameID, PArray<T>& nodeElements )
{
  for ( int i = 0, count = nodeElements.Count(); i < count; i++ )
    AddNode( key, nameID, nodeElements[i]->GetID() );
}


//-----------------------------------------------------------------------------
//     
// ---
void LibObj::SaveTree()
{
  IDocumentFramePtr docFrame( GetFrame() );
  if ( docFrame )
  {
    IKompasDocument3DPtr doc3D( docFrame->GetParent()->GetParent() );
    if ( doc3D )
    {
      IUserDataStoragesMngPtr storageMng = doc3D->GetUserDataStoragesMng();
      if ( storageMng )
      {
        IUserDataStoragesPtr storages = storageMng->Add( NULL );
        if ( storages )
        {
          _bstr_t treeName( FORCES_TREE );
          IUserDataStoragePtr treePars = storages->Item[treeName];
          if ( treePars )
            treePars->Clear( treeName );
          else
          {
            treePars = storages->Add( treeName );
            if ( treePars )
              treePars->SetPassword( _bstr_t(), treeName );
          }
          if ( treePars )
          {
            treePars->Version[treeName] = LIBVERSION; //  

            treePars->AddObject( treeName, m_arrowsIndex,          _bstr_t(_T("arrowsIndex")) );   //    
            treePars->AddObject( treeName, (long)m_arrows.Count(), _bstr_t(_T("arrowsCount")) );   //  
            for ( int i = 0, count = m_arrows.Count(); i < count; i++ )
              m_arrows[i]->Save( treeName, treePars );
            
            
          }
        }
      }  
    }
  }
}


//-----------------------------------------------------------------------------
//    
// ---
_variant_t GetObj( IUserDataStoragePtr & treePars, long index ) 
{
  _variant_t obj;
  long       num; 
  treePars->GetObject( index, &obj, &num );
  return obj;
}


//-----------------------------------------------------------------------------
//      
// ---
void LibObj::LoadTree()
{
  IDocumentFramePtr docFrame( GetFrame() );
  if ( docFrame )
  {
    IKompasDocument3DPtr doc3D( docFrame->GetParent()->GetParent() );
    if ( doc3D )
    {
      IUserDataStoragesMngPtr storageMng = doc3D->GetUserDataStoragesMng();
      if ( storageMng )
      {
        IUserDataStoragesPtr storages = storageMng->Add( NULL );
        if ( storages )
        {
          _bstr_t treeName( FORCES_TREE );
          IUserDataStoragePtr treePars = storages->Item[treeName];
          if ( treePars )
          {
            long version = treePars->Version[treeName];  //  
            if ( version <= LIBVERSION )
            {
              long index = 0; 

              m_arrowsIndex = GetObj(treePars, index++); //    
              long count    = GetObj(treePars, index++); //   
            
              for ( long i = 0; i < count; i++ )
              {
                ArrowParam * param = new ArrowParam;
                if ( param->Load( treePars, index, version ) )
                  m_arrows.Add( param );
                else
                  delete param; //      
              }
            
              MakeTessellations();
            }  
          }
        }
      }  
    }
  }
}


//-----------------------------------------------------------------------------
//   
// ---
void LibObj::MakeTessellations()
{
  IDocumentFramePtr docFrame( GetFrame() );
  if ( docFrame )
  {
    LoadArrowParams();
    
    for ( int i = 0, count = m_arrows.Count(); i < count; i++ )
      m_arrows[i]->Make( docFrame, arrowParams );

    docFrame->SetGabaritModifying();
    docFrame->RefreshWindow();
  }
}


//-----------------------------------------------------------------------------
//  
// ---
void LibObj::Refresh()
{
  OffAllTessellations();
  MakeTessellations();
} 


//-----------------------------------------------------------------------------
//    
// ---
void TeselationNodeParam::Save( _bstr_t & pasword, IUserDataStoragePtr & s )
{
  if ( s )
  {
    s->AddObject( pasword, m_index  , _bstr_t(_T("index"))   );    //  
    s->AddObject( pasword, m_visible, _bstr_t(_T("visible")) );    //  
    long count = m_faces.Count();
    s->AddObject( pasword, count,     _bstr_t(_T("facesCount")) ); //   
    
    if ( count )
    {
      _variant_t faces( CreateDispSafeArray(m_faces), false/*copy*/ );
      s->AddObject( pasword, faces,   _bstr_t(_T("faces"))   );    // 
    }
  }
}


//-----------------------------------------------------------------------------
//    
// ---
bool TeselationNodeParam::Load( IUserDataStoragePtr & s, long & index, long version )
{
  bool res = false;
  if ( s )
  {
    m_index    = GetObj( s, index++ );   //  
    m_visible  = GetObj( s, index++ );   //  
    long count = GetObj( s, index++ );   //  
    if ( count )
    {
      _variant_t faces( GetObj( s, index++ ) );
      FillObjectsDefinitions( faces, m_faces );
    }
    res = true;
  }
  return res;
}
     

#pragma warning( disable : 4786 )
//-----------------------------------------------------------------------------
//        
// ---
void ArrowParam::Make( IFaceDefinitionPtr & face, IDocumentFramePtr & frame, PArray<ExternalTeselationParam> & arrowParams )
{
  if ( face )
  {
    IKompasDocument3DPtr doc3D( frame->GetParent()->GetParent() );
    IExternalTessellationManagerPtr mng( doc3D );
    if ( mng )
    {
      SArray<Matrix3D> matrix;
      ISurfacePtr surf( face->GetSurface(), false/*AddRef*/ );
      
      //     
      MakeMatrixes( surf, !!face->GetNormalOrientation(), matrix );
      
      if ( doc3D->GetDocumentType() == ksDocumentAssembly )
      {
        //               
        //    
        Matrix3D summMtr;
        if ( GetSummMtr( doc3D, summMtr, face ) )
        {
          for ( int i = 0, count = matrix.Count(); i < count; i++ )
          {
            matrix[i] *= summMtr;
          }  
        }
      } 
      _variant_t matrixes( CreateSafeArray(matrix), false/*copy*/ );
      SArray<long> objects;
      for ( int i = 0, count = arrowParams.Count();i < count; i++ )
      {
        IExternalTessellationObjectPtr obj( mng->Add() );
        if ( obj )
        {
          long id = obj->ObjectID;
          objects.Add( id );
          arrowParams[i]->Init(obj);
          obj->SetPlaces( matrixes );
        }
      }
      if ( m_visible )
      {
        _variant_t iids( CreateSafeArray(objects), false );
        mng->ObjectsVisible[iids][frame] = true;
      } 
      m_iids += objects;
    }
  }
}
#pragma warning( once : 4786 ) 


//-----------------------------------------------------------------------------
//  
// ---
void ArrowParam::Make( IDocumentFramePtr & frame, PArray<ExternalTeselationParam> & arrowParams )
{
  if ( (bool)frame && arrowParams.Count() )
  {
    for( int i = 0, count = m_faces.Count(); i < count; i++ )
      Make( *m_faces[i], frame, arrowParams );
  }  
}




                            