////////////////////////////////////////////////////////////////////////////////
//
// studs3d.cpp -    Visual C++ - 
//
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <afxdllx.h>
#include "resource.h"

#ifndef  __STUDS3D_H
#include "studs3d.h"
#endif   

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


//-------------------------------------------------------------------------------
// 
// ---
AFX_EXTENSION_MODULE StepDLL = { NULL, NULL };


//-------------------------------------------------------------------------------
//   
//    DLL
// ---
extern "C" int APIENTRY
DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
{
  UNREFERENCED_PARAMETER( lpReserved );

  if ( dwReason == DLL_PROCESS_ATTACH )
  {
    TRACE0( "DLL Initializing!" );
 
    if ( !AfxInitExtensionModule( StepDLL, hInstance ) )
      return 0;

    new CDynLinkLibrary( StepDLL );
  }
  else if ( dwReason == DLL_PROCESS_DETACH )
  {
    TRACE0( "DLL Terminating!" );
    AfxTermExtensionModule( StepDLL );
  }
  return 1;
}


//-------------------------------------------------------------------------------
//   
// ---
unsigned int WINAPI LIBRARYID()
{
	return IDR_LIBID;
}


//-------------------------------------------------------------------------------
//  
// ---
Shpeel* obj;
static reference spcObj;


//------------------------------------------------------------------------------
//    
// ---
LPTSTR LoadStr( int id ) 
{ 
  static TCHAR buf[512]; 
  //       
  ksConvertLangStrExT( StepDLL.hModule, id, buf, 512 );
  return buf;
}


//-------------------------------------------------------------------------------
//   
// ---
void WINAPI LIBRARYENTRY( unsigned int ) 
{
  IDocument3DPtr pDocument3d( ksGetActive3dDocument(), false /*AddRef*/ ); //       
  if ( (bool)pDocument3d && !pDocument3d->IsDetail() )
  {
    Shpeel* shpeel = new Shpeel();
	  if ( shpeel ) 
    {
	  	shpeel->Draw3D( pDocument3d );
			delete shpeel;
		}
//    pDocument3d->RebuildDocument();
  }
  else
  {
    //       3D-
    ErrorT( LoadStr( IDS_3DDOCERROR ) ); //    
  }

	if ( ReturnResult() == etError10 ) //  
	  ResultNULL();
}


////////////////////////////////////////////////////////////////////////////////
//
//  
//
////////////////////////////////////////////////////////////////////////////////
//------------------------------------------------------------------------------
//    ( *.loa)
// ---
static void NumberGost( int gost, int *gNumb, int *stNumb ) 
{
  switch ( gost ) 
  {
    case 22032 : *gNumb = STR_200; *stNumb = STR_220; break;
    case 22033 : *gNumb = STR_201; *stNumb = STR_221; break;
    case 22034 : *gNumb = STR_202; *stNumb = STR_222; break;
    case 22035 : *gNumb = STR_203; *stNumb = STR_223; break;
    case 22036 : *gNumb = STR_204; *stNumb = STR_224; break;
    case 22037 : *gNumb = STR_205; *stNumb = STR_225; break;
    case 22038 : *gNumb = STR_206; *stNumb = STR_226; break;
    case 22039 : *gNumb = STR_207; *stNumb = STR_227; break;
    case 22040 : *gNumb = STR_208; *stNumb = STR_228; break;
    case 22041 : *gNumb = STR_209; *stNumb = STR_229; break;
    case 22042 : *gNumb = STR_210; *stNumb = STR_230; break;
    case 22043 : *gNumb = STR_211; *stNumb = STR_231; break;
  }
}


//------------------------------------------------------------------------------
//    ()
// ---
static int NumberStr( int gost ) 
{
	int n;
  switch ( gost ) 
  {
    case 22032 : n = STR59;	break;
    case 22033 : n = STR60;  break;
    case 22034 : n = STR61;  break;
    case 22035 : n = STR62;  break;
    case 22036 : n = STR63;  break;
    case 22037 : n = STR64;  break;
    case 22038 : n = STR65;  break;
    case 22039 : n = STR66;  break;
    case 22040 : n = STR67;  break;
    case 22041 : n = STR68;  break;
    case 22042 : n = STR69;  break;
    case 22043 : n = STR70;  break;
  }              
  return n;
}


//-------------------------------------------------------------------------------
//   
// ---
int _ConnectDB( reference bd, LPCTSTR name ) 
{
  static TCHAR fullName[512];
  bool res = false;
  if( GetModuleFileName( StepDLL.hModule, fullName, sizeof(fullName) ) ) 
  {
    TCHAR *c = _tcsrchr( fullName, _T('\\'));
    if ( c ) 
    {
      *(c + 1) = _T('\0');
      _tcscat( fullName, name );
      OFSTRUCT ofs;
      if ( OpenFile(_bstr_t(fullName), &ofs, OF_EXIST) != HFILE_ERROR )
        res = true;
      else 
      {
        *(c + 1) = _T('\0');
        _tcscat( fullName, _T("load\\") );
        _tcscat( fullName, name );
        if ( OpenFile(_bstr_t(fullName) , &ofs, OF_EXIST) != HFILE_ERROR )
          res = true;
      }
    }
  }
  return res ? ConnectDBT( bd, fullName ) : ConnectDBT( bd, (LPTSTR)name );
}


//------------------------------------------------------------------------------
//     varName  val
// ---
void SetVarValue( IVariableCollectionPtr& varArr, TCHAR* varName, double val ) 
{
	IVariablePtr var( varArr->GetByName( _bstr_t(varName), true, false), false/*AddRef*/ ); //  
  if ( var )
    var->SetValue( val ); //  
}  


//------------------------------------------------------------------------------
//      ( planar = true - ,
// planar = false -   )
// ---
bool IsSurface( IEntityPtr& entity, bool planar = true, double * = NULL ) 
{
	bool res = false; 
  if ( entity ) 
  {
    IFaceDefinitionPtr faceDef( IUnknownPtr(entity->GetDefinition(), false /*AddRef*/ ) ); 
    if ( faceDef ) 
    {
      if ( planar && faceDef->IsPlanar() )
        res = true;
      if ( !planar && faceDef->IsCylinder() )
        res = true;
    }
  }
  return res;
} 


//------------------------------------------------------------------------------
//     
// ---
bool IsAxis( IEntityPtr& entity ) 
{
  if ( entity ) 
  {
  	return entity->IsIt( o3d_axis2Planes )        ||  //    
    				 entity->IsIt( o3d_axisOperation )    ||  //  
            	 entity->IsIt( o3d_axis2Points )    ||  //    
                 entity->IsIt( o3d_axisConeFace ) ||  //   
                 	 entity->IsIt( o3d_axisEdge );      //   
  }
  return false;
}
    

//------------------------------------------------------------------------------
//  
// ---
void AddMates( Shpeel& obj, IEntityCollectionPtr& collection, IPart* p = NULL, IMateConstraintCollection* mCol = NULL ) {
  IEntityPtr ent( collection->GetByIndex(0), false/*AddRef*/ );
  if ( (bool)ent && IsSurface(ent) )                    // 
    if ( !obj.AddMate( mc_Coincidence, obj.GetDirectionElem(), 1/*fixed*/, 0/*val*/,
                       ent, _T("Plane"), p, mCol )) {
    	collection->SetByIndex( NULL, 0 );
    }

  ent.Attach( collection->GetByIndex(1) );
  if ( (bool)ent && IsSurface(ent, false/*planar*/) )   //  
    if ( !obj.AddMate( mc_Concentric, 0/*direct*/, 1/*fixed*/, 0/*val*/,
                       ent, _T("Axis"), p, mCol )) {
    	collection->SetByIndex( NULL, 1 );
    }

  ent.Attach( collection->GetByIndex(2) );
  if ( (bool)ent && IsAxis(ent) )                              // 
    if ( !obj.AddMate( mc_Concentric, 0/*direct*/, 1/*fixed*/, 0/*val*/,
                       ent, _T("Axis"), p, mCol )) {
    	collection->SetByIndex( NULL, 2 );
    }
}


//------------------------------------------------------------------------------
//  
// ---
void DelMates( Shpeel& obj, IDocument3DPtr& doc, IEntityCollectionPtr& collection ) 
{
  IEntityPtr entity( collection->GetByIndex(0), false /*AddRef*/ );
  if ( (bool)entity && IsSurface(entity) ) // 
    doc->RemoveMateConstraint( mc_Coincidence, entity, obj.GetEntityByName(_T("Plane")) );

  entity.Attach( collection->GetByIndex(1) );
  if ( (bool)entity && IsSurface(entity, false /*planar*/) ) //  
    doc->RemoveMateConstraint( mc_Concentric, entity, obj.GetEntityByName(_T("Axis")) );

  entity.Attach( collection->GetByIndex(2) );
  if ( (bool)entity && IsAxis(entity) ) // 
    doc->RemoveMateConstraint( mc_Concentric, entity, obj.GetEntityByName(_T("Axis")) );
}

 
////////////////////////////////////////////////////////////////////////////////
//
//    
//
////////////////////////////////////////////////////////////////////////////////
bool openBase = false;

//------------------------------------------------------------------------------
//  
// ---
void CloseShpeelBase( ShpeelBase &base ) 
{
	if ( base.bg )
	  ::DeleteDB( base.bg );
  if ( base.bs )
	  ::DeleteDB( base.bs );
  openBase = false;
}


//------------------------------------------------------------------------------
//     
// ---
int OpenShpeelBase( int gost , ShpeelBase &base ) 
{
  base.bg = ::CreateDBT( _T("TXT_DB") );
  base.bs = ::CreateDBT( _T("TXT_DB") );

  int gNumb, stNumb;
  ::NumberGost( gost, &gNumb, &stNumb );
  if( !_ConnectDB( base.bg, LoadStr( gNumb ) ) ) // 22032.loa ..
   return 0;
  else 
  {
    if( !_ConnectDB( base.bs, LoadStr( stNumb ) ) )  // st22032.loa ..
      return 0;
    else 
    {
      base.rg1 = ::Relation( base.bg );
        ::RIntT(_T("t"));
        ::RChar( "d", 20, 0 );
      ::EndRelation();
      if ( !::DoStatementT(base.bg, base.rg1, _T("1 2") ) ) 
        return 0;
      else 
      {
        base.rg2 = ::Relation( base.bg );
          ::RIntT  (_T("t"));
          ::RFloatT(_T("d"));
          ::RFloatT(_T(""));
          ::RFloatT(_T(""));
          ::RFloatT(_T(""));
          ::RFloatT(_T(""));
        ::EndRelation();
        if ( !::DoStatementT( base.bg, base.rg2, _T("")) )
          return 0;
        else 
        {
          base.rs1 = ::Relation( base.bs );
            ::RIntT( _T("t") );
            ::RChar( "L",20,0 );
            ::RFloatT( _T("d") );
          ::EndRelation();
          if ( !::DoStatementT(base.bs, base.rs1, _T("1 2 3") ) )
            return 0;
          else 
          {
            base.rs2 = ::Relation( base.bs );
              ::RIntT  (_T("t"));
              ::RFloatT(_T("L"));
              ::RFloatT(_T("d"));
              ::RFloatT(_T(""));
              ::RFloatT(_T(""));
              ::RFloatT(_T(""));
            ::EndRelation();
            if ( !::DoStatementT( base.bs, base.rs2, _T("")) )
              return 0;
            else 
            {
              openBase = true;
              return 1;
            }
          }
        }
      }
    }
  }
}


//------------------------------------------------------------------------------
//  
// ---
int Shpeel::OpenBase() 
{
  return ::OpenShpeelBase( tmp.gost, bBase );
}


//------------------------------------------------------------------------------
//  
// ---
void Shpeel::CloseBase()
{
  ::CloseShpeelBase( bBase );
}


//------------------------------------------------------------------------------
//  
// ---
int Shpeel::GetParam() 
{
  return part ? part->GetUserParam( &par, Size() ) : 0;
}


//------------------------------------------------------------------------------
// 
// ---
Shpeel::Shpeel() : part    ( NULL  ),
                   collect ( NULL  ),
                   collectChanged( false )
{
  par.flagAttr    = 1;
  par.typeSwitch  = 0;
  par.ang         = 0;
  par.drawType    = 0;

  ::memset( &bBase, 0, sizeof(ShpeelBase) );
  if( !GetParam() ) 
  {
    Init();
  }
  else 
  {
    if ( !tmp.ver )
      tmp.ver = 1;
  }
}


//------------------------------------------------------------------------------
//  
// ---
Shpeel::Shpeel( const Shpeel& other ) : part    ( NULL  ),
                                        collect ( NULL  ),
                                        collectChanged( false )
{
  par.flagAttr    = 1;
  par.typeSwitch  = 0;
  par.ang         = 0;
  par.drawType    = 0;

  ::memcpy( &bBase, &other.bBase, sizeof(ShpeelBase) );
  Assign( other );
}


//------------------------------------------------------------------------------
//  
// ---
Shpeel* Shpeel::Dublicate() 
{
  return new Shpeel( *this );
}


//------------------------------------------------------------------------------
//
// ---
void Shpeel::Assign( const Shpeel& other ) 
{
  part     = other.part;
  flagMode = other.flagMode;
  par      = other.par;
  collect  = other.collect;

  ::memcpy( &tmp, &other.tmp, sizeof(SHPEEL) );
}


//------------------------------------------------------------------------------
// 
// ---
void Shpeel::Init() 
{
  tmp.gost       = (unsigned short)22032;
  par.drawType   = ID_VID;
  par.ang        = 0;
  tmp.f          = 0;
  tmp.f         |= TAKEISPOLN;
  tmp.d          = 20;
  tmp.p1         = 2.5;
  tmp.p2         = 1.5;
  tmp.c          = 2.5;
  tmp.indexMassa = 0;
  tmp.ver        = 1;
  tmp.b1         = 20;
  tmp.klass      = 2; /*klass=B*/
  tmp.l          = 90;
  tmp.b          = 46;
  tmp.m1         = 245.9f;
  tmp.m2         = 228.9f;
}


//------------------------------------------------------------------------------
//                
// ---
CString& Shpeel::GetFileName() 
{        
  static TCHAR fullName[512];
  bool res = false;
  if( GetModuleFileName( StepDLL.hModule, fullName, sizeof(fullName) ) ) 
  {
    TCHAR *c = _tcsrchr( fullName, _T('\\'));
    if ( c ) 
    {
      *(c + 1) = _T('\0');
      _tcscat( fullName, STUDS_FILE );
      OFSTRUCT ofs;
      if ( OpenFile(_bstr_t(fullName), &ofs, OF_EXIST) != HFILE_ERROR )
        res = true;
      else 
      {
        *(c + 1) = _T('\0');
        _tcscat( fullName, _T("model\\") );
        _tcscat( fullName, STUDS_FILE );
        if ( OpenFile(_bstr_t(fullName), &ofs, OF_EXIST) != HFILE_ERROR )
          res = true;
      }
    }
  }

  if( res )
  {
    _tcscat( fullName, STUDS_INPUT_PATH );
    fileName = fullName;
  }
  
  return fileName;
}


//------------------------------------------------------------------------------
//  
// ---
void Shpeel::SetParam( IPartPtr& pPart ) 
{
  //   
  if ( !(bool)pPart )
    pPart = part;
  if( pPart ) 
  {
    //    
    IVariableCollectionPtr varArr( pPart->VariableCollection(), false/*AddRef*/ );
    if ( varArr ) 
    {
      float l, b1 = 0, b; //      - b1=0
      l = tmp.b1 + tmp.l; //   
      b = tmp.b;
      float step = tmp.f & PITCH ? tmp.p1 : tmp.p2;
      if( fabs(tmp.b1) < 0.001 ) //  22042,  22043
      { 
        if( fabs(tmp.b) > 0.001 ) 
          b1 = b;
      }
      else 
      {
        b1 = tmp.b1;
        if ( fabs(tmp.b) < 0.001  )
          b = tmp.l - 0.5f * tmp.d - 2 * step;
      }
      
      //  
    	::SetVarValue( varArr, _T("d"),      tmp.d                        ); //  
      float len = fabs(b1 - b) < 0.001 ? tmp.l - b1 : tmp.l;
    	::SetVarValue( varArr, _T("l"),      len                          ); //  
    	::SetVarValue( varArr, _T("b1"),     b1                           ); //   
    	::SetVarValue( varArr, _T("c1"),     tmp.c                        ); //     
      if ( fabs(l - b1 - b) > 0.001 )
	    	::SetVarValue( varArr, _T("l1"),   l - b1 - b                   ); //    
    	::SetVarValue( varArr, _T("t"),      (step * 0.866 * 3 / 8)       ); //   
      int perf2 = ( !(tmp.f & ISPOLN) ) || ( tmp.f & ALLST ) || ( fabs(l - b1 - b) < 0.001 ) ? 1 : 0;
    	::SetVarValue( varArr, _T("cut1"),   perf2                        ); // /  2
    	::SetVarValue( varArr, _T("f1"),     !(tmp.f & SIMPLE) ? 0.0 /**/ : 1.0 /**/ ); // / 

      //   
      TCHAR buf[255];
      ::_stprintf( buf, LoadStr( IDS_STUD_NAME ), tmp.d, tmp.l, tmp.gost ); //   
      pPart->SetName( _bstr_t(buf) ); //    
      pPart->Update();        //  

      //      
      pPart->RebuildModel();
    }

    pPart->SetUserParam( &par, Size(), 0, 0, -1 );
  }
}


//------------------------------------------------------------------------------
//  
// ---
int Shpeel::ChoiceMenuId() 
{
  switch ( par.drawType ) 
  {
    case ID_VID    : // 
      return  !par.typeSwitch ?  MENU_22032_1 : MENU_22032_3;
    case ID_TOPVID : //  
      return  !par.typeSwitch ?  MENU_22032_2 : MENU_22032_4;
  }
  return 0;
}


//------------------------------------------------------------------------------
//   
// ---
reference Shpeel::EditSpcObj( reference spcObj )
{
  ISpecification3DPtr specification( doc->GetSpecification(), false/*AddRef*/ );
  if ( (!flagMode && !par.flagAttr) || !(bool)specification )
    return 0;

  if ( flagMode ) 
  {
    spcObj = specification->GetSpcObjForGeomWithLimit( NULL,             //   
                          						                 0,                //   
                                      				         part,
                                              				 1,                // 1 -   0-  
                                              				 STANDART_SECTION, //  
                                              				 81764182256.0 );
    if( !par.flagAttr )
      return spcObj;


    if ( spcObj && !::ksSpcObjectEdit( spcObj ) )
      spcObj = 0;
  }

  if ( !!spcObj || ksSpcObjectCreate( NULL,                 //   
 																		  0,                    //   
                                      STANDART_SECTION, 0,  //    
                                      81764182256.0, 0) )   //  
  { 
    // 
    UINT uBuf = !!(tmp.f & ISPOLN );
    ::ksSpcVisible( SPC_NAME, 2, uBuf );
    if ( uBuf ) 
    {
      uBuf = 2;
      ::ksSpcChangeValue( SPC_NAME, 2, &uBuf, UINT_ATTR_TYPE  );
    }

    //  
    ::ksSpcChangeValue( SPC_NAME, 4, &tmp.d, FLOAT_ATTR_TYPE  );

    //   
    uBuf = !(tmp.f & PITCHOFF || !(tmp.f &PITCH));
    ::ksSpcVisible( SPC_NAME, 5, uBuf );
    ::ksSpcVisible( SPC_NAME, 6, uBuf ); // 
    if ( uBuf )
      ::ksSpcChangeValue( SPC_NAME, 6, &tmp.p2, FLOAT_ATTR_TYPE );

    //  
    uBuf = (UINT)tmp.l;
    ::ksSpcChangeValue( SPC_NAME, 9, &uBuf, UINT_ATTR_TYPE  );

    if( !flagMode ) 
    {
      ::ksSpcVisible( SPC_NAME, 7,  0 ); //   
      ::ksSpcVisible( SPC_NAME, 10, 0 ); //   
      ::ksSpcVisible( SPC_NAME, 11, 0 ); //  
      ::ksSpcVisible( SPC_NAME, 12, 0 ); //  
    }

    //  
    uBuf = tmp.gost;
    ::ksSpcChangeValue( SPC_NAME , 14, &uBuf, UINT_ATTR_TYPE  );
    float  massa  = tmp.f & ISPOLN ? tmp.m2 : tmp.m1;
    massa = massa*( !tmp.indexMassa ? 1 : tmp.indexMassa==1 ? 0.356f : tmp.indexMassa==3 ? 0.97f : 1.08f )/COUNT_MASSA;

    TCHAR buf[128];
    _stprintf( buf, _T("%f") , massa );
    ksSpcMassaT( buf ); //  

    //  
    specification->SpcIncludePart( part, false );

    return ::ksSpcObjectEnd();
  }
  return 0;
}


//-------------------------------------------------------------------------------
//    
// ---
bool Shpeel::DrawSpcObj() 
{
  spcObj = 0;
  if( obj->IsSpcObjCreate() ) 
  {
    if ( ReturnResult() == etError10 ) //  
      ResultNULL();

    spcObj = obj->EditSpcObj( spcObj );
    if( !obj->par.flagAttr && spcObj ) 
    {
      ::DeleteObj( spcObj );
      spcObj = 0;
    }
  }
  return !!spcObj;
}



//-------------------------------------------------------------------------------------
//  3D 
// ---
void Shpeel::Draw3D( IDocument3DPtr& _doc )  
{
  if ( _doc )
  {
    doc = _doc;
    flagMode = doc->IsEditMode() ;
    obj = this;
    _bstr_t bstr;
    //  
    part.Attach( doc->GetPart( flagMode ? pEdit_Part : pNew_Part ) ); 
    if ( part ) 
    {
      //       
      if ( flagMode )
        GetParam();
      else {
         bstr = GetFileName();  
         part->SetFileName( bstr );
      } 
      if ( obj->MacroElementParam()== IDOK ) 
      {
        IRequestInfoPtr info( doc->GetRequestInfo(part), false/*AddRef*/ );
        if ( info )
        {
          //     
          _bstr_t bstr( LoadStr( flagMode ? STR_SELECT_PLANE : STR_SELECT_POINT ) );
          info->SetPrompt( bstr );
          SetCallBackAndFilterFunction( info );

          info->CreatePhantom();                                    // C 
          IPartPtr phantom( info->GetIPhantom(), false/*AddRef*/ ); //  
          if ( phantom )
            SetParam( phantom ); 

          if ( doc->UserGetPlacementAndEntity(3) ) 
          {
            bstr = obj->GetFileName();
            if ( IsCollectionEmpty(info) )   //  placement
            {
              IPlacementPtr place( info->GetPlacement(), false/*AddRef*/ );
              part->SetPlacement( place );
              part->UpdatePlacement();       //   
            }
            SetParam( part );
            if ( flagMode || doc->SetPartFromFile( bstr, part, false ) ) 
            {
              if ( IsCollectionChange(info) )  //  Mate' 
              { 
                if ( flagMode )                //  
                  SetMates( doc, info, true ); //  
                SetMates( doc, info );         // C 
              }


              //  ,  
              part->SetStandardComponent( true );
            }
						DrawSpcObj(); //   

            if ( spcObj ) //   
            {                       
              //  
             	::ksEditWindowSpcObject( spcObj );
              spcObj = 0;
            }
          }
          phantom = NULL; //   
          info    = NULL; //   RequestInfo
        }
      }
      part = NULL;
    }
  }
}


//------------------------------------------------------------------------------
//  
// ---
bool WINAPI SELECTFILTERPROC( IEntity* entity ) 
{
  bool res = false; //      
  if ( entity )                                  
  {                                 
  	IEntityPtr ePtr( entity ); 
    IPartPtr entPart( entity->GetParent(), false/*AddRef*/ ); //      
    if ( entPart != obj->GetPart() )  
      //      ,    
      res = IsSurface( ePtr ) || 
            IsSurface( ePtr, false /*planar*/ ) || 
            IsAxis( ePtr );   
  }                                               
  return res;
}


//------------------------------------------------------------------------------
//   
//  collection ( 0 - , 1 - , 2 -  ) 
// ---
int WINAPI SELECTCALLBACKPROC( IEntity * entity, IRequestInfo * info ) 
{
  IEntityCollectionPtr collection( info ? info->GetEntityCollection() : NULL, false/*AddRef*/ );
  IMateConstraintCollectionPtr mateCollection( info ? info->GetMateConstraintCollection() : NULL, false/*AddRef*/ );
  //  
  if ( mateCollection )
    mateCollection->Clear();
  if ( entity )
  {
  	IEntityPtr ePtr( entity ); 
    if ( collection ) 
    {
      int res = 0;
      if ( IsSurface(ePtr) ) 
      {
        //        
        IEntityPtr oldPlane( collection->GetByIndex(0), false/*AddRef*/ );
        if ( oldPlane == ePtr )
          collection->SetByIndex( NULL, 0 ); //  
        else
          collection->SetByIndex( ePtr, 0 ); //  

        res = 1;
      }

      double diam;
      if ( IsSurface(ePtr, false /*planar*/, &diam) ) 
      {
        //        
        IEntityPtr oldPlane( collection->GetByIndex(1), false/*AddRef*/ );
        if ( oldPlane == ePtr )
          collection->SetByIndex( NULL, 1 ); //   
        else
        {
          collection->SetByIndex( ePtr, 1 ); //   
          collection->SetByIndex( NULL, 2 ); //  
        }
        res = 1;
      }

      if ( IsAxis(ePtr) ) 
      {
        //        
        IEntityPtr oldAxis( collection->GetByIndex(2), false/*AddRef*/ );
        if ( oldAxis == ePtr )
          collection->SetByIndex( NULL, 2 );  //  
        else
        {
          collection->SetByIndex( ePtr, 2 ); //  
          collection->SetByIndex( NULL, 1 ); //   
        }
        res = 1;
      }

      if ( res )
        obj->GetCollectChanged() = true;

      //     
      info->SetPrompt( _bstr_t(LoadStr(STR_SELECT_PLANE)) );

      if ( (bool)mateCollection && obj ) {
        IPartPtr phantom ( info->GetIPhantom(), false/*AddRef*/ );
        if ( phantom )
          ::AddMates( *obj, collection, phantom, mateCollection );
      }
      return res;
    }
  }
  else 
  {
  	if ( collection )
    	for ( int i = 0; i < 3; i++ )
        collection->SetByIndex( NULL, i ); // 

    //     
    info->SetPrompt( _bstr_t(LoadStr(STR_SELECT_PLANE)) );

    return 1;
  }
  return 0;
}


//------------------------------------------------------------------------------
//       
// ---
void Shpeel::SetCallBackAndFilterFunction( IRequestInfoPtr& info ) 
{
	info->SetFilterCallBack( SELECTFILTERPROC );
  info->SetCallBack( SELECTCALLBACKPROC );
}


//------------------------------------------------------------------------------
//    -  true    Mate'
// ---
bool Shpeel::IsCollectionChange( IRequestInfoPtr& info ) 
{
  bool res = true;  
  if ( !collectChanged ) //      -  
  {                             
    //         info  NULL'   
    res = false; //   
    IEntityCollectionPtr collection1( info->GetEntityCollection(),      false/*AddRef*/ ); //  
    IEntityCollectionPtr collection2( part->GetMateConstraintObjects(), false/*AddRef*/ ); //  
    if ( (bool)collection1 && (bool)collection2 && 
       ( collection1->GetCount() > 2 ) && 
       ( collection2->GetCount() > 2 ) ) 
    {
      for( int i = 0; i < 3; i++ ) //   
      {                        
        IEntityPtr ent1( collection1->GetByIndex(i), false/*AddRef*/ ); //   1
        IEntityPtr ent2( collection2->GetByIndex(i), false/*AddRef*/ ); //   2
        if ( ent1 != ent2 ) //    
        {                 
          res = true; // 
          break;
        }
      }
    }
  }
  return res; 
}



//------------------------------------------------------------------------------
//  
// ---
void Shpeel::SetMates( IDocument3DPtr& doc, IRequestInfoPtr& info, bool delMates ) 
{
  IEntityCollectionPtr collection( !delMates ? info->GetEntityCollection() : 
                                               part->GetMateConstraintObjects(), false/*AddRef*/ );
  if ( collection ) 
  {
    if ( (bool)doc && collection->GetCount() > 2 )
	    if ( !delMates )
  	  	::AddMates( *this, collection );
      else
  	  	::DelMates( *this, doc, collection );

    if ( !delMates )
	    part->SetMateConstraintObjects( collection );
  }
}

   
//------------------------------------------------------------------------------
//       
// ---
IEntityPtr Shpeel::GetEntityByName( const TCHAR * name, IPart* p ) 
{
  IEntityPtr entity( NULL );
  IPartPtr _part( p ? p : part );

  if ( _part ) 
  {
    if ( !(bool)collect )  //    ,       - 
    	collect = IEntityCollectionPtr( _part->EntityCollection(o3d_constrElement), false );

    IEntityPtr findEntity( collect->GetByName( _bstr_t(name), true, true ), false/*AddRef*/ );
    if ( (bool)findEntity && findEntity->IsCreated() ) 
//      {
//        IUnknownPtr defin( findEntity->GetDefinition(), false );
//        if ( defin ) 
//        {
        entity = findEntity;
//        }
//      }
  }
  return entity;
}


//------------------------------------------------------------------------------
//   -  placement
// ---
bool Shpeel::IsCollectionEmpty( IRequestInfoPtr& info ) 
{
  bool res = true; //  
  IEntityCollectionPtr collection( info->GetEntityCollection(), false/*AddRef*/ ); //  
  if ( collection )
    for( int i = 0, count = collection->GetCount(); i < count; i++ )               //   
    {       
      IEntityPtr entity( collection->GetByIndex(i), false/*AddRef*/ );             //  
      if ( entity )                                                                //    NULL
      {                                     
        res = false;                                                               //   
        break;                                                                     //  
      }
    }
  return res; // 
}


//------------------------------------------------------------------------------
//  
// ---
bool Shpeel::AddMate( short constraintType, short direction, short fixed, double val,
                      IEntityPtr &ent, LPCTSTR surfaceName, IPart* p,
                      IMateConstraintCollection* mCol ) {
  bool rez = false;
  if ( !p && !mCol ) { //  
    if ( doc->AddMateConstraint(constraintType, ent, GetEntityByName(surfaceName, part),
                                direction, fixed, val) ) {
      rez = true;
    }
  }
  else {// 
    IMateConstraintPtr mate( doc->GetMateConstraint(), false/*AddRef*/ );
    if ( mate ) {
      mate->SetConstraintType( constraintType );
      mate->SetDirection( direction );
      mate->SetFixed( fixed );
      mate->SetBaseObj(1, ent );
      mate->SetBaseObj(2, GetEntityByName(surfaceName, p) );
      if ( mate->Create() ) {
        mCol->AddMateConstraint( mate );
        rez = true;
      }
    }
  }
  return rez;
}

















