/*
	Copyright (c) 2024 PTC Inc. and/or Its Subsidiary Companies. All Rights Reserved.
*/


/*--------------------------------------------------------------------*\
    Pro/TOOLKIT includes
  \*--------------------------------------------------------------------*/
  #include <GearDesign.h>

#include "ProDimension.h"
#include "ProDtmPln.h"
#include "ProDtmCrv.h"
#include "ProElement.h"
#include "ProElempath.h"
#include "ProExtrude.h"
#include "ProFeature.h"
#include "ProFeatForm.h"
#include "ProFeatType.h"
#include "ProGroup.h"
#include "ProHole.h"
#include "ProLayer.h"
#include "ProMdl.h"
#include "ProMenu.h"
#include "ProMenuBar.h"
#include "ProMessage.h"
#include "ProModelitem.h"
#include "ProModFeat.h"
#include "ProParameter.h"
#include "ProParamval.h"
#include "ProPattern.h"
#include "ProSecdim.h"
#include "ProSelection.h"
#include "ProSolid.h"
#include "ProSurface.h"
#include "ProStdSection.h"
#include "ProUtil.h"
#include "ProTKRunTime.h"
#include <ProMdlUnits.h>


/*--------------------------------------------------------------------*\
    C System includes
\*--------------------------------------------------------------------*/
#include <math.h>

/*--------------------------------------------------------------------*\
    Application includes
\*--------------------------------------------------------------------*/
#include "TestError.h"
#include "UtilMessage.h"
#include "UtilString.h"
#include "UtilMath.h"
#include "UtilMenu.h"
#include "UtilTree.h"
#include "UtilCollect.h"
#include "PTApplsUnicodeUtils.h"

/*--------------------------------------------------------------------*\
    Macros
\*--------------------------------------------------------------------*/

#define SIZEOFARR(a) (sizeof(a)/sizeof(a[0]))

FILE* errlog_fp;

#define C_PRINT(a) ProTKPrintf ( "%s\n", a);

#define PT_TEST_LOG(func,status,err) \
if (status) \
{ \
    printf (" LOG Error: %s\t%d\n", func, status); \
    fprintf (errlog_fp, " LOG Error: %s\t%d\n", func, status); \
} \
else \
{ \
   printf (" LOG %s\t%d\n", func, status); \
    fprintf (errlog_fp, " LOG %s\t%d\n", func, status); \
}

#define PT_TEST_LOG_SUCC(func) \
 PT_TEST_LOG (func, status, status != PRO_TK_NO_ERROR)

#define PTTestResfileWrite(str) \
 {\
   printf(str);\
   printf("\n");\
 }


#define STR_PARAM   0
#define INT_PARAM   1
#define DOUB_PARAM  2
#define TAB_PARAM   3

typedef struct tableraw
{
    char *string_val;
    int  int_val;
} TableRaw;

typedef struct param
{
    int type;	/* 0 - string, 1 - int, 2 - double, 3 - table */
    int length; /* for string - max lenght */
    char *param_name;
    ProBool  required; /* 1 - required, 0 - optional */
    TableRaw *table; /* for table only */
    int	 tablesize;  /* for table only */   
    ProBool  set;    
    void *value;
} Param;

/*--------------------------------------------------------------------*\
    Application global/external data
\*--------------------------------------------------------------------*/
static TableRaw Length_unit[] = {
    {"cm", PRO_UNITLENGTH_CM },
    {"foot", PRO_UNITLENGTH_FT},
    {"inch", PRO_UNITLENGTH_IN},
    {"m", PRO_UNITLENGTH_M},
    {"mm", PRO_UNITLENGTH_MM}};
static TableRaw Yes_no_tab[] = {
    {"no", 0},
    {"yes", 1}};
static TableRaw GearType [] = {
    {"spur", SPUR_GEAR},
    {"ring", RING_GEAR}};


static Param param_def[] = {
    {STR_PARAM,  PRO_NAME_SIZE, "Name_of_model", 1},
    {TAB_PARAM,  0, "Units", 1, Length_unit, SIZEOFARR(Length_unit)},
    {STR_PARAM,  PRO_NAME_SIZE, "Material", 0},
    {TAB_PARAM,  0, "GearType", 0, GearType, SIZEOFARR(GearType)},
    {DOUB_PARAM, 0, "Datum_X_Offset", 0},
    {DOUB_PARAM, 0, "Datum_Y_Offset", 0},
    {DOUB_PARAM, 0, "Datum_Z_Offset", 0},
    {DOUB_PARAM, 0, "Gear_Outer_Diameter", 1},
    {DOUB_PARAM, 0, "Gear_Disk_Depth", 1},
    {DOUB_PARAM, 0, "Helix_Angle", 1},
    {DOUB_PARAM, 0, "Outer_Plate_Diameter", 0},
    {DOUB_PARAM, 0, "Outer_Plate_Depth", 0},
    {DOUB_PARAM, 0, "Support_Hub_Outer_Diameter", 0},
    {DOUB_PARAM, 0, "Support_Hub_Depth", 0},
    {DOUB_PARAM, 0, "Inner_Diameter", 1},
    {INT_PARAM,  0, "Number_of_teeth", 1},
    {DOUB_PARAM, 0, "Keyway_inner_width", 0},
    {DOUB_PARAM, 0, "Keyway_inner_height", 0},
    {DOUB_PARAM, 0, "Key_outer_width", 0},  
    {DOUB_PARAM, 0, "Key_outer_height", 0},  
    {DOUB_PARAM, 0, "GearTooth_param1", 1},  
    {DOUB_PARAM, 0, "Backnotch_Radius", 0},
    {DOUB_PARAM, 0, "Pressure_angle", 1}
};

static int ProUserFeatsReorder(GearParam *g_ptr);



/*=============================================================*\
  Function: 	ProUserDeleteDesign
  Purpose:	delete current design
\*=============================================================*/
int ProUserDeleteDesign(GearParam *g_ptr) 
{
    int n_sel, *feat_ids, i;
    ProSelection *p_sel;
    ProFeatureDeleteOptions opt[]= {PRO_FEAT_DELETE_CLIP};
    ProModelitem modelitem;
    ProError status;
   
    status = ProMessageDisplay(MSGFIL , "PROTKGD Select feature(s) to be deleted");
    PT_TEST_LOG_SUCC("ProMessageDisplay..........ProUserDeleteDesign");
    
    status = ProSelect("feature", -1, NULL, NULL, NULL, NULL, &p_sel, &n_sel);
    PT_TEST_LOG_SUCC("ProSelect");
    
    if (status != PRO_TK_NO_ERROR || n_sel<=0)
	return 0;

    feat_ids = (int *)calloc(n_sel, sizeof(int));
    for (i=0; i<n_sel; i++)
    {
	status = ProSelectionModelitemGet(p_sel[i], &modelitem);
	PT_TEST_LOG_SUCC("ProSelectionModelitemGet");
	
	feat_ids[i] = modelitem.id;
    }

    status = ProFeatureDelete((ProSolid)g_ptr->model, feat_ids, n_sel, opt, 1);
    PT_TEST_LOG_SUCC("ProFeatureDelete");
    
    status = ProTreetoolRefresh(g_ptr->model);
    PT_TEST_LOG_SUCC("ProTreetoolRefresh");
    
    status = ProSolidDisplay((ProSolid)g_ptr->model);
    PT_TEST_LOG_SUCC("ProSolidDisplay");

    free (feat_ids);
    
    return (0);
}

/*=============================================================*\
  Function: 	ProUserModifyDesign
  Purpose:	modify current design
\*=============================================================*/
int ProUserModifyDesign(GearParam *g_ptr)
{
    int dim_id;
    ProSelection  *p_sel;
    int n_sels;
    int  brk=0;
    double value, drange[2];
    ProModelitem item;
    ProError status;
    
    do
    {
	status = ProMessageDisplay(MSGFIL , "PROTKGD Select feature or dimension");
	PT_TEST_LOG_SUCC("ProMessageDisplay.........ProUserModifyDesign");
	
	if (ProSelect("dimension,feature", 1, NULL, NULL, NULL, NULL,
		      &p_sel, &n_sels) != PRO_TK_NO_ERROR)
	    return 0;

	status = ProSelectionModelitemGet (p_sel [0], &item);
	PT_TEST_LOG_SUCC("ProSelectionModelitemGet");
	
	if (item.type == PRO_FEATURE)
	{
	    status = ProFeatureParamsDisplay(p_sel[0], PRO_DIM_PARAM);
	    PT_TEST_LOG_SUCC("ProFeatureParamsDisplay");
	}
	else
	{
	  status = ProDimensionValueGet (&item, &value);
	  PT_TEST_LOG_SUCC("ProDimensionValueGet");
	  
	  status = ProMessageDisplay(MSGFIL , 
			    "PROTKGD Enter new value for dimension [%0f]",
			    &value);
	  PT_TEST_LOG_SUCC("ProMessageDisplay");
	  
	  drange[0] = 0;
	  drange[1] = 1e10;
	  if (ProMessageDoubleRead(drange, &value)==PRO_TK_NO_ERROR)
	    {
	      status = ProDimensionValueSet (&item, value);
	      PT_TEST_LOG_SUCC("ProDimensionValueSet");
	      
	      status = ProDimensionDisplayUpdate (&item);
	      PT_TEST_LOG_SUCC("ProDimensionDisplayUpdate");
	    }
	}
    } while (!brk);
}

/*=============================================================*\
  Function: 	ProUserRegenerate
  Purpose:	regenerate model
\*=============================================================*/
int ProUserRegenerate(GearParam *g_ptr)
{

   ProError status;

    if (g_ptr->model != NULL)
	status = ProSolidRegenerate((ProSolid)g_ptr->model, PRO_B_FALSE);
	PT_TEST_LOG_SUCC("ProSolidRegenerate..........ProUserRegenerate");
	
    status = ProSolidDisplay((ProSolid)g_ptr->model);
    PT_TEST_LOG_SUCC("ProSolidDisplay");
    
   return (0);
}

/*=============================================================*\
  Function: 	ProUserMaterial
  Purpose:	change material for gear
\*=============================================================*/
int ProUserMaterial(GearParam *g_ptr)
{
    ProName name;
    ProError status;
    
    status = ProPartMaterialNameGet((ProPart)g_ptr->model, name);
    PT_TEST_LOG_SUCC("ProPartMaterialNameGet........ProUserMaterial");
    
    if (status != PRO_TK_NO_ERROR)
	ProStringToWstring(name, "");
    do 
    {
	status = PRO_TK_NO_ERROR;
	
	status = ProMessageDisplay(MSGFIL, "PROTKGD Enter material name [%0w]", name);
	PT_TEST_LOG_SUCC("ProMessageDisplay");
	
	if (ProMessageStringRead(PRO_NAME_SIZE, name) == PRO_TK_NO_ERROR)
	{
	    status = ProPartMaterialSet((ProPart)g_ptr->model, name);
	    PT_TEST_LOG_SUCC("ProPartMaterialSet");
	    
	    if (status != PRO_TK_NO_ERROR)
	    {
		status = ProMessageDisplay(MSGFIL, "PROTKGD Unable assign material %0w", name);
		PT_TEST_LOG_SUCC("ProMessageDisplay");
            }
		
	    else
	    {
		status = ProMessageDisplay(MSGFIL, "PROTKGD Material %0w was assigned to part", name);
		PT_TEST_LOG_SUCC("ProMessageDisplay");
	    }
	}
    } while (status!=PRO_TK_NO_ERROR);   
    
  return (0);
}

/*=============================================================*\
  Function: 	ProUserCreateViewAuto
  Purpose:	Create "FRONT", "SIDE" and "BOTTOM" views
\*=============================================================*/
int ProUserCreateViewAuto(GearParam *g_ptr)
{
    ProView view;
    ProName name;
    int i;
    static char *names[]={"FRONT", "SIDE", "BOTTOM"};
    ProMatrix ident={{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}};
    double m[4];
    ProError status;
    
    for (i=0; i<3; i++)
    {
	ProStringToWstring(name, names[i]);
	ProViewStore(g_ptr->model, name, &view);
	ProViewMatrixSet(g_ptr->model, view, ident);
	memcpy(m, ident[0], 3*sizeof(double));
	memcpy(ident[0], ident[1], 3*sizeof(double));
	memcpy(ident[1], ident[2], 3*sizeof(double));
	memcpy(ident[2], m, 3*sizeof(double));
    }
    
   return (0);
}

/*=============================================================*\
  Function: 	ProUserCreateViewManual
  Purpose:	Create an user defined view
\*=============================================================*/
int ProUserCreateViewManual(GearParam *g_ptr)
{
    ProView view;
    ProName name;
    ProError status;
    
    status = ProMessageDisplay(MSGFIL, "PROTKGD Enter a view name");
    PT_TEST_LOG_SUCC("ProMessageDisplay.........ProUserCreateViewManual");
    
    status = ProMessageStringRead(PRO_NAME_SIZE, name);
    PT_TEST_LOG_SUCC("ProMessageStringRead");
    
    if (status == PRO_TK_NO_ERROR)
    {
	status = ProViewStore(g_ptr->model, name, &view);
	PT_TEST_LOG_SUCC("ProViewStore");
    }
    
    
    return (status);
}

/*=============================================================*\
  Function: 	ProUserCreateDatum
  Purpose:	create "FRONT", "SIDE", "BOTTOM" datum planes 
\*=============================================================*/
int ProUserCreateDatum(GearParam *g_ptr)
{
    ElemTreeData def_tree[]={
	{0, PRO_E_FEATURE_TREE, {(ProValueDataType)-1}},
	{1, PRO_E_FEATURE_TYPE, {PRO_VALUE_TYPE_INT, PRO_FEAT_DATUM}},
	{1, PRO_E_DTMPLN_CONSTRAINTS, {(ProValueDataType)-1}},
	{2, PRO_E_DTMPLN_CONSTRAINT, {(ProValueDataType)-1}},
	{3, PRO_E_DTMPLN_CONSTR_TYPE, {PRO_VALUE_TYPE_INT, PRO_DTMPLN_DEF_X}}
    };
    ElemTreeData offs_tree[]={
      {0, PRO_E_FEATURE_TREE, {(ProValueDataType)-1}},
      {1, PRO_E_FEATURE_TYPE, {PRO_VALUE_TYPE_INT, PRO_FEAT_DATUM}},
      {1, PRO_E_DTMPLN_CONSTRAINTS, {(ProValueDataType)-1}},
      {2, PRO_E_DTMPLN_CONSTRAINT, {(ProValueDataType)-1}},
      {3, PRO_E_DTMPLN_CONSTR_TYPE, {PRO_VALUE_TYPE_INT, PRO_DTMPLN_OFFS}},
      {3, PRO_E_DTMPLN_CONSTR_REF, {PRO_VALUE_TYPE_SELECTION}},
      {3, PRO_E_DTMPLN_CONSTR_REF_OFFSET, {PRO_VALUE_TYPE_DOUBLE, 0.0}}
    };
    
    int axes[3] = { 
	PRO_DTMPLN_DEF_X,
	PRO_DTMPLN_DEF_Y,
	PRO_DTMPLN_DEF_Z
    };

    wchar_t *names[]={L"GD_SIDE",L"GD_BOTTOM",L"GD_FRONT"};
    int  i, *id[3], *dim_id[3];
    ProSelection featsel;
    ProModelitem modelitem;
    ProFeature f;
    ProErrorlist errs;
    ProError status;
    
    ProElement elem_tree;
    double offset;
    
    if (!g_ptr->datum_created)
      {
	id[0] = &g_ptr->side_surface_id;
	id[1] = &g_ptr->bottom_surface_id;
	id[2] = &g_ptr->front_surface_id;
	dim_id[0] = &g_ptr->datum_x_offset_dim_id;
	dim_id[1] = &g_ptr->datum_y_offset_dim_id;
	dim_id[2] = &g_ptr->datum_z_offset_dim_id;
	
	for (i=0; i<3; i++)
	  {
	    
	    switch (i)
	      {
	      case 0:
		offset = g_ptr->datum_x_offset;
		break;
	      case 1:
		offset = g_ptr->datum_y_offset;
		break;
	      case 2:
		offset = g_ptr->datum_z_offset;
		break;
	      }
	    
	    offs_tree[6].data.v.d = offset;
	    
	    
	    /*-----------------------------------------------------------------*\
	      Create Element Tree
	      \*-----------------------------------------------------------------*/
	    def_tree[4].data.v.i = axes[i];
	    status = ProUtilElemtreeCreate(def_tree, SIZEOFARR(def_tree), NULL, &elem_tree);
	    PT_TEST_LOG_SUCC("ProUtilElemtreeCreate.......ProUserCreateDatum");
	    
	    /*-----------------------------------------------------------------*\
	      Create Default Datum
	      \*-----------------------------------------------------------------*/
	    status = ProMdlToModelitem(g_ptr->model, &modelitem);
	    PT_TEST_LOG_SUCC("ProMdlToModelitem");
	    
	    status = ProSelectionAlloc(NULL, &modelitem, &featsel);
	    PT_TEST_LOG_SUCC("ProSelectionAlloc");
	    
	    status = ProFeatureCreate(featsel, elem_tree, NULL, 0, &f, &errs);
	    PT_TEST_LOG_SUCC("ProFeatureCreate");
	    
	    if (status != PRO_TK_NO_ERROR)
	      {
		ProUtilFeatErrsWrite("ProFeatureCreate", status, elem_tree, &errs);
				
		return (-1);
	      }
	    
	  /*-----------------------------------------------------------------*\
	    Find surface ID for datum plane feature
	    \*-----------------------------------------------------------------*/
	    status = ProUtilFeatFirstGeomitem(&f, PRO_SURFACE, id[i]);
	    PT_TEST_LOG_SUCC("ProUtilFeatFirstGeomitem");
	    
	    status = ProUtilSelectionFromSurfaceId(g_ptr->model, *id [i], &offs_tree[5].data.v.r);
	    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");
	    
	    status = ProUtilElemtreeCreate(offs_tree, SIZEOFARR(offs_tree), NULL, &elem_tree);
	    PT_TEST_LOG_SUCC("ProUtilElemtreeCreate");
	    
	    status = ProFeatureCreate(featsel, elem_tree, NULL, 0, &f, &errs);
	    PT_TEST_LOG_SUCC("ProFeatureCreate");
	    
	    if (status != PRO_TK_NO_ERROR)
	      {
		ProUtilFeatErrsWrite("ProFeatureCreate", status, elem_tree, &errs);
				
		return (-1);
	      }
	    
	    status = ProModelitemNameSet((ProModelitem*)&f, names[i]);
	    PT_TEST_LOG_SUCC("ProModelitemNameSet");
	    
	    if (status != PRO_TK_NO_ERROR)
	      return (-1);
	    
	    status = ProSelectionFree(&featsel);
	    PT_TEST_LOG_SUCC("ProSelectionFree");
	    
	    status = ProUtilFeatFirstGeomitem(&f, PRO_SURFACE, id[i]);
	    PT_TEST_LOG_SUCC("ProUtilFeatFirstGeomitem");
	    
	    status = ProUtilFeatFirstDimension(&f, dim_id[i]);
	    PT_TEST_LOG_SUCC("ProUtilFeatFirstDimension");
	  }
      }
    else 
      {
	ProDimension dx, dy, dz;
	
	status = ProModelitemInit (g_ptr->model, g_ptr->datum_x_offset_dim_id,  PRO_DIMENSION, &dx);
	PT_TEST_LOG_SUCC("ProModelitemInit");
	
	status = ProDimensionValueSet (&dx, g_ptr->datum_x_offset);
	PT_TEST_LOG_SUCC("ProDimensionValueSet");
	
	status = ProModelitemInit (g_ptr->model, g_ptr->datum_y_offset_dim_id, PRO_DIMENSION, &dy);
	PT_TEST_LOG_SUCC("ProModelitemInit");
	
	status = ProDimensionValueSet (&dy, g_ptr->datum_y_offset);
	PT_TEST_LOG_SUCC("ProDimensionValueSet");
	
	status = ProModelitemInit (g_ptr->model, g_ptr->datum_z_offset_dim_id, PRO_DIMENSION, &dz);
	PT_TEST_LOG_SUCC("ProModelitemInit");
	
	status = ProDimensionValueSet (&dz, g_ptr->datum_z_offset);
	PT_TEST_LOG_SUCC("ProDimensionValueSet");
	
	status = ProSolidRegenerate (g_ptr->model, 0);
	PT_TEST_LOG_SUCC("ProSolidRegenerate");

	status = ProWindowRepaint (-1);
	PT_TEST_LOG_SUCC("ProWindowRepaint");
      }

    g_ptr->datum_created = PRO_B_TRUE;

    return (0);
    
  }

/*=============================================================*\
  Function: 	ProUserCreateDisk
  Purpose:	create gear disk
  \*=============================================================*/
  int ProUserCreateDisk(GearParam *g_ptr)
  {
     ElemTreeData tree[]={
       /* 0 */ {0, PRO_E_FEATURE_TREE, {(ProValueDataType)-1}},
       /* 1 */ {1, PRO_E_FEATURE_TYPE, {PRO_VALUE_TYPE_INT, PRO_FEAT_PROTRUSION}},
       /* 2 */ {1, PRO_E_FEATURE_FORM, {PRO_VALUE_TYPE_INT, PRO_EXTRUDE}},
       /* 3 */ {1, PRO_E_EXT_SURF_CUT_SOLID_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_FEAT_TYPE_SOLID}},
       /* 4 */ {1, PRO_E_REMOVE_MATERIAL, {PRO_VALUE_TYPE_INT, PRO_EXT_MATERIAL_ADD}},
       /* 5 */ {1, PRO_E_STD_SECTION,  {(ProValueDataType)-1}},
       /* 6 */ {2, PRO_E_STD_SEC_SETUP_PLANE, {(ProValueDataType)-1}},
       /* 7 */ {3, PRO_E_STD_SEC_PLANE, {PRO_VALUE_TYPE_SELECTION}},
       /* 8 */ {3, PRO_E_STD_SEC_PLANE_VIEW_DIR, {PRO_VALUE_TYPE_INT, PRO_SEC_VIEW_DIR_SIDE_ONE}},
       /* 9 */ {3, PRO_E_STD_SEC_PLANE_ORIENT_DIR, {PRO_VALUE_TYPE_INT, PRO_SEC_ORIENT_DIR_LEFT}},
       /* 10 */{3, PRO_E_STD_SEC_PLANE_ORIENT_REF, {PRO_VALUE_TYPE_SELECTION}},
       /* 11 */{1, PRO_E_FEAT_FORM_IS_THIN, {PRO_VALUE_TYPE_INT, PRO_EXT_FEAT_FORM_NO_THIN}},
       /* 12 */{1, PRO_E_STD_DIRECTION, {PRO_VALUE_TYPE_INT, PRO_EXT_CR_IN_SIDE_TWO}},
       /* 13 */{1, PRO_E_STD_EXT_DEPTH, {(ProValueDataType)-1}},
       /* 14 */{2, PRO_E_EXT_DEPTH_FROM, {(ProValueDataType)-1}},
       /* 15 */{3, PRO_E_EXT_DEPTH_FROM_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_DEPTH_FROM_NONE}},
       /* 16 */{2, PRO_E_EXT_DEPTH_TO, {(ProValueDataType)-1}},
       /* 17 */{3, PRO_E_EXT_DEPTH_TO_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_DEPTH_TO_BLIND}},
       /* 18 */{3, PRO_E_EXT_DEPTH_TO_VALUE, {PRO_VALUE_TYPE_DOUBLE}}
     };
     ProElempathItem depth_path[] = {
       {PRO_ELEM_PATH_ITEM_TYPE_ID, PRO_E_STD_EXT_DEPTH},
       {PRO_ELEM_PATH_ITEM_TYPE_ID, PRO_E_EXT_DEPTH_FROM},
       {PRO_ELEM_PATH_ITEM_TYPE_ID, PRO_E_EXT_DEPTH_FROM_VALUE}
     };

     ElemTreeData axis_tree[] = {
     /* 0 */ {0, PRO_E_FEATURE_TREE, {(ProValueDataType)-1}},
     /* 1 */ {1, PRO_E_FEATURE_TYPE, {PRO_VALUE_TYPE_INT, PRO_FEAT_DATUM_AXIS}},
     /* 2 */ {1, PRO_E_DTMAXIS_CONSTRAINTS, {(ProValueDataType)-1}},
     /* 3 */ {2, PRO_E_DTMAXIS_CONSTRAINT, {(ProValueDataType)-1}},
     /* 4 */ {3, PRO_E_DTMAXIS_CONSTR_TYPE, {PRO_VALUE_TYPE_INT, 1}},
     /* 5 */ {3, PRO_E_DTMAXIS_CONSTR_REF, {PRO_VALUE_TYPE_SELECTION}},
     /* 6 */ {2, PRO_E_DTMAXIS_CONSTRAINT, {(ProValueDataType)-1}},
     /* 7 */ {3, PRO_E_DTMAXIS_CONSTR_TYPE, {PRO_VALUE_TYPE_INT, 1}},
     /* 8 */ {3, PRO_E_DTMAXIS_CONSTR_REF, {PRO_VALUE_TYPE_SELECTION}}
     };

     ElemTreeData dtm_tree[]={
       /* 0 */ {0, PRO_E_FEATURE_TREE, {(ProValueDataType)-1}},
       /* 1 */ {1, PRO_E_FEATURE_TYPE, {PRO_VALUE_TYPE_INT, PRO_FEAT_DATUM}},
       /* 2 */ {1, PRO_E_DTMPLN_CONSTRAINTS, {(ProValueDataType)-1}},
       /* 3 */ {2, PRO_E_DTMPLN_CONSTRAINT, {(ProValueDataType)-1}},
       /* 4 */ {3, PRO_E_DTMPLN_CONSTR_TYPE, {PRO_VALUE_TYPE_INT, 0}},
       /* 5 */ {3, PRO_E_DTMPLN_CONSTR_REF, {PRO_VALUE_TYPE_SELECTION, NULL}},
       /* 6 */ {2, PRO_E_DTMPLN_CONSTRAINT, {(ProValueDataType)-1}},
       /* 7 */ {3, PRO_E_DTMPLN_CONSTR_TYPE, {PRO_VALUE_TYPE_INT, 4}},
       /* 8 */ {3, PRO_E_DTMPLN_CONSTR_REF, {PRO_VALUE_TYPE_SELECTION}},
       /* 9 */ {3, PRO_E_DTMPLN_CONSTR_REF_ANGLE, {PRO_VALUE_TYPE_DOUBLE}}
     };

     ElemTreeData dtm_tree_normal[]={
       /* 0 */ {0, PRO_E_FEATURE_TREE, {(ProValueDataType)-1}},
       /* 1 */ {1, PRO_E_FEATURE_TYPE, {PRO_VALUE_TYPE_INT, PRO_FEAT_DATUM}},
       /* 2 */ {1, PRO_E_DTMPLN_CONSTRAINTS, {(ProValueDataType)-1}},
       /* 3 */ {2, PRO_E_DTMPLN_CONSTRAINT, {(ProValueDataType)-1}},
       /* 4 */ {3, PRO_E_DTMPLN_CONSTR_TYPE, {PRO_VALUE_TYPE_INT, 0}},
       /* 5 */ {3, PRO_E_DTMPLN_CONSTR_REF, {PRO_VALUE_TYPE_SELECTION, NULL}},
       /* 6 */	{2, PRO_E_DTMPLN_CONSTRAINT, {(ProValueDataType)-1}},
       /* 7 */ {3, PRO_E_DTMPLN_CONSTR_TYPE, {PRO_VALUE_TYPE_INT, 1}},
       /* 8 */ {3, PRO_E_DTMPLN_CONSTR_REF, {PRO_VALUE_TYPE_SELECTION}},
       /* 9 */ {3, PRO_E_DTMPLN_CONSTR_REF_ANGLE, {PRO_VALUE_TYPE_DOUBLE}}
     };

     
     FeatureDef feat_def;
     ProFeature feature, feature_handle;
     ProModelitem modelitem;
     Pro3dPnt pnt;
     ProMdl model;

     /* Declaration for axis element tree generation */
     ProElement elem_axis_tree;
     ProSelection featsel_axis;
     ProFeature feature_axis;
     ProModelitem model_item;
     ProErrorlist axis_errs;
     int axis_id, id;
     ProFeatureCreateOptions opts[2], *cr_opts;

     /* Declaration for datum plane tree generation */
     ProElement elem_tree;
     ProSelection featsel_plane;
     ProErrorlist errs_plane;
     ProFeature feature_plane;
     ProModelitem model_item_plane;

     /* Declarations for second datum plane */
     ProElement elem_dtm_tree;
     ProSelection feat_plane_sel;
     ProErrorlist errs_dtm;
     ProFeature feature_dtm;
     ProModelitem model_dtm;
     int surf_id;
     ProError status;
     
     if (g_ptr->gear_depth == 0.0 || g_ptr->gear_diam == 0.0 )
     return 1;

     /*-----------------------------------------------------------------*\
     Preparation of feature data
     \*-----------------------------------------------------------------*/
     memset(&feat_def, 0, sizeof(feat_def));
     
     status =ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->front_surface_id, &tree[7].data.v.r);
     PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId.........ProUserCreateDisk");
     
     status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->side_surface_id, &tree[10].data.v.r);
     PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");

     tree[18].data.v.d = g_ptr->gear_depth; 

     feat_def.tree = tree;
     feat_def.sizeof_tree = SIZEOFARR(tree);

     feat_def.params[0].d = g_ptr->gear_diam;
     feat_def.params[1].r = tree[10].data.v.r;
     
     status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->bottom_surface_id, &feat_def.params[2].r);
     PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");
     
     feat_def.section_create_func = ProUtilCreateCircleSection;

     feat_def.feat_name  = "Gear_Disk";

     /*-----------------------------------------------------------------*\
     Create new feature
     \*-----------------------------------------------------------------*/
     status  = ProUtilCreateSketchedFeature(g_ptr, &feat_def, &feature);
     PT_TEST_LOG_SUCC("ProUtilCreateSketchedFeature");
     
     if (status == PRO_TK_NO_ERROR)
     {
       g_ptr->disk_created = 1;

     /*-----------------------------------------------------------------*\
     Create new axis
     \*-----------------------------------------------------------------*/
     opts[0] = PRO_FEAT_CR_NO_OPTS;

     status = ProArrayAlloc(0, sizeof(ProFeatureCreateOptions),1, (ProArray*)&cr_opts);
     PT_TEST_LOG_SUCC("ProArrayAlloc");

     status = ProArrayObjectAdd((ProArray*)&cr_opts,PRO_VALUE_UNUSED, 1, (void*)&(opts[0])); 
     PT_TEST_LOG_SUCC("ProArrayObjectAdd");

     status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->front_surface_id, &axis_tree[5].data.v.r);
     PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");

     status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->side_surface_id,  &axis_tree[8].data.v.r);
     PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");

     status = ProUtilElemtreeCreate(axis_tree, SIZEOFARR(axis_tree), NULL, &elem_axis_tree);
     PT_TEST_LOG_SUCC("ProUtilElemtreeCreate");

     status = ProMdlToModelitem(g_ptr->model, &model_item);
     PT_TEST_LOG_SUCC("ProMdlToModelitem");

     status = ProSelectionAlloc(NULL, &model_item, &featsel_axis);
     PT_TEST_LOG_SUCC("ProSelectionAlloc");

     status = ProFeatureWithoptionsCreate(featsel_axis, elem_axis_tree, cr_opts, PRO_REGEN_FORCE_REGEN, &feature_axis, &axis_errs);
     PT_TEST_LOG_SUCC("ProFeatureWithoptionsCreate");
     
     if (status != PRO_TK_NO_ERROR)
     {
       ProUtilFeatErrsWrite("ProFeatureCreate", status, elem_axis_tree, &axis_errs);
       
       return (-1);
     }

     status = ProUtilAxisGeomitem(&feature_axis, PRO_AXIS, &axis_id);    
     PT_TEST_LOG_SUCC("ProUtilAxisGeomitem");
     
     if (status != PRO_TK_NO_ERROR)
       return(status);

     status = ProArrayFree((ProArray*)&cr_opts);
     PT_TEST_LOG_SUCC("ProArrayFree");
     
     status = ProSelectionFree(&featsel_axis);
     PT_TEST_LOG_SUCC("ProSelectionFree");
     
     status = ProSelectionFree(&axis_tree[5].data.v.r);
     PT_TEST_LOG_SUCC("ProSelectionFree");
     
     status = ProSelectionFree(&axis_tree[8].data.v.r);
     PT_TEST_LOG_SUCC("ProSelectionFree");

     /*-----------------------------------------------------------------*\
     Set datum axis name
     \*-----------------------------------------------------------------*/
     status = ProUtilModelitemNameSet((ProModelitem*)&feature_axis, "DTM_AXIS_1");
     PT_TEST_LOG_SUCC("ProUtilModelitemNameSet");
     
     if (status != PRO_TK_NO_ERROR)
       return (-1);

     /*-----------------------------------------------------------------*\
     Create Datum Plane first
     \*-----------------------------------------------------------------*/
     
     status = ProArrayAlloc(0, sizeof(ProFeatureCreateOptions),1, (ProArray*)&cr_opts);
     PT_TEST_LOG_SUCC("ProArrayAlloc");

     status = ProArrayObjectAdd((ProArray*)&cr_opts,PRO_VALUE_UNUSED, 1, (void*)&(opts[0])); 
     PT_TEST_LOG_SUCC("ProArrayObjectAdd");

     status = ProUtilSelectionFromAxisId(g_ptr->model, axis_id, &dtm_tree[5].data.v.r);
     PT_TEST_LOG_SUCC("ProUtilSelectionFromAxisId");
     
     status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->side_surface_id, &dtm_tree[8].data.v.r);
     PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");
     
     if(g_ptr->gear_type == HELICAL_GEAR)
     {
     	dtm_tree[9].data.v.d = g_ptr->helix_angle;
     }
     else
     {
     	dtm_tree[9].data.v.d = 0.0;
     }

     status = ProUtilElemtreeCreate(dtm_tree, SIZEOFARR(dtm_tree), NULL, &elem_tree);
     PT_TEST_LOG_SUCC("ProUtilElemtreeCreate");

     status = ProMdlToModelitem(g_ptr->model, &model_item_plane);
     PT_TEST_LOG_SUCC("ProMdlToModelitem");

     status = ProSelectionAlloc(NULL, &model_item_plane, &featsel_plane);
     PT_TEST_LOG_SUCC("ProSelectionAlloc");

     status = ProFeatureWithoptionsCreate(featsel_plane, elem_tree, cr_opts, PRO_REGEN_FORCE_REGEN, &feature_plane, &errs_plane);
     PT_TEST_LOG_SUCC("ProFeatureWithoptionsCreate");

     if (status != PRO_TK_NO_ERROR)
     {
       ProUtilFeatErrsWrite("ProFeatureCreate", status, elem_tree, &errs_plane);
       
       return (-1);
     }
     
     ProUtilAxisGeomitem(&feature_plane, PRO_SURFACE, &surf_id);    
     
     if (status != PRO_TK_NO_ERROR)
     return(status);
     
     status = ProArrayFree((ProArray*)&cr_opts); 
     PT_TEST_LOG_SUCC("ProArrayFree");
     
     status = ProSelectionFree(&featsel_plane);
     PT_TEST_LOG_SUCC("ProSelectionFree");
     
     status = ProSelectionFree(&dtm_tree[5].data.v.r);
     PT_TEST_LOG_SUCC("ProSelectionFree");
     
     status = ProSelectionFree(&dtm_tree[8].data.v.r);
     PT_TEST_LOG_SUCC("ProSelectionFree");

     /*-----------------------------------------------------------------*\
     Set datum plane name
     \*-----------------------------------------------------------------*/
     status = ProUtilModelitemNameSet((ProModelitem*)&feature_plane, "DTM_TOOTH_1");
     PT_TEST_LOG_SUCC("ProUtilModelitemNameSet");
     
     if (status != PRO_TK_NO_ERROR)
      return (-1);

     /*-----------------------------------------------------------------*\
     Create Datum Plane second
     \*-----------------------------------------------------------------*/

     status = ProArrayAlloc(0, sizeof(ProFeatureCreateOptions),1, (ProArray*)&cr_opts);
     PT_TEST_LOG_SUCC("ProArrayAlloc");

     status = ProArrayObjectAdd((ProArray*)&cr_opts,PRO_VALUE_UNUSED, 1, (void*)&(opts[0])); 
     PT_TEST_LOG_SUCC("ProArrayObjectAdd");

     status = ProUtilSelectionFromAxisId(g_ptr->model, axis_id, &dtm_tree_normal[5].data.v.r);
     PT_TEST_LOG_SUCC("ProUtilSelectionFromAxisId");

     status = ProUtilSelectionFromSurfaceId(g_ptr->model, surf_id, &dtm_tree_normal[8].data.v.r);
     PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");
     
     dtm_tree[9].data.v.d = 00.0;

     status = ProUtilElemtreeCreate(dtm_tree_normal, SIZEOFARR(dtm_tree_normal), NULL, &elem_dtm_tree);
     PT_TEST_LOG_SUCC("ProUtilElemtreeCreate");

     status = ProMdlToModelitem(g_ptr->model, &model_dtm);
     PT_TEST_LOG_SUCC("ProMdlToModelitem");

     status = ProSelectionAlloc(NULL, &model_item_plane, &feat_plane_sel);
     PT_TEST_LOG_SUCC("ProSelectionAlloc");

     status = ProFeatureWithoptionsCreate(feat_plane_sel, elem_dtm_tree, cr_opts, PRO_REGEN_FORCE_REGEN, &feature_dtm, &errs_dtm);
     PT_TEST_LOG_SUCC("ProFeatureWithoptionsCreate");

     if (status != PRO_TK_NO_ERROR)
     {
       ProUtilFeatErrsWrite("ProFeatureCreate", status, elem_dtm_tree, &errs_dtm);
       
       return (-1);
     }
     status = ProArrayFree((ProArray*)&cr_opts); 
     PT_TEST_LOG_SUCC("ProArrayFree");
     
     status = ProSelectionFree(&feat_plane_sel);
     PT_TEST_LOG_SUCC("ProSelectionFree");
     
     status = ProSelectionFree(&dtm_tree_normal[5].data.v.r);
     PT_TEST_LOG_SUCC("ProSelectionFree");
     
     status = ProSelectionFree(&dtm_tree_normal[8].data.v.r);
     PT_TEST_LOG_SUCC("ProSelectionFree");

     /*-----------------------------------------------------------------*\
     Set datum plane name
     \*-----------------------------------------------------------------*/
     status = ProUtilModelitemNameSet((ProModelitem*)&feature_dtm, "DTM_TOOTH_2");
     PT_TEST_LOG_SUCC("ProUtilModelitemNameSet");
     
     if (status != PRO_TK_NO_ERROR)
      return (-1);

     /*-----------------------------------------------------------------*\
     Find and name required surfaces
     \*-----------------------------------------------------------------*/

       pnt[0] = g_ptr->datum_x_offset;
       pnt[1] = g_ptr->datum_y_offset;
       pnt[2] = g_ptr->gear_depth + g_ptr->datum_z_offset;
       
       status = ProUtilGeometryAtPointFind((ProPart)g_ptr->model, pnt, &modelitem);
       PT_TEST_LOG_SUCC("ProUtilGeometryAtPointFind");
       
       g_ptr->disk_front_surf_id = modelitem.id;
       
       status = ProUtilModelitemNameSet(&modelitem, "DISK_FRONT");
       PT_TEST_LOG_SUCC("ProUtilModelitemNameSet");

       pnt[0] = g_ptr->datum_x_offset;
       pnt[1] = (g_ptr->gear_diam/2) + g_ptr->datum_y_offset; 
       pnt[2] = g_ptr->gear_depth/2 + g_ptr->datum_z_offset;
       
       status = ProUtilGeometryAtPointFind((ProPart)g_ptr->model, pnt, &modelitem);
       PT_TEST_LOG_SUCC("ProUtilGeometryAtPointFind");
       
       g_ptr->disk_side_surf_id = modelitem.id;
       
       status = ProUtilModelitemNameSet(&modelitem, "DISK_SIDE");
       PT_TEST_LOG_SUCC("ProUtilModelitemNameSet");

       status = ProViewRefit (g_ptr->model, NULL);
       PT_TEST_LOG_SUCC("ProViewRefit");

    }
    
/*-----------------------------------------------------------------*\
    Free allocated memory
\*-----------------------------------------------------------------*/
    status = ProSelectionFree(&tree[7].data.v.r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    status = ProSelectionFree(&tree[10].data.v.r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    status = ProSelectionFree(&feat_def.params[2].r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    return (status);
}

/*=============================================================*\
  Function: 	ProUserCreateHole
  Purpose:	create gear hole
\*=============================================================*/
int ProUserCreateHole(GearParam *g_ptr)
{
    ElemTreeData tree[]={
  /* 0*/ 	{0, PRO_E_FEATURE_TREE, {(ProValueDataType)-1}},
  /* 1*/	{1, PRO_E_FEATURE_TYPE, {PRO_VALUE_TYPE_INT, PRO_FEAT_HOLE}},
  /* 2*/	{1, PRO_E_FEATURE_FORM, {PRO_VALUE_TYPE_INT, PRO_EXTRUDE}},
  /* 3*/	{1, PRO_E_HLE_COM, {(ProValueDataType)-1}},
  /* 4*/ 	{2, PRO_E_HLE_TYPE_NEW, {PRO_VALUE_TYPE_INT, 16}},
  /* 5*/ 	{2, PRO_E_DIAMETER, {PRO_VALUE_TYPE_DOUBLE, 4}},		
  /* 6*/ 	{2, PRO_E_HOLE_STD_DEPTH, {(ProValueDataType)-1}},
  /* 7*/ 	{3, PRO_E_HOLE_DEPTH_TO, {(ProValueDataType)-1}},
  /* 8*/ 	{4, PRO_E_HOLE_DEPTH_TO_TYPE, {PRO_VALUE_TYPE_INT, 3}},
  /* 9*/	{3, PRO_E_HOLE_DEPTH_FROM, {(ProValueDataType)-1}},
  /* 10*/	{4, PRO_E_HOLE_DEPTH_FROM_TYPE, {PRO_VALUE_TYPE_INT, 3}},
  /* 11*/	{1, PRO_E_HLE_PLACEMENT, {(ProValueDataType)-1}},
  /* 12*/	{2, PRO_E_HLE_PRIM_REF, {PRO_VALUE_TYPE_SELECTION}},		
  /* 13*/	{2, PRO_E_HLE_PL_TYPE, {PRO_VALUE_TYPE_INT, 5}},
  /* 14*/	{2, PRO_E_HLE_PLCMNT_PLANE, {PRO_VALUE_TYPE_SELECTION}},	
	};


	
    int axis_id;
    ProFeature feature, f;
    ProErrorlist errs;
    Pro3dPnt pnt;
    ProModelitem modelitem;
    ProElement elem_tree;
    ProSelection featsel;
    int n_of_teeth;
    ProError status;
        
    FeatByName feat_disk[] = {
	{"GEAR_DISK"}
    };
    
    if (g_ptr->inner_diam == 0.0)
	 return 1;
/*-----------------------------------------------------------------*\
    Preparation of feature data
\*-----------------------------------------------------------------*/
    status = ProUtilFeatsByName(g_ptr->model, feat_disk, 1);
    PT_TEST_LOG_SUCC("ProUtilFeatsByName..........ProUserCreateHole");
    
    if (status != PRO_TK_NO_ERROR || feat_disk[0].id == -1)
	return (status);

    status = ProFeatureInit(g_ptr->model, feat_disk[0].id, &feature);
    PT_TEST_LOG_SUCC("ProFeatureInit");
    
    status = ProUtilFeatFirstGeomitem(&feature, PRO_AXIS, &axis_id); 
    PT_TEST_LOG_SUCC("ProUtilFeatFirstGeomitem");
       
    if (status != PRO_TK_NO_ERROR)
	return (status);

    status = ProModelitemInit(g_ptr->model, axis_id, PRO_AXIS, &modelitem);
    PT_TEST_LOG_SUCC("ProModelitemInit");
    
    if (status!=PRO_TK_NO_ERROR) 
	return (status);

    status = ProSelectionAlloc(NULL, &modelitem, &tree[12].data.v.r);
    PT_TEST_LOG_SUCC("ProSelectionAlloc");
 
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->front_surface_id, &tree[14].data.v.r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");
    
    tree[5].data.v.d = g_ptr->inner_diam;

/*-----------------------------------------------------------------*\
    Create new feature
\*-----------------------------------------------------------------*/
    status = ProUtilElemtreeCreate(tree, SIZEOFARR(tree), NULL, &elem_tree);
    PT_TEST_LOG_SUCC("ProUtilElemtreeCreate");
    
    status = ProMdlToModelitem(g_ptr->model, &modelitem);
    PT_TEST_LOG_SUCC("ProUtilFeatsByName");
    
    status = ProSelectionAlloc(NULL, &modelitem, &featsel);
    PT_TEST_LOG_SUCC("ProSelectionAlloc");
    
    status = ProFeatureCreate(featsel, elem_tree, NULL, 0, &f, &errs);
    PT_TEST_LOG_SUCC("ProFeatureCreate");
    
    status = ProSelectionFree(&featsel);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    if (status != PRO_TK_NO_ERROR)
    {
	ProUtilFeatErrsWrite("ProFeatureCreate", status, elem_tree, &errs);
	return (-1);
    }
    else
    {

/*-----------------------------------------------------------------*\
    Set feature name
\*-----------------------------------------------------------------*/
        status = ProUtilModelitemNameSet((ProModelitem*)&f, "GEAR_HOLE");
	PT_TEST_LOG_SUCC("ProUtilModelitemNameSet");
	
        if (status != PRO_TK_NO_ERROR)
            return (-1);

	g_ptr->hole_created = 1;

/*-----------------------------------------------------------------*\
    Find and name required surfaces
\*-----------------------------------------------------------------*/
	pnt[0] = g_ptr->datum_x_offset;
	pnt[1] = g_ptr->datum_y_offset + g_ptr->inner_diam/2;  /* point on surface */
	if (g_ptr->gear_type == SPUR_GEAR)
	    pnt[2] = g_ptr->datum_z_offset + g_ptr->gear_depth/2;
	else
	    pnt[2] = g_ptr->datum_z_offset - g_ptr->backplate_depth/2;
	
	status = ProUtilGeometryAtPointFind((ProPart)g_ptr->model, pnt, &modelitem);
	PT_TEST_LOG_SUCC("ProUtilGeometryAtPointFind");
	
	g_ptr->hole_side_surf_id = modelitem.id;
	
	status = ProUtilModelitemNameSet(&modelitem, "HOLE_SIDE");
	PT_TEST_LOG_SUCC("ProUtilModelitemNameSet");
    }
/*-----------------------------------------------------------------*\
    Free allocated memory
\*-----------------------------------------------------------------*/
    status = ProSelectionFree(&tree[12].data.v.r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    status = ProSelectionFree(&tree[14].data.v.r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    return (status);
}


/*=============================================================*\
  Function: 	ProUserCreateToothSurf
  Purpose:	create all gear tooth surface locator hole (ring gear)
\*=============================================================*/
int ProUserCreateToothSurf(GearParam *g_ptr)
{
    ElemTreeData tree[]={
	/* 0 */ {0, PRO_E_FEATURE_TREE, {(ProValueDataType)-1}},
	/* 1 */ {1, PRO_E_FEATURE_TYPE, {PRO_VALUE_TYPE_INT, PRO_FEAT_CUT}},
	/* 2 */ {1, PRO_E_FEATURE_FORM, {PRO_VALUE_TYPE_INT, PRO_EXTRUDE}},
	/* 3 */ {1, PRO_E_EXT_SURF_CUT_SOLID_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_FEAT_TYPE_SOLID}},
	/* 4 */ {1, PRO_E_REMOVE_MATERIAL, {PRO_VALUE_TYPE_INT, PRO_EXT_MATERIAL_REMOVE}},
	/* 5 */ {1, PRO_E_STD_SECTION,  {(ProValueDataType)-1}},
	/* 6 */ {2, PRO_E_STD_SEC_SETUP_PLANE,  {(ProValueDataType)-1}},
	/* 7 */ {3, PRO_E_STD_SEC_PLANE, {PRO_VALUE_TYPE_SELECTION}},
	/* 8 */ {3, PRO_E_STD_SEC_PLANE_VIEW_DIR, {PRO_VALUE_TYPE_INT, PRO_SEC_VIEW_DIR_SIDE_TWO}},
	/* 9 */ {3, PRO_E_STD_SEC_PLANE_ORIENT_DIR, {PRO_VALUE_TYPE_INT, PRO_SEC_ORIENT_DIR_LEFT}},
	/* 10 */{3, PRO_E_STD_SEC_PLANE_ORIENT_REF, {PRO_VALUE_TYPE_SELECTION}},
	/* 11 */{1, PRO_E_FEAT_FORM_IS_THIN, {PRO_VALUE_TYPE_INT, PRO_EXT_FEAT_FORM_NO_THIN}},
	/* 12 */{1, PRO_E_STD_DIRECTION, {PRO_VALUE_TYPE_INT, PRO_EXT_CR_IN_SIDE_ONE}},
	/* 13 */{1, PRO_E_STD_MATRLSIDE, {PRO_VALUE_TYPE_INT, PRO_EXT_MATERIAL_SIDE_TWO}},
	/* 14 */{1, PRO_E_STD_EXT_DEPTH, {(ProValueDataType)-1}},
	/* 15 */{2, PRO_E_EXT_DEPTH_FROM, {(ProValueDataType)-1}},
	/* 16 */{3, PRO_E_EXT_DEPTH_FROM_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_DEPTH_FROM_NONE}},
	/* 17 */{2, PRO_E_EXT_DEPTH_TO, {(ProValueDataType)-1}},
	/* 18 */{3, PRO_E_EXT_DEPTH_TO_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_DEPTH_TO_NEXT}}
    };
   
    FeatureDef feat_def;
    ProFeature feature;
    Pro3dPnt pnt;
    ProModelitem modelitem;
    double diam;
    ProError status;
    
/*-----------------------------------------------------------------*\
    Preparation of feature data
\*-----------------------------------------------------------------*/
    memset(&feat_def, 0, sizeof(feat_def));
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->front_surface_id, &tree[7].data.v.r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId........ProUserCreateToothSurf");
    
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->side_surface_id, &tree[10].data.v.r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");

    feat_def.tree = tree;
    feat_def.sizeof_tree = SIZEOFARR(tree);

    diam = (g_ptr->n_of_teeth - 2) * g_ptr->tooth_par1;
    feat_def.params[0].d = diam;
    feat_def.params[1].r = tree[10].data.v.r;
    
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->bottom_surface_id, &feat_def.params[2].r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");
    
    feat_def.section_create_func = ProUtilCreateCircleSection;

    feat_def.feat_name  = "Tooth_Surf";

    

/*-----------------------------------------------------------------*\
    Create new feature
\*-----------------------------------------------------------------*/
    status  = ProUtilCreateSketchedFeature(g_ptr, &feat_def, &feature);
    PT_TEST_LOG_SUCC("ProUtilCreateSketchedFeature");
    
    if (status == PRO_TK_NO_ERROR)
    {
	g_ptr->tooth_surf_created = 1;

/*-----------------------------------------------------------------*\
    Find and name required surfaces
\*-----------------------------------------------------------------*/
	pnt[0] = g_ptr -> datum_x_offset;
	pnt[1] = g_ptr -> datum_y_offset + diam/2;  /* point on surface */
	pnt[2] = g_ptr -> datum_z_offset + g_ptr->gear_depth/2;
	
	status = ProUtilGeometryAtPointFind((ProPart)g_ptr->model, pnt, &modelitem);
	PT_TEST_LOG_SUCC("ProUtilGeometryAtPointFind");
	
	g_ptr->tooth_surf_side_surf_id = modelitem.id;
	
	status = ProUtilModelitemNameSet(&modelitem, "TOOTH_SURF_SIDE");
	PT_TEST_LOG_SUCC("ProUtilModelitemNameSet");
    }
/*-----------------------------------------------------------------*\
    Free allocated memory
\*-----------------------------------------------------------------*/
    status = ProSelectionFree(&tree[7].data.v.r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    status = ProSelectionFree(&tree[10].data.v.r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    status = ProSelectionFree(&feat_def.params[2].r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    return (0);
}

/*=============================================================*\
  Function: 	ProUserCreateTooth
  Purpose:	create first gear tooth
\*=============================================================*/
int ProUserCreateTooth(GearParam *g_ptr)
{

  ElemTreeData sketch_tree[]={
     /* 0 */ {0, PRO_E_FEATURE_TREE, {(ProValueDataType)-1}},
     /* 1 */ {1, PRO_E_FEATURE_TYPE, {PRO_VALUE_TYPE_INT, PRO_FEAT_CURVE}},
     /* 2 */ {1, PRO_E_CURVE_TYPE, {PRO_VALUE_TYPE_INT, 0}},
     /* 3 */ {1, PRO_E_STD_SECTION, {(ProValueDataType)-1}},
     /* 4 */ {2, PRO_E_STD_SEC_METHOD, {PRO_VALUE_TYPE_INT, 0}},
     /* 5 */ {2, PRO_E_STD_SEC_SELECT, {(ProValueDataType)-1}},
     /* 6 */ {3, PRO_E_SURF_CHAIN_CMPND, {(ProValueDataType)-1}},
     /* 7 */ {4, PRO_E_SURF_CHAIN_METHOD, {PRO_VALUE_TYPE_INT, 0}},
     /* 8 */ {2, PRO_E_STD_SEC_SETUP_PLANE, {(ProValueDataType)-1}},
     /* 9 */ {3, PRO_E_STD_SEC_PLANE, {PRO_VALUE_TYPE_SELECTION}},
     /* 10 */{3, PRO_E_STD_SEC_PLANE_VIEW_DIR, {PRO_VALUE_TYPE_INT, 1}},
     /* 11 */{3, PRO_E_STD_SEC_PLANE_ORIENT_DIR, {PRO_VALUE_TYPE_INT, 4}},
     /* 12 */{3, PRO_E_STD_SEC_PLANE_ORIENT_REF, {PRO_VALUE_TYPE_SELECTION}},
     /* 13 */{1, PRO_E_ATTRIBUTES, {(ProValueDataType)-1}},
     /* 14 */{2, PRO_E_DTMCRV_DISPLAY_HATCH, {PRO_VALUE_TYPE_INT, 0}},
     /* 15 */{2, PRO_E_DTMCRV_HATCH_DENSITY, {PRO_VALUE_TYPE_DOUBLE, 0.0}}
  };

  ElemTreeData tree[]={
     /* 0 */ {0, PRO_E_FEATURE_TREE, {(ProValueDataType)-1}},
     /* 1 */ {1, PRO_E_FEATURE_TYPE, {PRO_VALUE_TYPE_INT, PRO_FEAT_CUT}},
     /* 2 */ {1, PRO_E_FEATURE_FORM, {PRO_VALUE_TYPE_INT, PRO_EXTRUDE}},
     /* 3 */ {1, PRO_E_EXT_SURF_CUT_SOLID_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_FEAT_TYPE_SOLID}},
     /* 4 */ {1, PRO_E_REMOVE_MATERIAL, {PRO_VALUE_TYPE_INT, PRO_EXT_MATERIAL_REMOVE}},
     /* 5 */ {1, PRO_E_STD_SECTION,  {(ProValueDataType)-1}},
     /* 6 */ {2, PRO_E_STD_SEC_SETUP_PLANE,  {(ProValueDataType)-1}},
     /* 7 */ {3, PRO_E_STD_SEC_PLANE, {PRO_VALUE_TYPE_SELECTION}},
     /* 8 */ {3, PRO_E_STD_SEC_PLANE_VIEW_DIR, {PRO_VALUE_TYPE_INT, 1}},
     /* 9 */ {3, PRO_E_STD_SEC_PLANE_ORIENT_DIR, {PRO_VALUE_TYPE_INT, 2}},
     /* 10 */{3, PRO_E_STD_SEC_PLANE_ORIENT_REF, {PRO_VALUE_TYPE_SELECTION}},
     /* 11 */{1, PRO_E_FEAT_FORM_IS_THIN, {PRO_VALUE_TYPE_INT, PRO_EXT_FEAT_FORM_NO_THIN}},
     /* 12 */{1, PRO_E_STD_DIRECTION, {PRO_VALUE_TYPE_INT, -1}},
     /* 13 */{1, PRO_E_STD_MATRLSIDE, {PRO_VALUE_TYPE_INT, 1}},
     /* 14 */{1, PRO_E_STD_EXT_DEPTH, {(ProValueDataType)-1}},
     /* 15 */{2, PRO_E_EXT_DEPTH_FROM, {(ProValueDataType)-1}},
     /* 16 */{3, PRO_E_EXT_DEPTH_FROM_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_DEPTH_FROM_NONE}},
     /* 17 */{2, PRO_E_EXT_DEPTH_TO, {(ProValueDataType)-1}},
     /* 18 */{3, PRO_E_EXT_DEPTH_TO_TYPE, {PRO_VALUE_TYPE_INT, 268435456}},
     /* 19 */{3, PRO_E_EXT_DEPTH_TO_VALUE, {PRO_VALUE_TYPE_DOUBLE}}
  };

  ElemTreeData tree_1[]={
     /* 0 */ {0, PRO_E_FEATURE_TREE, {(ProValueDataType)-1}},
     /* 1 */ {1, PRO_E_FEATURE_TYPE, {PRO_VALUE_TYPE_INT, PRO_FEAT_CUT}},
     /* 2 */ {1, PRO_E_FEATURE_FORM, {PRO_VALUE_TYPE_INT, PRO_EXTRUDE}},
     /* 3 */ {1, PRO_E_EXT_SURF_CUT_SOLID_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_FEAT_TYPE_SOLID}},
     /* 4 */ {1, PRO_E_REMOVE_MATERIAL, {PRO_VALUE_TYPE_INT, PRO_EXT_MATERIAL_REMOVE}},
     /* 5 */ {1, PRO_E_STD_SECTION,  {(ProValueDataType)-1}},
     /* 6 */ {2, PRO_E_STD_SEC_SETUP_PLANE,  {(ProValueDataType)-1}},
     /* 7 */ {3, PRO_E_STD_SEC_PLANE, {PRO_VALUE_TYPE_SELECTION}},
     /* 8 */ {3, PRO_E_STD_SEC_PLANE_VIEW_DIR, {PRO_VALUE_TYPE_INT, 1}},
     /* 9 */ {3, PRO_E_STD_SEC_PLANE_ORIENT_DIR, {PRO_VALUE_TYPE_INT, 2}},
     /* 10 */{3, PRO_E_STD_SEC_PLANE_ORIENT_REF, {PRO_VALUE_TYPE_SELECTION}},
     /* 11 */{1, PRO_E_FEAT_FORM_IS_THIN, {PRO_VALUE_TYPE_INT, PRO_EXT_FEAT_FORM_NO_THIN}},
     /* 12 */{1, PRO_E_STD_DIRECTION, {PRO_VALUE_TYPE_INT, PRO_EXT_MATERIAL_SIDE_TWO}},
     /* 13 */{1, PRO_E_STD_MATRLSIDE, {PRO_VALUE_TYPE_INT, PRO_EXT_MATERIAL_SIDE_TWO}},
     /* 14 */{1, PRO_E_STD_EXT_DEPTH, {(ProValueDataType)-1}},
     /* 15 */{2, PRO_E_EXT_DEPTH_FROM, {(ProValueDataType)-1}},
     /* 16 */{3, PRO_E_EXT_DEPTH_FROM_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_DEPTH_FROM_NONE}},
     /* 17 */{2, PRO_E_EXT_DEPTH_TO, {(ProValueDataType)-1}},
     /* 18 */{3, PRO_E_EXT_DEPTH_TO_TYPE, {PRO_VALUE_TYPE_INT, 268435456}},
     /* 19 */{3, PRO_E_EXT_DEPTH_TO_VALUE, {PRO_VALUE_TYPE_DOUBLE}}
  };

  
  FeatureDef feat_def;
  ProFeature feature, feat_tooth, feature_datum_1, feature_datum_2;
  ProModelitem modelitem;
  int axis_id, surface_id_1, *feats_ids, ret, n_dims, *p_dim_ids, surface_id_2, sketch_id;
  ProErrorlist errs, errors;
  ProElement elem_tree,  elemtree;
  ProSelection featsel;
  ProLayer layer;
  ProLayerItem layer_item;
  ProGroup group;
  ProName w_name;
  Pro3dPnt pnt;
  ProError status;
  ProElement elem_tree_1, tree_2;
  FeatureDef feat_def_1,feat_def_sketch, feat_def_sketch_1;
  ProFeature sketch, sketch_1;
  ProModelitem model_sktech, model_item_tooth, model_item_edge, model_item_surf, item, model_item;
  ProSection section;
  ProFeature feature_sketch, feature_tooth;
  int sec_id, r_ent_id, sel_count, i;
  ProSelection    *sel_ptr = NULL, sel1, sel2;
  ProFeatureCreateOptions opts[1],  *cr_opts;
  ProValue	 value;
  ProValueData value_data;
  ProElement        sketch_element; 
  ProFeatureCreateOptions redefine_options[] = {PRO_FEAT_CR_DEFINE_MISS_ELEMS};
  ProElement pro_e_std_matrlside;
  int sel_no_surf, sel_no_edge;
  int size;
  ProIntlist p_id_list;
  int curve_id;
  ProModelitem ref_item;
  ProModelitem app_data;

  FeatByName feat_disk[] = {
     {"GEAR_DISK"}
  };

  FeatByName datum_1[] = {
     {"DTM_TOOTH_1"}
  };

  FeatByName datum_2[] = {
     {"DTM_TOOTH_2"}
  };


  if (g_ptr->Pressure_angle == 0.0 || g_ptr->n_of_teeth == 0 )

   return 1;
  /*--------------------------------------------------------------------------*\
	     Blank cut for making disk of outer diameter
  \*--------------------------------------------------------------------------*/
  if(g_ptr->gear_type != RING_GEAR)
  {
      memset(&feat_def, 0, sizeof(feat_def));
      status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->front_surface_id, &tree[7].data.v.r);
      PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId.......ProUserCreateTooth");
      
      status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->side_surface_id, &tree[10].data.v.r);
      PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");
      
      tree[19].data.v.d = 5*g_ptr->gear_depth;

      feat_def.tree = tree;
      feat_def.sizeof_tree = SIZEOFARR(tree);

      feat_def.params[0].d = (g_ptr->n_of_teeth * g_ptr->tooth_par1) + (2 * g_ptr->tooth_par1);
      feat_def.params[1].r = tree[10].data.v.r;      
      
      status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->bottom_surface_id, &feat_def.params[2].r);
      PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");
      
      feat_def.section_create_func = ProUtilCreateCircleSection;

      feat_def.feat_name  = "Tooth_hole";

      /*-----------------------------------------------------------------*\
        	   Create new feature
      \*-----------------------------------------------------------------*/
      status  = ProUtilCreateSketchedFeature(g_ptr, &feat_def, &feature);
      PT_TEST_LOG_SUCC("ProUtilCreateSketchedFeature");
      
      /*-----------------------------------------------------------------*\
      Free allocated memory
      \*-----------------------------------------------------------------*/
      status = ProSelectionFree(&tree[7].data.v.r);
      PT_TEST_LOG_SUCC("ProSelectionFree");
      
      status = ProSelectionFree(&tree[10].data.v.r);
      PT_TEST_LOG_SUCC("ProSelectionFree");
      
      status = ProSelectionFree(&feat_def.params[2].r);
      PT_TEST_LOG_SUCC("ProSelectionFree");
  }
    /*--------------------------------------------------------------------------*\
     Init Datum planes along which extrude feature is to be performed
  \*--------------------------------------------------------------------------*/

  status = ProUtilFeatsByName(g_ptr->model, datum_1, 1);
  PT_TEST_LOG_SUCC("ProUtilFeatsByName");
  
  if (status != PRO_TK_NO_ERROR || datum_1[0].id == -1)
     return (status);

  status = ProFeatureInit(g_ptr->model, datum_1[0].id, &feature_datum_1);
  PT_TEST_LOG_SUCC("ProFeatureInit");

  status = ProUtilFeatFirstGeomitem(&feature_datum_1, PRO_SURFACE, &surface_id_1);
  PT_TEST_LOG_SUCC("ProUtilFeatFirstGeomitem");
  
  if (status != PRO_TK_NO_ERROR)
     return (-1);

  status = ProUtilFeatsByName(g_ptr->model, datum_2, 1);
  PT_TEST_LOG_SUCC("ProUtilFeatsByName");
  
  if (status != PRO_TK_NO_ERROR || datum_2[0].id == -1)
     return (status);

  status = ProFeatureInit(g_ptr->model, datum_2[0].id, &feature_datum_2);
  PT_TEST_LOG_SUCC("ProFeatureInit");
  
  status = ProUtilFeatFirstGeomitem(&feature_datum_2, PRO_SURFACE, &surface_id_2);
  PT_TEST_LOG_SUCC("ProUtilFeatFirstGeomitem");
  
  if (status != PRO_TK_NO_ERROR)
     return (-1);

  status = ProUtilFeatsByName(g_ptr->model, feat_disk, 1);
  PT_TEST_LOG_SUCC("ProUtilFeatsByName");
  
  if (status != PRO_TK_NO_ERROR || feat_disk[0].id == -1)
     return (status);

  status = ProFeatureInit(g_ptr->model, feat_disk[0].id, &feature);
  PT_TEST_LOG_SUCC("ProFeatureInit");
  
  status = ProUtilFeatFirstGeomitem(&feature, PRO_AXIS, &axis_id);    
  PT_TEST_LOG_SUCC("ProUtilFeatFirstGeomitem");
  
  if (status != PRO_TK_NO_ERROR)
     return (status);

  status=ProModelitemInit(g_ptr->model, axis_id, PRO_AXIS, &modelitem);
  PT_TEST_LOG_SUCC("ProModelitemInit");
  
  if (status!=PRO_TK_NO_ERROR) 
     return (status);
  /*--------------------------------------------------------------------------*\
	     Draw the tooth profile
  \*--------------------------------------------------------------------------*/
  memset(&feat_def_sketch, 0, sizeof(feat_def_sketch));

  status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->front_surface_id, &sketch_tree[9].data.v.r); 
  PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");
  
  status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->side_surface_id, &sketch_tree[12].data.v.r); 
  PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");

  feat_def_sketch.tree = sketch_tree;
  feat_def_sketch.sizeof_tree = SIZEOFARR(sketch_tree);

  feat_def_sketch.params[0].d = g_ptr->tooth_par1;
  feat_def_sketch.params[1].i = g_ptr->n_of_teeth;
  feat_def_sketch.params[2].d = g_ptr->Pressure_angle;
  
  if(g_ptr->gear_type == HELICAL_GEAR || g_ptr->gear_type == SPUR_GEAR)
  {
  	status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->disk_side_surf_id, &feat_def_sketch.params[3].r);
	PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");
  }
  
  else
  {
        status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->tooth_surf_side_surf_id, &feat_def_sketch.params[3].r);
	PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");
  }
		       
  feat_def_sketch.params[4].r = sketch_tree[12].data.v.r;

  feat_def_sketch.section_create_func = ProUtilCreateToothSection;

  feat_def_sketch.feat_name = "SKETCH_1";
  
  status  = ProUtilCreateSketchedFeature(g_ptr, &feat_def_sketch, &sketch);
  PT_TEST_LOG_SUCC("ProUtilCreateSketchedFeature");
  
  if (status!=PRO_TK_NO_ERROR)
	 return (-1);

 
  /*--------------------------------------------------------------------------*\
	     Create tooth
  \*--------------------------------------------------------------------------*/
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, surface_id_2, &tree_1[7].data.v.r); 
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");
    
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, surface_id_1, &tree_1[10].data.v.r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");
    
    tree_1[19].data.v.d = 5 * g_ptr->gear_depth; 
        
    memset(&feat_def_1, 0, sizeof(feat_def_1));
    
    feat_def_1.tree = tree_1;
    feat_def_1.sizeof_tree = SIZEOFARR(tree_1);

    feat_def_1.params[0].r = tree_1[7].data.v.r;
    feat_def_1.params[1].r = tree_1[10].data.v.r;
     
    feat_def_1.section_create_func = ProUtilSecEntityUseCurveLoop;

    feat_def_1.feat_name = "TOOTH_1";
    
    status  = ProUtilCreateSketchedFeature(g_ptr, &feat_def_1, &feat_tooth);
    PT_TEST_LOG_SUCC("ProUtilCreateSketchedFeature");
    
    if (status!=PRO_TK_NO_ERROR)
	    return (-1);
    
    ProStringToWstring(w_name, "TOOTH");
    
    status = ProArrayAlloc(0, sizeof(int), 1, (ProArray*)&feats_ids);
    PT_TEST_LOG_SUCC("ProArrayAlloc");
    
    status = ProArrayObjectAdd((ProArray*)&feats_ids, -1, 1, &feat_tooth.id);
    PT_TEST_LOG_SUCC("ProArrayObjectAdd");
    
    status = ProLocalGroupCreate(g_ptr->model, feats_ids, 1, w_name, &group);
    PT_TEST_LOG_SUCC("ProLocalGroupCreate");
    
    status = ProArrayFree((ProArray*)&feats_ids);
    PT_TEST_LOG_SUCC("ProArrayFree");
    
    if (status == PRO_TK_NO_ERROR)
    {
	g_ptr->tooth_created = 1;
    }
    
  /*-----------------------------------------------------------------*\
  Hide Sketch 
  \*-----------------------------------------------------------------*/
  status = ProFeatureGeomitemVisit(&sketch, PRO_CURVE, ProUtilGeomItemVisitCurve, NULL, (ProAppData)&app_data);
  PT_TEST_LOG_SUCC("ProFeatureGeomitemVisit");

  curve_id = app_data.id;

  status = ProModelitemInit (g_ptr->model,  curve_id, PRO_CURVE,  &ref_item);
  PT_TEST_LOG_SUCC("ProModelitemInit");
  
  status = ProModelitemHide(&ref_item);
  PT_TEST_LOG_SUCC("ProModelitemHide");
  /*-----------------------------------------------------------------*\
  Free allocated memory
  \*-----------------------------------------------------------------*/
  status = ProSelectionFree(&tree_1[10].data.v.r);
  PT_TEST_LOG_SUCC("ProSelectionFree");
  
  status = ProSelectionFree(&tree_1[7].data.v.r);
  PT_TEST_LOG_SUCC("ProSelectionFree");

  return (0);
}

/*=============================================================*\
  Function: 	ProUserCreateTeeth
  Purpose:	create gear teeth
\*=============================================================*/
int ProUserCreateTeeth(GearParam *g_ptr)
{
    FeatByName tooth_datum[] = {
	{"TOOTH_1"}
    };
    FeatByName feat_disk[] = {
	{"GEAR_DISK"}
    };

  ElemTreeData tree[] = {
	/* 0 */ {0, PRO_E_PATTERN_ROOT, {(ProValueDataType)-1}},
	/* 1 */ {1, PRO_E_GENPAT_TYPE, {PRO_VALUE_TYPE_INT, PRO_GENPAT_AXIS_DRIVEN}},
	/* 2 */ {1, PRO_E_GENPAT_DIM, {(ProValueDataType)-1}},
	/* 3 */ {2, PRO_E_GENPAT_DIM_FIRST_DIR_NUM_INST, {PRO_VALUE_TYPE_INT, 0}},
	/* 4 */ {2, PRO_E_GENPAT_DIM_SECOND_DIR_NUM_INST, {PRO_VALUE_TYPE_INT, 0}},
	/* 5 */ {1, PRO_E_GENPAT_TABLE, {(ProValueDataType)-1}},
	/* 6 */ {2, PRO_E_GENPAT_TABLE_SET_ACTIVE, {PRO_VALUE_TYPE_INT, 0}},
	/* 7 */ {1, PRO_E_GENPAT_REF, {(ProValueDataType)-1}},
	/* 8 */ {2, PRO_E_GENPAT_REF_TYPE, {PRO_VALUE_TYPE_INT, 0}},
	/* 9 */ {1, PRO_E_GENPAT_CURVE, {(ProValueDataType)-1}},
	/* 10 */{2, PRO_E_GENPAT_CRV_PLC_TYPE, {PRO_VALUE_TYPE_INT, 0}},
	/* 11 */{2, PRO_E_GENPAT_CRV_SPACING, {PRO_VALUE_TYPE_DOUBLE, 0}},
	/* 12 */{2, PRO_E_GENPAT_CRV_NUMBER, {PRO_VALUE_TYPE_INT, 0}},
	/* 13 */{2, PRO_E_GENPAT_CRV_FLIP, {PRO_VALUE_TYPE_INT, 0}},
	/* 14 */{1, PRO_E_GENPAT_DIR, {(ProValueDataType)-1}},
	/* 15 */{2, PRO_E_GENPAT_DIR1, {(ProValueDataType)-1}},
	/* 16 */{3, PRO_E_DIRECTION_COMPOUND, {(ProValueDataType)-1}},
	/* 17 */{4, PRO_E_DIRECTION_FLIP, {PRO_VALUE_TYPE_INT, 0}},
	/* 18 */{2, PRO_E_GENPAT_DIR1_INC, {PRO_VALUE_TYPE_DOUBLE, 0}},
	/* 19 */{2, PRO_E_DIR1_X_OFFSET, {PRO_VALUE_TYPE_DOUBLE, 0}},
	/* 20 */{2, PRO_E_DIR1_Y_OFFSET, {PRO_VALUE_TYPE_DOUBLE, 0}},
	/* 21 */{2, PRO_E_DIR1_Z_OFFSET, {PRO_VALUE_TYPE_DOUBLE, 0}},
	/* 22 */{2, PRO_E_DIR_PAT_DIR1_FLIP, {PRO_VALUE_TYPE_INT, 0}},
	/* 23 */{2, PRO_E_DIR_PAT_DIR1_OPT, {PRO_VALUE_TYPE_INT, 0}},
	/* 24 */{2, PRO_E_GENPAT_DIR2, {(ProValueDataType)-1}},
	/* 25 */{3, PRO_E_DIRECTION_COMPOUND, {(ProValueDataType)-1}},
	/* 26 */{4, PRO_E_DIRECTION_FLIP, {PRO_VALUE_TYPE_INT, 0}},
	/* 27 */{2, PRO_E_GENPAT_DIR2_INC, {PRO_VALUE_TYPE_DOUBLE, 0}},
	/* 28 */{2, PRO_E_DIR1_X_OFFSET, {PRO_VALUE_TYPE_DOUBLE, 0}},
	/* 29 */{2, PRO_E_DIR1_Y_OFFSET, {PRO_VALUE_TYPE_DOUBLE, 0}},
	/* 30 */{2, PRO_E_DIR1_Z_OFFSET, {PRO_VALUE_TYPE_DOUBLE, 0}},
	/* 31 */{2, PRO_E_DIR_PAT_DIR2_FLIP, {PRO_VALUE_TYPE_INT, 0}},
	/* 32 */{2, PRO_E_DIR_PAT_DIR2_OPT, {PRO_VALUE_TYPE_INT, 0}},
	/* 33 */{2, PRO_E_GENPAT_DIM_FIRST_DIR_NUM_INST, {PRO_VALUE_TYPE_INT, 0}},
	/* 34 */{2, PRO_E_GENPAT_DIM_SECOND_DIR_NUM_INST, {PRO_VALUE_TYPE_INT, 0}},
	/* 35 */{1, PRO_E_GENPAT_AXIS, {(ProValueDataType)-1}},
	/* 36 */{2, PRO_E_GENPAT_AXIS_REF, {PRO_VALUE_TYPE_SELECTION}},
	/* 37 */{2, PRO_E_GENPAT_AXIS1_INC, {PRO_VALUE_TYPE_DOUBLE}},
	/* 38 */{2, PRO_E_AXIS_PAT_DIR1_FLIP, {PRO_VALUE_TYPE_INT, 0}},
	/* 39 */{2, PRO_E_GENPAT_AXIS2_INC, {PRO_VALUE_TYPE_DOUBLE, 4.0200}},
	/* 40 */{2, PRO_E_AXIS_PAT_DIR2_FLIP, {PRO_VALUE_TYPE_INT, 0}},
	/* 41 */{2, PRO_E_GENPAT_AXIS_ANG_WHOLE, {PRO_VALUE_TYPE_DOUBLE, 360}},
	/* 42 */{2, PRO_E_GENPAT_DIM_FIRST_DIR_NUM_INST, {PRO_VALUE_TYPE_INT}},
	/* 43 */{2, PRO_E_GENPAT_DIM_SECOND_DIR_NUM_INST, {PRO_VALUE_TYPE_INT, 1}},
	/* 44 */{1, PRO_E_GEOMPAT_SOLIDIFY_OPT, {PRO_VALUE_TYPE_INT, 0}},
	/* 45 */{1, PRO_E_GENPAT_REGEN_METHOD, {PRO_VALUE_TYPE_INT, 4}},
	/* 46 */{1, PRO_E_STD_SECTION, {(ProValueDataType)-1}},
	/* 47 */{2, PRO_E_STD_SEC_METHOD, {PRO_VALUE_TYPE_INT, 0}},
	/* 48 */{2, PRO_E_STD_SEC_SETUP_PLANE, {(ProValueDataType)-1}},
	/* 49 */{3, PRO_E_STD_SEC_PLANE_VIEW_DIR, {PRO_VALUE_TYPE_INT, 0}},
	/* 50 */{3, PRO_E_STD_SEC_PLANE_ORIENT_DIR, {PRO_VALUE_TYPE_INT, 0}},
	/* 51 */{1, PRO_E_GENPAT_PROJECT, {(ProValueDataType)-1}},
	/* 52 */{2, PRO_E_GENPAT_PROJ_OPT, {PRO_VALUE_TYPE_INT, 0}},
	/* 53 */{2, PRO_E_GENPAT_PROJ_OR_TYPE, {PRO_VALUE_TYPE_INT, 1}},
	/* 54 */{1, PRO_E_GENPAT_ALT_ORIG, {(ProValueDataType)-1}},
	/* 55 */{2, PRO_E_GENPAT_ALT_ORG_OPT, {PRO_VALUE_TYPE_INT, 0}},
	/* 56 */{1, PRO_E_GENPAT_CRV_OR_TYPE, {PRO_VALUE_TYPE_INT, 1}},
	/* 57 */{1, PRO_E_GENPAT_POINT, {(ProValueDataType)-1}},
	/* 58 */{2, PRO_E_GENPAT_POINT_REF_TYPE, {PRO_VALUE_TYPE_INT, 0}},
	/* 59 */{1, PRO_E_GENPAT_OFFSET_FROM_SKET, {PRO_VALUE_TYPE_INT, 0}},
	/* 60 */{1, PRO_E_PAT_APPLICATIONS, {(ProValueDataType)-1}},
	/* 61 */{2, PRO_E_PAT_MFG_TOOL_PATH, {(ProValueDataType)-1}},
	/* 62 */{3, PRO_E_PAT_MFG_ORD_LEADER, {PRO_VALUE_TYPE_INT, 0}},
	/* 63 */{3, PRO_E_PAT_MFG_ORDER_OPT, {PRO_VALUE_TYPE_INT, 0}},
	/* 64 */{3, PRO_E_PAT_MFG_ORD_REVERSE, {PRO_VALUE_TYPE_INT, 0}},
	/* 65 */{3, PRO_E_PAT_MFG_ORD_ALT_ROWS, {PRO_VALUE_TYPE_INT, 0}},
	/* 66 */{3, PRO_E_PAT_MFG_ORD_ALT_DIR, {PRO_VALUE_TYPE_INT, 0}},
	/* 67 */{3, PRO_E_PAT_MFG_ORD_SHARED, {PRO_VALUE_TYPE_INT, 0}},
	/* 68 */{3, PRO_E_PAT_MFG_FIX_OFFSET, {PRO_VALUE_TYPE_INT, 0}},
	/* 69 */{3, PRO_E_PAT_MFG_FIX_OFF_INIT, {PRO_VALUE_TYPE_INT, 0}},
	/* 70 */{3, PRO_E_PAT_MFG_FIX_OFF_INCR, {PRO_VALUE_TYPE_INT, 0}}	
    };    
    int n_dims, ret, *p_dim_ids, *p_feat_ids, *p_tooth_ids, i, n_feats;
    int n_tooth_feats, axis_id;
    ProFeature feature, feature_disk;
    ProLayerItem layer_item;
    ProLayer layer;
    ProCharName str;
    ProName     w_str;
    ProElement elem_tree;
    ProModelitem modelitem, modelitem_disk;
    ProError status;
    
    ProSelection featsel;

    if (!g_ptr->tooth_created)
      return (-1);


  /*=====================================================================*/

    status = ProUtilFeatsByName(g_ptr->model, feat_disk, 1);
    PT_TEST_LOG_SUCC("ProUtilFeatsByName.......ProUserCreateTeeth");
    
    if (status != PRO_TK_NO_ERROR || feat_disk[0].id == -1)
	return (status);

    status = ProFeatureInit(g_ptr->model, feat_disk[0].id, &feature_disk);
    PT_TEST_LOG_SUCC("ProFeatureInit");
    
    status = ProUtilFeatFirstGeomitem(&feature_disk, PRO_AXIS, &axis_id);    
    PT_TEST_LOG_SUCC("ProUtilFeatFirstGeomitem");
    
    if (status != PRO_TK_NO_ERROR)
	return (status);

    status = ProModelitemInit(g_ptr->model, axis_id, PRO_AXIS, &modelitem_disk);
    PT_TEST_LOG_SUCC("ProModelitemInit");
    
    if (status!=PRO_TK_NO_ERROR) 
	return (status);


  /*-----------------------------------------------------------------*\
    Preparation of feature data
  \*-----------------------------------------------------------------*/
    status = ProUtilFeatsByName(g_ptr->model, tooth_datum, 1);
    PT_TEST_LOG_SUCC("ProUtilFeatsByName");
    
    if (status != PRO_TK_NO_ERROR || tooth_datum[0].id == -1)
	return (status);

    status = ProFeatureInit(g_ptr->model, tooth_datum[0].id, &feature);
    PT_TEST_LOG_SUCC("ProFeatureInit");

    status = ProUtilSelectionFromAxisId(g_ptr->model, axis_id, &tree[36].data.v.r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromAxisId");

    tree[42].data.v.i = g_ptr->n_of_teeth;

    tree[37].data.v.d = (float)360.00 / g_ptr->n_of_teeth;

    status = ProUtilElemtreeCreate(tree, SIZEOFARR(tree), NULL, &elem_tree);
    PT_TEST_LOG_SUCC("ProUtilElemtreeCreate");

    status = ProPatternCreate(&feature, PRO_FEAT_PATTERN, elem_tree);
    PT_TEST_LOG_SUCC("ProPatternCreate");

   return (status); 

  }

  /*=============================================================*\
  Function: 	ProUserCreateHub
  Purpose:	create inner support hub
\*=============================================================*/
int ProUserCreateHub(GearParam *g_ptr)
{
    ElemTreeData tree[]={
	{0, PRO_E_FEATURE_TREE, {(ProValueDataType)-1}},
	{1, PRO_E_FEATURE_TYPE, {PRO_VALUE_TYPE_INT, PRO_FEAT_PROTRUSION}},
	{1, PRO_E_FEATURE_FORM, {PRO_VALUE_TYPE_INT, PRO_EXTRUDE}},

	{1, PRO_E_EXT_SURF_CUT_SOLID_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_FEAT_TYPE_SOLID}},
	{1, PRO_E_REMOVE_MATERIAL, {PRO_VALUE_TYPE_INT, PRO_EXT_MATERIAL_ADD}},
	{1, PRO_E_STD_SECTION,  {(ProValueDataType)-1}},
	{2, PRO_E_STD_SEC_SETUP_PLANE,  {(ProValueDataType)-1}},
	{3, PRO_E_STD_SEC_PLANE, {PRO_VALUE_TYPE_SELECTION}},
	{3, PRO_E_STD_SEC_PLANE_VIEW_DIR, {PRO_VALUE_TYPE_INT, PRO_SEC_VIEW_DIR_SIDE_ONE}},
	{3, PRO_E_STD_SEC_PLANE_ORIENT_DIR, {PRO_VALUE_TYPE_INT, PRO_SEC_ORIENT_DIR_LEFT}},
	{3, PRO_E_STD_SEC_PLANE_ORIENT_REF, {PRO_VALUE_TYPE_SELECTION}},
	{1, PRO_E_FEAT_FORM_IS_THIN, {PRO_VALUE_TYPE_INT, PRO_EXT_FEAT_FORM_NO_THIN}},
	{1, PRO_E_STD_DIRECTION, {PRO_VALUE_TYPE_INT, PRO_EXT_CR_IN_SIDE_TWO}},
	{1, PRO_E_STD_EXT_DEPTH, {(ProValueDataType)-1}},
	{2, PRO_E_EXT_DEPTH_FROM, {(ProValueDataType)-1}},
	{3, PRO_E_EXT_DEPTH_FROM_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_DEPTH_FROM_NONE}},
	{2, PRO_E_EXT_DEPTH_TO, {(ProValueDataType)-1}},
	{3, PRO_E_EXT_DEPTH_TO_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_DEPTH_TO_BLIND}},
	{3, PRO_E_EXT_DEPTH_TO_VALUE, {PRO_VALUE_TYPE_DOUBLE}},
    };
    
    FeatureDef feat_def;
    ProFeature feature;
    Pro3dPnt pnt;
    ProModelitem modelitem;
    ProError status;

    if (g_ptr->hub_out_diam == 0.0 || g_ptr->hub_depth == 0.0)
      return 1;

/*-----------------------------------------------------------------*\
    Preparation of feature data
\*-----------------------------------------------------------------*/
    memset(&feat_def, 0, sizeof(feat_def));
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->gear_type == SPUR_GEAR ?
	g_ptr->disk_front_surf_id : g_ptr->backplate_back_surf_id, 
	&tree[7].data.v.r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId........ProUserCreateHub");
    
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->side_surface_id, &tree[10].data.v.r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");
    
    tree[18].data.v.d = g_ptr->hub_depth; 

    feat_def.tree = tree;
    feat_def.sizeof_tree = SIZEOFARR(tree);

    feat_def.params[0].d = g_ptr->hub_out_diam;
    feat_def.params[1].r = tree[10].data.v.r;
    
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->bottom_surface_id, &feat_def.params[2].r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");
    
    feat_def.section_create_func = ProUtilCreateCircleSection;

    feat_def.feat_name  = "Hub";

/*-----------------------------------------------------------------*\
    Create new feature
\*-----------------------------------------------------------------*/
    status  = ProUtilCreateSketchedFeature(g_ptr, &feat_def, &feature);
    PT_TEST_LOG_SUCC("ProUtilCreateSketchedFeature");
    
    if (status == PRO_TK_NO_ERROR)
    {
	g_ptr->hub_created = 1;
	
	ProUserFeatsReorder(g_ptr);
	
/*-----------------------------------------------------------------*\
    Find and name required surfaces
\*-----------------------------------------------------------------*/
	pnt[0] = g_ptr->datum_x_offset;
	pnt[1] = g_ptr->datum_y_offset + (g_ptr->inner_diam + g_ptr->hub_out_diam)/4; /* This point is located on flat surface of hub away from gear */
	if (g_ptr->gear_type == SPUR_GEAR || g_ptr->gear_type == HELICAL_GEAR)
	  pnt[2] = g_ptr->datum_z_offset + g_ptr->gear_depth + g_ptr->hub_depth;  /* For spur and helical gear hub is in positive direction of z-axis */
	else
	    pnt[2] = g_ptr->datum_z_offset - g_ptr->backplate_depth - g_ptr->hub_depth; /* For ring gear hub is in negative direction of z-axis */
	ProUtilGeometryAtPointFind((ProPart)g_ptr->model, pnt, &modelitem);

	g_ptr->hub_front_surf_id = modelitem.id;

	status = ProUtilModelitemNameSet(&modelitem, "HUB_FRONT");
        PT_TEST_LOG_SUCC("ProUtilModelitemNameSet");

	pnt[0] = g_ptr->datum_x_offset;
	pnt[1] = g_ptr->datum_y_offset + g_ptr->hub_out_diam/2; /* This point is located on circular surface of hub (Along the depth)*/
	
	if (g_ptr->gear_type == SPUR_GEAR || g_ptr->gear_type == HELICAL_GEAR)
	    pnt[2] = g_ptr->datum_z_offset + g_ptr->gear_depth + g_ptr->hub_depth/2;
	else
	    pnt[2] = g_ptr->datum_z_offset - g_ptr->backplate_depth - g_ptr->hub_depth/2;
	
	status = ProUtilGeometryAtPointFind((ProPart)g_ptr->model, pnt, &modelitem);
        PT_TEST_LOG_SUCC("ProUtilGeometryAtPointFind");

	g_ptr->hub_side_surf_id = modelitem.id;

	status = ProUtilModelitemNameSet(&modelitem, "HUB_SIDE");
        PT_TEST_LOG_SUCC("ProUtilModelitemNameSet");
    }
/*-----------------------------------------------------------------*\
    Free allocated memory
\*-----------------------------------------------------------------*/
    status = ProSelectionFree(&tree[7].data.v.r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    status = ProSelectionFree(&tree[10].data.v.r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    status = ProSelectionFree(&feat_def.params[2].r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    return (status);
}

/*=============================================================*\
  Function: 	ProUserCreateBackPlate
  Purpose:	create first gear tooth
\*=============================================================*/
int ProUserCreateBackPlate(GearParam *g_ptr)
{
    ElemTreeData tree[]={
	{0, PRO_E_FEATURE_TREE, {(ProValueDataType)-1}},
	{1, PRO_E_FEATURE_TYPE, {PRO_VALUE_TYPE_INT, PRO_FEAT_PROTRUSION}},
	{1, PRO_E_FEATURE_FORM, {PRO_VALUE_TYPE_INT, PRO_EXTRUDE}},
	{1, PRO_E_EXT_SURF_CUT_SOLID_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_FEAT_TYPE_SOLID}},
	{1, PRO_E_REMOVE_MATERIAL, {PRO_VALUE_TYPE_INT, PRO_EXT_MATERIAL_ADD}},
	{1, PRO_E_STD_SECTION,  {(ProValueDataType)-1}},
	{2, PRO_E_STD_SEC_SETUP_PLANE, {(ProValueDataType)-1}},
	{3, PRO_E_STD_SEC_PLANE, {PRO_VALUE_TYPE_SELECTION}},
	{3, PRO_E_STD_SEC_PLANE_VIEW_DIR, {PRO_VALUE_TYPE_INT, PRO_SEC_VIEW_DIR_SIDE_TWO}},
	{3, PRO_E_STD_SEC_PLANE_ORIENT_DIR, {PRO_VALUE_TYPE_INT, PRO_SEC_ORIENT_DIR_LEFT}},
	{3, PRO_E_STD_SEC_PLANE_ORIENT_REF, {PRO_VALUE_TYPE_SELECTION}},
	{1, PRO_E_FEAT_FORM_IS_THIN, {PRO_VALUE_TYPE_INT, PRO_EXT_FEAT_FORM_NO_THIN}},
	{1, PRO_E_STD_DIRECTION, {PRO_VALUE_TYPE_INT, PRO_EXT_CR_IN_SIDE_TWO}},
	{1, PRO_E_STD_EXT_DEPTH, {(ProValueDataType)-1}},
	{2, PRO_E_EXT_DEPTH_FROM, {(ProValueDataType)-1}},
	{3, PRO_E_EXT_DEPTH_FROM_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_DEPTH_FROM_NONE}},
	{2, PRO_E_EXT_DEPTH_TO, {(ProValueDataType)-1}},
	{3, PRO_E_EXT_DEPTH_TO_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_DEPTH_TO_BLIND}},
	{3, PRO_E_EXT_DEPTH_TO_VALUE, {PRO_VALUE_TYPE_DOUBLE}},
    };
    
    FeatureDef feat_def;
    ProFeature feature;
    Pro3dPnt pnt;
    ProModelitem modelitem;
    ProError status;
    
    if (g_ptr->backplate_diam == 0.0 || g_ptr->backplate_depth == 0.0)
      return 1;
    
/*-----------------------------------------------------------------*\
    Preparation of feature data
\*-----------------------------------------------------------------*/
    memset(&feat_def, 0, sizeof(feat_def));
    
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->front_surface_id, &tree[7].data.v.r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId......ProUserCreateBackPlate");
    
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->side_surface_id, &tree[10].data.v.r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");
    
    tree[18].data.v.d = g_ptr->backplate_depth; 

    feat_def.tree = tree;
    feat_def.sizeof_tree = SIZEOFARR(tree);

    feat_def.params[0].d = g_ptr->backplate_diam;
    feat_def.params[1].r = tree[10].data.v.r;
    
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->bottom_surface_id, &feat_def.params[2].r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");
    
    feat_def.section_create_func = ProUtilCreateCircleSection;

    feat_def.feat_name  = "Back_Plate";

/*-----------------------------------------------------------------*\
    Create new feature
\*-----------------------------------------------------------------*/
    status  = ProUtilCreateSketchedFeature(g_ptr, &feat_def, &feature);
    PT_TEST_LOG_SUCC("ProUtilCreateSketchedFeature");
    
    if (status == PRO_TK_NO_ERROR)
    {
	g_ptr->backplate_created = 1;
	
	ProUserFeatsReorder(g_ptr);
	
/*-----------------------------------------------------------------*\
    Find and name required surfaces
\*-----------------------------------------------------------------*/
	pnt[0] = g_ptr->datum_x_offset + (g_ptr->backplate_diam - g_ptr->inner_diam)/2;
	pnt[1] = g_ptr->datum_y_offset; 
	pnt[2] = g_ptr->datum_z_offset - g_ptr->backplate_depth;
	
	status = ProUtilGeometryAtPointFind((ProPart)g_ptr->model, pnt, &modelitem);
	PT_TEST_LOG_SUCC("ProUtilGeometryAtPointFind");
	
	g_ptr->backplate_back_surf_id = modelitem.id;
	
	status = ProUtilModelitemNameSet(&modelitem, "BACKPLATE_BACK");
	PT_TEST_LOG_SUCC("ProUtilModelitemNameSet");

	pnt[0] = g_ptr->datum_x_offset;
	pnt[1] = g_ptr->datum_y_offset + g_ptr->backplate_diam/2; 
	pnt[2] = g_ptr->datum_z_offset - g_ptr->backplate_depth/2;
	
	status = ProUtilGeometryAtPointFind((ProPart)g_ptr->model, pnt, &modelitem);
	PT_TEST_LOG_SUCC("ProUtilGeometryAtPointFind");
	
	g_ptr->backplate_side_surf_id = modelitem.id;
	
	status = ProUtilModelitemNameSet(&modelitem, "BACKPLATE_SIDE");
	PT_TEST_LOG_SUCC("ProUtilModelitemNameSet");
	
    }
/*-----------------------------------------------------------------*\
    Free allocated memory
\*-----------------------------------------------------------------*/
    status = ProSelectionFree(&tree[7].data.v.r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    status = ProSelectionFree(&tree[10].data.v.r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    status = ProSelectionFree(&feat_def.params[2].r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    return (status);
}

/*=============================================================*\
  Function: 	ProUserCreateKeyway
  Purpose:	create keyway inner
\*=============================================================*/
int ProUserCreateKeyway(GearParam *g_ptr)
{
    ElemTreeData tree[]= {
	{0, PRO_E_FEATURE_TREE, {(ProValueDataType)-1}},
	{1, PRO_E_FEATURE_TYPE, {PRO_VALUE_TYPE_INT, PRO_FEAT_CUT}},
	{1, PRO_E_FEATURE_FORM, {PRO_VALUE_TYPE_INT, PRO_EXTRUDE}},
	{1, PRO_E_EXT_SURF_CUT_SOLID_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_FEAT_TYPE_SOLID}},
	{1, PRO_E_REMOVE_MATERIAL, {PRO_VALUE_TYPE_INT, PRO_EXT_MATERIAL_REMOVE}},
	{1, PRO_E_STD_SECTION,  {(ProValueDataType)-1}},
	{2, PRO_E_STD_SEC_SETUP_PLANE,  {(ProValueDataType)-1}},
	{3, PRO_E_STD_SEC_PLANE, {PRO_VALUE_TYPE_SELECTION}},
	{3, PRO_E_STD_SEC_PLANE_VIEW_DIR, {PRO_VALUE_TYPE_INT, PRO_SEC_VIEW_DIR_SIDE_ONE}},
	{3, PRO_E_STD_SEC_PLANE_ORIENT_DIR, {PRO_VALUE_TYPE_INT, PRO_SEC_ORIENT_DIR_RIGHT}},
	{3, PRO_E_STD_SEC_PLANE_ORIENT_REF, {PRO_VALUE_TYPE_SELECTION}},
	{1, PRO_E_FEAT_FORM_IS_THIN, {PRO_VALUE_TYPE_INT, PRO_EXT_FEAT_FORM_NO_THIN}},
	{1, PRO_E_STD_DIRECTION, {PRO_VALUE_TYPE_INT, PRO_EXT_CR_IN_SIDE_TWO}},
	{1, PRO_E_STD_MATRLSIDE, {PRO_VALUE_TYPE_INT, PRO_EXT_MATERIAL_SIDE_TWO}},
	{1, PRO_E_STD_EXT_DEPTH, {(ProValueDataType)-1}},
	{2, PRO_E_EXT_DEPTH_FROM, {(ProValueDataType)-1}},
	{3, PRO_E_EXT_DEPTH_FROM_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_DEPTH_FROM_NONE}},
	{2, PRO_E_EXT_DEPTH_TO, {(ProValueDataType)-1}},
	{3, PRO_E_EXT_DEPTH_TO_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_DEPTH_TO_ALL}}
    };
    
    FeatureDef feat_def;
    ProFeature feature;
    ProError status;

    if (g_ptr->keyway_in_width == 0.0 || g_ptr->keyway_in_height == 0.0)
      return 1;

/*-----------------------------------------------------------------*\
    Preparation of feature data
\*-----------------------------------------------------------------*/
    memset(&feat_def, 0, sizeof(feat_def));
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->disk_front_surf_id, &tree[7].data.v.r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId........ProUserCreateKeyway");
    
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->side_surface_id, &tree[10].data.v.r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");
    
    tree[12].data.v.i = g_ptr->gear_type == RING_GEAR ?
      PRO_EXT_CR_IN_SIDE_ONE : PRO_EXT_CR_IN_SIDE_TWO;
  
    feat_def.tree = tree;
    feat_def.sizeof_tree = SIZEOFARR(tree);

    feat_def.params[0].d = g_ptr->keyway_in_width;
    feat_def.params[1].d = g_ptr->keyway_in_height;
    
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->hole_side_surf_id, &feat_def.params[2].r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");

    feat_def.section_create_func = ProUtilCreateKeySection;

    feat_def.feat_name  = "Keyway";

/*-----------------------------------------------------------------*\
    Create new feature
\*-----------------------------------------------------------------*/
    status  = ProUtilCreateSketchedFeature(g_ptr, &feat_def, &feature);
    PT_TEST_LOG_SUCC("ProUtilCreateSketchedFeature");
    
    if (status == PRO_TK_NO_ERROR)
    {
	g_ptr->keyway_created = 1;
    }
/*-----------------------------------------------------------------*\
    Free allocated memory
\*-----------------------------------------------------------------*/
    status = ProSelectionFree(&tree[7].data.v.r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    status = ProSelectionFree(&tree[10].data.v.r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    status = ProSelectionFree(&feat_def.params[2].r);
    PT_TEST_LOG_SUCC("ProSelectionFree");

    return (status);
}

/*=============================================================*\
  Function: 	ProUserCreateKey
  Purpose:	create keyway outer
\*=============================================================*/
int ProUserCreateKey(GearParam *g_ptr)
{
    ElemTreeData tree[]= {
	{0, PRO_E_FEATURE_TREE, {(ProValueDataType)-1}},
	{1, PRO_E_FEATURE_TYPE, {PRO_VALUE_TYPE_INT, PRO_FEAT_PROTRUSION}},
	{1, PRO_E_FEATURE_FORM, {PRO_VALUE_TYPE_INT, PRO_EXTRUDE}},
	{1, PRO_E_EXT_SURF_CUT_SOLID_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_FEAT_TYPE_SOLID}},
	{1, PRO_E_REMOVE_MATERIAL, {PRO_VALUE_TYPE_INT, PRO_EXT_MATERIAL_ADD}},
	{1, PRO_E_STD_SECTION,  {(ProValueDataType)-1}},
	{2, PRO_E_STD_SEC_SETUP_PLANE,  {(ProValueDataType)-1}},
	{3, PRO_E_STD_SEC_PLANE, {PRO_VALUE_TYPE_SELECTION}},
	{3, PRO_E_STD_SEC_PLANE_VIEW_DIR, {PRO_VALUE_TYPE_INT, PRO_SEC_VIEW_DIR_SIDE_ONE}},
	{3, PRO_E_STD_SEC_PLANE_ORIENT_DIR, {PRO_VALUE_TYPE_INT, PRO_SEC_ORIENT_DIR_RIGHT}},
	{3, PRO_E_STD_SEC_PLANE_ORIENT_REF, {PRO_VALUE_TYPE_SELECTION}},
	{1, PRO_E_FEAT_FORM_IS_THIN, {PRO_VALUE_TYPE_INT, 0}},
	{1, PRO_E_STD_DIRECTION, {PRO_VALUE_TYPE_INT, PRO_EXT_CR_IN_SIDE_ONE}},
	{1, PRO_E_STD_MATRLSIDE, {PRO_VALUE_TYPE_INT, PRO_EXT_MATERIAL_SIDE_TWO}},	
	{1, PRO_E_STD_EXT_DEPTH, {(ProValueDataType)-1}},
	{2, PRO_E_EXT_DEPTH_FROM, {(ProValueDataType)-1}},
	{3, PRO_E_EXT_DEPTH_FROM_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_DEPTH_FROM_NONE}},
	{2, PRO_E_EXT_DEPTH_TO, {(ProValueDataType)-1}},
	{3, PRO_E_EXT_DEPTH_TO_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_DEPTH_TO_NEXT}}
   };
    
    FeatureDef feat_def;
    ProFeature feature;
    ProError status;

    if (g_ptr->keyway_out_width == 0.0 || g_ptr->keyway_out_height == 0.0)
      return 1;

/*-----------------------------------------------------------------*\
    Preparation of feature data
\*-----------------------------------------------------------------*/
    memset(&feat_def, 0, sizeof(feat_def));
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->hub_front_surf_id, &tree[7].data.v.r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId.........ProUserCreateKey");
    
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->side_surface_id, &tree[10].data.v.r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");
    
    tree[9].data.v.i = g_ptr->gear_type == RING_GEAR ?
      PRO_SEC_ORIENT_DIR_LEFT : PRO_SEC_ORIENT_DIR_RIGHT;
  
    feat_def.tree = tree;
    feat_def.sizeof_tree = SIZEOFARR(tree);

    feat_def.params[0].d = g_ptr->keyway_out_width;
    feat_def.params[1].d = g_ptr->keyway_out_height;
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->hub_side_surf_id, &feat_def.params[2].r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");

    feat_def.section_create_func = ProUtilCreateKeySection;

    feat_def.feat_name  = "Key";

/*-----------------------------------------------------------------*\
    Create new feature
\*-----------------------------------------------------------------*/
    status  = ProUtilCreateSketchedFeature(g_ptr, &feat_def, &feature);
    PT_TEST_LOG_SUCC("ProUtilCreateSketchedFeature");
    
    if (status == PRO_TK_NO_ERROR)
    {
	g_ptr->key_created = 1;
    }
/*-----------------------------------------------------------------*\
    Free allocated memory
\*-----------------------------------------------------------------*/
    status = ProSelectionFree(&tree[7].data.v.r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    status = ProSelectionFree(&tree[10].data.v.r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    status = ProSelectionFree(&feat_def.params[2].r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    return (status);
}

/*=============================================================*\
  Function: 	ProUserCreateBackNotch
  Purpose:	create a notch on the Back Plate
\*=============================================================*/
int ProUserCreateBackNotch(GearParam *g_ptr)
{
    ElemTreeData tree[]={
	{0, PRO_E_FEATURE_TREE, {(ProValueDataType)-1}},
	{1, PRO_E_FEATURE_TYPE, {PRO_VALUE_TYPE_INT, PRO_FEAT_CUT}},
	{1, PRO_E_FEATURE_FORM, {PRO_VALUE_TYPE_INT, PRO_EXTRUDE}},
	{1, PRO_E_EXT_SURF_CUT_SOLID_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_FEAT_TYPE_SOLID}},
	{1, PRO_E_REMOVE_MATERIAL, {PRO_VALUE_TYPE_INT, PRO_EXT_MATERIAL_REMOVE}},
	{1, PRO_E_STD_SECTION,  {(ProValueDataType)-1}},
	{2, PRO_E_STD_SEC_SETUP_PLANE,  {(ProValueDataType)-1}},
	{3, PRO_E_STD_SEC_PLANE, {PRO_VALUE_TYPE_SELECTION}},
	{3, PRO_E_STD_SEC_PLANE_VIEW_DIR, {PRO_VALUE_TYPE_INT, PRO_SEC_VIEW_DIR_SIDE_ONE}},
	{3, PRO_E_STD_SEC_PLANE_ORIENT_DIR, {PRO_VALUE_TYPE_INT, PRO_SEC_ORIENT_DIR_RIGHT}},
	{3, PRO_E_STD_SEC_PLANE_ORIENT_REF, {PRO_VALUE_TYPE_SELECTION}},
	{1, PRO_E_FEAT_FORM_IS_THIN, {PRO_VALUE_TYPE_INT, PRO_EXT_FEAT_FORM_NO_THIN}},
	{1, PRO_E_STD_DIRECTION, {PRO_VALUE_TYPE_INT, PRO_EXT_CR_IN_SIDE_ONE}},
	{1, PRO_E_STD_MATRLSIDE, {PRO_VALUE_TYPE_INT, PRO_EXT_MATERIAL_SIDE_TWO}},	
	{1, PRO_E_STD_EXT_DEPTH, {(ProValueDataType)-1}},
	{2, PRO_E_EXT_DEPTH_FROM, {(ProValueDataType)-1}},
	{3, PRO_E_EXT_DEPTH_FROM_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_DEPTH_FROM_NONE}},
	{2, PRO_E_EXT_DEPTH_TO, {(ProValueDataType)-1}},
	{3, PRO_E_EXT_DEPTH_TO_TYPE, {PRO_VALUE_TYPE_INT, PRO_EXT_DEPTH_TO_NEXT}}
    };
    
    FeatureDef feat_def;
    ProFeature feature;
    ProError status;

    if (g_ptr->backnotch_rad == 0.0 || g_ptr->backplate_diam == 0.0)
      return 1;

/*-----------------------------------------------------------------*\
    Preparation of feature data
\*-----------------------------------------------------------------*/
    memset(&feat_def, 0, sizeof(feat_def));
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->front_surface_id, &tree[7].data.v.r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId...........ProUserCreateBackNotch");
    
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->side_surface_id, &tree[10].data.v.r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");

    feat_def.tree = tree;
    feat_def.sizeof_tree = SIZEOFARR(tree);

    feat_def.params[0].d = g_ptr->backplate_diam;
    feat_def.params[1].d = g_ptr->backnotch_rad;
    status = ProUtilSelectionFromSurfaceId(g_ptr->model, g_ptr->backplate_side_surf_id, &feat_def.params[2].r);
    PT_TEST_LOG_SUCC("ProUtilSelectionFromSurfaceId");

    feat_def.section_create_func = ProUtilCreateNotchSection;

    feat_def.feat_name  = "Back_Notch";

/*-----------------------------------------------------------------*\
    Create new feature
\*-----------------------------------------------------------------*/
    status  = ProUtilCreateSketchedFeature(g_ptr, &feat_def, &feature);
    PT_TEST_LOG_SUCC("ProUtilCreateSketchedFeature");
    
    if (status == PRO_TK_NO_ERROR)
    {
	g_ptr->backnotch_created = 1;
    }
/*-----------------------------------------------------------------*\
    Free allocated memory
\*-----------------------------------------------------------------*/
    status = ProSelectionFree(&tree[7].data.v.r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    status = ProSelectionFree(&tree[10].data.v.r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    status = ProSelectionFree(&feat_def.params[2].r);
    PT_TEST_LOG_SUCC("ProSelectionFree");
    
    return (status);
}

/*=============================================================*\
  Function: 	ProUserFeatsReorder
  Purpose:	move hole and keyslot to end 
  Return :      0 if successfull, -1 otherwise
\*=============================================================*/
int ProUserFeatsReorder(GearParam *g_ptr)
{
    
    int *p_feat_id_ar, n_features, ids[2], n = 0;
    ProFeatStatus *p_status_ar;
    ProError status;
    FeatByName feats[2];

    feats [0].name = "GEAR_HOLE";
    feats [1].name = "KEYWAY";

    if (g_ptr->hole_created == 0) 
	return (0);

/*-----------------------------------------------------------------*\
    Find "hole" and "keyway" features
\*-----------------------------------------------------------------*/
    status = ProUtilFeatsByName((ProSolid)g_ptr->model, feats, 2);
    PT_TEST_LOG_SUCC("ProUtilFeatsByName...........ProUserFeatsReorder");
    
    if (status != PRO_TK_NO_ERROR)
	return (status);

    status = ProArrayAlloc(0, sizeof(int), 1, (ProArray*)&p_feat_id_ar);
    PT_TEST_LOG_SUCC("ProArrayAlloc");
    
    status = ProArrayAlloc(0, sizeof(ProFeatStatus), 1, (ProArray*)&p_status_ar);
    PT_TEST_LOG_SUCC("ProArrayAlloc");

    status = ProSolidFeatstatusGet((ProSolid)g_ptr->model, &p_feat_id_ar, &p_status_ar, &n_features);
    PT_TEST_LOG_SUCC("ProSolidFeatstatusGet");

    if (g_ptr->hole_created) 
	ids[n++] = feats[0].id;
    if (g_ptr->keyway_created) 
	ids[n++] = feats[1].id;
/*-----------------------------------------------------------------*\
    Set changed order of features
\*-----------------------------------------------------------------*/
    if (n)
      status = ProFeatureReorder((ProSolid)g_ptr->model, ids, n, n_features); 
      PT_TEST_LOG_SUCC("ProFeatureReorder");
/*-----------------------------------------------------------------*\
    Free allocated memory
\*-----------------------------------------------------------------*/
    status = ProArrayFree((ProArray*)&p_feat_id_ar);
    PT_TEST_LOG_SUCC("ProArrayFree");
    
    status = ProArrayFree((ProArray*)&p_status_ar);
    PT_TEST_LOG_SUCC("ProArrayFree");

/*-----------------------------------------------------------------*\
    Redisplay model
\*-----------------------------------------------------------------*/
    status = ProSolidDisplay((ProSolid)g_ptr->model);
    PT_TEST_LOG_SUCC("ProSolidDisplay");
    
    status = ProTreetoolRefresh(g_ptr->model);
    PT_TEST_LOG_SUCC("ProTreetoolRefresh");
    
    return (0);
}

typedef struct
{
  double*  value;
  int find_index;
  int index;
} ProUserDimensionFinddata;


/*=============================================================*\
  Function: 	ProUserGetDimensionValue
  Purpose:	find first dimension; store value 
\*=============================================================*/
ProError   ProUserGetDimensionValue (ProDimension* dim, 
				 ProError status, 
				 ProAppData data)
{
  ProUserDimensionFinddata* find_data = (ProUserDimensionFinddata*) data;

  status = ProDimensionValueGet (dim, find_data->value);
  PT_TEST_LOG_SUCC("ProDimensionValueGet........ProUserGetDimensionValue");

  return PRO_TK_ABORT;
}

/*=============================================================*\
  Function: 	ProUserFindDiameterDimension
  Purpose:	find diameter dimension
\*=============================================================*/
ProError   ProUserFindDiameterDimension (ProDimension* dim, 
				 ProAppData data)
{
  ProDimensiontype type;
  ProError status;

  ProDimensionTypeGet (dim, &type);

  if (type == PRODIMTYPE_DIAMETER)
    return PRO_TK_NO_ERROR;
  else
    return PRO_TK_CONTINUE;
}

/*=============================================================*\
  Function: 	ProUserFindDiameterDimension
  Purpose:	find non-diameter dimension
\*=============================================================*/
ProError   ProUserFindNondiameterDimension (ProDimension* dim, 
				 ProAppData data)
{
  ProDimensiontype type;
  double value;
  ProError status;

  ProDimensionTypeGet (dim, &type);

  if (type == PRODIMTYPE_DIAMETER || type == PRODIMTYPE_UNKNOWN)
    return PRO_TK_CONTINUE;
  else
    return PRO_TK_NO_ERROR;
}

/*=============================================================*\
  Function: 	ProUserFindDiameterDimension
  Purpose:	find nth dimension in the visit
\*=============================================================*/
ProError   ProUserFindDimensionByIndex (ProDimension* dim, 
					ProAppData data)
{
   ProUserDimensionFinddata* find_data = (ProUserDimensionFinddata*) data;

   ProDimensiontype type;
   ProError status;
   ProDimensionTypeGet (dim, &type);
   if (type == PRODIMTYPE_UNKNOWN)
     return PRO_TK_CONTINUE;

   find_data->index ++;
   
   if (find_data->index == find_data->find_index)
     return PRO_TK_NO_ERROR;
   else
     return PRO_TK_CONTINUE;
}

/*=============================================================*\
  Function: 	ProUserCheckFeatures
  Purpose:	to check models features
  Return :      0 if successfull, PRO_TK_E_NOT_FOUND if no 
		default csys or datum planes found, 
		PRO_TK_GENERAL_ERROR otherwise
\*=============================================================*/
ProError ProUserCheckFeatures(GearParam *g_ptr)
{
    static FeatByName feats[] = {
	{"GD_FRONT"},		/*  0 */
	{"GD_SIDE"},		/*  1 */
	{"GD_BOTTOM"},		/*  2 */
	{"GEAR_DISK"},		/*  3 */
	{"GEAR_HOLE"},		/*  4 */
	{"KEYWAY"},		/*  5 */
	{"TOOTH_1"},		/*  6 */
	{"TOOTH_2"},		/*  7 */
	{"HUB"},		/*  8 */
	{"KEY"},		/*  9 */
	{"BACK_PLATE"},		/* 10 */
	{"BACK_NOTCH"},		/* 11 */
	{"TOOTH_SURF"}		/* 12 */
    };
    int feat_num = SIZEOFARR(feats), b;
    ProFeature f, feature;
    ProGeomitem geomitem;
    ProSolid solid = (ProSolid)g_ptr->model;
    
    ProName w_name;
    ProUserDimensionFinddata find_data;
    ProError status;

    status = ProUtilFeatsByName(solid, feats, feat_num);
    PT_TEST_LOG_SUCC("ProUtilFeatsByName.........ProUserCheckFeatures");
    
    b =(feats[0].id!=-1) || (feats[1].id!=-1) || (feats[2].id!=-1);
    if (b)
    {
	if (!g_ptr->datum_created)
	{
/*-----------------------------------------------------------------*\
    Find datum planes surfaces
\*-----------------------------------------------------------------*/
	    status = ProFeatureInit(solid, feats[0].id, &f);
	    PT_TEST_LOG_SUCC("ProFeatureInit");
	    
	    status = ProUtilFeatFirstGeomitem(&f, PRO_SURFACE, &g_ptr->front_surface_id);
	    PT_TEST_LOG_SUCC("ProUtilFeatFirstGeomitem");
	    
	    if (status != PRO_TK_NO_ERROR)
		return (PRO_TK_GENERAL_ERROR);
	    
	    find_data.value = &g_ptr->datum_z_offset;
	    status = ProFeatureDimensionVisit (&f, ProUserGetDimensionValue, NULL, (ProAppData)&find_data);
	    PT_TEST_LOG_SUCC("ProFeatureDimensionVisit");
	    

	    status = ProFeatureInit(solid, feats[1].id, &f);
	    PT_TEST_LOG_SUCC("ProFeatureInit");
	    
	    status = ProUtilFeatFirstGeomitem(&f, PRO_SURFACE, &g_ptr->side_surface_id);
	    PT_TEST_LOG_SUCC("ProUtilFeatFirstGeomitem");
	    
	    if (status != PRO_TK_NO_ERROR)
		return (PRO_TK_GENERAL_ERROR);

	    find_data.value = &g_ptr->datum_x_offset;
	    status = ProFeatureDimensionVisit (&f, ProUserGetDimensionValue, NULL, (ProAppData)&find_data);
	    PT_TEST_LOG_SUCC("ProFeatureDimensionVisit");

	    status = ProFeatureInit(solid, feats[2].id, &f);
	    PT_TEST_LOG_SUCC("ProFeatureInit");
	    
	    status =ProUtilFeatFirstGeomitem(&f, PRO_SURFACE, &g_ptr->bottom_surface_id);
	    PT_TEST_LOG_SUCC("ProUtilFeatFirstGeomitem");
	    
	    if (status != PRO_TK_NO_ERROR)
		return (PRO_TK_GENERAL_ERROR);

	    find_data.value = &g_ptr->datum_y_offset;
	    
	    status = ProFeatureDimensionVisit (&f, ProUserGetDimensionValue, NULL, (ProAppData)&find_data);
	    PT_TEST_LOG_SUCC("ProFeatureDimensionVisit");
	}
    }
    g_ptr->datum_created = b;
    if ((feats[3].id!=-1) && (g_ptr->disk_created==0)) 
    {
/*-----------------------------------------------------------------*\
    Find gear disk surfaces
\*-----------------------------------------------------------------*/
        status = ProFeatureInit(solid, feats[3].id, &feature);
	PT_TEST_LOG_SUCC("ProFeatureInit");
	
        ProStringToWstring(w_name, "DISK_FRONT");
	
        status = ProUtilFindFeatureGeomitemByName(&feature, PRO_SURFACE, w_name, &geomitem);
	PT_TEST_LOG_SUCC("ProUtilFindFeatureGeomitemByName");
	
	if (status != PRO_TK_NO_ERROR)
	    return (PRO_TK_GENERAL_ERROR);
	g_ptr->disk_front_surf_id = geomitem.id;
        
	ProStringToWstring(w_name, "DISK_SIDE");
	
        status = ProUtilFindFeatureGeomitemByName(&feature, PRO_SURFACE, w_name, &geomitem);
	PT_TEST_LOG_SUCC("ProUtilFindFeatureGeomitemByName");
	
	if (status != PRO_TK_NO_ERROR)
	    return (PRO_TK_GENERAL_ERROR);
	g_ptr->disk_side_surf_id = geomitem.id;

	find_data.value = &g_ptr->gear_diam;
	
	status = ProFeatureDimensionVisit (&feature, ProUserGetDimensionValue, ProUserFindDiameterDimension, (ProAppData)&find_data);
	PT_TEST_LOG_SUCC("ProFeatureDimensionVisit");

	find_data.value = &g_ptr->gear_depth;
	
	status = ProFeatureDimensionVisit (&feature, ProUserGetDimensionValue, ProUserFindNondiameterDimension, (ProAppData)&find_data);
	PT_TEST_LOG_SUCC("ProFeatureDimensionVisit");
    }
    g_ptr->disk_created = feats[3].id!=-1;	    
    if ((feats[4].id!=-1) && (g_ptr->hole_created==0)) 
    {
      g_ptr->hole_created = 1;
/*-----------------------------------------------------------------*\
    Find hole surfaces
\*-----------------------------------------------------------------*/
        status = ProFeatureInit(solid, feats[4].id, &feature);
	PT_TEST_LOG_SUCC("ProFeatureInit");
	
        ProStringToWstring(w_name, "HOLE_SIDE");
	
        ProUtilFindFeatureGeomitemByName(&feature, PRO_SURFACE, w_name, &geomitem);
	
	if (status != PRO_TK_NO_ERROR)
	    return (PRO_TK_GENERAL_ERROR);
	g_ptr->hole_side_surf_id = geomitem.id;

	find_data.value = &g_ptr->inner_diam;
	status = ProFeatureDimensionVisit (&feature, ProUserGetDimensionValue, ProUserFindDiameterDimension, (ProAppData)&find_data);
	PT_TEST_LOG_SUCC("ProFeatureDimensionVisit");
	
    }    
    if (g_ptr->keyway_created = (feats[5].id!=-1))
      {
	status = ProFeatureInit(solid, feats[5].id, &feature);
	PT_TEST_LOG_SUCC("ProFeatureInit");
	
	find_data.value = &g_ptr->keyway_out_width;
	find_data.find_index = 1;
	find_data.index = 0;
	
	status = ProFeatureDimensionVisit (&feature, ProUserGetDimensionValue, ProUserFindDimensionByIndex, (ProAppData)&find_data);
	PT_TEST_LOG_SUCC("ProFeatureDimensionVisit");
	
	find_data.value = &g_ptr->keyway_out_height;
	find_data.find_index = 2;
	find_data.index = 0;

	status = ProFeatureDimensionVisit (&feature, ProUserGetDimensionValue, ProUserFindDimensionByIndex, (ProAppData)&find_data);
	PT_TEST_LOG_SUCC("ProFeatureDimensionVisit");
	
      }
    g_ptr->tooth_created = feats[6].id!=-1;	    
    g_ptr->teeth_created = feats[7].id!=-1;	    
    if ((feats[8].id!=-1) && (g_ptr->hub_created==0)) 
    {
      g_ptr->hub_created = 1;
/*-----------------------------------------------------------------*\
    Find hub surfaces
\*-----------------------------------------------------------------*/
        status = ProFeatureInit(solid, feats[8].id, &feature);
	PT_TEST_LOG_SUCC("ProFeatureInit");
	
        ProStringToWstring(w_name, "HUB_FRONT");
	
        ProUtilFindFeatureGeomitemByName(&feature, PRO_SURFACE, w_name, &geomitem);
	
	if (status != PRO_TK_NO_ERROR)
	    return (PRO_TK_GENERAL_ERROR);
	g_ptr->hub_front_surf_id = geomitem.id;
        
	ProStringToWstring(w_name, "HUB_SIDE");
	
        status = ProUtilFindFeatureGeomitemByName(&feature, PRO_SURFACE, w_name, &geomitem);
	PT_TEST_LOG_SUCC("ProUtilFindFeatureGeomitemByName");
	
	if (status != PRO_TK_NO_ERROR)
	    return (PRO_TK_GENERAL_ERROR);
	g_ptr->hub_side_surf_id = geomitem.id;

	find_data.value = &g_ptr->hub_out_diam;
	
	status = ProFeatureDimensionVisit (&feature, ProUserGetDimensionValue, ProUserFindDiameterDimension, (ProAppData)&find_data);
	PT_TEST_LOG_SUCC("ProFeatureDimensionVisit");

	find_data.value = &g_ptr->hub_depth;
	
	status = ProFeatureDimensionVisit (&feature, ProUserGetDimensionValue, ProUserFindNondiameterDimension, (ProAppData)&find_data);
	PT_TEST_LOG_SUCC("ProFeatureDimensionVisit");
    }
    if (g_ptr->key_created = (feats[9].id!=-1))
    {
      status = ProFeatureInit(solid, feats[9].id, &feature);
      PT_TEST_LOG_SUCC("ProFeatureInit");
      
      find_data.value = &g_ptr->keyway_in_width;
      find_data.find_index = 1;
      find_data.index = 0;
      
      status = ProFeatureDimensionVisit (&feature, ProUserGetDimensionValue, ProUserFindDimensionByIndex, (ProAppData)&find_data);
      PT_TEST_LOG_SUCC("ProFeatureDimensionVisit");
            
      find_data.value = &g_ptr->keyway_in_height;
      find_data.find_index = 2;
      find_data.index = 0;
      
      status = ProFeatureDimensionVisit (&feature, ProUserGetDimensionValue, ProUserFindDimensionByIndex, (ProAppData)&find_data);
      PT_TEST_LOG_SUCC("ProFeatureDimensionVisit");
      
    }
    if ((feats[10].id!=-1) && (g_ptr->backplate_created==0)) 
    {
      g_ptr->backplate_created = 1;
/*-----------------------------------------------------------------*\
    Find backplate surfaces
\*-----------------------------------------------------------------*/
        status = ProFeatureInit(solid, feats[10].id, &feature);
	PT_TEST_LOG_SUCC("ProFeatureInit");
	
        ProStringToWstring(w_name, "BACKPLATE_SIDE");
	
        status = ProUtilFindFeatureGeomitemByName(&feature, PRO_SURFACE, w_name, &geomitem);
	PT_TEST_LOG_SUCC("ProUtilFindFeatureGeomitemByName");
	
	if (status != PRO_TK_NO_ERROR)
	    return (PRO_TK_GENERAL_ERROR);
	g_ptr->backplate_side_surf_id = geomitem.id;

        ProStringToWstring(w_name, "BACKPLATE_BACK");
	
        status = ProUtilFindFeatureGeomitemByName(&feature, PRO_SURFACE, w_name, &geomitem);
	PT_TEST_LOG_SUCC("ProUtilFindFeatureGeomitemByName");
	
	if (status != PRO_TK_NO_ERROR)
	    return (PRO_TK_GENERAL_ERROR);
	g_ptr->backplate_back_surf_id = geomitem.id;

	find_data.value = &g_ptr->backplate_diam;
	status = ProFeatureDimensionVisit (&feature, ProUserGetDimensionValue, ProUserFindDiameterDimension, (ProAppData)&find_data);
	PT_TEST_LOG_SUCC("ProFeatureDimensionVisit");
	
	find_data.value = &g_ptr->backplate_depth;
	
	status = ProFeatureDimensionVisit (&feature, ProUserGetDimensionValue, ProUserFindNondiameterDimension, (ProAppData)&find_data);
	PT_TEST_LOG_SUCC("ProFeatureDimensionVisit");
    }
    if (g_ptr->backnotch_created = (feats[11].id!=-1))
      {
	status = ProFeatureInit(solid, feats[11].id, &feature);
	PT_TEST_LOG_SUCC("ProFeatureInit");
	
	find_data.value = &g_ptr->backnotch_rad;
	
	status = ProFeatureDimensionVisit (&feature, ProUserGetDimensionValue, ProUserFindNondiameterDimension, (ProAppData)&find_data);
	PT_TEST_LOG_SUCC("ProFeatureDimensionVisit");
	
      }
    if ((feats[12].id!=-1) && (g_ptr->tooth_surf_created==0)) 
    {
/*-----------------------------------------------------------------*\
    Find tooth surface feature surfaces
\*-----------------------------------------------------------------*/
        status = ProFeatureInit(solid, feats[12].id, &feature);
	PT_TEST_LOG_SUCC("ProFeatureInit");
	
        ProStringToWstring(w_name, "TOOTH_SURF_SIDE");
	
        status = ProUtilFindFeatureGeomitemByName(&feature, PRO_SURFACE, w_name, &geomitem);
	PT_TEST_LOG_SUCC("ProUtilFindFeatureGeomitemByName");
	

	if (status != PRO_TK_NO_ERROR)
	    return (PRO_TK_GENERAL_ERROR);
	g_ptr->tooth_surf_side_surf_id = geomitem.id;
    }
    g_ptr->tooth_surf_created = feats[12].id!=-1;	    
    return (PRO_TK_NO_ERROR);
}

/*=============================================================*\
  Function: 	ProUserAssignParamDef
  Purpose:	assign default gear parameters
\*=============================================================*/
int ProUserAssignParamDef (GearParam *g_ptr)
{
  int i = 0;
  int table_size = sizeof (param_def);

    param_def[i++].value =  g_ptr->name;
    param_def[i++].value = &g_ptr->units;
    param_def[i++].value =  g_ptr->material; 
    param_def[i++].value = &g_ptr->gear_type;
    param_def[i++].value = &g_ptr->datum_x_offset;
    param_def[i++].value = &g_ptr->datum_y_offset;
    param_def[i++].value = &g_ptr->datum_z_offset;
    param_def[i++].value = &g_ptr->gear_diam; 
    param_def[i++].value = &g_ptr->gear_depth; 
    param_def[i++].value = &g_ptr->helix_angle; 
    param_def[i++].value = &g_ptr->backplate_diam;
    param_def[i++].value = &g_ptr->backplate_depth;
    param_def[i++].value = &g_ptr->hub_out_diam;
    param_def[i++].value = &g_ptr->hub_depth;
    param_def[i++].value = &g_ptr->inner_diam;
    param_def[i++].value = &g_ptr->n_of_teeth;
    param_def[i++].value = &g_ptr->keyway_in_width;
    param_def[i++].value = &g_ptr->keyway_in_height;
    param_def[i++].value = &g_ptr->keyway_out_width;
    param_def[i++].value = &g_ptr->keyway_out_height;
    param_def[i++].value = &g_ptr->tooth_par1;
    param_def[i++].value = &g_ptr->backnotch_rad;
    param_def[i++].value = &g_ptr->Pressure_angle;

    return 0;
} 
    

/*=============================================================*\
  Function: 	ProUserReadParamFile
  Purpose:	read gear parameter file
  Return :      0 if successfull, -1 otherwise
\*=============================================================*/
int ProUserReadParamFile(char *filename, GearParam *g_ptr)
{
    ProCharLine line, str1, str2;
    FILE *fp;
    int i=0, j, table_size=SIZEOFARR(param_def);
    ProParameter param;
    ProParamvalue parvalue;
    ProModelitem modelitem;
    ProName w_name;
    ProError status;
    

    fp = PTApplsUnicodeFopen(filename, "r");
    if (fp == NULL)
    {
	status = ProMessageDisplay(MSGFIL, "PROTKGD Unable to open parameter file %0s",  filename);
	PT_TEST_LOG_SUCC("ProMessageDisplay........ProUserReadParamFile");
	
	return (-1);
    }

    for (i=0; i<table_size; i++)
        param_def[i].set = PRO_B_FALSE;   

    while (!feof(fp))
    {
	if (fgets(line, PRO_LINE_SIZE-1, fp)==NULL)
	    break;
	if (line[0]=='!' || line[0]=='/') 
	    continue;
	if (sscanf(line, "%s %s", str1, str2)!=2)
	    continue;
	for (i=0; i<table_size; i++)
	{
	    if (ProUtilStrcmp(param_def[i].param_name, str1)==0)
	    {
		switch (param_def[i].type)
		{
		case STR_PARAM: /* string */
		    strncpy((char *)param_def[i].value, str2, 
			param_def[i].length);
		    *(((char*)param_def[i].value)+param_def[i].length)='\0';

		    ProStringToWstring(w_name, str2);
		    
		    status = ProParamvalueSet(&parvalue, (void *)w_name, PRO_PARAM_STRING);
		    PT_TEST_LOG_SUCC("ProParamvalueSet");
		    
		    break;
		
		case INT_PARAM: /* int */
		    sscanf(str2, "%d", param_def[i].value);
		    
		    status = ProParamvalueSet(&parvalue, param_def[i].value, PRO_PARAM_INTEGER);
		    PT_TEST_LOG_SUCC("ProParamvalueSet");
		    
		    break;
		
		case DOUB_PARAM: /* double */
		    sscanf(str2, "%lf", param_def[i].value);
		    
		    status = ProParamvalueSet(&parvalue, param_def[i].value, PRO_PARAM_DOUBLE);
		    PT_TEST_LOG_SUCC("ProParamvalueSet");
		    
		    break;
		    
		case TAB_PARAM: /* table */
		    for (j=0; j<param_def[i].tablesize; j++)
			if (!ProUtilStrcmp(param_def[i].table[j].string_val,
			    str2))
			{
			    *((int*)param_def[i].value) = 
				param_def[i].table[j].int_val;
			    break;
			}
		    if (j==param_def[i].tablesize)
			status = ProMessageDisplay(MSGFIL, 
    			    "PROTKGD Bad value \"%0s\" for param \"%1s\"", 
			    str2, str1);
			PT_TEST_LOG_SUCC("ProMessageDisplay");
		    break;
		}
		param_def[i].set = PRO_B_TRUE;
/*--------------------------------------------------------------------------*\
    Create parameter or change value
\*--------------------------------------------------------------------------*/
		if (param_def[i].type != TAB_PARAM)
		{
		    status = ProMdlToModelitem(g_ptr->model, &modelitem);
		    PT_TEST_LOG_SUCC("ProMdlToModelitem");
		    
		    ProStringToWstring(w_name, str1);
		    
		    status = ProParameterInit(&modelitem, w_name, &param);
		    PT_TEST_LOG_SUCC("ProParameterInit");
		    
		    if (status != PRO_TK_NO_ERROR)
		    {
			status = ProParameterWithUnitsCreate(&modelitem, w_name, &parvalue, NULL, &param);
			PT_TEST_LOG_SUCC("ProParameterWithUnitsCreate");
		    }
		    else
		    {
			status = ProParameterValueWithUnitsSet(&param, &parvalue, NULL);
			PT_TEST_LOG_SUCC("ProParameterValueWithUnitsSet");
		    }
		}
		break;
    	    }
	}
	if (i == table_size)
	{
    	    status = ProMessageDisplay(MSGFIL, "PROTKGD Unknown parameter %0s", str1); 
	    PT_TEST_LOG_SUCC("ProMessageDisplay");
	}
    }
    fclose (fp);
/*-----------------------------------------------------------------*\
    Check all required parameters
\*-----------------------------------------------------------------*/
    for (i=0; i<table_size; i++)
    {
	if ((param_def[i].required == PRO_B_TRUE) && 
	    (param_def[i].set == PRO_B_FALSE))
	{
	    status = ProMessageDisplay(MSGFIL, 
    		"PROTKGD Required parameter \"%0s\" missing", 
		param_def[i].param_name);
            PT_TEST_LOG_SUCC("ProMessageDisplay");
	    
	    return (-1);
	}
    }
    return (0);
}



/*=============================================================*\
  Function: 	ProTKGDAccess
  Purpose:	Determine if gear design should be accessible from menus
\*=============================================================*/
static uiCmdAccessState ProTKGDAccess (uiCmdAccessMode access_mode)
{
  ProMdl current;
  ProMdlType type;
  ProError status;

  status = ProMdlCurrentGet (&current);
  PT_TEST_LOG_SUCC("ProMdlCurrentGet...........uiCmdAccessState");

  if (status != PRO_TK_NO_ERROR)
    return ACCESS_INVISIBLE;

  status = ProMdlTypeGet (current, &type);
  PT_TEST_LOG_SUCC("ProMdlTypeGet");
  
  if (status != PRO_TK_NO_ERROR || type != PRO_MDL_PART)
    return ACCESS_INVISIBLE;

  return (ACCESS_AVAILABLE);
}

/*=============================================================*\
  Function: 	user_initialize
  Purpose:	Create menu button
\*=============================================================*/
int user_initialize(
int	argc,			 /* Inp: Pro/E arg count */
char	*argv[],		 /* Inp: Pro/E args	 */
char	*version,		 /* Inp: Pro/E version	 */
char	*build, 		 /* Inp: Pro/E build date code */
wchar_t errbuf[80])		 /* Out: error message (opt)   */
{
		/* Declare external functions */
    int m_id, wchar_size;
    ProError status;
    
    int ProUserNewgearMenu();
    uiCmdCmdId cmd_id;
    
    errlog_fp = fopen("GearDesign.log", "w");
    
    if	(ProWcharSizeVerify(sizeof (wchar_t), &wchar_size)!=PRO_TK_NO_ERROR)
    {
	ProMessageDisplay(MSGFIL, "PROTKGD %0s", "Incorrect size of 'wchar_t'."); 
	return(-1); 
    }
    
    status = ProCmdActionAdd("ProTKGearDesign",
			     (uiCmdCmdActFn)ProUserNewgearUI,
			     uiProe2ndImmediate, ProTKGDAccess,
			     PRO_B_FALSE, PRO_B_FALSE, &cmd_id);
    PT_TEST_LOG_SUCC("ProCmdActionAdd.........user_initialize");

    status = ProMenubarmenuPushbuttonAdd(
        "Applications", "-ProTKGD", "-ProTKGD", "-ProTKGDHelp",
	NULL, PRO_B_TRUE, cmd_id, MSGFIL);
    PT_TEST_LOG_SUCC("ProMenubarmenuPushbuttonAdd");

    return (0);
}



/*=============================================================*\
  Function: 	user_terminate
  Purpose:	To handle any termination actions
\*=============================================================*/
void user_terminate()
{
    ProTKPrintf("\tEnd of Application\n");
    fclose(errlog_fp);

}