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


/*--------------------------------------------------------------------*\
Pro/Toolkit includes -- include this first
\*--------------------------------------------------------------------*/
#include <ProToolkit.h>
#include <ProModFeat.h>
#include <ProFeatType.h>
#include <ProGraphic.h>
#include <ProDisplist.h>
#include <ProExtrude.h>
#include <ProFeatForm.h>
#include <ProStdSection.h>
#include <ProTKRunTime.h>
/*--------------------------------------------------------------------*\
Application includes
\*--------------------------------------------------------------------*/
#include "UtilMath.h"
#include "UtilMatrix.h"
#include "UtilTree.h"
#include "TestSect.h"
#include <ProSolid.h>
#include <ProMenu.h>
#include <ProMdl.h>
#include <TestError.h>
#include <ProSolid.h>
#include <UtilMessage.h>
#include <ProWindows.h>
#include <ProSurface.h>
#include <ProUtil.h>
#include <ProMessage.h>
#include <UtilVisit.h>

/*--------------------------------------------------------------------*\
Application data types 
\*--------------------------------------------------------------------*/
/* Section data structure */
typedef struct tag_SketchingData
	{
	    ProSection	section;	/* The section to add sketched 
						entities to */
	    ProMatrix	trf_matrix;	/* The matrix to transform screen
						coords to section coords */
	    ProMatrix	mdl_matrix;	/* The matrix to transform screen 
						coords to model coords */
	} SketchingData;

typedef struct tag_DepthData
	{
	    ProExtDepthFromType from_type;
	    ProValueData        from_value;
	    ProExtDepthToType   to_type;
	    ProValueData        to_value;

	} DepthData;

typedef struct tag_DirectionArrow
{
    ProPoint3d		origin;
    ProVector		dir_vector;
    ProSecViewDirType	direction;
    int			disp_id;

} DirectionArrow;


/* Message file name */
#define msgfil			"feat"



/* Array direction actions */
#define OKAY_DIRECTION		0
#define FLIP_DIRECTION		1

/* Sketching reference plane types */
#define SK_REF_NONE		0
#define SK_REF_TOP		1
#define SK_REF_BOTTOM		2
#define SK_REF_RIGHT		3
#define SK_REF_LEFT		4
#define SK_REF_DEFAULT		5

/* Sektcher actions */
#define SKETCHER_QUIT		0
#define SKETCHER_DONE		1
#define SKETCHER_SKETCH		2

/* Planes disposition constants */
#define UNKNOWN_PLANES		-1
#define PARALLEL_PLANES		0
#define PERPENDICULAR_PLANES	1

/* Feature depth type */
#define DEPTH_TYPE_QUIT		0
#define DEPTH_TYPE_DONE		1
#define DEPTH_TYPE_BLIND	2
#define DEPTH_TYPE_2SIDEBLIND	3
#define DEPTH_TYPE_THRU_NEXT	4
#define DEPTH_TYPE_THRU_ALL	5
#define DEPTH_TYPE_THRU_UNTIL	6
#define DEPTH_TYPE_UPTO_PNT	7
#define DEPTH_TYPE_UPTO_CURVE	8
#define DEPTH_TYPE_UPTO_SURFACE	9
#define DEPTH_TYPE_NONE		10

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

/*--------------------------------------------------------------------*\
Application global variables
\*--------------------------------------------------------------------*/
static int		Disp_ID = 745;


/*--------------------------------------------------------------------*\
Functions declaration 
\*--------------------------------------------------------------------*/
ProError ProTestFeatureExtrudeCreate();

ProError ProTestFirstFeatureCreate(ProMdl model);

ProError ProTestFeatureAttrsRetrieve(ProSides *p_sides);

int ProTestFeatSidesSet(
    ProSides		*p_sides,
    ProSides		sides );

ProError ProTestPlaneSelect(ProSurface *p_plane, ProSelection *p_plane_sel);

ProError ProTestFeatureDirectionRetrieve (
	ProSurface plane, ProSecViewDirType *p_direction);

ProError ProTestDirectionArrowCreate(
    ProSurface			plane,		/* In: Sketching plane */
    ProSecViewDirType		init_dir,	/* In: Init arrow direction:
							1 - along normal vect;
							-1- reversed normal */
    DirectionArrow		*p_dir_arrow );	/* Out: Created direction 
							arrow */

int ProTestDirectionArrowFlip(
    DirectionArrow		*p_dir_arrow,	/* In: [0] is origin point, 
						     [1] is direction vector */
    int				action );	/* In: OKAY_DIRECTION or
							FLIP_DIRECTION */

ProError ProTestDirectionArrowDraw(
    ProPoint3d		point1,
    ProPoint3d		point2,
    ProColor	*p_color);

ProError ProTestDirectionArrowDelete(
    DirectionArrow       *p_dir_arrow );

ProError ProTestSketchingViewSet(
    ProSurface		sk_plane,		/* In: Sketching plane */
    ProSecViewDirType   direction,              /* In: Feature direction */
    int			*p_ref_type,		/* Out: Reference type */
    ProSelection	*p_ref_plane_sel,	/* Out: Reference plane 
							selection structure */
    ProMatrix		sk_view_matrix );

int ProTestRefPlaneTypeSet(
    int			*p_ref_type,
    int			ref_type );

ProError ProTestModelOrient(
    ProSurface		sk_plane,		/* In: Sketching plane */
    ProSecViewDirType	direction,		/* In: Feature direction */
    int			ref_type,		/* In: Orientation of reference 
							plane */
    ProSelection	*p_ref_plane_sel,	/* Out: Reference plane 
							selection structure.
							Use ProSelectionFree to 
							free the memory */
    ProMatrix		view_matrix );		/* Out: Matrix to to transform 
							model coords to section
							coords */

ProBoolean ProTestPlanesPerpendicular(
    ProSurface		plane1,
    ProSurface		plane2 );
    
ProError ProTestSectionSketcher(
    ProMatrix		sk_view_matrix, /* In: Matrix to convert model coords
                                                to section coords, (NULL-
						for 1st feature) */
    ProSection		*p_out_section,	/* Out: The undimesioned section */
    ProSelection	**p_refs );	/* Out: Allocated array with selected
                                                references. Array must be
                                                released with 
						ProTestSectionRefsFree.
						Pass NULL when creating the
						1st feature */
                                                
int ProTestSpecifyRefsMenuPostaction();

ProError ProTestSketchingDataInit(
    ProSection		section,	/* In: The section */
    ProMatrix		sk_view_matrix,	/* In: Matrix to convert model coords
						to section coords (NULL - for 
						first feature */
    SketchingData	*p_sk_data );	/* Out: Initialized sketching data */
    
int ProTestSectionSketch(
    SketchingData	*p_sk_data,
    int			sketcher_action );
    
int ProTestSectionRefsSet(
    ProSelection	**p_ref_sel);
    
ProError ProTestSectionRefsFree(
    ProSelection	**p_ref_sel );
    
ProError ProTestSectionDraw();

int ProTestSectionLineEntityCreate(
    SketchingData	*p_sk_data);
    
ProError ProTestSectionLineEntityAdd( 
    SketchingData	*p_sk_data,	/* In: Sketching data */
    ProPoint3d		point1,		/* In: Line end 1 in screen coords */
    ProPoint3d		point2 );	/* In: Line end 2 in screen coords */
    
ProError ProTestLineDraw(
     ProPoint3d		point1,		/* In: Screen coords of line end point*/
     ProPoint3d		point2,		/* In: Screen coords of line end point*/
     ProMatrix		trf_matrix );	/* In: Matrx to convert screen coords
						into model coords (NULL)*/
                                                
int ProTestSectionRectangleEntityCreate(
    SketchingData       *p_sk_data);
    
ProError ProTestSectionRectangleEntityAdd(
    SketchingData	*p_sk_data,	/* In: Sketching data */
    ProPoint3d		point1,		/* In: Screen coords of top point*/
    ProPoint3d		point3 );	/* In: Screen coords of bottom point */
    
ProError ProTestRectangleDraw(
     ProPoint3d         point1,         /* In: Screen coords of top point*/
     ProPoint3d         point3,         /* In: Screen coords of bottom point */
     ProMatrix          trf_matrix );    /* In: Matrx to convert screen coords
                                                into model coords (NULL)*/
                                                
int ProTestSectionCircleEntityCreate(
    SketchingData	*p_sk_data);
    
ProError ProTestSectionCircleEntityAdd(
    SketchingData       *p_sk_data,     /* In: Sketching data */
    ProPoint3d		center,		/* In: The center point */
    ProPoint3d          circle );	/* In: Circle point */
    
int ProTestSectionArcEntityCreate(
    SketchingData	*p_sk_data);
    
ProError ProTestCircleDraw( 
    ProPoint3d		center,		/* In: Screen coords of center point */
    ProPoint3d		circle,		/* In: Screen coords of circle point */
    ProMatrix		trf_matrix );	/* In: Matrx to convert screen coords
						into model coords (NULL) */
                                                
ProError ProTestPointDraw(
    ProPoint3d		point,		/* In: Point screen coords */
    ProMatrix		trf_matrix );	/* In: Matrx to convert screen coords
						into model coords (NULL) */
                                                
wchar_t *ProTestNewSectionNameGet(
    ProName		w_name );

ProError ProTestProtrusionFeatureCreate(
    ProSecViewDirType	view_direction,	/* In: Feature direction */
    ProSelection	sk_plane_sel,	/* In: The sketching plane selection */
    int			ref_type, 	/* In: The reference plane type 
						(TOP, ...) */ 
    ProSelection	ref_plane_sel,	/* In: The reference plane selection */
    ProSection		section,	/* In: The sketched section */
    ProSelection        *p_references,	/* In: The sketching references */
    DepthData		*p_depth,	/* In: Initialized depth data */
    ProFeature		*p_feature );	/* Out: Created feature */
    
    
ProError ProTestFeatureSectionInit(
    ProFeature		*p_feature,	/* In: Incomplete feature */
    ProSection		section,	/* In: Sketched section */
    ProSelection	*p_references,  /* In: Sketching refs (NULL) */
    ProBoolean          is_first);	/* In: If first feature or not */
    
ProError ProTestFeatureSectionRefsAdd(
    ProSection		section,	/* In: The section */
    ProSelection	*p_references );	/* In: The selected refs */
    
ProError ProTestSectionRegenerate(
    ProSection		section );

ProError ProTestFeatureDepthRetrieve(
    ProSides		sides,		/* In: ONE_SIDE or
						BOTH_SIDES */
    ProSecViewDirType	direction,	/* In: Feature direction */
    ProSurface		sk_plane,	/* In: Sketching plane */

    DepthData		*p_depth );	/* Out: Initialized depth data.  
					If ONE_SIDE, init only p_depth->to_*, 
					setting from_type to DEPTH_TYPE_NONE */
                                        
ProError ProTestFeatureDepthTypeGet(
    ProSides		sides,
    ProBoolean          is_second_side, /* In: TRUE for 2nd side depth 
                                                initialization. In this case
                                                "Blind" and "2 Side Blind"
                                                buttons are disabled */
    int			*p_depth_type );	/* Out: Depth type */
    
int ProTestFeatureDepthTypeSet(
    int			*p_depth_type,
    int			depth_type );
    
ProError ProTestFeatureDepthValueInit(
    ProSides            sides,
    ProBoolean		is_second_side,	/* In: TRUE if for 2nd side depth 
						initialization. In this case
						"Blind" and "2 Side Blind"
						buttons are disabled */
    int			*p_depth_type,
    ProValueData	*p_depth_value );
    
double ProTestDoubleValueGet( 
    double		def );


/*--------------------------------------------
Declaration of variable SKETCHER_DONE_LOCAL and
it is initialized to SKETCHER_QUIT to mean that
sketch has not been done in the sketcher mode.
--------------------------------------------*/

int SKETCHER_DONE_LOCAL = SKETCHER_QUIT;


/*====================================================================*\
FUNCTION : ProTestFeatureExtrudeCreate
PURPOSE  : Retrieve all the necessary data and create extruded 
		protrusion feature
\*====================================================================*/
ProError ProTestFeatureExtrudeCreate()
{
    ProError		status;
    ProMdl		model;
    int			n_csys;
    ProSides		sides;
    ProSecViewDirType	direction;
    ProSurface		sk_plane;
    ProSelection	sk_plane_selection = NULL;
    int			ref_plane_type;
    ProSelection	ref_plane_selection = NULL;
    ProSection		section;
    ProSelection	*p_references = NULL;
    DepthData		depth_data;
    ProMatrix		sk_view_matrix;
    ProFeature		feature;


    status = ProMdlCurrentGet( &model );
    TEST_CALL_REPORT( "ProMdlCurrentGet()", "ProTestFeatureExtrudeCreate()", 
	status, status != PRO_TK_NO_ERROR);

    /*--------------------------------------------------------------*\
	Try to find the feature which is not csys. If there are no
	such kind of feature create one of type FIRST_FEATURE.
    \*--------------------------------------------------------------*/
    status = ProSolidFeatVisit((ProSolid)model,
        (ProFeatureVisitAction)ProUtilNonCsysFeatCheck,
        (ProFeatureFilterAction)NULL, (ProAppData)&n_csys);
    TEST_CALL_REPORT("ProSolidFeatVisit()", "ProTestFeatureExtrudeCreate()", 
	status, status != PRO_TK_NO_ERROR && status != PRO_TK_E_FOUND &&
	status != PRO_TK_E_NOT_FOUND);
    if( status != PRO_TK_E_FOUND )
    {
      return ProTestFirstFeatureCreate( model );
    }


    status = ProTestFeatureAttrsRetrieve( &sides );
    if( status == PRO_TK_NO_ERROR )
    {
        ProUtilMsgPrint( msgfil, 
		(char *)"USER Select or create a SKETCHING PLANE." );
        status = ProTestPlaneSelect( &sk_plane, &sk_plane_selection );
    }

    if( status == PRO_TK_NO_ERROR )
	status = ProTestFeatureDirectionRetrieve( sk_plane, &direction );

    if( status == PRO_TK_NO_ERROR )
        status = ProTestSketchingViewSet( sk_plane, direction, 
		&ref_plane_type, &ref_plane_selection, sk_view_matrix );


    if( status == PRO_TK_NO_ERROR )
        status = ProTestSectionSketcher( sk_view_matrix, 
		&section, &p_references );


    if( status == PRO_TK_NO_ERROR )
        status = ProTestFeatureDepthRetrieve( sides, direction, sk_plane, 
		&depth_data );


    if( status == PRO_TK_NO_ERROR )
        ProTestProtrusionFeatureCreate( direction, 
	    sk_plane_selection, 
	    ref_plane_type, ref_plane_selection, 
	    section, p_references, 
	    &depth_data,
	    &feature );

    ProWindowRepaint( PRO_VALUE_UNUSED );


    /* Free allocated memory */
    if( sk_plane_selection != NULL )
	ProSelectionFree( &sk_plane_selection );
    if( ref_plane_selection != NULL )
	ProSelectionFree( &ref_plane_selection );
    if( p_references != NULL )
    	ProTestSectionRefsFree( &p_references );


    return PRO_TK_NO_ERROR;
}



/*====================================================================*\
FUNCTION : ProTestFeatureAttrsRetrieve
PURPOSE  : Retrieve direction of feature creation
\*====================================================================*/
ProError ProTestFeatureAttrsRetrieve( 
    ProSides		*p_sides )	/* Out: Direction of feature creation */
{
    ProError		status;
    ProSides		sides = (ProSides)(-1);
    int			menu_id;
    int			action;


    /*------------------------------------*\
      Choose direction of feature creation 
    \*------------------------------------*/
    ProMenuFileRegister( (char *)"TK SIDES", (char *)"tksides.mnu", &menu_id );
    ProMenubuttonActionSet( (char *)"TK SIDES", (char *)"One Side",
        (ProMenubuttonAction)ProTestFeatSidesSet, &sides, PRO_SIDES_ONE_SIDE );
    ProMenubuttonActionSet( (char *)"TK SIDES", (char *)"Both Sides",
        (ProMenubuttonAction)ProTestFeatSidesSet, &sides,PRO_SIDES_BOTH_SIDES );
    ProMenubuttonActionSet( (char *)"TK SIDES", (char *)"TK SIDES", 
        (ProMenubuttonAction)ProMenuDelete, NULL, 0 );
 
    status = ProMenuCreate( PROMENUTYPE_MAIN, (char *)"TK SIDES", &menu_id );
    if( status == PRO_TK_NO_ERROR )
    {
        status = ProMenuProcess( (char *)"TK SIDES", &action );
    }
 

    if( sides != -1 )
    {
	*p_sides = sides;
        status = PRO_TK_NO_ERROR;
    }
    else
	status = PRO_TK_GENERAL_ERROR;


    return status;
}



/*====================================================================*\
FUNCTION : ProTestFeatSidesSet
PURPOSE  : ProMenubuttonAction for TK SIDES
\*====================================================================*/
int ProTestFeatSidesSet(
    ProSides		*p_sides,
    ProSides		sides )
{
    *p_sides = sides;
    ProMenuDelete();


    return 0;
}



/*====================================================================*\
FUNCTION : ProTestPlaneSelect
PURPOSE  : Select plane feature in current model
\*====================================================================*/
ProError ProTestPlaneSelect(
    ProSurface		*p_plane,	/* Out: Selected plane */
    ProSelection	*p_plane_sel )	/* Out: Selection structure (NULL).
						Use ProSelectionFree to 
						free the memory */
{
    ProError		status;
    ProSelection	*p_sel;
    int			n_sel;
    ProModelitem	model_item;
    ProSurface		surface;
    ProSrftype		srf_type = PRO_SRF_NONE;


    do
    {
	n_sel = 0;
	srf_type = PRO_SRF_NONE;

        /* Select surface */
        status = ProSelect( (char *)"surface,sldface,qltface,datum", 1, NULL, NULL, 
        	NULL, NULL, &p_sel, &n_sel );
        TEST_CALL_REPORT( "ProSelect()", "ProTestPlaneSelect()",
            status, status != PRO_TK_NO_ERROR);
        if( status != PRO_TK_NO_ERROR || n_sel < 1 )
	    return PRO_TK_GENERAL_ERROR;

        /* Check out model item */
        status = ProSelectionModelitemGet( p_sel[0], &model_item );
	TEST_CALL_REPORT( "ProSelectionModelitemGet", "ProTestPlaneSelect()",
	    status, status != PRO_TK_NO_ERROR);
        if( model_item.type != PRO_SURFACE && 
	    model_item.type != PRO_DATUM_PLANE )
        {
	    ProUtilMsgPrint( msgfil, (char *)"USER Only planes are allowed" );
            continue;
        }

        /* Get the selected surface  */
        status = ProSurfaceInit( model_item.owner, model_item.id, &surface );
	TEST_CALL_REPORT( "ProSurfaceInit", "ProTestPlaneSelect()",
	    status, status != PRO_TK_NO_ERROR);
        if( status != PRO_TK_NO_ERROR )
	    continue;

	/* Check out the surface type. A plane is only acceptable */
        status = ProSurfaceTypeGet( surface, &srf_type );
	TEST_CALL_REPORT( "ProSurfaceTypeGet", "ProTestPlaneSelect()",
	    status, status != PRO_TK_NO_ERROR);
        if( srf_type != PRO_SRF_PLANE )
        {
	    ProUtilMsgPrint( msgfil, (char *)"USER Only planes are allowed" );
            continue;
        }

    } while( srf_type != PRO_SRF_PLANE );

    memcpy( p_plane, &surface, sizeof(ProSurface) );
    if( p_plane_sel )
    {
	status = ProSelectionCopy( *p_sel, p_plane_sel );
	TEST_CALL_REPORT( "ProSelectionCopy", "ProTestPlaneSelect()",
	    status, status != PRO_TK_NO_ERROR );
    }


    return PRO_TK_NO_ERROR;
}



/*====================================================================*\
FUNCTION : ProTestFeatureDirectionRetrieve
PURPOSE  : Retrieve feature creation direction basing on sketching plane
\*====================================================================*/
ProError ProTestFeatureDirectionRetrieve( 
    ProSurface		plane,		/* In: Sketching plane */
    ProSecViewDirType	*p_direction )	/* Out: Direction */
{
    ProError		status;
    int                 menu_id;
    int                 action = OKAY_DIRECTION;
    DirectionArrow 	dir_arrow;
 

    ProUtilMsgPrint( msgfil, 
	(char *)"USER Arrow shows direction of feature creation" );

    /* Create and display initial direction arrow */
    ProTestDirectionArrowCreate( plane, (ProSecViewDirType)1, &dir_arrow );

    /* Choose feature direction */
    ProMenuFileRegister( (char *)"TK DIRECTION", (char *)"tkdirection.mnu", &menu_id );
    ProMenubuttonActionSet( (char *)"TK DIRECTION", (char *)"Flip",
        (ProMenubuttonAction)ProTestDirectionArrowFlip, 
	&dir_arrow, FLIP_DIRECTION );
    ProMenubuttonActionSet( (char *)"TK DIRECTION", (char *)"Okay",
        (ProMenubuttonAction)ProTestDirectionArrowFlip, 
	&dir_arrow, OKAY_DIRECTION );
 
    status = ProMenuCreate( PROMENUTYPE_MAIN, (char *)"TK DIRECTION", &menu_id );
    if( status == PRO_TK_NO_ERROR )
    {
        status = ProMenuProcess( (char *)"TK DIRECTION", &action );
    }

    /* Init output value */
    if( dir_arrow.direction > 0 )
	*p_direction = PRO_SEC_VIEW_DIR_SIDE_ONE;
    else
	*p_direction = PRO_SEC_VIEW_DIR_SIDE_TWO;

    /* Delete direction arrow */
    ProTestDirectionArrowDelete( &dir_arrow );


    return PRO_TK_NO_ERROR;
}



/*====================================================================*\
FUNCTION :  ProTestDirectionArrowCreate
PURPOSE  :  Create arrow image
\*====================================================================*/
ProError ProTestDirectionArrowCreate(
    ProSurface			plane,		/* In: Sketching plane */
    ProSecViewDirType		init_dir,	/* In: Init arrow direction:
							1 - along normal vect;
							-1- reversed normal */
    DirectionArrow		*p_dir_arrow )	/* Out: Created direction 
							arrow */
{
    ProError		status;
    ProPoint3d		point2;
    ProGeomitemdata	*p_geom_data;
    ProColor	color;
    ProMatrix		transform;


    /* Get the plane geom data */
    status = ProSurfaceDataGet( plane, &p_geom_data );
    TEST_CALL_REPORT( "ProSurfaceDataGet", "ProTestDirectionArrowCreate()",
        status, status != PRO_TK_NO_ERROR );

    /* Retrieve the point on the plane to place direction arrow */
    status = ProSurfaceXyzdataEval( plane, 
	p_geom_data->data.p_surface_data->uv_max,
	p_dir_arrow->origin, NULL, NULL, p_dir_arrow->dir_vector );
    TEST_CALL_REPORT( "ProSurfaceXyzdataEval", "ProTestDirectionArrowCreate()",
        status, status != PRO_TK_NO_ERROR );

    p_dir_arrow->direction = init_dir;
    p_dir_arrow->disp_id = Disp_ID++;


    /* Get the end point of direction vector */
    point2[0] = p_dir_arrow->origin[0] + p_dir_arrow->dir_vector[0]*0.6*init_dir;
    point2[1] = p_dir_arrow->origin[1] + p_dir_arrow->dir_vector[1]*0.6*init_dir;
    point2[2] = p_dir_arrow->origin[2] + p_dir_arrow->dir_vector[2]*0.6*init_dir;

    /* Draw the arrow */
	color.method = PRO_COLOR_METHOD_TYPE;
	color.value.type = PRO_COLOR_HIGHLITE;	
    status = ProWindowCurrentMatrixGet( transform );
    TEST_CALL_REPORT( "ProWindowCurrentMatrixGet", 
	"ProTestDirectionArrowCreate()",
        status, status != PRO_TK_NO_ERROR );
    status = ProDisplist3dCreate( p_dir_arrow->disp_id, 
	(ProDisplistCallback)ProTestDirectionArrowDraw, p_dir_arrow->origin, point2, &color );
    TEST_CALL_REPORT( "ProDisplist3dCreate", "ProTestDirectionArrowCreate()",
        status, status != PRO_TK_NO_ERROR );
    status = ProDisplist3dDisplay( p_dir_arrow->disp_id, transform );
    TEST_CALL_REPORT( "ProDisplist3dDisplay", "ProTestDirectionArrowCreate()",
        status, status != PRO_TK_NO_ERROR );
    status = ProWindowRepaint( PRO_VALUE_UNUSED );
    TEST_CALL_REPORT( "ProWindowRepaint", "ProTestDirectionArrowCreate()",
        status, status != PRO_TK_NO_ERROR );


    /* Release the memory allocated by ProSurfaceDataGet */
    status = ProGeomitemdataFree( &p_geom_data );
    TEST_CALL_REPORT( "ProGeomitemdataFree", "ProTestDirectionArrowCreate()",
        status, status != PRO_TK_NO_ERROR );


    return PRO_TK_NO_ERROR;
}



/*====================================================================*\
FUNCTION :  ProTestDirectionArrowFlip
PURPOSE  :  Flip arrow image
\*====================================================================*/
int ProTestDirectionArrowFlip(
    DirectionArrow		*p_dir_arrow,	/* In: [0] is origin point, 
						     [1] is direction vector */
    int				action )	/* In: OKAY_DIRECTION or
							FLIP_DIRECTION */
{
    ProError		status;
    ProPoint3d		point2;
    ProColor        color;
    ProMatrix		transform;


    if( action == OKAY_DIRECTION )
    {
	ProMenuDelete();
	return 0;
    }


    /* Inverse direction */
    p_dir_arrow->direction = (ProSecViewDirType)-p_dir_arrow->direction;

    /* Set the arrow color */
    if( p_dir_arrow->direction > 0 )
	{
		color.method = PRO_COLOR_METHOD_TYPE;
		color.value.type = PRO_COLOR_HIGHLITE;		
	}
    else
	{
		color.method = PRO_COLOR_METHOD_TYPE;
		color.value.type = PRO_COLOR_LETTER;				
	}

    /* Get the end point og direction vector */
    point2[0]  =  p_dir_arrow->origin[0] + p_dir_arrow->dir_vector[0] *
	p_dir_arrow->direction * 0.6;
    point2[1]  =  p_dir_arrow->origin[1] + p_dir_arrow->dir_vector[1] *
	p_dir_arrow->direction * 0.6;
    point2[2]  =  p_dir_arrow->origin[2] + p_dir_arrow->dir_vector[2] *
	p_dir_arrow->direction * 0.6;

    /* Delete previous arrow */
    ProDisplist3dDelete( p_dir_arrow->disp_id );

    /* Draw the arrow */
    status = ProWindowCurrentMatrixGet( transform );
    TEST_CALL_REPORT( "ProWindowCurrentMatrixGet","ProTestDirectionArrowFlip()",
        status, status != PRO_TK_NO_ERROR );
    status = ProDisplist3dCreate( p_dir_arrow->disp_id, 
	(ProDisplistCallback)ProTestDirectionArrowDraw, p_dir_arrow->origin, point2, &color );
    TEST_CALL_REPORT( "ProDisplist3dCreate","ProTestDirectionArrowFlip()",
        status, status != PRO_TK_NO_ERROR );
    status = ProDisplist3dDisplay( p_dir_arrow->disp_id, transform );
    TEST_CALL_REPORT( "ProDisplist3dDisplay","ProTestDirectionArrowFlip()",
        status, status != PRO_TK_NO_ERROR );
    status = ProWindowRepaint( PRO_VALUE_UNUSED );
    TEST_CALL_REPORT( "ProWindowRepaint","ProTestDirectionArrowFlip()",
        status, status != PRO_TK_NO_ERROR );


    return 0;
}



/*====================================================================*\
FUNCTION :  ProTestDirectionArrowDraw
PURPOSE  :  Draw the arrow. This is the display list creation callback 
		function
\*====================================================================*/
ProError ProTestDirectionArrowDraw(
    ProPoint3d		point1,
    ProPoint3d		point2,
    ProColor	*p_color)
{
    ProError		status;
    ProLinestyle	old_line_style;
    ProColor	old_color;	
    ProPoint3d		center;
    double		radius;
    double		dx, dy, dz;
    int			i;


    /* Set new style and color */
    status = ProLinestyleSet( PRO_LINESTYLE_SOLID, &old_line_style );
    TEST_CALL_REPORT( "ProLinestyleSet","ProTestDirectionArrowDraw()",
        status, status != PRO_TK_NO_ERROR && status != PRO_TK_NO_CHANGE);
    status = ProGraphicsColorModify( p_color, &old_color ); 
    TEST_CALL_REPORT( "ProGraphicsColorModify","ProTestDirectionArrowDraw()",
        status, status != PRO_TK_NO_ERROR );

    ProGraphicsPenPosition( point1 );
    ProGraphicsLineDraw( point2 );

    dx = (point2[0] - point1[0]) / 6;
    dy = (point2[1] - point1[1]) / 6;
    dz = (point2[2] - point1[2]) / 6;
    center[0] = point1[0];
    center[1] = point1[1];
    center[2] = point1[2];
    radius = 0.08;

    for( i=0; i<8; i++ )
    {
	ProGraphicsCircleDraw( center, radius );
	center[0] += dx;
	center[1] += dy;
	center[2] += dz;
	radius -= 0.01;
    }

    /* Restore style and color */
    status = ProLinestyleSet( old_line_style, &old_line_style );
    TEST_CALL_REPORT( "ProLinestyleSet","ProTestDirectionArrowDraw()",
        status, status != PRO_TK_NO_ERROR && status != PRO_TK_NO_CHANGE);
    status = ProGraphicsColorModify( &old_color, NULL ); 
    TEST_CALL_REPORT( "ProGraphicsColorModify","ProTestDirectionArrowDraw()",
        status, status != PRO_TK_NO_ERROR );

    return PRO_TK_NO_ERROR;
}



/*====================================================================*\
FUNCTION :  ProTestDirectionArrowDelete
PURPOSE  :  Delete the arrow.
\*====================================================================*/
ProError ProTestDirectionArrowDelete(
    DirectionArrow       *p_dir_arrow )	/* In: Dir arrow structure */
{
    ProError		status;


    status = ProDisplist3dDelete( p_dir_arrow->disp_id );
    TEST_CALL_REPORT( "ProDisplist3dDelete","ProTestDirectionArrowDelete()",
        status, status != PRO_TK_NO_ERROR );

    status = ProWindowRepaint( PRO_VALUE_UNUSED );
    TEST_CALL_REPORT( "ProWindowRepaint","ProTestDirectionArrowDelete()",
        status, status != PRO_TK_NO_ERROR );


    return PRO_TK_NO_ERROR;
}



/*====================================================================*\
FUNCTION :  ProTestSketchingViewSet
PURPOSE  :  Select reference type and set the view for sketching
\*====================================================================*/
ProError ProTestSketchingViewSet(
    ProSurface		sk_plane,		/* In: Sketching plane */
    ProSecViewDirType   direction,              /* In: Feature direction */
    int			*p_ref_type,		/* Out: Reference type */
    ProSelection	*p_ref_plane_sel,	/* Out: Reference plane 
							selection structure */
    ProMatrix		sk_view_matrix )	/* Out: Matrix to to transform
                                                        model coords to section
                                                        coords */

{
    ProError		status;
    int			menu_id;
    int			action = 0;
    int			ref_type = SK_REF_NONE;


    ProUtilMsgPrint( msgfil, (char *)"USER Select reference for sketching" );

    /*--------------------------------------------*\
	Choose reference plane type
    \*--------------------------------------------*/
    ProMenuFileRegister( (char *)"TK SKET VIEW", (char *)"tk_orient.mnu", &menu_id );
    ProMenubuttonActionSet( (char *)"TK SKET VIEW", (char *)"Top",
        (ProMenubuttonAction)ProTestRefPlaneTypeSet,
        (ProAppData)&ref_type, SK_REF_TOP );
    ProMenubuttonActionSet( (char *)"TK SKET VIEW", (char *)"Bottom",
        (ProMenubuttonAction)ProTestRefPlaneTypeSet,
        (ProAppData)&ref_type, SK_REF_BOTTOM );
    ProMenubuttonActionSet( (char *)"TK SKET VIEW", (char *)"Right",
        (ProMenubuttonAction)ProTestRefPlaneTypeSet,
        (ProAppData)&ref_type, SK_REF_RIGHT );
    ProMenubuttonActionSet( (char *)"TK SKET VIEW", (char *)"Left",
        (ProMenubuttonAction)ProTestRefPlaneTypeSet,
        (ProAppData)&ref_type, SK_REF_LEFT );
    ProMenubuttonActionSet( (char *)"TK SKET VIEW", (char *)"Quit",
        (ProMenubuttonAction)ProTestRefPlaneTypeSet,
        (ProAppData)&ref_type, SK_REF_NONE );
    ProMenubuttonActionSet( (char *)"TK SKET VIEW", (char *)"TK SKET VIEW",
	(ProMenubuttonAction)ProTestRefPlaneTypeSet,
	(ProAppData)&ref_type, SK_REF_NONE );
 
    status = ProMenuCreate( PROMENUTYPE_MAIN, (char *)"TK SKET VIEW", &menu_id );
    if( status == PRO_TK_NO_ERROR )
    {
        status = ProMenuProcess( (char *)"TK SKET VIEW", &action );
	if( action != 0 )
	    return PRO_TK_GENERAL_ERROR;
    }


    /*--------------------------------------------*\
	Set the new view for sketching
    \*--------------------------------------------*/
    status = ProTestModelOrient( sk_plane, direction, ref_type, 
        p_ref_plane_sel, sk_view_matrix );

    *p_ref_type = ref_type;


    return status;
}



/*====================================================================*\
FUNCTION :  ProTestRefPlaneTypeSet
PURPOSE  :  
\*====================================================================*/
int ProTestRefPlaneTypeSet(
    int			*p_ref_type,
    int			ref_type )
{
    *p_ref_type = ref_type;

    if( ref_type == SK_REF_NONE )
        ProMenuDeleteWithStatus( -1 );
    else
	ProMenuDeleteWithStatus( 0 );
 
 
    return 0;
}



#if 0
int print_matrix( ProMatrix m )
{
    int i,j;

    for( i=0; i<4; i++ )
    {
	for( j=0; j<4; j++ )
	    printf( "%f  ", m[i][j] );
	putchar( '\n' );
    }

    putchar( '\n' );

    return 0;
}

int print_vector( ProVector m )
{
    int i,j;
 
    for( i=0; i<3; i++ )
        printf( "%f  ", m[i] );
 
    putchar( '\n' );
 
    return 0;
}
#endif
 


/*====================================================================*\
FUNCTION :  ProTestModelOrient
PURPOSE  :  Select reference plane, generate sketching view matrix and
		set the view for sketching
\*====================================================================*/
ProError ProTestModelOrient(
    ProSurface		sk_plane,		/* In: Sketching plane */
    ProSecViewDirType	direction,		/* In: Feature direction */
    int			ref_type,		/* In: Orientation of reference 
							plane */
    ProSelection	*p_ref_plane_sel,	/* Out: Reference plane 
							selection structure.
							Use ProSelectionFree to 
							free the memory */
    ProMatrix		view_matrix )		/* Out: Matrix to to transform 
							model coords to section
							coords */
{
    ProError		status;
    ProSurface		ref_plane;
    ProVector		orig_vector = { 0.0, 0.0, 0.0 };
    ProVector		tmp_orig;
    ProGeomitemdata	*p_geom_data;
    ProVector		x_vector;
    ProVector		y_vector;
    ProVector		z_vector;
    ProVector		sk_plane_normal;
    ProVector		ref_plane_normal;
    ProMatrix		new_matrix;


    /* Select the reference plane which is perpendicular 
	to the sketching plane */
    do
    {
	status = ProTestPlaneSelect( &ref_plane, p_ref_plane_sel );
	if( status != PRO_TK_NO_ERROR )
	    return status;

    } while( ProTestPlanesPerpendicular( sk_plane, ref_plane ) != PRO_B_TRUE );


    /* Get the reference plane normal vector */
    status = ProSurfaceDataGet( ref_plane, &p_geom_data );
    TEST_CALL_REPORT( "ProSurfaceDataGet","ProTestModelOrient()",
        status, status != PRO_TK_NO_ERROR );
    status = ProSurfaceXyzdataEval( ref_plane,
        p_geom_data->data.p_surface_data->uv_max,
        tmp_orig, NULL, NULL, ref_plane_normal );
    TEST_CALL_REPORT( "ProSurfaceXyzdataEval","ProTestModelOrient()",
        status, status != PRO_TK_NO_ERROR );
    status = ProGeomitemdataFree( &p_geom_data );
    TEST_CALL_REPORT( "ProGeomitemdataFree","ProTestModelOrient()",
        status, status != PRO_TK_NO_ERROR );

    /* Get the sketching plane normal vector */
    status = ProSurfaceDataGet( sk_plane, &p_geom_data );
    TEST_CALL_REPORT( "ProSurfaceDataGet","ProTestModelOrient()",
        status, status != PRO_TK_NO_ERROR );
    status = ProSurfaceXyzdataEval( sk_plane,
        p_geom_data->data.p_surface_data->uv_max,
        tmp_orig, NULL, NULL, sk_plane_normal );
    TEST_CALL_REPORT( "ProSurfaceXyzdataEval","ProTestModelOrient()",
        status, status != PRO_TK_NO_ERROR );
    status = ProGeomitemdataFree( &p_geom_data );
    TEST_CALL_REPORT( "ProGeomitemdataFree","ProTestModelOrient()",
        status, status != PRO_TK_NO_ERROR );

    /* Use sketching plane normal vector as Z vector of new view */
    ProUtilVectorCopy( sk_plane_normal, z_vector );

    /* Reverse Z vector if we use "flipped" direction for protrusion creation */
    if( direction == PRO_SEC_VIEW_DIR_SIDE_TWO )
        ProUtilVectorScale( -1.0, z_vector, z_vector );

    /* Generate the vectors for new view */
    switch( ref_type )
    {
	case SK_REF_TOP:
	    ProUtilVectorCopy( ref_plane_normal, y_vector );
	    ProUtilVectorCross( y_vector, z_vector, x_vector );
	    break;

	case SK_REF_BOTTOM:
	    ProUtilVectorScale( -1.0, ref_plane_normal, y_vector );
	    ProUtilVectorCross( y_vector, z_vector, x_vector );
	    break;

	case SK_REF_RIGHT:
	    ProUtilVectorCopy( ref_plane_normal, x_vector );
	    ProUtilVectorCross( z_vector, x_vector, y_vector );
	    break;

	case SK_REF_LEFT:
	    ProUtilVectorScale( -1.0, ref_plane_normal, x_vector );
	    ProUtilVectorCross( z_vector, x_vector, y_vector );
	    break;
    }

    /* Set new view matrix */
    status = ProMatrixInit( x_vector, y_vector, z_vector, orig_vector, 
	new_matrix );
    TEST_CALL_REPORT( "ProMatrixInit","ProTestModelOrient()",
        status, status != PRO_TK_NO_ERROR );
    ProUtilMatrixInvert( new_matrix, view_matrix );
    status = ProViewMatrixSet( NULL, NULL, view_matrix  );
    TEST_CALL_REPORT( "ProViewMatrixSet","ProTestModelOrient()",
        status, status != PRO_TK_NO_ERROR );

    ProWindowRefresh( PRO_VALUE_UNUSED );
    status = ProWindowRepaint( PRO_VALUE_UNUSED );
    TEST_CALL_REPORT( "ProWindowRepaint","ProTestModelOrient()",
        status, status != PRO_TK_NO_ERROR );


    return PRO_TK_NO_ERROR;
}



/*====================================================================*\
FUNCTION :  ProTestPlanesPerpendicular
PURPOSE  :  Check out if two planes are perpendicular.
\*====================================================================*/
ProBoolean ProTestPlanesPerpendicular(
    ProSurface		plane1,
    ProSurface		plane2 )
{
    ProError		status;
    ProGeomitemdata	*p_geom_data1 = NULL;
    ProGeomitemdata	*p_geom_data2 = NULL;
    double		dot;


    /* Get the planes geom data */
    status = ProSurfaceDataGet( plane1, &p_geom_data1 );
    TEST_CALL_REPORT( "ProSurfaceDataGet","ProTestPlanesPerpendicular()",
        status, status != PRO_TK_NO_ERROR );
    if( status != PRO_TK_NO_ERROR )
	return PRO_B_FALSE;

    status = ProSurfaceDataGet( plane2, &p_geom_data2 );
    TEST_CALL_REPORT( "ProSurfaceDataGet","ProTestPlanesPerpendicular()",
        status, status != PRO_TK_NO_ERROR );
    if( status != PRO_TK_NO_ERROR )
        return PRO_B_FALSE;

    /* If dot product of planes normals is 0.0 the planes are perpendicular */
    dot = ProUtilVectorDot( 
	p_geom_data1->data.p_surface_data->srf_shape.plane.e3, 
	p_geom_data2->data.p_surface_data->srf_shape.plane.e3 );

    /* Release the mem allocated with ProSurfaceDataGet */
    status = ProGeomitemdataFree( &p_geom_data1 );
    TEST_CALL_REPORT( "ProGeomitemdataFree","ProTestPlanesPerpendicular()",
        status, status != PRO_TK_NO_ERROR );
    status = ProGeomitemdataFree( &p_geom_data2 );
    TEST_CALL_REPORT( "ProGeomitemdataFree","ProTestPlanesPerpendicular()",
        status, status != PRO_TK_NO_ERROR );


    if( fabs( dot ) < EPSM6 )
	return PRO_B_TRUE;
    else
	return PRO_B_FALSE;
}



/*====================================================================*\
FUNCTION :  ProTestSectionSketcher
PURPOSE  :  Create the section
\*====================================================================*/
ProError ProTestSectionSketcher(
    ProMatrix		sk_view_matrix, /* In: Matrix to convert model coords
                                                to section coords, (NULL-
						for 1st feature) */
    ProSection		*p_out_section,	/* Out: The undimesioned section */
    ProSelection	**p_refs )	/* Out: Allocated array with selected
                                                references. Array must be
                                                released with 
						ProTestSectionRefsFree.
						Pass NULL when creating the
						1st feature */
{
    ProError		status = PRO_TK_NO_ERROR;
    int			menu_id;
    int			action = SKETCHER_QUIT;
    static char		*p_menus[] = { (char *)"TK SKETCHER", (char *)"DONE QUIT", (char *)"" };
    ProSection		section;
    ProName             w_section_name;
    ProSelection	*p_ref_sel = NULL;
    SketchingData	sk_data;


    /*-------------------------------------------*\
	Allocate the new section and set its name
    \*-------------------------------------------*/
    status = ProSection2DAlloc( &section );
    TEST_CALL_REPORT( "ProSection2DAlloc","ProTestSectionSketcher()",
	status, status != PRO_TK_NO_ERROR );

    if( status == PRO_TK_NO_ERROR )
    {
	status = ProSectionNameSet( section, 
	    ProTestNewSectionNameGet( w_section_name ) );
    	TEST_CALL_REPORT( "ProSectionNameSet","ProTestSectionSketcher()",
            status, status != PRO_TK_NO_ERROR );
     }

    if( status != PRO_TK_NO_ERROR )
	return status;


    /*-------------------------------------------*\
	Init sketching data structure
    \*-------------------------------------------*/
    ProTestSketchingDataInit( section, sk_view_matrix, &sk_data );

    /*-------------------------------------------*\
	Specify references and draw the section.
    \*-------------------------------------------*/
    ProMenuFileRegister( (char *)"TK SKETCHER", (char *)"tksketcher.mnu", &menu_id );
    ProMenubuttonActionSet( (char *)"TK SKETCHER", (char *)"Sketch",
        (ProMenubuttonAction)ProTestSectionSketch,
        (ProAppData)&sk_data, SKETCHER_SKETCH );

    ProMenubuttonActionSet( (char *)"TK SKETCHER", (char *)"Specify Refs",
        (ProMenubuttonAction)ProTestSectionRefsSet,
        (ProAppData)&p_ref_sel, 0 );
    
    ProMenubuttonActionSet( (char *)"TK SKETCHER", (char *)"TK SKETCHER",
	(ProMenubuttonAction)ProTestSectionSketch,
	(ProAppData)&sk_data, SKETCHER_QUIT );
    ProMenuFileRegister( (char *)"DONE QUIT", (char *)"tkdonequit.mnu", &menu_id );

    ProMenubuttonActionSet( (char *)"DONE QUIT", (char *)"-Done",
        (ProMenubuttonAction)ProTestSectionSketch,
        (ProAppData)&sk_data, SKETCHER_DONE );

    ProMenubuttonActionSet( (char *)"DONE QUIT", (char *)"-Quit",
        (ProMenubuttonAction)ProTestSectionSketch,
        (ProAppData)&sk_data, SKETCHER_QUIT );
    
    ProMenubuttonActionSet( (char *)"DONE QUIT", (char *)"DONE QUIT", 
        (ProMenubuttonAction)ProTestSectionSketch,
        (ProAppData)&sk_data, SKETCHER_QUIT );

    action = SKETCHER_QUIT;

    status = ProCompoundmenuCreate( p_menus,  &menu_id );
    if( status == PRO_TK_NO_ERROR )
    {
        /*--------------------------------------------------*\
            Do not specify references for the 1st feature
        \*--------------------------------------------------*/
        if( p_refs == NULL )
	{
            ProMenubuttonDeactivate( (char *)"TK SKETCHER", (char *)"Specify Refs" );
	    ProMenuCommandPush( (char *)"Sketch" );
	}
        else
	{
            ProMenubuttonActivate( (char *)"TK SKETCHER", (char *)"Specify Refs" );
	    ProMenuCommandPush( (char *)"Specify Refs" );
	}

        ProMenuProcess( (char *)"TK SKETCHER", &action );
    }
/*------------------------------------------------------------------
This if block is executed only if the user sketch entities in the 
Sketcher mode and pick -Done in the menu.Otherwise this fn will
return PRO_TK_USER_ABORT.
------------------------------------------------------------------*/

    if( action == SKETCHER_DONE && SKETCHER_DONE_LOCAL == SKETCHER_DONE)
    {
	/* Init output data */
	memcpy( p_out_section, &(sk_data.section), sizeof(ProSection) );
	if( p_refs != NULL )
	    *p_refs = p_ref_sel;
	status = PRO_TK_NO_ERROR;
    }
    else
    {
	/* Section creation process was canceled.
	    Delete incomplete section. */

	status = ProSectionFree( &section );
        TEST_CALL_REPORT( "ProSectionFree","ProTestSectionSketcher()",
            status, status != PRO_TK_NO_ERROR );

	if( p_ref_sel != NULL )
	    ProTestSectionRefsFree( &p_ref_sel );

	status = PRO_TK_USER_ABORT;
    }

    return status;
}



/*====================================================================*\
FUNCTION :  ProTestSketchingDataInit
PURPOSE  :  Initialize sketching data structure to use it 
		in sketching menu actions
\*====================================================================*/
ProError ProTestSketchingDataInit(
    ProSection		section,	/* In: The section */
    ProMatrix		sk_view_matrix,	/* In: Matrix to convert model coords
						to section coords (NULL - for 
						first feature */
    SketchingData	*p_sk_data )	/* Out: Initialized sketching data */
{
    ProMatrix		mdl_matrix;
    ProMatrix		identity_matrix = { {1.0, 0.0, 0.0, 0.0},
                                        {0.0, 1.0, 0.0, 0.0},
                                        {0.0, 0.0, 1.0, 0.0},
                                        {0.0, 0.0, 0.0, 1.0} };
 

    p_sk_data->section = section;

    /*------------------------------------------------------------------*\
	Create matrix to transform screen coords to model coords
    \*------------------------------------------------------------------*/
    ProViewMatrixGet( NULL, NULL, mdl_matrix );
    ProUtilMatrixInvert( mdl_matrix, p_sk_data->mdl_matrix );

    if( sk_view_matrix == NULL )
    {
    /*------------------------------------------------------------------*\
    	For the first feature use identity matrix to transform 
	screen coords to section coords
    \*------------------------------------------------------------------*/
    	ProUtilMatrixCopy( identity_matrix, p_sk_data->trf_matrix ); 
	return PRO_TK_NO_ERROR;
    }

    /*------------------------------------------------------------------*\
        Create matrix to transform screen coords to section coords
    \*------------------------------------------------------------------*/
    ProUtilMatrixProduct( p_sk_data->mdl_matrix, sk_view_matrix, 
	p_sk_data->trf_matrix );


    return PRO_TK_NO_ERROR;
}



/*====================================================================*\
FUNCTION :  ProTestSectionSketch
PURPOSE  :  Select from menu to draw the entities of section
\*====================================================================*/
int ProTestSectionSketch(
    SketchingData	*p_sk_data,
    int			sketcher_action )
{
    ProError		status;
    int			menu_id;
    int			action;


    /*-------------------------------------------*\
        Check for sketcher exiting 
    \*-------------------------------------------*/
    if( sketcher_action == SKETCHER_DONE || sketcher_action == SKETCHER_QUIT )
    {
	ProMenuDeleteWithStatus( sketcher_action );
	ProMenuDeleteWithStatus( sketcher_action );
	return 0;
    }

    /*-------------------------------------------*\
        Choose entity type and draw it
    \*-------------------------------------------*/

    ProMenuFileRegister( (char *)"TK GEOMETRY", (char *)"tksketgeom.mnu", &menu_id );
    ProMenubuttonActionSet( (char *)"TK GEOMETRY", (char *)"Point", 
	(ProMenubuttonAction)NULL, 
	(ProAppData)p_sk_data, 0 );



    ProMenubuttonActionSet( (char *)"TK GEOMETRY", (char *)"Line",
        (ProMenubuttonAction)ProTestSectionLineEntityCreate,
        (ProAppData)p_sk_data, 0 );

    ProMenubuttonActionSet( (char *)"TK GEOMETRY", (char *)"Rectangle",
        (ProMenubuttonAction)ProTestSectionRectangleEntityCreate,
        (ProAppData)p_sk_data, 0 );

    ProMenubuttonActionSet( (char *)"TK GEOMETRY", (char *)"Circle",
        (ProMenubuttonAction)ProTestSectionCircleEntityCreate,
        (ProAppData)p_sk_data, 0 );

    ProMenubuttonActionSet( (char *)"TK GEOMETRY", (char *)"Arc",
        (ProMenubuttonAction)ProTestSectionArcEntityCreate,
        (ProAppData)p_sk_data, 0 );

    ProMenubuttonActionSet( (char *)"TK GEOMETRY", (char *)"TK GEOMETRY",
        (ProMenubuttonAction)ProMenuDelete,
        (ProAppData)p_sk_data, 0 );


    status = ProMenuCreate( PROMENUTYPE_MAIN, (char *)"TK GEOMETRY", &menu_id );
    if( status == PRO_TK_NO_ERROR )
    {
	ProMenubuttonDeactivate(  (char *)"TK GEOMETRY", (char *)"Point");
	ProMenubuttonDeactivate( (char *)"TK GEOMETRY", (char *)"Arc" );
        status = ProMenuProcess( (char *)"TK GEOMETRY", &action );
    }


    return 0;
}



/*====================================================================*\
FUNCTION :  ProTestSectionRefsSet
PURPOSE  :  "Set Refs" on-button function. 
		Select sketching references
\*====================================================================*/
int ProTestSectionRefsSet(
    ProSelection	**p_ref_sel)	/* Out: If NULL - Allocated array with 
						selected references. Array must 
						be released with 
						ProTestSectionRefsFree.
						If !NULL - contains previously 
						selected references. */
{
    ProError		status;
    ProSelection	*p_sel;
    int			n_sel = 0;
    int			i;

/*-------------------------------------------------
Note:
   The variable SKETCHER_DONE_LOCAL is set to  SKETCHER_QUIT 
   and this can be changed to SKETCHER_DONE only by a fn call 
   to create entities in the sketcher.Those calls are 

   ProTestSectionRectangleEntityCreate()
   ProTestSectionCircleEntityCreate()
   ProTestSectionLineEntityCreate()

---------------------------------------------------*/

    SKETCHER_DONE_LOCAL = SKETCHER_QUIT;

/*-------------------------------------------------
Note:The Sketch menu is hiden untill the sketcher reference
is not given.
---------------------------------------------------*/

    ProMenubuttonDeactivate( (char *)"TK SKETCHER", (char *)"Sketch" );
	
	
    ProUtilMsgPrint( msgfil, (char *)"USER Select a perpendicular surface" );

    /* Select an edge to use as dimension/constrain reference */
    status = ProSelect( 
	(char *)"datum,sldedge,edge,curve,point,edge_end,surface,sldface", 
	2, *p_ref_sel, NULL, NULL, NULL, &p_sel, &n_sel );
    TEST_CALL_REPORT( "ProSelect","ProTestSectionRefsSet()",
        status, status != PRO_TK_NO_ERROR );
    if( status != PRO_TK_NO_ERROR || n_sel < 1 )
    {
	return -1;
    }
    else
    {
	ProMenubuttonActivate( (char *)"TK SKETCHER", (char *)"Sketch" );
    }

    /* Delete initial references if necessary */
    if( *p_ref_sel != NULL )
	ProTestSectionRefsFree( p_ref_sel );

    /* Copy selected referencies to output array */
    status = ProArrayAlloc( n_sel, sizeof(ProSelection), 1, 
	(ProArray*)p_ref_sel );
    TEST_CALL_REPORT( "ProArrayAlloc","ProTestSectionRefsSet()",
        status, status != PRO_TK_NO_ERROR );
    if( status != PRO_TK_NO_ERROR)
	return -1;

    for( i=0; i<n_sel; i++ )
    {
	status = ProSelectionCopy( p_sel[i], *p_ref_sel + i );
	TEST_CALL_REPORT( "ProSelectionCopy","ProTestSectionRefsSet()",
            status, status != PRO_TK_NO_ERROR );
    }

    /* Call the sketcher next */
    status = ProMenuCommandPush( (char *)"Sketch" );
    TEST_CALL_REPORT( "ProMenuCommandPush","ProTestSectionRefsSet()",
	status, status != PRO_TK_NO_ERROR ); 


    return 0;
}
 


/*====================================================================*\
FUNCTION :  ProTestSectionRefsFree
PURPOSE  :  Free array of selected section references.
\*====================================================================*/
ProError ProTestSectionRefsFree(
    ProSelection	**p_ref_sel )	/* In: ProArray of selected refs */
{
    ProError		status;
    int			n_refs = 0;
    int			i;


    status = ProArraySizeGet( (ProArray)(*p_ref_sel), &n_refs );
    TEST_CALL_REPORT( "ProArraySizeGet","ProTestSectionRefsFree()",
        status, status != PRO_TK_NO_ERROR );
    if( status != PRO_TK_NO_ERROR || n_refs < 1 )
	return PRO_TK_NO_ERROR;

    for( i=0; i<n_refs; i++ )
    {
	status = ProSelectionFree( *p_ref_sel + i );
	TEST_CALL_REPORT( "ProSelectionFree","ProTestSectionRefsFree()",
	    status, status != PRO_TK_NO_ERROR );
    }

    status = ProArrayFree( (ProArray*)p_ref_sel );
    TEST_CALL_REPORT( "ProArrayFree","ProTestSectionRefsFree()",
	status, status != PRO_TK_NO_ERROR );


    return PRO_TK_NO_ERROR;
}



/*---------------------------------------------------------------------------*\
    Sketching entities
 
\*---------------------------------------------------------------------------*/
 
/*====================================================================*\
FUNCTION :  ProTestSectionLineEntityCreate
PURPOSE  :  Draw the line entity and add it to the section
\*====================================================================*/
int ProTestSectionLineEntityCreate(
    SketchingData	*p_sk_data)
{
    ProError		status;
    ProMouseButton	mouse_button;
    ProPoint3d		point1, point2;
    ProColor        old_color;
	ProColor        warning_color;

/*------------------------------------------------------
Note:
Value of the SKETCHER_DONE_LOCAL is changed from SKETCHER_QUIT to
SKETCHER_DONE.This implies, the sketch has been done in the
Sketcher mode.
------------------------------------------------------*/
  
    SKETCHER_DONE_LOCAL = SKETCHER_DONE;

    /* Pick the first point */
    mouse_button = PRO_NO_BUTTON;
    status = ProMousePickGet( PRO_ANY_BUTTON, &mouse_button, point1 );
    TEST_CALL_REPORT( "ProMousePickGet","ProTestSectionLineEntityCreate()",
	status, status != PRO_TK_NO_ERROR );
    if( status != PRO_TK_NO_ERROR || mouse_button != PRO_LEFT_BUTTON )
        return -1;

    /* Draw the first point */
	warning_color.method = PRO_COLOR_METHOD_TYPE;
	warning_color.value.type = PRO_COLOR_WARNING;
    ProGraphicsColorModify( &warning_color, &old_color );
    ProTestPointDraw( point1, p_sk_data->mdl_matrix );

    while( mouse_button != PRO_MIDDLE_BUTTON )
    {
	/* Pick the line end point */
	status = ProMousePickGet( PRO_ANY_BUTTON, &mouse_button, point2 );
	TEST_CALL_REPORT( "ProMousePickGet","ProTestSectionLineEntityCreate()",
	    status, status != PRO_TK_NO_ERROR );
 	if( status != PRO_TK_NO_ERROR )
	    break;

	if( mouse_button == PRO_LEFT_BUTTON )
	{
	    /* Draw the line and line end point */
	    ProTestLineDraw( point1, point2, p_sk_data->mdl_matrix );

	    /* Add drawn line as entity */
	    ProTestSectionLineEntityAdd( p_sk_data, point1, point2 );

	    point1[0] = point2[0];
	    point1[1] = point2[1];
	    point1[2] = point2[2];
	}
    }


    ProGraphicsColorModify( &old_color, NULL );


    return 0;
}



/*====================================================================*\
FUNCTION :  ProTestSectionRectangleEntityCreate
PURPOSE  :  Draw the rectangle entity and add it to the section
\*====================================================================*/
int ProTestSectionRectangleEntityCreate(
    SketchingData       *p_sk_data)
{
    ProError            status;
    ProMouseButton      mouse_button;
    ProPoint3d          point1, point2;
    ProColor        	old_color;
	ProColor 	        warning_color;
    
/*------------------------------------------------------
Note:
Value of the SKETCHER_DONE_LOCAL is changed from SKETCHER_QUIT to
SKETCHER_DONE.This implies, the sketch has been done in the
Sketcher mode.
------------------------------------------------------*/
    SKETCHER_DONE_LOCAL = SKETCHER_DONE;


    /* Pick the first point */
    mouse_button = PRO_NO_BUTTON;
    status = ProMousePickGet( PRO_ANY_BUTTON, &mouse_button, point1 );
    TEST_CALL_REPORT( "ProMousePickGet","ProTestSectionRectangleEntityCreate()",
        status, status != PRO_TK_NO_ERROR );
    if( status != PRO_TK_NO_ERROR || mouse_button != PRO_LEFT_BUTTON )
        return -1;
 
    /* Draw the first point */
	warning_color.method = PRO_COLOR_METHOD_TYPE;
	warning_color.value.type = PRO_COLOR_WARNING;
    ProGraphicsColorModify( &warning_color, &old_color );
    ProTestPointDraw( point1, p_sk_data->mdl_matrix );


    /* Pick the circle point */
    while( mouse_button != PRO_MIDDLE_BUTTON )
    {
        /* Pick the line end point */
        status = ProMousePickGet( PRO_ANY_BUTTON, &mouse_button, point2 );
	TEST_CALL_REPORT( "ProMousePickGet",
		"ProTestSectionRectangleEntityCreate()", 
		status, status != PRO_TK_NO_ERROR );
        if( status != PRO_TK_NO_ERROR )
            break;
        if( mouse_button == PRO_LEFT_BUTTON )
        {
            /* Draw the rectangle */
            ProTestRectangleDraw( point1, point2, p_sk_data->mdl_matrix );
 
            /* Add drawn rectangle as entity */
            ProTestSectionRectangleEntityAdd( p_sk_data, point1, point2 );
 
            break;
        }
    }
 
    ProGraphicsColorModify( &old_color, NULL );


    return 0;
}



/*====================================================================*\
FUNCTION :  ProTestSectionCircleEntityCreate
PURPOSE  :  Draw the circle entity and add it to the section
\*====================================================================*/
int ProTestSectionCircleEntityCreate(
    SketchingData	*p_sk_data)
{
    ProError            status;
    ProMouseButton      mouse_button;
    ProPoint3d          point1, point2;
    ProColor            old_color;
	ProColor            warning_color;

/*------------------------------------------------------
Note:
Value of the SKETCHER_DONE_LOCAL is changed from SKETCHER_QUIT to
SKETCHER_DONE.This implies, the sketch has been done in the
Sketcher mode.
------------------------------------------------------*/
    SKETCHER_DONE_LOCAL = SKETCHER_DONE;

    /* Pick the center point */
    mouse_button = PRO_NO_BUTTON;
    status = ProMousePickGet( PRO_ANY_BUTTON, &mouse_button, point1 );
    TEST_CALL_REPORT( "ProMousePickGet","ProTestSectionCircleEntityCreate()",
        status, status != PRO_TK_NO_ERROR );
    if( status != PRO_TK_NO_ERROR || mouse_button != PRO_LEFT_BUTTON )
        return -1;
 
    /* Draw the center point */
	warning_color.method = PRO_COLOR_METHOD_TYPE;
	warning_color.value.type = PRO_COLOR_WARNING;
    ProGraphicsColorModify( &warning_color, &old_color );
    ProTestPointDraw( point1, p_sk_data->mdl_matrix );

    /* Pick the circle point */
    while( mouse_button != PRO_MIDDLE_BUTTON )
    {
        /* Pick the line end point */
        status = ProMousePickGet( PRO_ANY_BUTTON, &mouse_button, point2 );
	TEST_CALL_REPORT( "ProMousePickGet",
		"ProTestSectionCircleEntityCreate()",
		status, status != PRO_TK_NO_ERROR );
	if( status != PRO_TK_NO_ERROR )
	    break;
        if( mouse_button == PRO_LEFT_BUTTON )
        {
            /* Draw the circle */
	    ProTestCircleDraw( point1, point2, p_sk_data->mdl_matrix );
 
            /* Add drawn circle as entity */
            ProTestSectionCircleEntityAdd( p_sk_data, point1, point2 );

	    break;
        }
    }
 
    ProGraphicsColorModify( &old_color, NULL );
 
 
    return 0;
}



int ProTestSectionArcEntityCreate(
    SketchingData	*p_sk_data)
{
#if 0
    ProError		status;
    ProMouseButton	mouse_button;
    ProPoint3d		point1;
    ProPoint3d		point2;
    ProPoint3d		point3;
    ProColor	old_color;
	ProColor	warning_color;


    /* Pick the first end point */
    mouse_button = PRO_NO_BUTTON;
    status = ProMousePickGet( PRO_ANY_BUTTON, &mouse_button, point1 );
    if( status != PRO_TK_NO_ERROR || mouse_button != PRO_LEFT_BUTTON )
        return -1;
 
    /* Draw the first arc end point */
	warning_color.method = PRO_COLOR_METHOD_TYPE;
	warning_color.value.type = PRO_COLOR_WARNING;
    ProGraphicsColorModify( &warning_color, &old_color );
    ProTestPointDraw( point1, p_sk_data->mdl_matrix );

    /* Get the second arc end point */
    while( mouse_button != PRO_MIDDLE_BUTTON )
    {
        /* Pick the second arc end point */
        status = ProMousePickGet( PRO_ANY_BUTTON, &mouse_button, point2 );
        if( status != PRO_TK_NO_ERROR )
            break;
        if( mouse_button == PRO_LEFT_BUTTON )
        {
            /* Draw the second end point */
            ProTestPointDraw( point2, p_sk_data->mdl_matrix );
            break;
        }
    }

    /* Get the center point */
    while( mouse_button != PRO_MIDDLE_BUTTON )
    {
	/* Pick the center point */
	status = ProMousePickGet( PRO_ANY_BUTTON, &mouse_button, center );
	if( status != PRO_TK_NO_ERROR )
	    break;
	if( mouse_button == PRO_LEFT_BUTTON )
	{
	    /* Draw the center point */
	    ProTestPointDraw( center, p_sk_data->mdl_matrix );
	    break;
	}
    }

    ProGraphicsColorModify( &old_color, NULL );
 
 
#endif
    return 0;
}



/*---------------------------------------------------------------------------*\
    Adding entities

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

/*====================================================================*\
FUNCTION :  ProTestSectionLineEntityAdd
PURPOSE  :  Add the specified line to the section
\*====================================================================*/
ProError ProTestSectionLineEntityAdd( 
    SketchingData	*p_sk_data,	/* In: Sketching data */
    ProPoint3d		point1,		/* In: Line end 1 in screen coords */
    ProPoint3d		point2 )	/* In: Line end 2 in screen coords */
{
    ProError		status;
    Pro2dLinedef	line_def;
    int			entity_id;
    ProPoint3d		sec_point1, sec_point2;


    /* Transform from screen coords to section coords */
    status = ProPntTrfEval( point1, p_sk_data->trf_matrix, sec_point1 );
    TEST_CALL_REPORT( "ProPntTrfEval","ProTestSectionLineEntityAdd()",
        status, status != PRO_TK_NO_ERROR );
    status = ProPntTrfEval( point2, p_sk_data->trf_matrix, sec_point2 );
    TEST_CALL_REPORT( "ProPntTrfEval","ProTestSectionLineEntityAdd()",
        status, status != PRO_TK_NO_ERROR );

    /* Init the entity structure */
    line_def.type = PRO_2D_LINE;
    line_def.end1[0] = sec_point1[0];
    line_def.end1[1] = sec_point1[1];
    line_def.end2[0] = sec_point2[0];
    line_def.end2[1] = sec_point2[1];

    /* Add the entity */
    status = ProSectionEntityAdd( p_sk_data->section, (Pro2dEntdef*)&line_def, 
	&entity_id );
    TEST_CALL_REPORT( "ProSectionEntityAdd","ProTestSectionLineEntityAdd()",
        status, status != PRO_TK_NO_ERROR );


    return status;
}


/*====================================================================*\
FUNCTION :  ProTestSectionRectangleEntityAdd
PURPOSE  :  Add the specified rectangle to the section
\*====================================================================*/
ProError ProTestSectionRectangleEntityAdd(
    SketchingData	*p_sk_data,	/* In: Sketching data */
    ProPoint3d		point1,		/* In: Screen coords of top point*/
    ProPoint3d		point3 )	/* In: Screen coords of bottom point */
{
    ProError            status;
    Pro2dLinedef        line_def;
    int                 entity_id;
    ProPoint3d		point2, point4;
    ProPoint3d          sec_points[ 5 ];
    int			i;
 
 
    point2[0] = point3[0];
    point2[1] = point1[1];
    point2[2] = 0.0;
    point4[0] = point1[0];
    point4[1] = point3[1];
    point4[2] = 0.0;
 
    /* Transform from screen coords to section coords */
    ProPntTrfEval( point1, p_sk_data->trf_matrix, sec_points[0] );
    ProPntTrfEval( point2, p_sk_data->trf_matrix, sec_points[1] );
    ProPntTrfEval( point3, p_sk_data->trf_matrix, sec_points[2] );
    ProPntTrfEval( point4, p_sk_data->trf_matrix, sec_points[3] );
    status = ProPntTrfEval( point1, p_sk_data->trf_matrix, sec_points[4] ); 
    TEST_CALL_REPORT( "ProPntTrfEval","ProTestSectionRectangleEntityAdd()",
        status, status != PRO_TK_NO_ERROR );
 
    for( i=1; i<5; i++ )
    {
    	line_def.type = PRO_2D_LINE;
    	line_def.end1[0] = sec_points[i-1][0];
    	line_def.end1[1] = sec_points[i-1][1];
    	line_def.end2[0] = sec_points[i][0];
    	line_def.end2[1] = sec_points[i][1];

    	/* Add the entity */
    	status = ProSectionEntityAdd( p_sk_data->section, 
		(Pro2dEntdef*)&line_def, &entity_id );
	TEST_CALL_REPORT( "ProSectionEntityAdd",
		"ProTestSectionRectangleEntityAdd()",
		status, status != PRO_TK_NO_ERROR );
    }

 
    return status;
}
 
 

/*====================================================================*\
FUNCTION :  ProTestSectionCircleEntityAdd
PURPOSE  :  Add the specified circle to the section
\*====================================================================*/
ProError ProTestSectionCircleEntityAdd(
    SketchingData       *p_sk_data,     /* In: Sketching data */
    ProPoint3d		center,		/* In: The center point */
    ProPoint3d          circle )	/* In: Circle point */
{
    ProError		status;
    Pro2dCircledef	circle_def;
    int			entity_id;
    ProPoint3d		sec_center;
    ProPoint3d		sec_circle_point;


    /* Transform from screen coords to section coords */
    status = ProPntTrfEval( center, p_sk_data->trf_matrix, sec_center );
    TEST_CALL_REPORT( "ProPntTrfEval","ProTestSectionCircleEntityAdd()", 
        status, status != PRO_TK_NO_ERROR );
    status = ProPntTrfEval( circle, p_sk_data->trf_matrix, sec_circle_point );
    TEST_CALL_REPORT( "ProPntTrfEval","ProTestSectionCircleEntityAdd()", 
        status, status != PRO_TK_NO_ERROR );
 
    /* Init the entity structure */
    circle_def.type = PRO_2D_CIRCLE;
    circle_def.center[0] = sec_center[0];
    circle_def.center[1] = sec_center[1];
    circle_def.radius = ProUtilPointsDist( sec_center, sec_circle_point );

    /* Add the entity */
    status = ProSectionEntityAdd( p_sk_data->section, 
	(Pro2dEntdef*)&circle_def, &entity_id );
    TEST_CALL_REPORT( "ProSectionEntityAdd","ProTestSectionCircleEntityAdd()", 
        status, status != PRO_TK_NO_ERROR );


    return status;
}



/*---------------------------------------------------------------------------*\
    Displaying graphics
 
\*---------------------------------------------------------------------------*/
 
/*====================================================================*\
FUNCTION :  ProTestPointDraw
PURPOSE  :  Draw the point
\*====================================================================*/
ProError ProTestPointDraw(
    ProPoint3d		point,		/* In: Point screen coords */
    ProMatrix		trf_matrix )	/* In: Matrx to convert screen coords
						into model coords (NULL) */
{
    ProColor	old_color;
	ProColor	letter_color;
    ProPoint3d          mdl_point;


    /* Convert screen coords into model coords if necessary */
    if( trf_matrix != NULL )
        ProUtilPointTrans( trf_matrix, point, mdl_point );
    else
        ProUtilVectorCopy( point, mdl_point );

    /* Draw the point */
	letter_color.method = PRO_COLOR_METHOD_TYPE;
	letter_color.value.type = PRO_COLOR_LETTER;
    ProGraphicsColorModify(&letter_color , &old_color );
    ProGraphicsCircleDraw( mdl_point, 0.02 );
    ProGraphicsColorModify( &old_color, NULL );


    return PRO_TK_NO_ERROR;
}



/*====================================================================*\
FUNCTION :  ProTestLineDraw
PURPOSE  :  Draw the line
\*====================================================================*/
ProError ProTestLineDraw(
     ProPoint3d		point1,		/* In: Screen coords of line end point*/
     ProPoint3d		point2,		/* In: Screen coords of line end point*/
     ProMatrix		trf_matrix )	/* In: Matrx to convert screen coords
						into model coords (NULL)*/
{
    ProPoint3d		mdl_point1, mdl_point2;


    /* Convert screen coords into model coords if necessary */
    if( trf_matrix != NULL )
    {
	ProUtilPointTrans( trf_matrix, point1, mdl_point1 );
	ProUtilPointTrans( trf_matrix, point2, mdl_point2 );
    }
    else
    {
	ProUtilVectorCopy( point1, mdl_point1 );
	ProUtilVectorCopy( point2, mdl_point2 );
    }

    /* Draw the line and line end points */
    ProGraphicsPenPosition( mdl_point1 );
    ProGraphicsLineDraw( mdl_point2 );
    ProTestPointDraw( mdl_point1, NULL );
    ProTestPointDraw( mdl_point2, NULL );


    return PRO_TK_NO_ERROR;
}



/*====================================================================*\
FUNCTION :  ProTestRectangleDraw
PURPOSE  :  Draw the rectangle
\*====================================================================*/
ProError ProTestRectangleDraw(
     ProPoint3d         point1,         /* In: Screen coords of top point*/
     ProPoint3d         point3,         /* In: Screen coords of bottom point */
     ProMatrix          trf_matrix )    /* In: Matrx to convert screen coords
                                                into model coords (NULL)*/
{
    ProPoint3d		point2 = {0,0,0};
    ProPoint3d		point4 = {0,0,0};
    ProPoint3d          mdl_point1, mdl_point2, mdl_point3, mdl_point4;
 
 
    point2[0] = point3[0];
    point2[1] = point1[1];
    point2[2] = 0.0;
    point4[0] = point1[0];
    point4[1] = point3[1];
    point4[2] = 0.0;

    /* Convert screen coords into model coords if necessary */
    if( trf_matrix != NULL )
    {
        ProUtilPointTrans( trf_matrix, point1, mdl_point1 );
        ProUtilPointTrans( trf_matrix, point2, mdl_point2 );
        ProUtilPointTrans( trf_matrix, point3, mdl_point3 );
        ProUtilPointTrans( trf_matrix, point4, mdl_point4 );
    }
    else
    {
        ProUtilVectorCopy( point1, mdl_point1 );
        ProUtilVectorCopy( point2, mdl_point2 );
	ProUtilVectorCopy( point3, mdl_point3 );
	ProUtilVectorCopy( point4, mdl_point4 );
    }
 
    /* Draw the rectangle and its end points */
    ProGraphicsPenPosition( mdl_point1 );
    ProGraphicsLineDraw( mdl_point2 );
    ProGraphicsLineDraw( mdl_point3 );
    ProGraphicsLineDraw( mdl_point4 );
    ProGraphicsLineDraw( mdl_point1 );
    ProTestPointDraw( mdl_point1, NULL );
    ProTestPointDraw( mdl_point2, NULL );
    ProTestPointDraw( mdl_point3, NULL );
    ProTestPointDraw( mdl_point4, NULL );
 
 
    return PRO_TK_NO_ERROR;
}



/*====================================================================*\
FUNCTION :  ProTestCircleDraw
PURPOSE  :  Draw the circle
\*====================================================================*/
ProError ProTestCircleDraw( 
    ProPoint3d		center,		/* In: Screen coords of center point */
    ProPoint3d		circle,		/* In: Screen coords of circle point */
    ProMatrix		trf_matrix )	/* In: Matrx to convert screen coords
						into model coords (NULL) */
{
    ProPoint3d		mdl_center;
    ProPoint3d		mdl_circle;
    double		radius;


    /* Convert screen coords into model coords if necessary */
    if( trf_matrix != NULL )
    {
	ProUtilPointTrans( trf_matrix, center, mdl_center );
	ProUtilPointTrans( trf_matrix, circle, mdl_circle );
    }
    else
    {
	ProUtilVectorCopy( center, mdl_center );
	ProUtilVectorCopy( circle, mdl_circle );
    }

    radius = ProUtilPointsDist( mdl_center, mdl_circle );

    ProGraphicsCircleDraw( mdl_center, radius );


    return PRO_TK_NO_ERROR;
}



/*====================================================================*\
FUNCTION :  ProTestNewSectionNameGet
PURPOSE  :  Generate the name of the next new section 
\*====================================================================*/
wchar_t *ProTestNewSectionNameGet(
    ProName		w_name )	/* Out: Name of the new section.
						User must allocate w_name */
{
    static int		counter = 0;
    ProCharName		name;


    ProTKSprintf( name, (char *)"TKSECTION%04d", counter++ );
    ProStringToWstring( w_name, name );


    return w_name;
}



/*====================================================================*\
FUNCTION :  ProTestProtrusionFeatureCreate
PURPOSE  :  Initialize element tree and create extruded protrusion feature
\*====================================================================*/
ProError ProTestProtrusionFeatureCreate(
    ProSecViewDirType	view_direction,	/* In: Feature direction */
    ProSelection	sk_plane_sel,	/* In: The sketching plane selection */
    int			ref_type, 	/* In: The reference plane type 
						(TOP, ...) */ 
    ProSelection	ref_plane_sel,	/* In: The reference plane selection */
    ProSection		section,	/* In: The sketched section */
    ProSelection        *p_references,	/* In: The sketching references */
    DepthData		*p_depth,	/* In: Initialized depth data */
    ProFeature		*p_feature )	/* Out: Created feature */
{
    ProMdl		model;
    ProModelitem	model_item;
    ProSelection	model_sel;
    ProError		status;
    ProElement		elem_tree;
    ProFeatureCreateOptions *options = 0;
    ProErrorlist	err_list;


    static ElemTreeData tree[]={
        {0, PRO_E_FEATURE_TREE, {PRO_VALUE_TYPE_INT, PRO_VALUE_UNUSED}},
        {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}},

	    /* Section */
            {1, PRO_E_STD_SECTION,  {PRO_VALUE_TYPE_INT, PRO_VALUE_UNUSED}},
                    {2, PRO_E_STD_SEC_SETUP_PLANE, {PRO_VALUE_TYPE_INT, PRO_VALUE_UNUSED}},
                        {3, PRO_E_STD_SEC_PLANE, 
			    {PRO_VALUE_TYPE_SELECTION}},
                        {3, PRO_E_STD_SEC_PLANE_VIEW_DIR, 
			    {PRO_VALUE_TYPE_INT}},
                        {3, PRO_E_STD_SEC_PLANE_ORIENT_DIR, 
			    {PRO_VALUE_TYPE_INT}},
                        {3, PRO_E_STD_SEC_PLANE_ORIENT_REF, 
			    {PRO_VALUE_TYPE_SELECTION}},

	    /* Extrusion depth */
            {1, PRO_E_STD_EXT_DEPTH, {PRO_VALUE_TYPE_INT, PRO_VALUE_UNUSED}},
                {2, PRO_E_EXT_DEPTH_FROM, {PRO_VALUE_TYPE_INT, PRO_VALUE_UNUSED}},
                    {3, PRO_E_EXT_DEPTH_FROM_TYPE, 
			{PRO_VALUE_TYPE_INT}},
                    {3, PRO_E_EXT_DEPTH_FROM_VALUE, 
			{PRO_VALUE_TYPE_DOUBLE}},
		    {3, PRO_E_EXT_DEPTH_FROM_REF,
			{PRO_VALUE_TYPE_SELECTION}},
                {2, PRO_E_EXT_DEPTH_TO, {PRO_VALUE_TYPE_INT, PRO_VALUE_UNUSED}},
                    {3, PRO_E_EXT_DEPTH_TO_TYPE, 
			{PRO_VALUE_TYPE_INT,PRO_EXT_DEPTH_TO_NONE} },
		    {3, PRO_E_EXT_DEPTH_TO_VALUE, 
                        {PRO_VALUE_TYPE_DOUBLE}},
		    {3, PRO_E_EXT_DEPTH_TO_REF,
                        {PRO_VALUE_TYPE_SELECTION}}
    };


    /*-------------------------------------------------*\
	Complete section elements initialization
    \*-------------------------------------------------*/
    tree[7].data.v.r = sk_plane_sel;
    tree[8].data.v.i = view_direction;
    tree[10].data.v.r = ref_plane_sel;

    /*-------------------------------------------------*\
	Init orientation direction value
    \*-------------------------------------------------*/
    switch( ref_type )
    {
        case SK_REF_TOP:
            tree[9].data.v.i = PRO_SEC_ORIENT_DIR_UP;
            break;
 
        case SK_REF_BOTTOM:
            tree[9].data.v.i = PRO_SEC_ORIENT_DIR_DOWN;
            break;
 
        case SK_REF_RIGHT:
            tree[9].data.v.i = PRO_SEC_ORIENT_DIR_RIGHT;
            break;
 
        case SK_REF_LEFT:
            tree[9].data.v.i = PRO_SEC_ORIENT_DIR_LEFT;
            break;

	default:
	    return PRO_TK_NO_ERROR;
    }

    /*-------------------------------------------------*\
        Set PRO_E_EXT_DEPTH_FROM elements
    \*-------------------------------------------------*/
    switch( p_depth->from_type )
    {
        case DEPTH_TYPE_BLIND:  /* symmetric blind */
	case DEPTH_TYPE_2SIDEBLIND:
	    tree[13].data.v.i = PRO_EXT_DEPTH_FROM_BLIND;
	    tree[14].data.v.d = p_depth->from_value.v.d;
	    break;

	case DEPTH_TYPE_THRU_NEXT:
	    tree[13].data.v.i = PRO_EXT_DEPTH_FROM_NEXT;
	    break;

	case DEPTH_TYPE_THRU_ALL:
	    tree[13].data.v.i = PRO_EXT_DEPTH_FROM_ALL;
	    break;

	case DEPTH_TYPE_THRU_UNTIL:
	    tree[13].data.v.i = PRO_EXT_DEPTH_FROM_UNTIL;
	    ProSelectionCopy( p_depth->from_value.v.r, &(tree[15].data.v.r) );
	    break;

	case DEPTH_TYPE_UPTO_PNT:
	case DEPTH_TYPE_UPTO_CURVE:
	case DEPTH_TYPE_UPTO_SURFACE:
	    tree[13].data.v.i = PRO_EXT_DEPTH_FROM_REF;
	    ProSelectionCopy( p_depth->from_value.v.r, &(tree[15].data.v.r) );
	    break;
      
	default:
	    tree[13].data.v.i = PRO_EXT_DEPTH_FROM_NONE;
    }

    /*-------------------------------------------------*\
        Set PRO_E_EXT_DEPTH_TO elements
    \*-------------------------------------------------*/
    switch( p_depth->to_type )
    {
        case DEPTH_TYPE_BLIND:
	  if (p_depth->from_type == DEPTH_TYPE_BLIND)
	    {
	      tree[17].data.v.i = PRO_EXT_DEPTH_SYMMETRIC;
	    }
	  else
	    {
	      tree[17].data.v.i = PRO_EXT_DEPTH_TO_BLIND;
	      tree[18].data.v.d = p_depth->to_value.v.d;
	    }
	  break;


        case DEPTH_TYPE_2SIDEBLIND:
            tree[17].data.v.i = PRO_EXT_DEPTH_TO_BLIND;
            tree[18].data.v.d = p_depth->to_value.v.d;
            break;
 
        case DEPTH_TYPE_THRU_NEXT:
            tree[17].data.v.i = PRO_EXT_DEPTH_TO_NEXT;
            break;
 
        case DEPTH_TYPE_THRU_ALL:
            tree[17].data.v.i = PRO_EXT_DEPTH_TO_ALL;
            break;
 
        case DEPTH_TYPE_THRU_UNTIL:
            tree[17].data.v.i = PRO_EXT_DEPTH_TO_UNTIL;
            ProSelectionCopy( p_depth->to_value.v.r, &(tree[19].data.v.r) );
            break;
 
        case DEPTH_TYPE_UPTO_PNT:
        case DEPTH_TYPE_UPTO_CURVE:
        case DEPTH_TYPE_UPTO_SURFACE:
            tree[17].data.v.i = PRO_EXT_DEPTH_TO_REF;
            ProSelectionCopy( p_depth->to_value.v.r, &(tree[19].data.v.r) );
            break;
 
        default:
            tree[17].data.v.i = PRO_EXT_DEPTH_TO_NONE;
    }


    /*-------------------------------------------------*\
	Create element tree 
    \*-------------------------------------------------*/
    status = ProUtilElemtreeCreate( tree, SIZEOFARR(tree), NULL, &elem_tree );
    if( status != PRO_TK_NO_ERROR )
	return status;

    /*-------------------------------------------------*\
	Create selection structure for current model
    \*-------------------------------------------------*/
    status = ProMdlCurrentGet( &model );
    TEST_CALL_REPORT( "ProMdlCurrentGet","ProTestProtrusionFeatureCreate()",
        status, status != PRO_TK_NO_ERROR );
    status = ProMdlToModelitem( model, &model_item );
    TEST_CALL_REPORT( "ProMdlToModelitem","ProTestProtrusionFeatureCreate()",
        status, status != PRO_TK_NO_ERROR );
    status = ProSelectionAlloc( NULL, &model_item, &model_sel );
    TEST_CALL_REPORT( "ProSelectionAlloc","ProTestProtrusionFeatureCreate()",
        status, status != PRO_TK_NO_ERROR );

    /*-------------------------------------------------*\
	Create the incomplete feature
    \*-------------------------------------------------*/
    status = ProArrayAlloc(1,sizeof(ProFeatureCreateOptions),
        1, (ProArray*)&options);

    options[0]= PRO_FEAT_CR_INCOMPLETE_FEAT;

    status = ProFeatureWithoptionsCreate( model_sel, elem_tree,
        options, PRO_REGEN_NO_FLAGS, p_feature, &err_list );
    TEST_CALL_REPORT( "ProFeatureWithoptionsCreate","ProTestProtrusionFeatureCreate()",
        status, status != PRO_TK_NO_ERROR );

    status = ProArrayFree((ProArray*)&options);

    /*-------------------------------------------------*\
	Release element tree
    \*-------------------------------------------------*/
    status = ProElementFree( &elem_tree );
    TEST_CALL_REPORT( "ProElementFree","ProTestProtrusionFeatureCreate()",
        status, status != PRO_TK_NO_ERROR );

    /*-------------------------------------------------*\
	Complete the feature adding the sketched section
    \*-------------------------------------------------*/
    status = ProTestFeatureSectionInit( p_feature, section, p_references, PRO_B_FALSE );


    return status;
}



/*
    Complete PRO_E_SKETCHER element with section and references.
*/
ProError ProTestFeatureSectionInit(
    ProFeature		*p_feature,	/* In: Incomplete feature */
    ProSection		section,	/* In: Sketched section */
    ProSelection	*p_references,  /* In: Sketching refs (NULL) */
    ProBoolean          is_first)	/* In: If first feature or not */
{
    ProError		status;
    /*
    ProFeatureCreateOptions	redefine_options[] = { PRO_FEAT_CR_NO_OPTS };
    */
    ProFeatureCreateOptions *redefine_options = 0;
    ProElement		elem_tree;
    ProElement		sketcher_elem;
    ProValue		sketcher_elem_value, new_value;
    ProValueData	value_data;
    ProMatrix		location_matrix;
    ProMatrix		inv_matrix;
    ProVector		tran_vector = {0,0,0};
    ProErrorlist        err_list;

    int win_id;

    static ProElempathItem	sketcher_elempath[] = {
	{ PRO_ELEM_PATH_ITEM_TYPE_ID, {PRO_E_STD_SECTION} },
	{ PRO_ELEM_PATH_ITEM_TYPE_ID, {PRO_E_SKETCHER} } };
    static ProElempathItem	sketcher_elempath_first[] = {
	{ PRO_ELEM_PATH_ITEM_TYPE_ID, {PRO_E_SKETCHER} } };
    


    /* Get the element tree of newly created feature to init PRO_E_SKETCHER */
    status = ProFeatureElemtreeExtract( p_feature, NULL, PRO_FEAT_EXTRACT_NO_OPTS, &elem_tree );
    TEST_CALL_REPORT( "ProFeatureElemtreeExtract","ProTestFeatureSectionInit()",
        status, status != PRO_TK_NO_ERROR );
    if( status != PRO_TK_NO_ERROR )
	return status;
 
    if (is_first)
      {

	/* Find PRO_E_SKETCHER element in element tree */
	ProUtilElemtreeElementGet( elem_tree, sketcher_elempath_first, 1,
				   &sketcher_elem );
	
	status = ProElementSpecialvalueGet( sketcher_elem, NULL, (ProAppData*)&section );
	TEST_CALL_REPORT( "ProElementSpecialvalueGet","ProTestFeatureSectionInit()",
			  status, status != PRO_TK_NO_ERROR );
	
	/* Following call will Autodim & Regenerate the section */ 
	ProTestSectionRegenerate (section);

	status = ProElementSpecialvalueSet( sketcher_elem, (ProAppData)section );
	TEST_CALL_REPORT( "ProElementSpecialvalueSet","ProTestFeatureSectionInit()",
			  status, status != PRO_TK_NO_ERROR );

     }

    else
      {
	ProSection cur_sec;
	/* Find PRO_E_SKETCHER element in element tree */
	ProUtilElemtreeElementGet( elem_tree, sketcher_elempath, 2,
				   &sketcher_elem );
	status = ProElementSpecialvalueGet( sketcher_elem, NULL, (ProAppData*)&cur_sec );
	TEST_CALL_REPORT( "ProElementSpecialvalueGet","ProTestFeatureSectionInit()",
			  status, status != PRO_TK_NO_ERROR );
 
	/* Calc translation vector */ 
	status = ProSectionLocationGet( cur_sec, location_matrix );
	TEST_CALL_REPORT( "ProSectionLocationGet","ProTestFeatureSectionInit()",
			  status, status != PRO_TK_NO_ERROR );
	ProUtilMatrixInvert( location_matrix, inv_matrix );
	ProUtilVectorCopy( inv_matrix[3], tran_vector );
     
	/* Copy sketched section into elem tree usin translation vector */
	status = ProUtilSectionInfoCopy( section, cur_sec, tran_vector );
 
	/* Add sketching referencies, dimension and regenerate the section */
	if( p_references != NULL )
	  status = ProTestFeatureSectionRefsAdd(cur_sec, p_references );


	status = ProTestSectionRegenerate( cur_sec );

      }

    /* Redefine the feature with complete elem tree */
    status = ProArrayAlloc(1,sizeof(ProFeatureCreateOptions),
        1, (ProArray*)&redefine_options);

    redefine_options[0]= PRO_FEAT_CR_DEFINE_MISS_ELEMS;

    status = ProFeatureWithoptionsRedefine( NULL, p_feature, elem_tree,
        redefine_options, PRO_REGEN_NO_FLAGS, &err_list );
    TEST_CALL_REPORT( "ProFeatureWithoptionsRedefine","ProTestFeatureSectionInit()",
        status, status != PRO_TK_NO_ERROR );

    status = ProArrayFree((ProArray*)&redefine_options);

    /* Fit the nodel within the viewing window */
    status = ProWindowCurrentGet(&win_id);
    TEST_CALL_REPORT( "ProWindowCurrentGet","ProTestFeatureSectionInit()",
        status, status != PRO_TK_NO_ERROR );

    status = ProWindowRefit(win_id);
    TEST_CALL_REPORT( "ProWindowRefit","ProTestFeatureSectionInit()",
        status, status != PRO_TK_NO_ERROR );

    /* Release element tree */
    ProFeatureElemtreeFree( p_feature,elem_tree );

    return status;
}
    


/*
    Add references to the feature section.
*/
ProError ProTestFeatureSectionRefsAdd(
    ProSection		section,	/* In: The section */
    ProSelection	*p_references )	/* In: The selected refs */
{
    ProError		status;
    int			n_refs = 0;
    int			entity_id;
    int			i;


    /* Get the number of references */
    status = ProArraySizeGet( (ProArray)p_references, &n_refs );
    TEST_CALL_REPORT( "ProArraySizeGet","ProTestFeatureSectionRefsAdd()",
        status, status != PRO_TK_NO_ERROR );

    /* Add references to the section */
    for( i=0; i<n_refs; i++ )
    {
	status = ProSectionEntityFromProjection( section, p_references[i], 
		&entity_id );
	TEST_CALL_REPORT( "ProSectionEntityFromProjection",
	    "ProTestFeatureSectionRefsAdd()", 
	    status, status != PRO_TK_NO_ERROR );
	if( status != PRO_TK_NO_ERROR )
	    return status;
    }


    return PRO_TK_NO_ERROR;
}



/*
    Autodim and regenerate the section.
*/
ProError ProTestSectionRegenerate(
    ProSection		section )
{
    ProError            status;
    ProWSecerror        sec_errors;


    status = ProSectionEpsilonSet( section, 0.1 );
    TEST_CALL_REPORT( "ProSectionEpsilonSet","ProTestSectionRegenerate()",
        status, status != PRO_TK_NO_ERROR );
 
    /* Allocate the error list */
    status = ProSecerrorAlloc( &sec_errors );
    TEST_CALL_REPORT( "ProSecerrorAlloc","ProTestSectionRegenerate()",
        status, status != PRO_TK_NO_ERROR );
 
    /* Add all the missing dimensions */
    status = ProSectionAutodim( section, &sec_errors );
    TEST_CALL_REPORT( "ProSectionAutodim","ProTestSectionRegenerate()",
        status, status != PRO_TK_NO_ERROR );
    if( status == PRO_TK_NO_ERROR )
    {
        /* Regenerate the section */
        status = ProSectionRegenerate( section, &sec_errors );
        TEST_CALL_REPORT( "ProSectionRegenerate",
            "ProTestSectionRegenerate()",
            status, status != PRO_TK_NO_ERROR );
    }
 
    /* Release the error list */
    ProSecerrorFree( &sec_errors );
 
 
    return status;
}



/*
    Initialize depth values for both feature sides
*/
ProError ProTestFeatureDepthRetrieve(
    ProSides		sides,		/* In: ONE_SIDE or
						BOTH_SIDES */
    ProSecViewDirType	direction,	/* In: Feature direction */
    ProSurface		sk_plane,	/* In: Sketching plane */

    DepthData		*p_depth )	/* Out: Initialized depth data.  
					If ONE_SIDE, init only p_depth->to_*, 
					setting from_type to DEPTH_TYPE_NONE */
{
    ProError			status;
    DirectionArrow		dir_arrow;


    /*-----------------------------------------*\
	Init values for ONE_SIDE
    \*-----------------------------------------*/
    if( sides == PRO_SIDES_ONE_SIDE )
    {
        status = ProTestFeatureDepthValueInit( sides, PRO_B_FALSE,
            (int *)&(p_depth->to_type), &(p_depth->to_value) );

	p_depth->from_type = (ProExtDepthFromType)DEPTH_TYPE_NONE;
    }


    /*-----------------------------------------*\
	Init values for BOTH_SIDES 
    \*-----------------------------------------*/
    if( sides == PRO_SIDES_BOTH_SIDES )
    {
	/* Create and display the direction arrow */
	ProTestDirectionArrowCreate( sk_plane, direction, &dir_arrow );

	/* Init TO type & value */
	status = ProTestFeatureDepthValueInit( sides, PRO_B_FALSE,
                (int *)&(p_depth->to_type), &(p_depth->to_value) );
	
	if( status != PRO_TK_NO_ERROR )
	  {
	    ProTestDirectionArrowDelete( &dir_arrow );
	    return status;
	  }
	
        if( p_depth->to_type == DEPTH_TYPE_BLIND )
	  {
	    p_depth->from_type = (ProExtDepthFromType)DEPTH_TYPE_BLIND;  /* Symmetric */
	    p_depth->from_value.type = PRO_VALUE_TYPE_DOUBLE;
	    p_depth->from_value.v.d = p_depth->to_value.v.d;
	  }
        else if( p_depth->to_type == DEPTH_TYPE_2SIDEBLIND )
	  {
            p_depth->from_type = (ProExtDepthFromType)DEPTH_TYPE_2SIDEBLIND;
            p_depth->from_value.type = PRO_VALUE_TYPE_DOUBLE;
            p_depth->from_value.v.d = ProTestDoubleValueGet( 3.0 );
	  }
        else
	  {
	    /* Flip direction arrow */
            ProTestDirectionArrowFlip( &dir_arrow, -1 );
	    
            status = ProTestFeatureDepthValueInit(sides, PRO_B_TRUE,
						   (int *)&(p_depth->from_type), &(p_depth->from_value) );
	  }

	ProTestDirectionArrowDelete( &dir_arrow );
    }


    return status;
}



/*
    Use menu to select depth type. 
    p_depth_value will contain:
	double value  - for DEPTH_TYPE_BLIND, DEPTH_TYPE_2SIDEBLIND
	selection     - for DEPTH_TYPE_THRU_UNTIL, DEPTH_TYPE_UPTO_PNT,
			DEPTH_TYPE_UPTO_CURVE, DEPTH_TYPE_UPTO_SURFACE
	nothing       - for DEPTH_TYPE_THRU_NEXT, DEPTH_TYPE_THRU_ALL
*/
ProError ProTestFeatureDepthValueInit(
    ProSides            sides,
    ProBoolean		is_second_side,	/* In: TRUE if for 2nd side depth 
						initialization. In this case
						"Blind" and "2 Side Blind"
						buttons are disabled */
    int			*p_depth_type,
    ProValueData	*p_depth_value )
{
    ProError		status;
    int			depth_type;
    char		*p_option = NULL;
    ProSelection	*p_sel;
    int			n_sel = 0;


    ProUtilMsgPrint( msgfil, (char *)"USER Specify feature depth" );
    /* Display the menu to select depth type */
    status = ProTestFeatureDepthTypeGet( sides, is_second_side, &depth_type );
    if( status != PRO_TK_NO_ERROR )
        return status;

/*----------------------------------------------------
Note:
The default case is added to avoid the unexpected behaviour ,if the user 
enter DONE without giving the value of the DEPTH.
----------------------------------------------------*/
 
    switch( depth_type )
    {
        case DEPTH_TYPE_BLIND:
            p_depth_value->type = PRO_VALUE_TYPE_DOUBLE;
            p_depth_value->v.d = ProTestDoubleValueGet( 3.0 );
            break;
 
        case DEPTH_TYPE_2SIDEBLIND:
            p_depth_value->type = PRO_VALUE_TYPE_DOUBLE;
            p_depth_value->v.d = ProTestDoubleValueGet( 3.0 );
            break;
	
	case DEPTH_TYPE_THRU_NEXT:
	    break;

	case DEPTH_TYPE_THRU_ALL:
	    break;

        case DEPTH_TYPE_THRU_UNTIL:
            ProUtilMsgPrint( msgfil,
                (char *)"USER Select a surface to extrude until" );
	    p_option = (char *)"surface,sldface,qltface,datum";
	    break;

	case DEPTH_TYPE_UPTO_PNT:
	    ProUtilMsgPrint( msgfil,
		(char *)"USER Select a datum point or a vertex to extrude up to" );
	    p_option = (char *)"point,edge_end,curve_end";
	    break;

	case DEPTH_TYPE_UPTO_CURVE:
	    ProUtilMsgPrint( msgfil,
		(char *)"USER Select an axis to extrude up to" );
	    p_option = (char *)"axis,edge,curve,sldedge,qltedge";
	    break;

	case DEPTH_TYPE_UPTO_SURFACE:
	    ProUtilMsgPrint( msgfil,
		(char *)"USER Select a surface to extrude up to" );
	    p_option = (char *)"surface,sldface,qltface,datum";
	    break;

         default:
	    return (PRO_TK_GENERAL_ERROR);
    }


    if( p_option != NULL )
    {
        n_sel = 0;
        status = ProSelect( p_option, 1, NULL, NULL, NULL, NULL, 
	    &p_sel, &n_sel );
    	TEST_CALL_REPORT( "ProSelect","ProTestFeatureDepthValueInit()",
            status, status != PRO_TK_NO_ERROR );
        if( status != PRO_TK_NO_ERROR || n_sel < 1 )
	    return PRO_TK_GENERAL_ERROR;

        p_depth_value->type = PRO_VALUE_TYPE_SELECTION;
        status = ProSelectionCopy( *p_sel, &(p_depth_value->v.r) );
	TEST_CALL_REPORT( "ProSelectionCopy","ProTestFeatureDepthValueInit()",
	    status, status != PRO_TK_NO_ERROR );
    }

    *p_depth_type = depth_type;


    return PRO_TK_NO_ERROR;
}



/*
    Display the menu to select depth type
*/
ProError ProTestFeatureDepthTypeGet(
    ProSides		sides,
    ProBoolean          is_second_side, /* In: TRUE for 2nd side depth 
                                                initialization. In this case
                                                "Blind" and "2 Side Blind"
                                                buttons are disabled */
    int			*p_depth_type )	/* Out: Depth type */
{
    ProError            status;
    int                 menu_id;
    int                 action;
    static char         *p_enus[] = { (char *)"TK SPEC TO", (char *)"DONE QUIT", (char *)"" };
    int			depth_type;

    /*-------------------------------------------*\
        Choose depth type 
    \*-------------------------------------------*/
    ProMenuFileRegister( (char *)"TK SPEC TO", (char *)"tkdepth.mnu", &menu_id );
    ProMenubuttonActionSet( (char *)"TK SPEC TO", (char *)"Blind",
        (ProMenubuttonAction)ProTestFeatureDepthTypeSet,
        (ProAppData)&depth_type, DEPTH_TYPE_BLIND );
    ProMenubuttonActionSet( (char *)"TK SPEC TO", (char *)"2 Side Blind",
        (ProMenubuttonAction)ProTestFeatureDepthTypeSet,
        (ProAppData)&depth_type, DEPTH_TYPE_2SIDEBLIND );
    ProMenubuttonActionSet( (char *)"TK SPEC TO", (char *)"Thru Next",
        (ProMenubuttonAction)ProTestFeatureDepthTypeSet,
        (ProAppData)&depth_type, DEPTH_TYPE_THRU_NEXT );
    ProMenubuttonActionSet( (char *)"TK SPEC TO", (char *)"Thru All",
        (ProMenubuttonAction)ProTestFeatureDepthTypeSet,
        (ProAppData)&depth_type, DEPTH_TYPE_THRU_ALL );
    ProMenubuttonActionSet( (char *)"TK SPEC TO", (char *)"Thru Until",
        (ProMenubuttonAction)ProTestFeatureDepthTypeSet,
        (ProAppData)&depth_type, DEPTH_TYPE_THRU_UNTIL );
    ProMenubuttonActionSet( (char *)"TK SPEC TO", (char *)"UpTo Pnt/Vtx",
        (ProMenubuttonAction)ProTestFeatureDepthTypeSet,
        (ProAppData)&depth_type, DEPTH_TYPE_UPTO_PNT );
    ProMenubuttonActionSet( (char *)"TK SPEC TO", (char *)"UpTo Curve",
        (ProMenubuttonAction)ProTestFeatureDepthTypeSet,
        (ProAppData)&depth_type, DEPTH_TYPE_UPTO_CURVE );
    ProMenubuttonActionSet( (char *)"TK SPEC TO", (char *)"UpTo Surface",
        (ProMenubuttonAction)ProTestFeatureDepthTypeSet,
        (ProAppData)&depth_type, DEPTH_TYPE_UPTO_SURFACE );
    ProMenubuttonActionSet( (char *)"TK SPEC TO", (char *)"TK SPEC TO",
        (ProMenubuttonAction)ProTestFeatureDepthTypeSet,
        (ProAppData)&depth_type, DEPTH_TYPE_QUIT );
 
    ProMenuFileRegister( (char *)"DONE QUIT", (char *)"tkdonequit.mnu", &menu_id );
    ProMenubuttonActionSet( (char *)"DONE QUIT", (char *)"-Done",
        (ProMenubuttonAction)ProTestFeatureDepthTypeSet,
        (ProAppData)&depth_type, DEPTH_TYPE_DONE );
    ProMenubuttonActionSet( (char *)"DONE QUIT", (char *)"-Quit",
        (ProMenubuttonAction)ProTestFeatureDepthTypeSet,
        (ProAppData)&depth_type, DEPTH_TYPE_QUIT );
    ProMenubuttonActionSet( (char *)"DONE QUIT", (char *)"DONE QUIT",
        (ProMenubuttonAction)ProTestFeatureDepthTypeSet,
        (ProAppData)&depth_type, DEPTH_TYPE_QUIT );
 

    action = DEPTH_TYPE_QUIT;
    status = ProCompoundmenuCreate( p_enus,  &menu_id );

    if( status == PRO_TK_NO_ERROR )
    {
	if(sides == PRO_SIDES_ONE_SIDE || is_second_side == PRO_B_TRUE )
	{
	    ProMenubuttonDeactivate( (char *)"TK SPEC TO", (char *)"2 Side Blind" );
	}
	else
	{
	    ProMenubuttonActivate( (char *)"TK SPEC TO", (char *)"2 Side Blind" );
	}
        ProMenuProcess( (char *)"TK SPEC TO", &action );
    }

    if( action == DEPTH_TYPE_DONE )
    {
	status = PRO_TK_NO_ERROR;
	*p_depth_type = depth_type;
    }
    else
    {
	status = PRO_TK_USER_ABORT;
    }


    return status;
}



int ProTestFeatureDepthTypeSet(
    int			*p_depth_type,
    int			depth_type )
{
    /*-------------------------------------------*\
        Check for exiting
    \*-------------------------------------------*/
    if( depth_type == DEPTH_TYPE_DONE || depth_type == DEPTH_TYPE_QUIT )
    {
        ProMenuDeleteWithStatus( depth_type );
        ProMenuDeleteWithStatus( depth_type );
	return 0;
    }

    *p_depth_type = depth_type;


    return 0;
}



/*
    Get the double 
*/
double ProTestDoubleValueGet( 
    double		def )	/* In: Default value */
{
    ProError		status;
    double		double_value;

    do
    {
        ProUtilMsgPrint( msgfil, (char *)"USER Enter depth %0f", &def );
        status = ProMessageDoubleRead( NULL, &double_value );
        TEST_CALL_REPORT( "ProMessageDoubleRead","ProTestDoubleValueGet()",
            status, status != PRO_TK_NO_ERROR );

    } while( status == PRO_TK_MSG_USER_QUIT );
 
    if( status != PRO_TK_NO_ERROR )
        double_value = def;


    return double_value;
}



/*
    Create the first feature 
*/
ProError ProTestFirstFeatureCreate(
    ProMdl		model )		/* The model */
{
    ProError		status;
    ProElement		elem_tree;
    ProSection		section;
    ProSelection	model_sel;
    ProModelitem	model_item;
    ProFeature		feature;
    ProErrorlist        err_list;
 
    ProFeatureCreateOptions *options = 0;
    static ElemTreeData tree[]={
        {0, PRO_E_FEATURE_TREE, {PRO_VALUE_TYPE_INT, PRO_VALUE_UNUSED}},
	{1, PRO_E_FEATURE_TYPE, {PRO_VALUE_TYPE_INT, PRO_FEAT_FIRST_FEAT}},
	{1, PRO_E_FEATURE_FORM, {PRO_VALUE_TYPE_INT, PRO_EXTRUDE}},

	/* Extrusion depth */
	{1, PRO_E_STD_EXT_DEPTH, {PRO_VALUE_TYPE_INT, PRO_VALUE_UNUSED}},
	{2, PRO_E_EXT_DEPTH_FROM, {PRO_VALUE_TYPE_INT, PRO_VALUE_UNUSED}},
	{3, PRO_E_EXT_DEPTH_FROM_VALUE,
	 {PRO_VALUE_TYPE_DOUBLE}}
    };


    /*-------------------------------------------------*\
    	Sketch the section 
    \*-------------------------------------------------*/
    status = ProTestSectionSketcher( NULL, &section, NULL );
    if( status != PRO_TK_NO_ERROR )
	return status;

    /*-------------------------------------------------*\
    	Set feature depth
    \*-------------------------------------------------*/
    tree[5].data.v.d = ProTestDoubleValueGet( 3.0 );

    /*-------------------------------------------------*\
        Create element tree
    \*-------------------------------------------------*/
    status = ProUtilElemtreeCreate( tree, SIZEOFARR(tree), NULL, &elem_tree );
    if( status != PRO_TK_NO_ERROR )
        return status;
 
    /*-------------------------------------------------*\
        Create selection structure for current model
    \*-------------------------------------------------*/
    status = ProMdlToModelitem( model, &model_item );
    TEST_CALL_REPORT( "ProMdlToModelitem","ProTestFirstFeatureCreate()",
        status, status != PRO_TK_NO_ERROR );
    status = ProSelectionAlloc( NULL, &model_item, &model_sel );
    TEST_CALL_REPORT( "ProSelectionAlloc","ProTestFirstFeatureCreate()",
        status, status != PRO_TK_NO_ERROR );
 
    /*-------------------------------------------------*\
        Create the incomplete feature
    \*-------------------------------------------------*/
    /*
  status = ProFeatureCreate( model_sel, elem_tree, options,
        0, &feature, &err_list );
  */
    status = ProArrayAlloc(1,sizeof(ProFeatureCreateOptions),
        1, (ProArray*)&options);

    options[0]= PRO_FEAT_CR_INCOMPLETE_FEAT;

  status = ProFeatureWithoptionsCreate( model_sel, elem_tree,
        options, PRO_REGEN_NO_FLAGS, &feature, &err_list );
  
    TEST_CALL_REPORT( "ProFeatureWithoptionsCreate","ProTestFirstFeatureCreate()",
        status, status != PRO_TK_NO_ERROR );

    status = ProArrayFree((ProArray*)&options);
 
    /*-------------------------------------------------*\
        Release element tree
    \*-------------------------------------------------*/
    status = ProElementFree( &elem_tree );
    TEST_CALL_REPORT( "ProElementFree","ProTestFirstFeatureCreate()",
        status, status != PRO_TK_NO_ERROR );
 
    /*-------------------------------------------------*\
        Complete the feature adding the sketched section
    \*-------------------------------------------------*/
    
    status = ProTestFeatureSectionInit( &feature, section, NULL, PRO_B_TRUE );
    
    return status;
    
}