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


/*--------------------------------------------------------------------*\
Pro/TOOLKIT includes
\*--------------------------------------------------------------------*/
#include <ProToolkit.h>
#include <ProSolid.h>
#include <ProModelitem.h>
#include <ProObjects.h>
#include <ProMdl.h>
#include <ProAxis.h>
#include <ProGeomitem.h>
#include <ProSurface.h>
#include <ProQuilt.h>
#include <ProEdge.h>
#include <ProFeature.h>
#include <ProFeatType.h>
#include <ProCurve.h>
#include <ProSelection.h>
#include <ProPoint.h>
#include <ProCsys.h>
#include <ProContour.h>
#include <ProAsmcomp.h>
#include <ProMenu.h>
#include <ProMessage.h>
#include <ProUtil.h>


/*--------------------------------------------------------------------*\
C System includes
\*--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*\
Application includes
\*--------------------------------------------------------------------*/
#include <TestError.h>
#include <TestFiletypes.h>
#include <UtilFiles.h>
#include <UtilColor.h>
#include <UtilGeom.h>
#include <UtilMath.h>
#include <UtilMatrix.h>
#include <UtilMessage.h>
#include <UtilNames.h>
#include <UtilString.h>
#include <UtilTypes.h>
#include <UtilVisit.h>
#include <UtilCollect.h>

#include "TestError.h"
#include "TestGeom.h"

#include <PTApplsUnicodeUtils.h>
#include <ProTKRunTime.h>

/*--------------------------------------------------------------------*\
Application macros
\*--------------------------------------------------------------------*/
#define TRAVERSE	1
#define TEST_MESH	2
#define TESSELLATE	3

#define SURFAREA_TXT    "gen_msg.txt"
#define QCR_NAME        "sce_geom.inf"

#define TEST_CONT_AREA  1
#define TEST_CONT_BOX   2
#define TEST_CONT_PNT   3
#define TEST_CONT_CURV  4
#define TEST_CURV_LEN   5
#define TEST_CURV_PAR   6
#define TEST_PNT_ONSURF 7
#define TEST_SURF_SAME  8

/*--------------------------------------------------------------------*\
Application prototypes
\*--------------------------------------------------------------------*/
ProError ProTestCurveAct( ProModelitem* , ProError, ProAppData);
int ProTestGeomTraverse(ProMdl *, int);

ProError ProUtilContourSelect (
    ProSurface surface,
    ProContour *p_contour);

ProError ProTestContourHighlight (
    ProMdl model,
    ProAsmcomppath *p_asmcomp_path,
    ProSurface surface,
    ProContour contour,
    ProBoolean flag);

/*====================================================================*\
    FUNCTION :	ProTestGeometry()
    PURPOSE  :	Commands for testing geometry in Pro/TOOLKIT
\*====================================================================*/
int ProTestGeometry(
    ProMdl *model)
{
    int ProTestGeomShape();
    int ProTestGeomMindist();
    int ProTestGeometryAtPoint();
    int ProTestMeasureMenu();
    int ProTestSheetmetalSurfs();
    int ProTestSurfaceGeom ();
    int ProTestEdgeCurveGeom ();
    int ProTestPointGeom ();
    int ProTestSldVolumes ();
    int ProTestTesselCurve();
    ProError ProTestExportMainMenu(ProMdl mdl);
    
    ProError err;
    int id;

    err = ProMenuFileRegister((char*)"TkGeom",(char*)"tkgeom.mnu", &id);
    TEST_CALL_REPORT ("ProMenuFileRegister", "ProTestGeometry", err,
        err != PRO_TK_NO_ERROR);
    err = ProMenubuttonActionSet((char*)"TkGeom",(char*)"Traverse",  
        (ProMenubuttonAction)ProTestGeomTraverse, model, TRAVERSE);
    TEST_CALL_REPORT ("ProMenubuttonActionSet", "ProTestGeometry", err,
        err != PRO_TK_NO_ERROR);

    err = ProMenubuttonActionSet((char*)"TkGeom",(char*)"Mesh", 
        (ProMenubuttonAction)ProTestGeomTraverse, model, TEST_MESH);
    TEST_CALL_REPORT ("ProMenubuttonActionSet", "ProTestGeometry", err,
        err != PRO_TK_NO_ERROR);

    err = ProMenubuttonActionSet((char*)"TkGeom",(char*)"Tessellate", 
        (ProMenubuttonAction)ProTestGeomTraverse, model, TESSELLATE);
    TEST_CALL_REPORT ("ProMenubuttonActionSet", "ProTestGeometry", err,
        err != PRO_TK_NO_ERROR);

    err = ProMenubuttonActionSet((char*)"TkGeom",(char*)"TessExport", 
        (ProMenubuttonAction)ProTestExportMainMenu, NULL, 0);
    TEST_CALL_REPORT ("ProMenubuttonActionSet", "ProTestGeometry", err,
        err != PRO_TK_NO_ERROR);

    err = ProMenubuttonActionSet((char*)"TkGeom",(char*)"Shape", 
        (ProMenubuttonAction)ProTestGeomShape,    model, 0);
    TEST_CALL_REPORT ("ProMenubuttonActionSet", "ProTestGeometry", err,
        err != PRO_TK_NO_ERROR);

    err = ProMenubuttonActionSet((char*)"TkGeom",(char*)"Min Dist", 
        (ProMenubuttonAction)ProTestGeomMindist,  model, 0);
    TEST_CALL_REPORT ("ProMenubuttonActionSet", "ProTestGeometry", err,
        err != PRO_TK_NO_ERROR);

    err = ProMenubuttonActionSet((char*)"TkGeom",(char*)"Pnt On Geom", 
        (ProMenubuttonAction)  ProTestGeometryAtPoint,  model, 0);
    TEST_CALL_REPORT ("ProMenubuttonActionSet", "ProTestGeometry", err,
        err != PRO_TK_NO_ERROR);

    err = ProMenubuttonActionSet((char*)"TkGeom",(char*)"Measure", 
        (ProMenubuttonAction)ProTestMeasureMenu,  model, 0);
    TEST_CALL_REPORT ("ProMenubuttonActionSet", "ProTestGeometry", err,
        err != PRO_TK_NO_ERROR);

    err = ProMenubuttonActionSet((char*)"TkGeom",(char*)"Shtmetl Surfs",  
        (ProMenubuttonAction)ProTestSheetmetalSurfs,  model, 0);
    TEST_CALL_REPORT ("ProMenubuttonActionSet", "ProTestGeometry", err,
        err != PRO_TK_NO_ERROR);

    err = ProMenubuttonActionSet ((char*)"TkGeom", (char*)"Surface Area",
        (ProMenubuttonAction)ProTestSurfaceGeom, model, TEST_CONT_AREA);
    TEST_CALL_REPORT ("ProMenubuttonActionSet()", "ProTestGeometry()",
        err, err != PRO_TK_NO_ERROR);

    err = ProMenubuttonActionSet ((char*)"TkGeom", (char*)"Bound box",
        (ProMenubuttonAction)ProTestSurfaceGeom, model, TEST_CONT_BOX);
    TEST_CALL_REPORT ("ProMenubuttonActionSet()", "ProTestGeometry()",
        err, err != PRO_TK_NO_ERROR);
 
    err = ProMenubuttonActionSet ((char*)"TkGeom", (char*)"Point verify",
        (ProMenubuttonAction)ProTestSurfaceGeom, model, TEST_CONT_PNT);
    TEST_CALL_REPORT ("ProMenubuttonActionSet()", "ProTestGeometry()",
        err, err != PRO_TK_NO_ERROR);

    err = ProMenubuttonActionSet ((char*)"TkGeom", (char*)"Surf curvature",
        (ProMenubuttonAction)ProTestSurfaceGeom, model, TEST_CONT_CURV);
    TEST_CALL_REPORT ("ProMenubuttonActionSet()", "ProTestGeometry()",
        err, err != PRO_TK_NO_ERROR);

    err = ProMenubuttonActionSet ((char*)"TkGeom", (char*)"Edge/Curve Length",
        (ProMenubuttonAction)ProTestEdgeCurveGeom, model, TEST_CURV_LEN);
    TEST_CALL_REPORT ("ProMenubuttonActionSet()", "ProTestGeometry()",
        err, err != PRO_TK_NO_ERROR);

    err = ProMenubuttonActionSet ((char*)"TkGeom", (char*)"Edge/Curve Parameter",
        (ProMenubuttonAction)ProTestEdgeCurveGeom, model, TEST_CURV_PAR);
    TEST_CALL_REPORT ("ProMenubuttonActionSet()", "ProTestGeometry()",
        err, err != PRO_TK_NO_ERROR);

    err = ProMenubuttonActionSet ((char*)"TkGeom", (char*)"Point On Surface",
        (ProMenubuttonAction)ProTestPointGeom, model, TEST_PNT_ONSURF);
    TEST_CALL_REPORT ("ProMenubuttonActionSet()", "ProTestGeometry()",
        err, err != PRO_TK_NO_ERROR);

    err = ProMenubuttonActionSet ((char*)"TkGeom", (char*)"Sld Volumes",
        (ProMenubuttonAction)ProTestSldVolumes, model, 0);
    TEST_CALL_REPORT ("ProMenubuttonActionSet()", "ProTestGeometry()",
        err, err != PRO_TK_NO_ERROR);

    err = ProMenubuttonActionSet ((char*)"TkGeom", (char*)"Same Surfaces",
        (ProMenubuttonAction)ProTestSurfaceGeom, model, TEST_SURF_SAME);
    TEST_CALL_REPORT ("ProMenubuttonActionSet()", "ProTestGeometry()",
        err, err != PRO_TK_NO_ERROR);

    err = ProMenubuttonActionSet ((char*)"TkGeom", (char*)"Curve Tessel",
        (ProMenubuttonAction)ProTestTesselCurve, model, 0);
    TEST_CALL_REPORT ("ProMenubuttonActionSet()", "ProTestGeometry()",
        err, err != PRO_TK_NO_ERROR);
        
    err = ProMenubuttonActionSet((char*)"TkGeom",(char*)"TkGeom", 
        (ProMenubuttonAction)ProMenuDelete,NULL,  0);
    TEST_CALL_REPORT ("ProMenubuttonActionSet", "ProTestGeometry", err,
        err != PRO_TK_NO_ERROR);


    err = ProMenuCreate(PROMENUTYPE_MAIN, (char*)"TkGeom", &id);
    TEST_CALL_REPORT ("ProMenuCreate", "ProTestGeometry", err,
        err != PRO_TK_NO_ERROR);

    err = ProMenuProcess((char*)"TkGeom", &id);
    TEST_CALL_REPORT ("ProMenuProcess", "ProTestGeometry", err,
        err != PRO_TK_NO_ERROR && err != PRO_TK_E_FOUND);

    return(0);
}

/*====================================================================*\
    FUNCTION :  ProUtilPartSelect
    PURPOSE  :  Prompts to select a part (if asm mode) and return part handle
                and asm comp path
\*====================================================================*/
ProError ProUtilPartSelect (
    ProMdl model,
    ProPart *p_part,
    ProAsmcomppath **p_asm_comp_path)  /* Out: asm comp path
                                          function allocate memory for struct
                                          user must free it by free() */
{
    ProError status;
    ProMdlType type;
    ProSelection *p_sel;
    int num;
    ProModelitem part_item;

    if (model == NULL || p_part == NULL || p_asm_comp_path == NULL)
        return (PRO_TK_BAD_INPUTS);

    status = ProMdlTypeGet (model, &type);

    if (type != PRO_MDL_PART)
    {
        ProUtilMsgPrint("gen", "TEST %0s", "Select part");
        status = ProSelect ((char*)"part", 1, NULL, NULL, NULL, NULL,
            &p_sel, &num);
        if (status != PRO_TK_NO_ERROR || num != 1)
            return (PRO_TK_GENERAL_ERROR);
        status = ProSelectionModelitemGet (p_sel[0], &part_item);
        if (status != PRO_TK_NO_ERROR)
            return (PRO_TK_GENERAL_ERROR);
        status = ProModelitemMdlGet (&part_item, (ProMdl*)p_part);
        if (status != PRO_TK_NO_ERROR)
            return (PRO_TK_GENERAL_ERROR);
        *p_asm_comp_path = (ProAsmcomppath*) calloc (1, 
            sizeof (ProAsmcomppath));
        status = ProSelectionAsmcomppathGet (p_sel[0], *p_asm_comp_path);
        TEST_CALL_REPORT ("ProSelectionAsmcomppathGet()",
            "ProUtilPartSelec()",
            status, status != PRO_TK_NO_ERROR);
    }
    else
    {
        *p_asm_comp_path = NULL;
        *p_part = (ProPart)model;
    }
    return (PRO_TK_NO_ERROR);
}

/*====================================================================*\
    FUNCTION :  ProTestSldVolumes
    PURPOSE  :  Tests ProSldsurfaceVolumesFind function
\*====================================================================*/
int ProTestSldVolumes (
    ProMdl *model)
{
    ProPart part;
    ProError status;
    int num, i, j;
    ProSelection sel_surf;
    ProModelitem surf_item;
    ProAsmcomppath *p_asm_comp_path;
    int *p_count;
    int **p_surf_id_arr;
    FILE *fptr;
    ProCharLine line, str;

    fptr = (FILE *)PTApplsUnicodeFopen (QCR_NAME, "a");

    status = ProUtilPartSelect (*model, &part, &p_asm_comp_path);
    if (status != PRO_TK_NO_ERROR)
        return (0);

    status = ProSldsurfaceVolumesFind (part, &num, &p_count, &p_surf_id_arr);
    TEST_CALL_REPORT ("ProSldsurfaceVolumesFind()", "ProTestSldVolumes()",
        status, status != PRO_TK_NO_ERROR);
    if (status != PRO_TK_NO_ERROR)
        return (0);
    
    if (fptr != NULL)
        ProTKFprintf (fptr, "Part has %d volumes\n", num);
    for (i = 0; i < num; i++)
    {
        if (fptr != NULL)
            ProTKFprintf (fptr, "Volume %d contains %d surfaces\n", i, p_count[i]);
        
	line[0] ='\0';
        for (j = 0; j < p_count[i]; j++)
        {

            ProTKSprintf (str, "%d", p_surf_id_arr[i][j]);
   	    if (j < p_count[i]-1)
		ProUtilstrcat(str, ", ");		
	    ProUtilstrcat(line, (const char *) str);
	    if (strlen(line) >=72 || j == p_count[i]-1)
	    {
		ProTKFprintf(fptr, "%s\n", line);
		line[0] = '\0';
	    }
	
            ProModelitemInit ((ProMdl)part, p_surf_id_arr[i][j], PRO_SURFACE,
                &surf_item);
            ProSelectionAlloc (p_asm_comp_path, &surf_item, &sel_surf);
            ProSelectionHighlight (sel_surf, PRO_COLOR_EDGE_HIGHLIGHT);
        }
        ProArrayFree ((ProArray*)&p_surf_id_arr[i]);
    }
    ProArrayFree ((ProArray*)&p_surf_id_arr);
    ProArrayFree ((ProArray*)&p_count);
    if (p_asm_comp_path != NULL)
        free (p_asm_comp_path);
    if (fptr != NULL)
        fclose (fptr);

    return (0);
}
    

/*====================================================================*\
    FUNCTION :  ProTestPointGeom
    PURPOSE  :  Tests point geometry functions
\*====================================================================*/
int ProTestPointGeom (
    ProMdl *model)
{
    ProError status;
    ProSelection *p_sel;
    int num;
    ProModelitem surf_item;
    ProMatrix matrix;
    ProPoint3d point, free_point, closest_point;
    ProSurface surface;
    ProBoolean on_surface;
    ProMdl surf_item_owner; 
    ProMdlType type;
    ProAsmcomppath asm_comp_path;
    char test_msg[PRO_PATH_SIZE];
    FILE *fptr;

    fptr = PTApplsUnicodeFopen (QCR_NAME, "a");

    ProUtilMsgPrint("gen", "TEST %0s", "Select surface");
    status = ProSelect ((char*)"surface", 1, NULL, NULL, NULL, NULL,
        &p_sel, &num);
    if (status != PRO_TK_NO_ERROR || num != 1)
        return (0);
    status = ProSelectionModelitemGet (p_sel[0], &surf_item);
    TEST_CALL_REPORT("ProSelectionModelitemGet()", "ProTestPointGeom()",
        status, status != PRO_TK_NO_ERROR);
    status = ProModelitemMdlGet (&surf_item, &surf_item_owner);
    TEST_CALL_REPORT("ProModelitemMdlGet()", "ProTestPointGeom()",
        status, status != PRO_TK_NO_ERROR);
    status = ProSurfaceInit (surf_item_owner, surf_item.id, &surface);
    TEST_CALL_REPORT("ProSurfaceInit()", "ProTestPointGeom()",
        status, status != PRO_TK_NO_ERROR);
    ProSelectionPoint3dGet (p_sel[0], free_point);
    status = ProPoint3dOnsurfaceFind (free_point, surface, &on_surface,
        closest_point);
    TEST_CALL_REPORT("ProPoint3dOnsurfaceFind()", "ProTestPointGeom()",
        status, status != PRO_TK_NO_ERROR);
    ProMdlTypeGet (*model, &type);
    if (type != PRO_MDL_PART)
    {
        ProSelectionAsmcomppathGet (p_sel[0], &asm_comp_path);
        ProAsmcomppathTrfGet (&asm_comp_path, PRO_B_TRUE, matrix);
        ProUtilPointTrans (matrix, closest_point, point);
    }
    else
    {
        point[0] = closest_point[0];
        point[1] = closest_point[1];
        point[2] = closest_point[2];
    }
    ProGraphicsCircleDraw (point, 10.0);
    
    ProTKSprintf (test_msg, 
        "Point is %s on the surface, closest point is (%3.2f, %3.2f, %3.2f)",
        (on_surface == PRO_B_FALSE)? "not":"",
        point[0], point[1], point[2]);
    ProUtilMsgPrint("gen", "TEST %0s", test_msg);

    if (fptr != NULL)
    {
        ProTKFprintf (fptr, "%s \n", test_msg);
        fclose (fptr);
    }
        
    return (0);
}

/*====================================================================*\
    FUNCTION :  ProTestEdgeCurveGeom
    PURPOSE  :  Edge/Curve geometry
\*====================================================================*/
int ProTestEdgeCurveGeom (
    ProMdl *model,
    int action)
{
    ProName msg_file;
    ProError status;
    ProSelection *p_sel;
    int n_sel;
    ProMdl owner;
    ProModelitem modelitem;
    ProEdge edge;
    ProCurve curve;
    double t1, t2, length;
    char crv_msg[PRO_NAME_SIZE];
    ProVector point1, point2, der1, der2, dir;
    FILE *fptr;

    fptr = PTApplsUnicodeFopen (QCR_NAME, "a");

    ProStringToWstring (msg_file, (char*)SURFAREA_TXT);

    ProMessageDisplay (msg_file, (char*)"TEST %0s", "Select edge or curve");

    status = ProSelect ((char*)"edge,curve", 1, NULL, NULL, NULL, NULL, &p_sel,
        &n_sel);
    if (status != PRO_TK_NO_ERROR || n_sel != 1)
        return (0);

    status = ProSelectionModelitemGet (p_sel[0], &modelitem);
    TEST_CALL_REPORT ("ProSelectionModelitemGet()", "ProTestEdgeCurveGeom()",
        status, status != PRO_TK_NO_ERROR);

    status = ProModelitemMdlGet (&modelitem, &owner);
    TEST_CALL_REPORT ("ProModelitemMdlGet()", "ProTestEdgeCurveGeom()",
        status, status != PRO_TK_NO_ERROR);

    ProMessageDisplay (msg_file, (char*)"TEST %0s", "Enter start parameter t:");
    status = ProMessageDoubleRead (NULL, &t1);
    if (status != PRO_TK_NO_ERROR)
        return (0);

    if (action == TEST_CURV_LEN)
    {
        ProMessageDisplay (msg_file, (char*)"TEST %0s", "Enter end parameter t:");
        status = ProMessageDoubleRead (NULL, &t2);
        if (status != PRO_TK_NO_ERROR)
            return (0);
    }
    else if (action == TEST_CURV_PAR)
    {
        ProMessageDisplay (msg_file, (char*)"TEST %0s", "Enter length:");
        status = ProMessageDoubleRead (NULL, &length);
        if (status != PRO_TK_NO_ERROR)
            return (0);
    }

    switch (action)
    {
#ifndef PT_PRODUCTS_BUILD
    case TEST_CURV_LEN:
        if (modelitem.type == PRO_EDGE)
        {
            status = ProEdgeInit ((ProSolid)owner, modelitem.id, &edge);
            TEST_CALL_REPORT ("ProEdgeInit()",
                "ProTestEdgeCurveGeom()",
                status, status != PRO_TK_NO_ERROR);
            ProEdgeXyzdataEval (edge, t1, point1, der1, der2, dir);
            ProEdgeXyzdataEval (edge, t2, point2, der1, der2, dir);
            status = ProEdgeLengthT1T2Eval (edge, t1, t2, &length);
            TEST_CALL_REPORT ("ProEdgeLengthT1T2Eval()", 
                "ProTestEdgeCurveGeom()",
                status, status != PRO_TK_NO_ERROR);
        }
        else if (modelitem.type == PRO_CURVE)
        {
            status = ProCurveInit ((ProSolid)owner, modelitem.id, &curve);
            TEST_CALL_REPORT ("ProCurveInit()",
                "ProTestEdgeCurveGeom()",
                status, status != PRO_TK_NO_ERROR);
            ProCurveXyzdataEval (curve, t1, point1, der1, der2);
            ProCurveXyzdataEval (curve, t2, point2, der1, der2);
            status = ProCurveLengthT1T2Eval (curve, t1, t2, &length);
            TEST_CALL_REPORT ("ProCurveLengthT1T2Eval()", 
                "ProTestEdgeCurveGeom()",
                status, status != PRO_TK_NO_ERROR);
        }
        ProGraphicsCircleDraw (point1, 0.1);
        ProGraphicsCircleDraw (point2, 0.1);
        ProTKSprintf (crv_msg, "Length %4.2f", length);
        break;
    case TEST_CURV_PAR:
        if (modelitem.type == PRO_EDGE)
        {
            status = ProEdgeInit ((ProSolid)owner, modelitem.id, &edge);
            TEST_CALL_REPORT ("ProEdgeInit()",
                "ProTestEdgeCurveGeom()",
                status, status != PRO_TK_NO_ERROR);
            ProEdgeXyzdataEval (edge, t1, point1, der1, der2, dir);
            status = ProEdgeParamByLengthEval (edge, t1, length, &t2, point2);
            TEST_CALL_REPORT ("ProEdgeParamByLengthEval()",
                "ProTestEdgeCurveGeom()",
                status, status != PRO_TK_NO_ERROR);
        }
        else if (modelitem.type == PRO_CURVE)
        {
            status = ProCurveInit ((ProSolid)owner, modelitem.id, &curve);
            TEST_CALL_REPORT ("ProCurveInit()",
                "ProTestEdgeCurveGeom()",
                status, status != PRO_TK_NO_ERROR);
            ProCurveXyzdataEval (curve, t1, point1, der1, der2);
            status = ProCurveParamByLengthEval (curve, t1, length, &t2, point2);
            TEST_CALL_REPORT ("ProCurveParamByLengthEval()",
                "ProTestEdgeCurveGeom()",
                status, status != PRO_TK_NO_ERROR);
        }
        ProGraphicsCircleDraw (point1, 0.1);
        ProGraphicsCircleDraw (point2, 0.1);
        ProTKSprintf (crv_msg, "End parameter: %4.2f", t2);
        break;
#endif
    default:
        ProTKSprintf (crv_msg, "Unknown action");
        break;
    }

    ProMessageDisplay (msg_file, (char*)"TEST %0s", crv_msg);
    if (fptr != NULL)
    {
        ProTKFprintf (fptr, "%s \n", crv_msg);
        fclose (fptr);
    }

    return (0);
}

/*====================================================================*\
    FUNCTION :  ProTestSurfaceGeom
    PURPOSE  :  Surface geometry
\*====================================================================*/
int ProTestSurfaceGeom (
    ProMdl *model,
    int action)
{
    ProError status;
    ProMdl owner;
    ProSelection *p_sel_surf, sel_surf;
    ProModelitem srf_modelitem;
    ProSurface surface, *p_same_surf;
    ProContour contour;
    int i, n_sel, num, surf_id;
    ProName msg_file;
    double surf_area;
    char area_msg[PRO_LINE_SIZE], area_msg2[PRO_LINE_SIZE] = "";
    Pro2dPnt points[2], uv_point;
    ProUvStatus uv_status;
    ProVector point, der1[2], der2[3], norm;
    ProAsmcomppath *p_asm_comp_path;
    ProSolid solid;
    ProMdlType type;
    FILE *fptr;
    Pro3dPnt points3d[2];

    fptr = PTApplsUnicodeFopen (QCR_NAME, "a");

    p_asm_comp_path = NULL;
    if (action == TEST_SURF_SAME)
    {
        ProMdlTypeGet (*model, &type);
        if (type == PRO_MDL_PART)
            solid = (ProSolid) *model;
        else
        {
            status = ProUtilPartSelect (*model, 
                (ProPart*)&solid, &p_asm_comp_path);
            if (status != PRO_TK_NO_ERROR)
                return (0);
        }
    }

    ProStringToWstring (msg_file, (char*)SURFAREA_TXT);

    ProMessageDisplay (msg_file, (char*)"TEST %0s", "Select surface");

    status = ProSelect ((char*)"surface", 1, NULL, NULL, NULL, NULL, &p_sel_surf,
        &n_sel);
    if (status != PRO_TK_NO_ERROR || n_sel != 1)
        return (0);

    status = ProSelectionModelitemGet (p_sel_surf[0], &srf_modelitem); 
    TEST_CALL_REPORT ("ProSelectionModelitemGet()", "ProTestSurfaceGeom()",
        status, status != PRO_TK_NO_ERROR);

    status = ProModelitemMdlGet (&srf_modelitem, &owner); 
    TEST_CALL_REPORT ("ProModelitemMdlGet()", "ProTestSurfaceGeom()",
        status, status != PRO_TK_NO_ERROR);

    status = ProSurfaceInit (owner, srf_modelitem.id, &surface);
    TEST_CALL_REPORT ("ProSurfaceInit()", "ProTestSurfaceGeom()",
        status, status != PRO_TK_NO_ERROR);

    if (action != TEST_CONT_CURV && action != TEST_SURF_SAME)
    {
        ProMessageDisplay (msg_file, (char*)"TEST %0s", "Select contour");
    
        status = ProUtilContourSelect (surface, &contour);
        if (status == PRO_TK_E_NOT_FOUND) 
        {
            ProMessageDisplay (msg_file, (char*)"TEST %0s", 
                "Contour must be on specified surface");
            return (0);
        }
        if (status != PRO_TK_NO_ERROR)
        {
            ProMessageDisplay (msg_file, (char*)"TEST %0s", 
                "Error while contour selection");
            return (0);
        }
    }

    if (action == TEST_CONT_PNT || action == TEST_CONT_CURV)
    {
        ProMessageDisplay (msg_file, (char*)"TEST %0s", "Enter U parameter:");
        status = ProMessageDoubleRead (NULL, &uv_point[0]);
        if (status != PRO_TK_NO_ERROR)
            return (0);
        ProMessageDisplay (msg_file, (char*)"TEST %0s", "Enter V parameter:");
        status = ProMessageDoubleRead (NULL, &uv_point[1]);
        if (status != PRO_TK_NO_ERROR)
            return (0);
    }

    switch (action)
    {
#ifndef PT_PRODUCTS_BUILD

    case TEST_SURF_SAME:
        ProArrayAlloc (0, sizeof (ProSurface), 1, (ProArray*)&p_same_surf);
        status = ProSurfaceSameSrfsFind (solid, surface, 
            &p_same_surf, &num);
        TEST_CALL_REPORT ("ProSurfaceSameSrfsFind()", "ProTestSurfaceGeom()",
            status, status != PRO_TK_NO_ERROR);
        ProSurfaceIdGet (surface, &surf_id);
        ProTKSprintf (area_msg, "Found %d same surfaces for surface %d\n",
            num, surf_id);
        for (i = 0; i < num; i++)
        {
            ProSurfaceIdGet (p_same_surf[i], &surf_id);
            ProModelitemInit ((ProMdl)solid, surf_id, PRO_SURFACE,
                &srf_modelitem);
            ProSelectionAlloc (p_asm_comp_path, &srf_modelitem, &sel_surf);
            ProSelectionHighlight (sel_surf, PRO_COLOR_EDGE_HIGHLIGHT);
        }
        ProArrayFree ((ProArray*)&p_same_surf);
        break;
    case TEST_CONT_AREA:
        status = ProContourAreaEval (surface, contour, &surf_area);
        TEST_CALL_REPORT ("ProContourAreaEval()", "ProTestSurfaceGeom()",
            status, status != PRO_TK_NO_ERROR);
        ProTKSprintf (area_msg, "Surface area inside of outer contour: %4.2f", 
            surf_area);
        break;
    case TEST_CONT_BOX:
        status = ProContourBoundbox2dCompute (surface, contour, points);
        TEST_CALL_REPORT ("ProContourBoundbox2dCompute()", 
            "ProTestSurfaceGeom()",
            status, status != PRO_TK_NO_ERROR);
        ProTKSprintf (area_msg, "2d Box ( %.2f, %.2f), ( %.2f, %.2f)",
            points[0][0], points[0][1], points[1][0], points[1][1]);
	status=ProContourBoundbox3dCompute(surface,contour,points3d);
	TEST_CALL_REPORT("ProContourBoundbox3dCompute()",
		"ProTestSurfaceGeom()", status, status != PRO_TK_NO_ERROR);
	ProTKSprintf(area_msg2,"3d Box ( %.2f, %.2f, %.2f), ( %.2f, %.2f, %.2f)",
		points3d[0][0], points3d[0][1], points3d[0][2],
		points3d[1][0], points3d[1][1], points3d[1][2]);
        break;
    case TEST_CONT_PNT:
        status = ProContourUvpntVerify (surface, contour, uv_point, &uv_status);
        TEST_CALL_REPORT ("ProContourUvpntVerify()", "ProTestSurfaceGeom()",
            status, status != PRO_TK_NO_ERROR);
        ProSurfaceXyzdataEval (surface, uv_point, point, der1, der2, norm);
        ProGraphicsCircleDraw (point, 0.1);
        if (uv_status == PRO_UV_AMBIGUOUS)
            ProTKSprintf (area_msg, "Point is on the contour");
        else if (uv_status == PRO_UV_OUTSIDE)
            ProTKSprintf (area_msg, "Point is outside the contour");
        else if (uv_status == PRO_UV_INSIDE)
            ProTKSprintf (area_msg, "Point is inside the contour");
        else return (0);
        break;
    case TEST_CONT_CURV:
        status = ProSurfacePrincipalCrvtEval (surface, uv_point, &point[0],
            &point[1], der1);
        TEST_CALL_REPORT ("ProSurfacePrincipalCrvtEval()", 
            "ProTestSurfaceGeom()",
            status, status != PRO_TK_NO_ERROR);
        ProTKSprintf (area_msg,
   "Curvature max= %4.2f, min= %4.2f, dirs (%4.2f,%4.2f,%4.2f;%4.2f,%4.2f,%4.2f)",
   point[0], point[1], der1[0][0], der1[0][1], der1[0][2],
   der1[1][0], der1[1][1], der1[1][2]);
        ProSurfaceXyzdataEval (surface, uv_point, point, der1, der2, norm);
        ProGraphicsCircleDraw (point, 0.1);
        break;
#endif

    default:
        ProTKSprintf (area_msg, "Unknown action");
        break;
    }

    ProMessageDisplay (msg_file, (char*)"TEST %0s", area_msg);

    if (area_msg2[0]!='\0') 
	ProMessageDisplay (msg_file, (char*)"TEST %0s", area_msg2);

    if (p_asm_comp_path != NULL)
        free (p_asm_comp_path);
    if (fptr != NULL)
    {
        ProTKFprintf (fptr, "%s \n", area_msg);
	if( area_msg2[0] != '\0' ) 
	    ProTKFprintf( fptr, "%s \n", area_msg2 );

        fclose (fptr);
    }

    area_msg2[0] = '\0';

    return (0);
}


/*====================================================================*\
    FUNCTION :  ProUtilContourSelect
    PURPOSE  :  Selects contour and returns it
\*====================================================================*/
ProError ProUtilContourSelect (
    ProSurface surface,
    ProContour *p_contour)
{
    ProError status;
    int n_sel, i, cont_num, j, edge_num, edge_id;
    ProSelection *p_edge_sel;
    ProContour *p_contours;
    ProEdge    *p_edges;
    ProModelitem edge_modelitem;
    ProMdl     owner, current;
    ProBoolean is_contour_found;
    ProMdlType type;
    ProAsmcomppath asmcomp_path, *p_asmcomp_path;

    ProMdlCurrentGet (&current);
    ProMdlTypeGet (current, &type);

    status = ProSelect ((char*)"edge", 1, NULL, NULL, NULL, NULL, &p_edge_sel, &n_sel);
    if (status != PRO_TK_NO_ERROR)
        return (status);
    if (n_sel != 1)
        return (PRO_TK_GENERAL_ERROR);

    if (type == PRO_MDL_ASSEMBLY)
    {
        p_asmcomp_path = &asmcomp_path;
        ProSelectionAsmcomppathGet (p_edge_sel[0], p_asmcomp_path);
    }
    else
        p_asmcomp_path = NULL;

    status = ProSelectionModelitemGet (p_edge_sel[0], &edge_modelitem);
    TEST_CALL_REPORT ("ProSelectionModelitemGet()", "ProUtilContourSelect()",
        status, status != PRO_TK_NO_ERROR);

    status = ProModelitemMdlGet (&edge_modelitem, &owner);
    TEST_CALL_REPORT ("ProModelitemMdlGet()", "ProUtilContourSelect()",
        status, status != PRO_TK_NO_ERROR); 

    status = ProUtilCollectSurfaceContours (surface, &p_contours);
    if (status != PRO_TK_NO_ERROR)
        return (PRO_TK_GENERAL_ERROR);

    ProArraySizeGet ((ProArray)p_contours, &cont_num);

    is_contour_found = PRO_B_FALSE;
    for (i = 0; i < cont_num; i++)
    {
        status = ProUtilCollectContourEdges (surface, p_contours[i],
            &p_edges);
        ProArraySizeGet ((ProArray)p_edges, &edge_num);
        for (j = 0; j < edge_num; j++)
        {
            status = ProEdgeIdGet (p_edges[j], &edge_id);
	    TEST_CALL_REPORT ("ProEdgeIdGet()",
		"ProUtilContourSelect()", status, status != PRO_TK_NO_ERROR); 
            if (edge_modelitem.id == edge_id)
            {
                is_contour_found = PRO_B_TRUE;
                break;
            }
        }
        ProArrayFree ((ProArray*)&p_edges);
        if (is_contour_found == PRO_B_TRUE)
            break;
    }
    if (is_contour_found != PRO_B_TRUE)
        return (PRO_TK_E_NOT_FOUND);

    *p_contour = p_contours[i];
    ProTestContourHighlight (owner, 
        p_asmcomp_path, surface, *p_contour, PRO_B_TRUE);

    return (PRO_TK_NO_ERROR);
}

/*====================================================================*\
    FUNCTION : ProTestContourHighlight
    PURPOSE  : Highlight/unhighlights specified contour
\*====================================================================*/
ProError ProTestContourHighlight (
    ProMdl model,
    ProAsmcomppath *p_asmcomp_path,
    ProSurface surface,
    ProContour contour, 
    ProBoolean flag)
{
    ProEdge *p_edges;
    int edge_num, i;
    ProError status;
    ProSelection selection;
    ProModelitem edge_item;

    status = ProUtilCollectContourEdges (surface,
        contour, &p_edges);
    ProArraySizeGet ((ProArray)p_edges, &edge_num);
    for (i = 0; i < edge_num; i++)
    {
        ProEdgeToGeomitem((ProSolid)model, p_edges[i], 
	    (ProGeomitem*)&edge_item);
        ProSelectionAlloc (p_asmcomp_path, &edge_item, &selection);
        if (flag == PRO_B_TRUE)
            ProSelectionHighlight (selection, PRO_COLOR_EDGE_HIGHLIGHT);
        else
            ProSelectionUnhighlight (selection);
        ProSelectionFree (&selection);

    }
    ProArrayFree ((ProArray*)&p_edges);
    return (PRO_TK_NO_ERROR);
} 


/*====================================================================*\
    FUNCTION :	ProTestEdgeAct()
    PURPOSE  :  General action function for an edge	
\*====================================================================*/
ProError ProTestEdgeAct(
    ProEdge edge,
    ProError instatus,
    ProAppData tmp_app_data)
{
    ProTestGeomData *app_data = (ProTestGeomData *) tmp_app_data;
    ProError status;
    int action;
    FILE *fp;
    ProEnttype etype;
    ProUtilCname type_str;
    ProEdge edge1, edge2;
    ProSurface surface, face1, face2;
    int dir, end, n_tess;
    ProColor old_color;
	ProColor edge_hlite_color;
    char *dir_str;
    int count;
    ProName w_name;
    ProUtilCname name;
    ProVector xyz, der1, der2, direction;
    double t;
    ProModelitem modeledge;
    int face1_id, face2_id, edge1_id, edge2_id, edge_id;
    ProType itype;
    ProEdge *vertexlist;
    ProType *paramlist;
    ProSurface *surflist;
    int c;
    int surf_id;
 
/*--------------------------------------------------------------------*\
    Decode the action we have to perform
\*--------------------------------------------------------------------*/
    action = app_data->action;
    switch(action)
    {
    case TRAVERSE :
/*--------------------------------------------------------------------*\
	Just dump the edge data to the current file...
\*--------------------------------------------------------------------*/
	fp      = app_data->fp;
	surface = *(app_data->surface);

/*--------------------------------------------------------------------*\
	Get the edge type
\*--------------------------------------------------------------------*/
	status = ProEdgeTypeGet(edge, &etype);
	TEST_CALL_REPORT("ProEdgeTypeGet()", "ProTestEdgeAct()",
					status, status != PRO_TK_NO_ERROR);
	ProUtilEnttypeStr(etype, type_str);

/*--------------------------------------------------------------------*\
	Get the edge name
\*--------------------------------------------------------------------*/

        ProEdgeIdGet(edge, &modeledge.id);
	TEST_CALL_REPORT("ProEdgeIdGet()", "ProTestEdgeAct()",
				    status, (status != PRO_TK_NO_ERROR));
        modeledge.type = ProEdgeDatatypeGet();
        modeledge.owner = *(app_data->model);

	status = ProModelitemNameGet(&modeledge, w_name);
	TEST_CALL_REPORT("ProModelitemNameGet()", "ProTestEdgeAct()",
				    status, ((status != PRO_TK_NO_ERROR) &&
					     (status != PRO_TK_E_NOT_FOUND)));
	if(status == PRO_TK_NO_ERROR)
	    ProWstringToString(name, w_name);
	else
	    ProUtilstrcpy(name, "");

/*--------------------------------------------------------------------*\
	Print id, name, and type
\*--------------------------------------------------------------------*/
	if(strlen(name))
	    ProTKFprintf(fp,"%36s%d-%s\n%44s%-10s", " ", 
                           modeledge.id, name, " ", type_str);
	else
	    ProTKFprintf(fp,"%36s%-7d %-10s", " ", modeledge.id, type_str);

/*--------------------------------------------------------------------*\
	Direction ("->" means parameterized in the same direction as
			the contour)
\*--------------------------------------------------------------------*/
	status = ProEdgeDirGet(edge, surface, &dir);
	TEST_CALL_REPORT("ProEdgeDirGet()", "ProTestEdgeAct()",
					status, status != PRO_TK_NO_ERROR);
	switch(dir)
	{
	case  1 : dir_str = (char*)"->"; break;
	case -1 : dir_str = (char*)"<-"; break;
	default : dir_str = (char*)"**"; break;
	}
	ProTKFprintf(fp, "%s", dir_str);

/*--------------------------------------------------------------------*\
	Neighboring faces and the corresponding next edges
\*--------------------------------------------------------------------*/
	status = ProEdgeNeighborsGet(edge, &edge1, &edge2, &face1, &face2);
	TEST_CALL_REPORT("ProEdgeNeighborsGet()", "ProTestEdgeAct()",
					status, status != PRO_TK_NO_ERROR);

        status = ProSurfaceIdGet(face1, &face1_id);
	TEST_CALL_REPORT("ProSurfaceIdGet()", "ProTestEdgeAct()",
					status, status != PRO_TK_NO_ERROR);
        status = ProSurfaceIdGet(face2, &face2_id);
	TEST_CALL_REPORT("ProSurfaceIdGet()", "ProTestEdgeAct()",
					status, status != PRO_TK_NO_ERROR);

        status = ProEdgeIdGet(edge1, &edge1_id);
	TEST_CALL_REPORT("ProEdgeIdGet()", "ProTestEdgeAct()",
					status, status != PRO_TK_NO_ERROR);
        status = ProEdgeIdGet(edge2, &edge2_id);
	TEST_CALL_REPORT("ProEdgeIdGet()", "ProTestEdgeAct()",
					status, status != PRO_TK_NO_ERROR);

	ProTKFprintf(fp, "%d/%d,%d/%d\n",
			face1_id, edge1_id, face2_id, edge2_id);

/*--------------------------------------------------------------------*\
	Vertex data
\*--------------------------------------------------------------------*/
	for(end=0; end<2; end++)
	{
            count = 0;
	    itype = end==0 ? PRO_EDGE_START : PRO_EDGE_END;
	    status = ProEdgeVertexdataGet(edge, itype, 
                             &vertexlist, &paramlist, &surflist, &count);
	    TEST_CALL_REPORT("ProEdgeVertexdataGet()", "ProTestEdgeAct()",
					status, status != PRO_TK_NO_ERROR);

            if ( status == PRO_TK_NO_ERROR )
            {
	       ProTKFprintf(fp, "%s\n", end == 0 ? "First vertex" : "Last vertex");
	       for(c=0; c<count; c++)
               {
                   status = ProEdgeIdGet(vertexlist[c], &edge_id);
	           TEST_CALL_REPORT("ProEdgeIdGet()", "ProTestEdgeAct()",
		   			status, status != PRO_TK_NO_ERROR);
	   	   ProTKFprintf(fp, "edge %d = %d %s\n", c, edge_id, 
                        paramlist[c] == PRO_EDGE_START ? "First vertex" :
                          "Last vertex" );
               }
	       for(c=0; c<count; c++)
               {
                   status = ProSurfaceIdGet(surflist[c], &surf_id);
	           TEST_CALL_REPORT("ProSurfaceIdGet()", "ProTestEdgeAct()",
					status, status != PRO_TK_NO_ERROR);
		   ProTKFprintf(fp, "surf %d = %d\n", c, surf_id);
               }
               if ( count > 0 )
               {
                  status = ProArrayFree( (ProArray *) &vertexlist);
	          TEST_CALL_REPORT("ProArrayFree()", "ProTestEdgeAct()",
		   			status, status != PRO_TK_NO_ERROR);
                  status = ProArrayFree( (ProArray *) &paramlist);
	          TEST_CALL_REPORT("ProArrayFree()", "ProTestEdgeAct()",
		   			status, status != PRO_TK_NO_ERROR);
                  status = ProArrayFree( (ProArray *) &surflist);
	          TEST_CALL_REPORT("ProArrayFree()", "ProTestEdgeAct()",
		   			status, status != PRO_TK_NO_ERROR);
               }
            }
	}

	break;
    case TESSELLATE :
	fp      = app_data->fp;
	n_tess  = app_data->data.tessdata.n_tess;

	for(t=0.0;t<=1.0;t+= 1.0 / n_tess)
	{
	    status = ProEdgeXyzdataEval(edge, t, xyz, der1, der2, direction);
	    TEST_CALL_REPORT("ProEdgeXyzdataEval()", "ProTestEdgeAct()",
					    status, status != PRO_TK_NO_ERROR);

            status = ProEdgeIdGet(edge, &edge_id);
	    TEST_CALL_REPORT("ProEdgeIdGet()", "ProTestEdgeAct()",
					    status, status != PRO_TK_NO_ERROR);
            
	    ProTKFprintf(fp, "Edge %3d, pos  (%5.2f, %5.2f, %5.2f)\n",
			edge_id, xyz[0], xyz[1], xyz[2]);
	    ProTKFprintf(fp, "          der1 (%5.2f, %5.2f, %5.2f)\n",
			der1[0], der1[1], der1[2]);
	    ProTKFprintf(fp, "          der2 (%5.2f, %5.2f, %5.2f)\n",
			der2[0], der2[1], der2[2]);
	    ProTKFprintf(fp, "          dir  (%5.2f, %5.2f, %5.2f)\n",
			direction[0], direction[1], direction[2]);

	    edge_hlite_color.method = PRO_COLOR_METHOD_TYPE;
		edge_hlite_color.value.type = PRO_COLOR_EDGE_HIGHLIGHT;
		
		status = ProGraphicsColorModify(&edge_hlite_color, &old_color);
            TEST_CALL_REPORT("ProGraphicsColorModify()", "ProTestSurfaceAct()",
					status, status != PRO_TK_NO_ERROR);

	    if(t<0.01)
            {
		ProGraphicsPenPosition(xyz);
                TEST_CALL_REPORT("ProGraphicsPenPosition()", "ProTestEdgeAct()", 
                    status, status != PRO_TK_NO_ERROR);
            }
	    else
            {
		ProGraphicsLineDraw(xyz);
            }
	    status = ProGraphicsColorModify(&old_color, NULL);
            TEST_CALL_REPORT("ProGraphicsColorModify()", "ProTestEdgeAct()",
	       status, status != PRO_TK_NO_ERROR);
	}
    }

    return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
    FUNCTION :	user_dummy_fun()
    PURPOSE  :  General action function for a contour
\*====================================================================*/
ProError ProTestContourAct(
    ProContour contour,
    ProError instatus,
    ProAppData tmp_app_data)
{
    ProError status;
    int action;
    FILE *fp;
    ProContourTraversal traversal;
    char *trav_str;
    ProTestGeomData *app_data = (ProTestGeomData *) tmp_app_data;
    ProSurface surface;
    ProEdge *edges;
    int edges_num, i;
    ProContour cont_contour;

/*--------------------------------------------------------------------*\
    Decode the action to be performed
\*--------------------------------------------------------------------*/
    action = app_data->action;
    surface = *(app_data->surface);
    switch(action)
    {
    case TRAVERSE :
/*--------------------------------------------------------------------*\
	Write contour data to the file ..
\*--------------------------------------------------------------------*/
	fp = app_data->fp;

/*--------------------------------------------------------------------*\
	Internal or external
\*--------------------------------------------------------------------*/
	status = ProContourTraversalGet(contour, &traversal);
	TEST_CALL_REPORT("ProContourTraversalGet()", "ProTestContourAct()",
					status, status != PRO_TK_NO_ERROR);

	status = ProContainingContourFind((ProSolid)*app_data->model,
	    contour, &cont_contour);
	TEST_CALL_REPORT("ProContainingContourFind()", "ProTestContourAct()",
					status, status != PRO_TK_NO_ERROR);
	switch(traversal)
	{
	case PRO_CONTOUR_TRAV_INTERNAL : trav_str = (char*)"Internal"; break;
	case PRO_CONTOUR_TRAV_NONE : trav_str = (char*)"Erroneous"; break;
	case PRO_CONTOUR_TRAV_EXTERNAL : trav_str = (char*)"External"; break;
	default : trav_str = (char*)"Undefined"; break;
	}

	ProTKFprintf(fp,"%18s %7s %-20s\n", " ", " ", trav_str);

	break;
    }

/*--------------------------------------------------------------------*\
    Remember the contour (so that the lower Act functions know the
    context)
\*--------------------------------------------------------------------*/
    app_data->contour = &contour;

/*--------------------------------------------------------------------*\
    Now visit all the contour edges
\*--------------------------------------------------------------------*/
					
    status = ProUtilCollectContourEdges (surface, contour, &edges);
    if (status == PRO_TK_NO_ERROR)
    {
        status = ProArraySizeGet ((ProArray)edges, &edges_num);
        TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestContourAct()", 
            status, status != PRO_TK_NO_ERROR );
        for (i = 0; i < edges_num; i++)
        {
            status = ProTestEdgeAct (edges[i],
	        PRO_TK_NO_ERROR, (ProAppData)app_data);
        }
        status = ProArrayFree ((ProArray*)&edges);
        TEST_CALL_REPORT( "ProArrayFree()", "ProTestContourAct()", 
            status, status != PRO_TK_NO_ERROR );
    }

    return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
    FUNCTION :	ProTestMeshAct()
    PURPOSE  :	Test function (to be called at each surface mesh point)
		to draw and dump mesh coordinates.
\*====================================================================*/
int ProTestMeshAct(
    ProSurface *surface,/* I - The surface */
    double uv[2],	/* I - The UV values */
    int start,		/* I - 1 if this is the start of a new mesh line */
    ProAppData tmp_app_data)/* I - General data */
			/* Return 0        - continue,
				  non-zero - terminate meshing */
{
    ProError status;
    ProVector xyz, der1[2], der2[3], normal;
    ProTestGeomData *app_data = (ProTestGeomData *) tmp_app_data;
    FILE *fp = (FILE*)app_data->fp;
    int surface_id;

/*--------------------------------------------------------------------*\
    Get the xyz location for this surface point.
\*--------------------------------------------------------------------*/
    status = ProSurfaceXyzdataEval(*surface, uv, xyz, der1, der2, normal);
    TEST_CALL_REPORT("ProSurfaceXyzdataEval()", "ProTestMeshAct()",
					status, status != PRO_TK_NO_ERROR);

/*--------------------------------------------------------------------*\
    Draw (or start) a line
\*--------------------------------------------------------------------*/
    if(start)
    {
	ProGraphicsPenPosition(xyz);
    }
    else
    {
	ProGraphicsLineDraw(xyz);
    }

    if ( status == PRO_TK_NO_ERROR )
    {
/*--------------------------------------------------------------------*\
    Write the data to the file
\*--------------------------------------------------------------------*/
       status = ProSurfaceIdGet(*surface, &surface_id);
       TEST_CALL_REPORT("ProSurfaceIdGet()", "ProTestMeshAct()",
					status, status != PRO_TK_NO_ERROR);
       ProTKFprintf(fp,"Surf %3d, pos       (%10.2e, %10.2e, %10.2e)\n",
				    surface_id, xyz[0], xyz[1], xyz[2]);
       ProTKFprintf(fp,"          1st deriv (%10.2e, %10.2e, %10.2e)\n"
	       "                    (%10.2e, %10.2e, %10.2e)\n",
				der1[0][0], der1[0][1], der1[0][2],
				der1[1][0], der1[1][1], der1[1][2]);
       ProTKFprintf(fp,"          2nd deriv (%10.2e, %10.2e, %10.2e)\n"
	       "                    (%10.2e, %10.2e, %10.2e)\n"
	       "                    (%10.2e, %10.2e, %10.2e)\n",
				der2[0][0], der2[0][1], der2[0][2],
				der2[1][0], der2[1][1], der2[1][2],
				der2[2][0], der2[2][1], der2[2][2]);
       ProTKFprintf(fp,"          normal    (%10.2e, %10.2e, %10.2e)\n",
				    normal[0], normal[1], normal[2]);
    }

    return(0);
}

/*====================================================================*\
    FUNCTION :	ProTestSurfaceAct()
    PURPOSE  :  General action function for a surface
\*====================================================================*/
ProError ProTestSurfaceAct(
    ProSurface surface,
    ProError instatus,
    ProAppData tmp_app_data)
{
    ProError status;
    FILE *fp;
    ProSrftype stype;
    int action;
    ProUtilCname type_str, name;
    ProTestGeomData *app_data = (ProTestGeomData *) tmp_app_data;
    ProName w_name;
    ProModelitem modelitem_surface;
    ProColor old_color, highlite_color;
    ProContour	    *contours;
    int contours_num, i;
/*--------------------------------------------------------------------*\
    Decode the action to be performed
\*--------------------------------------------------------------------*/
    action = app_data->action;
    fp     = app_data->fp;

    switch(action)
    {
    case TRAVERSE :

/*--------------------------------------------------------------------*\
	Get the surface name, if any
\*--------------------------------------------------------------------*/
        status = ProSurfaceIdGet(surface, &modelitem_surface.id);
	TEST_CALL_REPORT("ProSurfaceIdGet()", "ProTestSurfaceAct()",
					status, status != PRO_TK_NO_ERROR);
        modelitem_surface.type = ProSurfaceDatatypeGet();
        modelitem_surface.owner = *(app_data->model);

	status = ProModelitemNameGet(&modelitem_surface, w_name);
	TEST_CALL_REPORT("ProModelitemNameGet()", "ProTestSurfaceAct()",
				    status, ((status != PRO_TK_NO_ERROR) &&
					     (status != PRO_TK_E_NOT_FOUND)));
	if(status == PRO_TK_NO_ERROR)
	    ProWstringToString(name, w_name);
	else
	    ProUtilstrcpy(name, "");

/*--------------------------------------------------------------------*\
	Get the surface type
\*--------------------------------------------------------------------*/
	status = ProSurfaceTypeGet(surface, &stype);
	TEST_CALL_REPORT("ProSurfaceTypeGet()", "ProTestSurfaceAct()",
					status, status != PRO_TK_NO_ERROR);
	ProUtilSrftypeStr(stype, type_str);

/*--------------------------------------------------------------------*\
	Print the id, type, and name
\*--------------------------------------------------------------------*/
	if(strlen(name))
	    ProTKFprintf(fp,"%d-%s\n        %s", modelitem_surface.id, 
                         name, type_str);
	else
	    ProTKFprintf(fp,"%-8d%s\n", modelitem_surface.id, type_str);

	break;
    case TEST_MESH :
/*--------------------------------------------------------------------*\
	Make a UV mesh over the surface
\*--------------------------------------------------------------------*/
	highlite_color.method = PRO_COLOR_METHOD_TYPE;
	highlite_color.value.type = PRO_COLOR_HIGHLITE;

	status = ProGraphicsColorModify(&highlite_color, &old_color);
        TEST_CALL_REPORT("ProGraphicsColorModify()", "ProTestSurfaceAct()",
					status, status != PRO_TK_NO_ERROR);

	ProUtilSurfaceMesh(&surface,
			app_data->data.meshdata.resolution,
			app_data->data.meshdata.nlines,
			ProTestMeshAct,
			(ProAppData)tmp_app_data);
	
	status = ProGraphicsColorModify(&old_color, NULL);
        TEST_CALL_REPORT("ProGraphicsColorModify()", "ProTestSurfaceAct()",
					status, status != PRO_TK_NO_ERROR);
	break;
    default :;
    }

/*--------------------------------------------------------------------*\
    Remember the surface (so that the lower Act functions know the
    context)
\*--------------------------------------------------------------------*/
    app_data->surface = &surface;

    ProTKPrintf("ProSurfaceContourVisit Function\n");
/*--------------------------------------------------------------------*\
    Visit all the face contours
\*--------------------------------------------------------------------*/
					
    status = ProUtilCollectSurfaceContours (surface, &contours);
    if (status == PRO_TK_NO_ERROR)
    {
        status = ProArraySizeGet ((ProArray)contours, &contours_num);
        TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestSurfaceAct()", 
            status, status != PRO_TK_NO_ERROR );
        for (i = 0; i < contours_num; i++)
        {
            status = ProTestContourAct (contours[i],
	        PRO_TK_NO_ERROR, (ProAppData)app_data);
        }
        status = ProArrayFree ((ProArray*)&contours);
        TEST_CALL_REPORT( "ProArrayFree()", "ProTestSurfaceAct()", 
            status, status != PRO_TK_NO_ERROR );
    }
    return(PRO_TK_NO_ERROR);
}

ProError ProTestDatumsurfAct(
    ProSurface datumsurf,
    ProError instatus,
    ProAppData app_data)
{
    FILE *fp;
    int id;
    ProError status;

/*--------------------------------------------------------------------*\
    Decode the action to be performed
\*--------------------------------------------------------------------*/
    fp     = ((ProTestGeomData*)app_data)->fp;

    status = ProSurfaceIdGet(datumsurf, &id);
    TEST_CALL_REPORT("ProSurfaceIdGet()", "ProTestDatumsurfAct()",
					status, status != PRO_TK_NO_ERROR);
    ProTKFprintf(fp,"DATUM SURFACE %d...\n", id);

    return(PRO_TK_NO_ERROR);
}

#ifndef PT_PRODUCTS_BUILD
/*====================================================================*\
    FUNCTION :	ProTestQuiltAct()
    PURPOSE  :  General action function for a quilt
\*====================================================================*/
ProError ProTestQuiltAct(
    ProQuilt quilt,
    ProError instatus,
    ProAppData tmp_app_data)
{
    FILE *fp;
    ProTestGeomData *app_data = (ProTestGeomData *) tmp_app_data;
    int quilt_id;
    ProError status;
    ProSurface	    *surfaces;
    int surfaces_num, i;

/*--------------------------------------------------------------------*\
    Decode the action to be performed
\*--------------------------------------------------------------------*/
    fp     = app_data->fp;

    status = ProQuiltIdGet(quilt, &quilt_id);
    TEST_CALL_REPORT("ProQuiltIdGet()", "ProTestQuiltAct()",
					status, status != PRO_TK_NO_ERROR);


    ProTKFprintf(fp,"QUILT %d...\n", quilt_id);
 
    status = ProUtilCollectQuiltSurfaces (quilt, &surfaces);
    if (status == PRO_TK_NO_ERROR)
    {
        status = ProArraySizeGet ((ProArray)surfaces, &surfaces_num);
        TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestQuiltAct()", 
            status, status != PRO_TK_NO_ERROR );
        for (i = 0; i < surfaces_num; i++)
        {
            status = ProTestDatumsurfAct (surfaces[i],
	        PRO_TK_NO_ERROR, (ProAppData)app_data);
        }
        status = ProArrayFree ((ProArray*)&surfaces);
        TEST_CALL_REPORT( "ProArrayFree()", "ProTestQuiltAct()", 
            status, status != PRO_TK_NO_ERROR );
    }

    return(PRO_TK_NO_ERROR);
}
#endif /* #ifndef PT_PRODUCTS_BUILD */

/*====================================================================*\
    FUNCTION :	ProTestAxisAct()
    PURPOSE  :  General action function for an axis
\*====================================================================*/
ProError ProTestAxisAct(
    ProAxis axis,
    ProError instatus,
    ProAppData tmp_app_data)
{
    ProError status;
    ProName w_name;
    ProUtilCname name;
    FILE *fp;
    ProTestGeomData *app_data = (ProTestGeomData *) tmp_app_data;
    ProModelitem axis_model_item;

    fp = app_data->fp;

    axis_model_item.type = PRO_AXIS;
    axis_model_item.owner = *(app_data->model);
    status = ProAxisIdGet(axis, &(axis_model_item.id));
    TEST_CALL_REPORT("ProAxisIdGet()", "ProTestAxisAct()",
				status, (status != PRO_TK_NO_ERROR));
    status = ProModelitemNameGet(&axis_model_item, w_name);
    TEST_CALL_REPORT("ProModelitemNameGet()", "ProTestAxisAct()",
				status, ((status != PRO_TK_NO_ERROR) &&
					 (status != PRO_TK_E_NOT_FOUND)));
    if(status == PRO_TK_NO_ERROR)
	ProWstringToString(name, w_name);
    else
	ProUtilstrcpy(name, "**(NOT FOUND)**");

    ProTKFprintf(fp, "%-8d%s\n", axis_model_item.id, name);

    return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
    FUNCTION :	ProTestCsysAct()
    PURPOSE  :  General action function for an axis
\*====================================================================*/
ProError ProTestCsysAct(
	ProCsys csys,
	ProError instatus,
        ProAppData tmp_app_data)
{
    ProError status;
    ProName w_name;
    ProUtilCname name;
    FILE *fp;
    int id ;
    ProTestGeomData *app_data = (ProTestGeomData *) tmp_app_data;
    ProModelitem modelitem;

    fp = app_data->fp;


    modelitem.type = ProCsysDatatypeGet();
    status = ProCsysIdGet(csys, &modelitem.id);
    TEST_CALL_REPORT("ProCsysIdGet()", "ProTestCsysAct()",
				status, status != PRO_TK_NO_ERROR);
    modelitem.owner = *(app_data->model);

    status = ProModelitemNameGet(&modelitem, w_name);
    TEST_CALL_REPORT("ProModelitemNameGet()", "ProTestCsysAct()",
				status, ((status != PRO_TK_NO_ERROR) &&
					 (status != PRO_TK_E_NOT_FOUND)));
    if(status == PRO_TK_NO_ERROR)
	ProWstringToString(name, w_name);
    else
	ProUtilstrcpy(name, "*****");

    status = ProCsysIdGet(csys,&id);
    TEST_CALL_REPORT("ProCsysIdGet()", "ProTestCsysAct()",
				status, status != PRO_TK_NO_ERROR);
    ProTKFprintf(fp, "%-8d%s\n",id, name);

    return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
    FUNCTION :	ProTestCurveAct()
    PURPOSE  :  General action function for a datum curve
\*====================================================================*/
ProError ProTestCurveAct(
    ProModelitem *curve,
    ProError instatus,
    ProAppData app_data)
{
    ProError status;
    FILE *fp;
    int action;
    ProEnttype etype;
    ProName w_name;
    ProUtilCname name;
    ProUtilCname type_str;
    ProTestGeomData *geomdata;
    int n_tess;
    int  i, n;
    double t;
    ProVector xyz, der1, der2;
    ProEnttype curve_type;
    ProBool visibility;
    ProColor old_color, red_color;
    ProCurve curvePtr = NULL;
    CurveComponent *curvecomps;
    ProModelitem(model_item);

/*--------------------------------------------------------------------*\
	Work only with visible curves
\*--------------------------------------------------------------------*/
    status = ProGeomitemIsInactive(curve, &visibility);
    TEST_CALL_REPORT("ProGeomitemIsInactive()", "ProTestCurveAct()",
				status, status != PRO_TK_NO_ERROR);
    if (visibility == PRO_B_TRUE)
	return PRO_TK_NO_ERROR;


    geomdata = (ProTestGeomData*)app_data;

    action = geomdata->action;

    ProTKPrintf("Curve id (%d) Type (%d)\n", curve->id, curve->type);

    status = ProCurveInit( (ProSolid) curve->owner, curve->id, &curvePtr);
    TEST_CALL_REPORT("ProCurveInit()", "ProTestCurveAct()",
				status, status != PRO_TK_NO_ERROR);
    switch(action)
    {
    case TRAVERSE :
/*--------------------------------------------------------------------*\
	Just dump the curve data to the current file...
\*--------------------------------------------------------------------*/
	fp      = geomdata->fp;

/*--------------------------------------------------------------------*\
	Get the curve type
\*--------------------------------------------------------------------*/
	status = ProCurveTypeGet(curvePtr, &etype);
	TEST_CALL_REPORT("ProCurveTypeGet()", "ProTestCurveAct()",
					status, status != PRO_TK_NO_ERROR);
	ProUtilEnttypeStr(etype, type_str);

/*--------------------------------------------------------------------*\
	Get the curve name
\*--------------------------------------------------------------------*/
	status = ProModelitemNameGet(curve, w_name);
	TEST_CALL_REPORT("ProModelitemNameGet()", "ProTestCurveAct()",
				    status, ((status != PRO_TK_NO_ERROR) &&
					     (status != PRO_TK_E_NOT_FOUND)));
	if(status == PRO_TK_NO_ERROR)
	    ProWstringToString(name, w_name);
	else
	    ProUtilstrcpy(name, "");

/*--------------------------------------------------------------------*\
	Print id, name, and type
\*--------------------------------------------------------------------*/
	if(strlen(name))
	    ProTKFprintf(fp,"    Id : %d, type %s, name : %s\n",
				curve->id, type_str, name);
	else
	    ProTKFprintf(fp,"    Id : %d, type %s\n", curve->id, type_str);


/*--------------------------------------------------------------------*\
	Try to traverse members in case it is a compound
\*--------------------------------------------------------------------*/
	status = ProCurveTypeGet(curvePtr, &curve_type);
        TEST_CALL_REPORT("ProCurveTypeGet()", "ProTestCurveAct()",
                          status, status != PRO_TK_NO_ERROR);

        ProTKPrintf("Curve Type (%d) (%d)\n", curve_type, status);

#ifndef PT_PRODUCTS_BUILD
        if (curve_type == PRO_ENT_CMP_CRV)	
	{
	    status = ProUtilCollectCurveComponents(curvePtr, &curvecomps);
	    if (status!=PRO_TK_NO_ERROR)
		break;

	    status = ProArraySizeGet((ProArray)curvecomps, &n);
	    TEST_CALL_REPORT("ProArraySizeGet()", "ProTestCurveAct()",
					    status, status != PRO_TK_NO_ERROR);
	    for (i=0; i<n; i++)
	    {
		status = ProCurveToGeomitem((ProSolid)curve->owner,
		    curvecomps[i].p_curve, &model_item);	 
		TEST_CALL_REPORT("ProCurveToGeomitem()", "ProTestCurveAct()",
					status, status != PRO_TK_NO_ERROR);
		ProTestCurveAct(&model_item, status, app_data);
	    }
	    status = ProArrayFree((ProArray*)&curvecomps);
	    TEST_CALL_REPORT("ProArrayFree()", "ProTestCurveAct()",
			    		    status, status != PRO_TK_NO_ERROR);
	  }
#endif /* #ifndef PT_PRODUCTS_BUILD */
			  

	break;
    case TESSELLATE :
/*--------------------------------------------------------------------*\
	Just dump the curve data to the current file...
\*--------------------------------------------------------------------*/
	fp      = geomdata->fp;

	n_tess  = geomdata->data.tessdata.n_tess;

	status = ProCurveTypeGet(curvePtr, &curve_type);
	TEST_CALL_REPORT("ProCurveTypeGet()", "ProTestCurveAct()",
                          status, status != PRO_TK_NO_ERROR);

#ifndef PT_PRODUCTS_BUILD
	if (curve_type == PRO_ENT_CMP_CRV)
	{
	    status = ProUtilCollectCurveComponents(curvePtr, &curvecomps);
	    if (status!=PRO_TK_NO_ERROR)
		break;

	    status = ProArraySizeGet((ProArray)curvecomps, &n);
	    TEST_CALL_REPORT("ProArraySizeGet()", "ProTestCurveAct()",
					    status, status != PRO_TK_NO_ERROR);
	    for (i=0; i<n; i++)
	    {
		status = ProCurveToGeomitem((ProSolid)curve->owner,
		    curvecomps[i].p_curve, &model_item);	 
		TEST_CALL_REPORT("ProCurveToGeomitem()", "ProTestCurveAct()",
					status, status != PRO_TK_NO_ERROR);
		ProTestCurveAct(&model_item, status, app_data);
	    }
	    status = ProArrayFree((ProArray*)&curvecomps);
	    TEST_CALL_REPORT("ProArrayFree()", "ProTestCurveAct()",
			    		    status, status != PRO_TK_NO_ERROR);
	    return (PRO_TK_NO_ERROR);
	}
#endif /* #ifndef PT_PRODUCTS_BUILD */

	for(t=0.0;t<=1.0;t+= 1.0 / n_tess)
	{
	    status = ProCurveXyzdataEval(curvePtr, t, xyz, der1, der2);
	    TEST_CALL_REPORT("ProCurveXyzdataEval()", "ProTestCurveAct()",
					status, status != PRO_TK_NO_ERROR);

	    ProTKFprintf(fp, "Edge %3d, pos  (%5.2f, %5.2f, %5.2f)\n",
			curve->id, xyz[0], xyz[1], xyz[2]);
	    ProTKFprintf(fp, "          der1 (%5.2f, %5.2f, %5.2f)\n",
			der1[0], der1[1], der1[2]);
	    ProTKFprintf(fp, "          der2 (%5.2f, %5.2f, %5.2f)\n",
			der2[0], der2[1], der2[2]);

	    red_color.method = PRO_COLOR_METHOD_RGB;
		red_color.value.map.red = 1.0;
		red_color.value.map.green = 0.0;
		red_color.value.map.blue = 0.0;
		
		status = ProGraphicsColorModify(&red_color, &old_color);
            TEST_CALL_REPORT("ProGraphicsColorModify()", "ProTestCurveAct()",
					status, status != PRO_TK_NO_ERROR);

	    if(t<0.01)
            {
		ProGraphicsPenPosition(xyz);
            }
	    else
		ProGraphicsLineDraw(xyz);
	    status = ProGraphicsColorModify(&old_color, NULL);
            TEST_CALL_REPORT("ProGraphicsColorModify()", "ProTestCurveAct()",
					status, status != PRO_TK_NO_ERROR);
	}

    default :;
    }

    return(PRO_TK_NO_ERROR);
}
/*====================================================================*\
    FUNCTION :	ProTestCurvefeatVisit()
    PURPOSE  :	Utility function to visit features of type DATUM curve.
\*====================================================================*/
ProError ProTestCurvefeatVisit(
    ProFeature *feature,
    ProError instatus,
    ProAppData app_data)
{
    ProError status;
    ProGeomitem	    *geomitems;
    int geomitems_num, i;

/*--------------------------------------------------------------------*\
    Visit the CURVES in the feature
\*--------------------------------------------------------------------*/
				     
    status = ProUtilCollectFeatureGeomitems (feature, PRO_CURVE, &geomitems);
    if (status == PRO_TK_NO_ERROR)
    {
        status = ProArraySizeGet ((ProArray)geomitems, &geomitems_num);
        TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestCurvefeatVisit()", 
            status, status != PRO_TK_NO_ERROR );
        for (i = 0; i < geomitems_num; i++)
        {
            status = ProTestCurveAct (&geomitems[i],
	        PRO_TK_NO_ERROR, (ProAppData)app_data);
        }
        status = ProArrayFree ((ProArray*)&geomitems);
        TEST_CALL_REPORT( "ProArrayFree()", "ProTestCurvefeatVisit()", 
            status, status != PRO_TK_NO_ERROR );
    }

    return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
    FUNCTION :	ProTestCurvefeatFilter()
    PURPOSE  :	To act as a filter to visit only features which are datum curves.
\*====================================================================*/
ProError ProTestCurvefeatFilter(
    ProFeature *feature)
{
    ProError status;
    ProFeattype ftype;

    status = ProFeatureTypeGet(feature, &ftype);
    TEST_CALL_REPORT("ProFeatureTypeGet()", "ProTestCurvefeatFilter()",
			    status, status != PRO_TK_NO_ERROR);

    return(ftype == PRO_FEAT_CURVE ? PRO_TK_NO_ERROR : PRO_TK_CONTINUE);
}

/*====================================================================*\
    FUNCTION :	ProTestPartTraverse()
    PURPOSE  :	Traverse all the geometry items on a part, and perform
		the specified action.
\*====================================================================*/
int ProTestPartTraverse(
    ProMdl *model,
    int action)
{
    ProError status;
    ProUtilCname fname;
    ProName w_fname;
    FILE *fp;
    double resolution;
    static double def_res = 0.1;
    static int def_nlines[2]={10,10};
    int n_u, n_v, def_tess, n_tess;
    ProTestGeomData app_data;
    ProSurface	    *surfaces;
    int i, surfaces_num, quilts_num, axis_num, csys_num;
    ProQuilt	    *quilts;
    ProAxis	    *axis;
    ProCsys	    *csys;
    ProFeature	    *features;
    int		    features_num;

/*--------------------------------------------------------------------*\
    Get the name of the output file
\*--------------------------------------------------------------------*/
    ProTestQcrName(model, (char*)TRAVERSAL, fname);
    fp = PTApplsUnicodeFopen(fname,"w");

/*--------------------------------------------------------------------*\
    Set up the general data with the action and the file
\*--------------------------------------------------------------------*/
    app_data.action = action;
    app_data.fp = fp;
    app_data.model = model;

    if(action == TRAVERSE)
    {
/*--------------------------------------------------------------------*\
	Set up a header for the file
\*--------------------------------------------------------------------*/
	ProTKFprintf(fp,"SURFACES..\n");
	ProTKFprintf(fp,"Id      Type      Contour Type      "
		   "Edge    Type      Neighbors (srf/edge)\n");
    }
    else if(action == TEST_MESH)
    {
/*--------------------------------------------------------------------*\
	Get the mesh parameters
\*--------------------------------------------------------------------*/
        ProUtilMsgPrint("geom","TEST Enter resolution [%0f] : ", &def_res);
	ProUtilDoubleGet(NULL, &def_res, &resolution);
	def_res = app_data.data.meshdata.resolution = resolution;

        ProUtilMsgPrint("geom","TEST Enter number of %0s lines [%1d]  : ",
					"U", &def_nlines[0]);
	ProUtilIntGet(NULL, &def_nlines[0], &n_u);
	def_nlines[0] = app_data.data.meshdata.nlines[0] = n_u;

        ProUtilMsgPrint("geom","TEST Enter number of %0s lines [%1d]  : ",
					"V", &def_nlines[1]);
	ProUtilIntGet(NULL, &def_nlines[1], &n_v);
	def_nlines[1] = app_data.data.meshdata.nlines[1] = n_v;
    }
    else if(action == TESSELLATE)
    {
/*--------------------------------------------------------------------*\
	Get the tesselation parameters
\*--------------------------------------------------------------------*/
	def_tess = 10;
        ProUtilMsgPrint("geom","TEST Enter number of tesselations [%0d] : ",
		    &def_tess);
	ProUtilIntGet(NULL, &def_tess, &n_tess);
	def_tess = app_data.data.tessdata.n_tess = n_tess;
    }

/*--------------------------------------------------------------------*\
    Visit all the solid surfaces
\*--------------------------------------------------------------------*/
    status = ProUtilCollectSolidSurfaces ((ProSolid) *model, &surfaces);
    if (status == PRO_TK_NO_ERROR)
    {
        status = ProArraySizeGet ((ProArray)surfaces, &surfaces_num);
        TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestPartTraverse()", 
            status, status != PRO_TK_NO_ERROR );
        for (i = 0; i < surfaces_num; i++)
        {
            status = ProTestSurfaceAct (surfaces[i],
	        PRO_TK_NO_ERROR, (ProAppData)&app_data);
        }
        status = ProArrayFree ((ProArray*)&surfaces);
        TEST_CALL_REPORT( "ProArrayFree()", "ProTestPartTraverse()", 
            status, status != PRO_TK_NO_ERROR );
    }
    
    if(status == PRO_TK_E_NOT_FOUND)
	ProTKFprintf(fp, " -- (No surfaces found) --\n");

#ifndef PT_PRODUCTS_BUILD
/*--------------------------------------------------------------------*\
    Visit all the quilt surfaces
\*--------------------------------------------------------------------*/

    status = ProUtilCollectSolidQuilts ((ProSolid) *model, &quilts);
    if (status == PRO_TK_NO_ERROR)
    {
        status = ProArraySizeGet ((ProArray)quilts, &quilts_num);
        TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestPartTraverse()", 
            status, status != PRO_TK_NO_ERROR );
        for (i = 0; i < quilts_num; i++)
        {
            status = ProTestQuiltAct (quilts[i],
	        PRO_TK_NO_ERROR, (ProAppData)&app_data);
        }
        status = ProArrayFree ((ProArray*)&quilts);
        TEST_CALL_REPORT( "ProArrayFree()", "ProTestPartTraverse()", 
            status, status != PRO_TK_NO_ERROR );
    }
     
    if(status == PRO_TK_E_NOT_FOUND)
	ProTKFprintf(fp, " -- (No quilts found) --\n");
#endif /* #ifndef PT_PRODUCTS_BUILD */

/*--------------------------------------------------------------------*\
    If we are TRAVERSING, visit all the other geometry elements
\*--------------------------------------------------------------------*/
    if(action == TRAVERSE)
    {
/*--------------------------------------------------------------------*\
	Visit all the axes
\*--------------------------------------------------------------------*/
	ProTKFprintf(fp, "AXES ..\n");
	ProTKFprintf(fp,"Id      Name\n");
					 
	status = ProUtilCollectSolidAxis ((ProSolid) *model, &axis);
        if (status == PRO_TK_NO_ERROR)
        {
            status = ProArraySizeGet ((ProArray)axis, &axis_num);
            TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestPartTraverse()", 
                status, status != PRO_TK_NO_ERROR );
            for (i = 0; i < axis_num; i++)
            {
                status = ProTestAxisAct (axis[i],
                    PRO_TK_NO_ERROR, (ProAppData)&app_data);
            }
            status = ProArrayFree ((ProArray*)&axis);
            TEST_CALL_REPORT( "ProArrayFree()", "ProTestPartTraverse()", 
                status, status != PRO_TK_NO_ERROR );
        }
	
	if(status == PRO_TK_E_NOT_FOUND)
	    ProTKFprintf(fp, " -- (No axes found) --\n");

/*--------------------------------------------------------------------*\
	Visit all the csys's
\*--------------------------------------------------------------------*/
	ProTKFprintf(fp, "CSYSs ..\n");
	ProTKFprintf(fp,"Id      Name\n");
					 
	status = ProUtilCollectSolidCsys ((ProSolid) *model, &csys);
        if (status == PRO_TK_NO_ERROR)
        {
            status = ProArraySizeGet ((ProArray)csys, &csys_num);
            TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestPartTraverse()", 
                status, status != PRO_TK_NO_ERROR );
            for (i = 0; i < csys_num; i++)
            {
                status = ProTestCsysAct (csys[i],
                    PRO_TK_NO_ERROR, (ProAppData)&app_data);
            }
            status = ProArrayFree ((ProArray*)&csys);
            TEST_CALL_REPORT( "ProArrayFree()", "ProTestPartTraverse()", 
                status, status != PRO_TK_NO_ERROR );
        }
	if(status == PRO_TK_E_NOT_FOUND)
	    ProTKFprintf(fp, " -- (No csys found) --\n");
    }

/*--------------------------------------------------------------------*\
    Visit all the datum curves
\*--------------------------------------------------------------------*/
    ProTKFprintf(fp,"DATUM CURVES..\n");

    status = ProUtilCollectDtmCurveFeat ((ProSolid) *model, &features);
    if (status == PRO_TK_NO_ERROR)
    {
        status = ProArraySizeGet ((ProArray)features, &features_num);
        TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestPartTraverse()", 
            status, status != PRO_TK_NO_ERROR );
        for (i = 0; i < features_num; i++)
        {
            status = ProTestCurvefeatVisit (&features[i],
                PRO_TK_NO_ERROR, (ProAppData)&app_data);
        }
        status = ProArrayFree ((ProArray*)&features);
        TEST_CALL_REPORT( "ProArrayFree()", "ProTestPartTraverse()", 
            status, status != PRO_TK_NO_ERROR );
        }

/*--------------------------------------------------------------------*\
    Close and display the file
\*--------------------------------------------------------------------*/
    fclose(fp);
    ProStringToWstring(w_fname, fname);
    if(action == TRAVERSE)
    {
	status = ProInfoWindowDisplay(w_fname, NULL, NULL);
	TEST_CALL_REPORT("ProInfoWindowDisplay()", "ProTestPartTraverse()",
					    status, status != PRO_TK_NO_ERROR);
    }
    return(0);
}

/*====================================================================*\
    FUNCTION :	ProTestAsmTravAct()
    PURPOSE  :	General action function for assembly components
\*====================================================================*/
ProError ProTestAsmTravAct(
    ProAsmcomppath *comp_path,
    ProTestGeomData *app_data)
{
    ProError status;
    ProMdl model;
    int i;
    ProUtilCname name, type;
    FILE *fp = app_data->fp;


    status = ProAsmcomppathMdlGet(comp_path, &model);
    TEST_CALL_REPORT("ProAsmcomppathMdlGet()", "ProTestAsmTravAct()",
				status, status != PRO_TK_NO_ERROR);

    ProUtilModelnameGet(&model, name, type);

    for(i=0;i<comp_path->table_num;i++)
	ProTKFprintf(fp,"    ");
    ProTKFprintf(fp,"%-12d%s.%s\n", comp_path->comp_id_table[comp_path->table_num-1],
					name, type);

    return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
    FUNCTION :	ProTestAsmCompAct()
    PURPOSE  :	General action function for assembly components
\*====================================================================*/
ProError ProTestAsmCompAct(
    ProFeature *component,
    ProError instatus,
    ProTestGeomData *app_data)
{
    ProError status;
    ProMdl model;
    ProUtilCname name, type;
    ProAsmcomppath comp_path;
    ProIdTable comp_id_table;
    ProMatrix matrix;
    int i,j;

    FILE *fp = app_data->fp;

    status = ProAsmcompMdlGet(component, &model);
    TEST_CALL_REPORT("ProAsmcompMdlGet()", "ProTestAsmCompAct()",
				status, status != PRO_TK_NO_ERROR);

    ProUtilModelnameGet(&model, name, type);

    ProTKFprintf(fp,"%-12d%s.%s\n", component->id, name, type);

/*--------------------------------------------------------------------*\
    Get the transformation matrix
\*--------------------------------------------------------------------*/
    comp_id_table[0] = component->id;
    comp_id_table[1] = -1;
    status = ProAsmcomppathInit( (ProSolid) *app_data->model, comp_id_table, 1, &comp_path);
    TEST_CALL_REPORT("ProAsmcomppathInit()", "ProTestAsmCompAct()",
				status, status != PRO_TK_NO_ERROR);

/*--------------------------------------------------------------------*\
    Top down
\*--------------------------------------------------------------------*/
    status = ProAsmcomppathTrfGet(&comp_path, PRO_B_FALSE, matrix);
    TEST_CALL_REPORT("ProAsmcomppathTrfGet()", "ProTestAsmCompAct()",
				status, status != PRO_TK_NO_ERROR);
    ProTKFprintf(fp,"Top down matrix ..\n");
    for(i=0;i<4;i++)
    {
	for(j=0;j<4;j++)
	    ProTKFprintf(fp,"%6.2f ", matrix[i][j]);
	ProTKFprintf(fp,"\n");
    }

/*--------------------------------------------------------------------*\
    Bottom up
\*--------------------------------------------------------------------*/
    status = ProAsmcomppathTrfGet(&comp_path, PRO_B_TRUE, matrix);
    TEST_CALL_REPORT("ProAsmcomppathTrfGet()", "ProTestAsmCompAct()",
				status, status != PRO_TK_NO_ERROR);
    ProTKFprintf(fp,"Bottom up matrix ..\n");
    for(i=0;i<4;i++)
    {
	for(j=0;j<4;j++)
	    ProTKFprintf(fp,"%6.2f ", matrix[i][j]);
	ProTKFprintf(fp,"\n");
    }

    return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
    FUNCTION :	ProTestAsmTraverse()
    PURPOSE  :	Traverse all the geometry items on an assembly, and
		perform the specified action.
\*====================================================================*/
int ProTestAsmTraverse(
    ProMdl *model,
    int action)
{
    ProError status;
    ProUtilCname fname;
    ProName w_fname;
    FILE *fp;
    ProTestGeomData app_data;
    ProAxis *axis;
    int axis_num, i;
    ProFeature *features;
    int features_num;

/*--------------------------------------------------------------------*\
    Temporary get out for tests not implemented for assmblies yet -
		MESH and TESSELLATE
\*--------------------------------------------------------------------*/
    if(action != TRAVERSE)
    {
	ProUtilMsgPrint("geom","TEST This test not implement for assemblies yet");
	return(0);
    }

/*--------------------------------------------------------------------*\
    Get the name of the output file
\*--------------------------------------------------------------------*/
    ProTestQcrName(model, (char*)TRAVERSAL, fname);
    fp = PTApplsUnicodeFopen(fname,"w");

/*--------------------------------------------------------------------*\
    Set up the general data with the action and the file
\*--------------------------------------------------------------------*/
    app_data.action = action;
    app_data.fp = fp;
    app_data.model = model;

    if(action == TRAVERSE)
    {
/*--------------------------------------------------------------------*\
	Traverse the components of the assembly
\*--------------------------------------------------------------------*/
	ProTKFprintf(fp,"COMPONENTS..\n");
	ProTKFprintf(fp,"Feat id     Model name\n");
	status = ProUtilAsmTraverse((ProAssembly)*model, 
		    (ProFunction)ProTestAsmTravAct, (ProAppData*)&app_data);
	if(status == PRO_TK_E_NOT_FOUND)
	    ProTKFprintf(fp, "--- (No assembly components) ---\n");

/*--------------------------------------------------------------------*\
	Visit all the axes
\*--------------------------------------------------------------------*/
	ProTKFprintf(fp, "AXES ..\n");
	ProTKFprintf(fp,"Id      Name\n");
					 
	status = ProUtilCollectSolidAxis ((ProSolid) *model, &axis);
        if (status == PRO_TK_NO_ERROR)
        {
            status = ProArraySizeGet ((ProArray)axis, &axis_num);
            TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestAsmTraverse()", 
                status, status != PRO_TK_NO_ERROR );
            for (i = 0; i < axis_num; i++)
            {
                status = ProTestAxisAct (axis[i],
                    PRO_TK_NO_ERROR, (ProAppData)&app_data);
            }
            status = ProArrayFree ((ProArray*)&axis);
            TEST_CALL_REPORT( "ProArrayFree()", "ProTestAsmTraverse()", 
                status, status != PRO_TK_NO_ERROR );
        }

	if(status == PRO_TK_E_NOT_FOUND)
	    ProTKFprintf(fp, " -- (No axes found) --\n");
    }

/*--------------------------------------------------------------------*\
    Visit all the datum curves
\*--------------------------------------------------------------------*/
    ProTKFprintf(fp,"DATUM CURVES..\n");

    status = ProUtilCollectDtmCurveFeat ((ProSolid) *model, &features);
    if (status == PRO_TK_NO_ERROR)
    {
        status = ProArraySizeGet ((ProArray)features, &features_num);
        TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestAsmTraverse()", 
            status, status != PRO_TK_NO_ERROR );
        for (i = 0; i < features_num; i++)
        {
            status = ProTestCurvefeatVisit (&features[i],
                PRO_TK_NO_ERROR, (ProAppData)&app_data);
        }
        status = ProArrayFree ((ProArray*)&features);
        TEST_CALL_REPORT( "ProArrayFree()", "ProTestAsmTraverse()", 
            status, status != PRO_TK_NO_ERROR );
    }

/*--------------------------------------------------------------------*\
    Close and display the file
\*--------------------------------------------------------------------*/
    fclose(fp);
    ProStringToWstring(w_fname, fname);
    if(action == TRAVERSE)
    {
	status = ProInfoWindowDisplay(w_fname, NULL, NULL);
        TEST_CALL_REPORT("ProInfoWindowDisplay()", "ProTestAsmTraverse()",
	    status, status != PRO_TK_NO_ERROR);
    }
    
    return(0);
}

/*====================================================================*\
    FUNCTION :	ProTestGeomTraverse()
    PURPOSE  :	Command Traversal for listing all geometry items in a model
\*====================================================================*/
int ProTestGeomTraverse(
    ProMdl *model,
    int action)
{
    ProError status;
	ProMdlExtension modelExtension;
    ProMdldata mdata;
    ProUtilCname type;

/*--------------------------------------------------------------------*\
    Find out the model type
\*--------------------------------------------------------------------*/
    status = ProMdlExtensionGet(*model, modelExtension);
    TEST_CALL_REPORT("ProMdlExtensionGet()", "ProTestGeomTraverse()",
					status, status != PRO_TK_NO_ERROR);
    ProWstringToString(type, modelExtension);

/*--------------------------------------------------------------------*\
    Use the appropriate traversal function
\*--------------------------------------------------------------------*/
    if(!ProUtilStrcmp(type, (char*)"PRT"))

	ProTestPartTraverse(model, action);

    else if(!ProUtilStrcmp(type, (char*)"ASM"))

	ProTestAsmTraverse(model, action);

    return(0);
}

/*====================================================================*\
    FUNCTION :	ProTestGeomShape()
    PURPOSE  :	Command to dump the geometry of selected geometry items
\*====================================================================*/
int ProTestGeomShape(
    ProMdl *model)
{
    ProError status;
    FILE *temp_fp, *qcr_fp;
    ProSelection *sel;
    ProUtilCname type_str, qcrname;
    char *temp;
    int n_sel, cont=1;
    ProUtilCname cname;
    ProName name;
    ProName w_fname;
    char sel_opt[] = "edge,axis,csys,curve,point,dtmqlt,comp_crv,surface,datum";
    ProModelitem model_item;

/*--------------------------------------------------------------------*\
    Open the QCR file
\*--------------------------------------------------------------------*/
    ProTestQcrName(model, (char*)TRAVERSAL, qcrname);
    qcr_fp = PTApplsUnicodeFopen(qcrname,"w");

/*--------------------------------------------------------------------*\
    While the user selects geometry items
\*--------------------------------------------------------------------*/
    ProUtilMsgPrint("geom","TEST Select a geometrical item");
    while(cont)
    {
	status = ProSelect(sel_opt, 1, NULL, NULL, NULL, NULL,
                              &sel, &n_sel);
	TEST_CALL_REPORT("ProSelect()", "ProTestGeomShape()", status,
			((status != PRO_TK_NO_ERROR &&
			  status != PRO_TK_USER_ABORT)));
	if(status == PRO_TK_USER_ABORT || n_sel < 1)
	   break;

/*--------------------------------------------------------------------*\
	Get a string for the item type
\*--------------------------------------------------------------------*/
	status = ProSelectionModelitemGet(sel[0], &model_item);
	TEST_CALL_REPORT("ProSelectionModelitemGet()", "ProTestGeomShape()",
			status, status != PRO_TK_NO_ERROR);
	ProUtilObjtypeStr(model_item.type, type_str);

/*--------------------------------------------------------------------*\
	Get the name of the item, and report the item
\*--------------------------------------------------------------------*/
	status = ProModelitemNameGet(&model_item, name);
	TEST_CALL_REPORT("ProModelitemNameGet()", "ProTestGeomShape()",
		status, (status != PRO_TK_NO_ERROR &&
			 status != PRO_TK_E_NOT_FOUND));
	if(status == PRO_TK_NO_ERROR)
	{
	    ProUtilMsgPrint("geom",
			    "TEST Item selected was %0s id %1d, named %2w",
			    type_str, &model_item.id, name);
	    ProWstringToString(cname, name);
	    ProTKFprintf(qcr_fp, "Item selected was %s, id %d, name %s\n",
				type_str, model_item.id, cname);
	}
	else
	{
	    ProUtilMsgPrint("geom","TEST Item selected was %0s id %1d",
					type_str, &model_item.id);
	    ProTKFprintf(qcr_fp, "Item selected was %s, id %d\n",
				type_str, model_item.id);
	}

/*--------------------------------------------------------------------*\
	Open a temporary file for the information window
\*--------------------------------------------------------------------*/
	temp = (char*)"temp";
	temp_fp = PTApplsUnicodeFopen(temp,"w");

/*--------------------------------------------------------------------*\
	Dump the geometry to the QCR file
\*--------------------------------------------------------------------*/
	ProUtilGeomitemDump(qcr_fp, &sel[0]);
	ProTKFprintf(qcr_fp,
"========================================================================\n");

/*--------------------------------------------------------------------*\
	Dump to the temporary info file
\*--------------------------------------------------------------------*/
	ProUtilGeomitemDump(temp_fp, &sel[0]);

/*--------------------------------------------------------------------*\
	Close and display the info file.
\*--------------------------------------------------------------------*/
	fclose(temp_fp);
	ProStringToWstring(w_fname, temp);
	status = ProInfoWindowDisplay(w_fname, NULL, NULL);
	TEST_CALL_REPORT("ProInfoWindowDisplay()", "ProTestGeomShape()",
					    status, status != PRO_TK_NO_ERROR);
    }

    fclose(qcr_fp);
    return(0);
}

/*====================================================================*\
    FUNCTION :	ProTestGeomMindist()
    PURPOSE  :	Command to calculate the minimum distance between a
		selected csys, datum point, or vertex, and selected
		edges, curves, and surfaces.
		This uses inverse evaluation.
\*====================================================================*/
int ProTestGeomMindist(
    ProMdl *model)
{
    ProError status;
    ProSelection *sel;
    ProCsys p_csys; 
    ProCurve p_curve ;
    ProUtilCname type_str, qcrname;
    FILE *qcr_fp;
    int n_sel, m, cont=1;
    ProColor old_color, highlite_color;
    ProGeomitemdata *geomdata;
    ProVector point, closest, point2;
    double dist;
    ProMatrix transform;
    ProPoint p_point;
    ProEdge p_edge;
    char sel_opt[] = "csys,point,edge_end,curve_end";
    ProModelitem model_item;
    ProUvParam uv_param;
    ProAsmcomppath comp_path;
    ProAsmcomppath sel_comp_path;

/*--------------------------------------------------------------------*\
    Open the QCR file
\*--------------------------------------------------------------------*/
    ProTestQcrName(model, (char*)TRAVERSAL, qcrname);
    qcr_fp = PTApplsUnicodeFopen(qcrname,"w");

/*--------------------------------------------------------------------*\
    Ask the user to select a csys, datum point, or vertex.
\*--------------------------------------------------------------------*/
    ProUtilMsgPrint("geom","TEST Select an item to specify the distance point");
    status = ProSelect(sel_opt, 1, NULL, NULL, NULL, NULL, &sel, &n_sel);
    TEST_CALL_REPORT("ProSelect()", "ProTestGeomMindist()", status,
	((status != PRO_TK_NO_ERROR && status != PRO_TK_USER_ABORT)));
    if(status == PRO_TK_USER_ABORT || n_sel < 1)
       return(0);

    status = ProSelectionModelitemGet(sel[0], &model_item);
    TEST_CALL_REPORT("ProSelectionModelitemGet()", "ProTestGeomMindist()",
                    status, status != PRO_TK_NO_ERROR);

/*--------------------------------------------------------------------*\
    Get the location of the point for each type of item
\*--------------------------------------------------------------------*/
    switch(model_item.type)
    {

    case PRO_CSYS :
	status = ProCsysInit( (ProSolid) model_item.owner,model_item.id, &p_csys);
	TEST_CALL_REPORT("ProCsysInit()", "ProTestGeomMindist()",
                status, status != PRO_TK_NO_ERROR );
	status = ProCsysDataGet(p_csys, &geomdata);
	TEST_CALL_REPORT("ProCsysDataGet()", "ProTestGeomMindist()",
		status, status != PRO_TK_NO_ERROR );

	if(status != PRO_TK_NO_ERROR)
	{
	    ProUtilMsgPrint("geom","TEST Failed to get geometry");
	    return(0);
	}

	ProUtilVectorCopy(geomdata->data.p_csys_data->origin, point);
	break;

    case PRO_POINT :
	status = ProPointInit( (ProSolid) model_item.owner,model_item.id,&p_point);
	TEST_CALL_REPORT("ProPointInit()", "ProTestGeomMindist()",
		status, status != PRO_TK_NO_ERROR );
	status = ProPointCoordGet(p_point, point);
	TEST_CALL_REPORT("ProPointCoordGet()", "ProTestGeomMindist()",
		status, status != PRO_TK_NO_ERROR );

	if(status != PRO_TK_NO_ERROR)
	{
	    ProUtilMsgPrint("geom","TEST Failed to get geometry");
	    return(0);
	}

	break;

    case PRO_EDGE_START :
    case PRO_EDGE_END :
        status = ProEdgeInit( (ProSolid) model_item.owner, model_item.id, &p_edge);
	TEST_CALL_REPORT("ProEdgeInit()", "ProTestGeomMindist()",
		status, status != PRO_TK_NO_ERROR );

	status = ProSelectionUvParamGet(sel[0], uv_param);
	TEST_CALL_REPORT("ProSelectionUvParamGet()", "ProTestGeomMindist()",
		status, status != PRO_TK_NO_ERROR );
	status = ProEdgeXyzdataEval(p_edge, uv_param[0], 
					point, NULL, NULL, NULL);
	TEST_CALL_REPORT("ProEdgeXyzdataEval()", "ProTestGeomMindist()",
		status, status != PRO_TK_NO_ERROR );

	if(status != PRO_TK_NO_ERROR)
	{
	    ProUtilMsgPrint("geom","TEST Failed to get geometry");
	    return(0);
	}
	break;

    case PRO_CRV_START :
    case PRO_CRV_END :
	status = ProCurveInit( (ProSolid) model_item.owner,model_item.id,&p_curve) ;
	status = ProSelectionUvParamGet(sel[0], uv_param);
	TEST_CALL_REPORT("ProSelectionUvParamGet()", "ProTestGeomMindist()",
		status, status != PRO_TK_NO_ERROR );
	status = ProCurveXyzdataEval(p_curve, uv_param[0], point, NULL, NULL);
	TEST_CALL_REPORT("ProCurveXyzdataEval()", "ProTestGeomMindist()",
		status, status != PRO_TK_NO_ERROR );

	if(status != PRO_TK_NO_ERROR)
	{
	    ProUtilMsgPrint("geom","TEST Failed to get geometry");
	    return(0);
	}
	break;

    default :;
    }

/*--------------------------------------------------------------------*\
    Transform to root coordinates (for assembly mode)
\*--------------------------------------------------------------------*/
    status = ProSelectionAsmcomppathGet(sel[0], &comp_path);
    TEST_CALL_REPORT("ProSelectionAsmcomppathGet()", "ProTestGeomMindist()",
		    status, status != PRO_TK_NO_ERROR);
    status = ProAsmcomppathTrfGet(&comp_path, PRO_B_TRUE, transform);
    TEST_CALL_REPORT("ProAsmcomppathTrfGet()", "ProTestGeomMindist()",
		    status, status != PRO_TK_NO_ERROR);
    ProUtilPointTrans(transform, point, point2);

    ProTKFprintf(qcr_fp, "Closest point to %6.2f, %6.2f, %6.2f to ...\n",
				point2[0], point2[1], point2[2]);

/*--------------------------------------------------------------------*\
    Select edges, curves, and surfaces for the min dist check
\*--------------------------------------------------------------------*/
    ProUtilMsgPrint("geom","TEST Select a surface, edge, or curve");

    while(cont)
    {
	status = ProSelect((char*)"edge,curve,surface", 1,
			    NULL, NULL, NULL, NULL, &sel, &n_sel);
	TEST_CALL_REPORT("ProSelect()", "ProTestGeomMindist()", status,
			    ((status != PRO_TK_NO_ERROR &&
			      status != PRO_TK_USER_ABORT)));
	if(status == PRO_TK_USER_ABORT || n_sel < 1)
	   break;

	status = ProSelectionModelitemGet(sel[0], &model_item);
	TEST_CALL_REPORT("ProSelectionModelitemGet()", "ProTestGeomMindist()",
                    status, status != PRO_TK_NO_ERROR);

        status = ProSelectionAsmcomppathGet(sel[0], &sel_comp_path);
/*--------------------------------------------------------------------*\
	Report the selected item
\*--------------------------------------------------------------------*/
	ProUtilObjtypeStr(model_item.type, type_str);
	ProTKFprintf(qcr_fp, "\n    %s id %d\n", type_str,  model_item.id);
	for(m=0;m<sel_comp_path.table_num;m++)
	    ProTKFprintf(qcr_fp,"        comp_id_table[%d] = %d\n",
				    m, sel_comp_path.comp_id_table[m]);

/*--------------------------------------------------------------------*\
	Get the minimum distance
\*--------------------------------------------------------------------*/
	if(ProUtilPointMindist(point2, &sel[0], &dist, closest) == 0)
	{
/*--------------------------------------------------------------------*\
	    Draw a line to closest point.
\*--------------------------------------------------------------------*/
	    highlite_color.method = PRO_COLOR_METHOD_TYPE;
		highlite_color.value.type = PRO_COLOR_HIGHLITE;

		status = ProGraphicsColorModify(&highlite_color, &old_color);
		TEST_CALL_REPORT("ProGraphicsColorModify()", "ProTestGeomMindist()",
					status, status != PRO_TK_NO_ERROR);
	    ProGraphicsPenPosition(point);
	    ProGraphicsLineDraw(closest);
	    status = ProGraphicsColorModify(&old_color, NULL);
            TEST_CALL_REPORT("ProGraphicsColorModify()", "ProTestSurfaceAct()",
					status, status != PRO_TK_NO_ERROR);
	    ProUtilMsgPrint("geom","TEST Distance = %0(6.2)f", &dist);
	}

	ProTKFprintf(qcr_fp,"    = (%6.2f, %6.2f, %6.2f) (distance %6.2f)\n",
			closest[0], closest[1], closest[2], dist);
    }

    fclose(qcr_fp);
    
    return(0);
}

/*====================================================================*\
    FUNCTION :	ProTestTesselCurve()
    PURPOSE  :  Retrieves the curve tessellation
\*====================================================================*/
int ProTestTesselCurve(ProMdl *mdl)
{
    ProError err;
    ProMdl owner;
    ProModelitem modelitem;
    ProCurve curve;
    ProSelection *p_sel;
    int n_sel;
    double tolerance = 0;
    Pro3dPnt *p_points;
    int count_pnt, i;
    ProUtilCname fname;
    FILE *qcr_fp;
    
    ProTestQcrName(mdl, (char*)".tsl", fname);
    qcr_fp = PTApplsUnicodeFopen(fname,"w");
    
    ProUtilMsgPrint("gen", (char*)"TEST %0s", "Select curve");
    err = ProSelect ((char*)"curve", 1, NULL, NULL, NULL, NULL, &p_sel,
        &n_sel);
    if (err != PRO_TK_NO_ERROR || n_sel != 1)
        return (0);

    err = ProSelectionModelitemGet (p_sel[0], &modelitem);
    TEST_CALL_REPORT ("ProSelectionModelitemGet()", "ProTestTesselCurve()",
        err, err != PRO_TK_NO_ERROR);
        
    
    err = ProModelitemMdlGet (&modelitem, &owner);
    TEST_CALL_REPORT ("ProModelitemMdlGet()", "ProTestTesselCurve()",
        err, err != PRO_TK_NO_ERROR);
        

    err = ProCurveInit ((ProSolid)owner, modelitem.id, &curve);
    TEST_CALL_REPORT ("ProCurveInit()", "ProTestTesselCurve()",
        err, err != PRO_TK_NO_ERROR);
        
    ProUtilMsgPrint ( "gen", "TEST %0s", "Enter tolerance" );
    err = ProMessageDoubleRead (NULL, &tolerance);
        
    err = ProCurveTessellationGet (curve, tolerance, &p_points, &count_pnt);
    TEST_CALL_REPORT ("ProCurveTessellationGet()", "ProTestTesselCurve()",
        err, err != PRO_TK_NO_ERROR);
        
    ProTKFprintf(qcr_fp, "Tessellation points: \n");   
    for(i = 0; i<count_pnt; i++)
    {
        ProGraphicsCircleDraw( p_points[i], 1 );
        ProTKFprintf(qcr_fp, "point %d : %f, %f, %f \n", i,
			p_points[i][0], p_points[i][1], p_points[i][2]);
    }
    ProArrayFree((ProArray*)&p_points);
    fclose(qcr_fp);    
    return(0);
}