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


/*--------------------------------------------------------------------*\
Pro/TOOLKIT includes
\*--------------------------------------------------------------------*/
#include <ProToolkit.h>
#include <ProObjects.h>
#include <ProSurface.h>
#include <ProFeature.h>
#include <ProFeatType.h>
#include <ProSelection.h>
#include <ProSolid.h>
#include <ProAsmcomp.h>
#include <ProEdge.h>
#include <ProAxis.h>
#include <ProCsys.h>
#include <ProCurve.h>
#include <ProPoint.h>
#include <ProGeomitem.h>

/*--------------------------------------------------------------------*\
Application includes
\*--------------------------------------------------------------------*/
#include "TestGeom.h"
#include "UtilColor.h"
#include "UtilGeom.h"
#include "UtilIntfData.h"
#include "UtilMath.h"
#include "UtilMatrix.h"
#include "UtilNames.h"
#include "UtilString.h"
#include "UtilVisit.h"
#include "UtilCollect.h"
#include <UtilTypes.h>
#include <UtilMessage.h>
#include <UtilFiles.h>
#include <PTApplsUnicodeUtils.h>
#include <ProTKRunTime.h>
/*====================================================================*\
    FUNCTION :  ProUtilSurfaceMesh()
    PURPOSE  :  Make a UV mesh over a specified surface
\*====================================================================*/
int ProUtilSurfaceMesh(
    ProSurface *surface,
    double resolution,          /* The step size in model unit */
    int nlines[2],              /* No of U and V lines */
    ProUtilMeshAct action,      /* Function to call at each mesh point */
    ProAppData tmp_app_data)    /* General data */
{
    ProError status;
    ProGeomitemdata  *sdata;
    double u_min, v_min, u_max, v_max, u_step, v_step, u_res, v_res,
                                uv[2], last_uv[2], der1[2][3];
    ProTestGeomData *app_data = (ProTestGeomData *) tmp_app_data;
    ProUvStatus uvstatus;
    int start, error;
    ProSolid solid;

    solid = (ProSolid)*(app_data->model);
/*--------------------------------------------------------------------*\
    Get the maxmum and minium U and V for the surface
\*--------------------------------------------------------------------*/
    status = ProSurfaceDataGet(*surface, &sdata);
    TEST_CALL_REPORT("ProSurfaceDataGet()","ProUtilSurfaceMesh()",
                        status, status != PRO_TK_NO_ERROR);

/*--------------------------------------------------------------------*\
    Calculate the U and V parameters
\*--------------------------------------------------------------------*/
    u_min = sdata->data.p_surface_data->uv_min[0];
    v_min = sdata->data.p_surface_data->uv_min[1];
    u_max = sdata->data.p_surface_data->uv_max[0];
    v_max = sdata->data.p_surface_data->uv_max[1];
    u_step = (u_max - u_min) / (nlines[0] + 1);
    v_step = (v_max - v_min) / (nlines[1] + 1);

/*--------------------------------------------------------------------*\
    Calculate the U and V resolution to give the correct resolution in
    model units.
\*--------------------------------------------------------------------*/
    uv[0] = (u_max + u_min) / 2.0;
    uv[1] = (v_max + v_min) / 2.0;
    status = ProSurfaceXyzdataEval(*surface, uv, NULL, der1, NULL, NULL);
    TEST_CALL_REPORT("ProSurfaceXyzdataEval()","ProUtilSurfaceMesh()",
                        status, status != PRO_TK_NO_ERROR);
    u_res = resolution / ProUtilVectorLength(der1[0]);
    v_res = resolution / ProUtilVectorLength(der1[1]);

/*--------------------------------------------------------------------*\
    Adjust the upper limits to ensure that we get a mesh line at the max
\*--------------------------------------------------------------------*/
    u_max += u_res/ 2.0;
    v_max += v_res/ 2.0;
/*--------------------------------------------------------------------*\
    Do lines of constant U
\*--------------------------------------------------------------------*/
    for(uv[0] =  u_min;
        uv[0] <= u_max;
        uv[0] += u_step)
    {
        last_uv[1] = -1000000.0;
        for(uv[1] =  v_min;
            uv[1] <= v_max;
            uv[1] += v_res)
        {
/*--------------------------------------------------------------------*\
            If this point is outside the domain, skip it
\*--------------------------------------------------------------------*/
            status = ProSurfaceUvpntVerify(solid, *surface, uv, &uvstatus);
            TEST_CALL_REPORT("ProSurfaceUvpntVerify()", "ProUtilSurfaceMesh()",
                                        status, status != PRO_TK_NO_ERROR);
            if(uvstatus == PRO_UV_OUTSIDE)
                continue;

            start = (uv[1] - last_uv[1]) > (u_res + EPSM6);

            error = (*action)(surface, uv, start, app_data);
            if(error != 0)
	      { 
		status = ProGeomitemdataFree(&sdata);
		TEST_CALL_REPORT("ProGeomitemdataFree()","ProUtilSurfaceMesh()"                                  ,status, status != PRO_TK_NO_ERROR);
		return(error);
	      }
	  
            last_uv[1] = uv[1];
        }
    }

/*--------------------------------------------------------------------*\
    Do lines of constant V
\*--------------------------------------------------------------------*/
    for(uv[1] =  v_min;
        uv[1] <= v_max;
        uv[1] += v_step)
    {
        last_uv[0] = -1000000.0;
        for(uv[0] =  u_min;
            uv[0] <= u_max;
            uv[0] += u_res)
        {
/*--------------------------------------------------------------------*\
            If this point is outside the domain, skip it
\*--------------------------------------------------------------------*/
            status = ProSurfaceUvpntVerify(solid, *surface, uv, &uvstatus);
            TEST_CALL_REPORT("ProSurfaceUvpntVerify()", "ProUtilSurfaceMesh()",
                                        status, status != PRO_TK_NO_ERROR);
            if(uvstatus == PRO_UV_OUTSIDE)
                continue;

            start = (uv[0] - last_uv[0]) > (v_res + EPSM6);

            error = (*action)(surface, uv, start, tmp_app_data);
            if(error != 0)
	      {
		status = ProGeomitemdataFree(&sdata);
		TEST_CALL_REPORT("ProGeomitemdataFree()","ProUtilSurfaceMesh()",
                        status, status != PRO_TK_NO_ERROR);
		return(error);
	      }
	    last_uv[0] = uv[0];
        }
    }
    status = ProGeomitemdataFree(&sdata);
    TEST_CALL_REPORT("ProGeomitemdataFree()","ProUtilSurfaceMesh()",
                        status, status != PRO_TK_NO_ERROR);

    return(0);
}

/*====================================================================*\
    FUNCTION :  ProUtilGeomitemshapeDump()
    PURPOSE  :  Dump the geometry of a geometry item
\*====================================================================*/
int ProUtilGeomitemshapeDump(
    FILE *fp,
    ProGeomitemdata *geom)
{
    ProUtilCname type_str;

    switch(geom->obj_type)
    {
    case PRO_AXIS :
    case PRO_EDGE :
    case PRO_CURVE :
    case PRO_POINT :
/*--------------------------------------------------------------------*\
        Get and dump geometry of the curve for the axis, edge, or curve
\*--------------------------------------------------------------------*/
        ProUtilObjtypeStr(geom->obj_type, type_str);

        ProTKFprintf(fp,"CURVE geometry for %s\n", type_str);
        ProUtilCurvedataPrint(fp, (char*)"\0", geom->data.p_curve_data);
        break;
    case PRO_CSYS :
/*--------------------------------------------------------------------*\
        Dump directly the CSYS geometry
\*--------------------------------------------------------------------*/
        ProTKFprintf(fp,"CSYS geometry\n");
        ProTKFprintf(fp,"X vector = %.5f, %.5f, %.5f\n",
                                geom->data.p_csys_data->x_vector[0],
                                geom->data.p_csys_data->x_vector[1],
                                geom->data.p_csys_data->x_vector[2]);
        ProTKFprintf(fp,"Y vector = %.5f, %.5f, %.5f\n",
                                geom->data.p_csys_data->y_vector[0],
                                geom->data.p_csys_data->y_vector[1],
                                geom->data.p_csys_data->y_vector[2]);
        ProTKFprintf(fp,"Z vector = %.5f, %.5f, %.5f\n",
                                geom->data.p_csys_data->z_vector[0],
                                geom->data.p_csys_data->z_vector[1],
                                geom->data.p_csys_data->z_vector[2]);
        ProTKFprintf(fp,"Shift vec= %.5f, %.5f, %.5f\n",
                                geom->data.p_csys_data->origin[0],
                                geom->data.p_csys_data->origin[1],
                                geom->data.p_csys_data->origin[2]);
        break;
    case PRO_SURFACE :
/*--------------------------------------------------------------------*\
        Get and dump the surface geometry
\*--------------------------------------------------------------------*/
        ProUtilObjtypeStr(geom->obj_type, type_str);

        ProTKFprintf(fp,"SURFACE geometry for %s\n", type_str);
        ProUtilSurfacedataPrint(fp, (char*)"\0", geom->data.p_surface_data);

    default :;
    }

    return(0);
}

/*====================================================================*\
    FUNCTION :  ProUtilGeomitemDump()
    PURPOSE  :  Dump the geometry of a selected geometry item
                EDGE, AXIS, CSYS, CURVE, POINT, QUILT, SURFACE
\*====================================================================*/
int ProUtilGeomitemDump(
    FILE *fp,
    ProSelection *item)
{
    ProError status;
    ProVector xyz_point,  xyz_min, xyz_max, dir;
    double area, length;
    int m, i, n, curve_id, comp_crv_id;
    ProMdl comp;
    ProAsmcomppath temp_comp_path;
    ProCharName name, type;
    ProGeomitemdata *gitem_data = NULL;
    ProAxis axis;
    ProPoint point, point2;
    ProCsys p_csys;
    ProCurve p_curve ;
    ProEdge p_edge;
    ProQuilt p_quilt;
    ProSurface p_surface;
    ProAsmcomppath comp_path;
    ProModelitem model_item;
    ProGeomitem geomitem;
    ProCurvedata *p_curve_data;
    ProSurfacedata *p_surf_data;
    ProMdlType mdltype;
    CurveComponent *curvecomps;
    ProEnttype curve_type;
    ProVectorlist vect_list;
    int         num, id;
    double	t;
    ProUvParam uv[2], uvd1[2], uvd2[2];
    ProCharName type_str;
    ProContour  *p_contours;

    status = ProSelectionAsmcomppathGet(*item, &comp_path);
    TEST_CALL_REPORT("ProSelectionAsmcomppathGet()", "ProUtilGeomitemDump()",
                    status, status != PRO_TK_NO_ERROR);

/*--------------------------------------------------------------------*\
    Dump the component id table (the path through the assembly)
\*--------------------------------------------------------------------*/
    ProTKFprintf(fp,"Component table ..\n");
    memcpy(&temp_comp_path, &comp_path, sizeof(ProAsmcomppath));
    for(m=0; m < comp_path.table_num; m++)
    {
        temp_comp_path.table_num = m+1;
        status = ProAsmcomppathMdlGet(&temp_comp_path, &comp);
        TEST_CALL_REPORT("ProAsmcomppathMdlGet()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);

        ProUtilModelnameGet(&comp, name, type);

        ProTKFprintf(fp, "    comp_id_table[%2d] = %2d, model = %s.%s\n",
                                m, comp_path.comp_id_table[m],
                                name, type);
    }
    ProTKFprintf(fp,"\n");
/*--------------------------------------------------------------------*\
    Depending upon the object type, get its geometry
\*--------------------------------------------------------------------*/
    status = ProSelectionModelitemGet(*item, &model_item);
    TEST_CALL_REPORT("ProSelectionModelitemGet()", "ProUtilGeomitemDump()",
                    status, status != PRO_TK_NO_ERROR);

/*--------------------------------------------------------------------*\
    Dump the geomitem type and id
\*--------------------------------------------------------------------*/
    ProUtilObjtypeStr(model_item.type, type_str);

    ProTKFprintf(fp, "Geometry item %s id %d.\n",  type_str, model_item.id);

    switch(model_item.type)
    {
    case PRO_EDGE :
/*--------------------------------------------------------------------*\
        Get the length of the edge
\*--------------------------------------------------------------------*/
        status = ProEdgeInit((ProSolid)model_item.owner, model_item.id, &p_edge);
        TEST_CALL_REPORT("ProEdgeInit()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);

        status = ProEdgeToGeomitem((ProSolid)model_item.owner, p_edge, &geomitem);
        TEST_CALL_REPORT("ProEdgeToGeomitem()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);
        status = ProGeomitemToEdge(&geomitem, &p_edge);
        TEST_CALL_REPORT("ProGeomitemToEdge()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);

        status = ProEdgeLengthEval(p_edge, &length);
        TEST_CALL_REPORT("ProEdgeLengthEval()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);
        ProTKFprintf(fp,"Edge length = %6.2f\n\n", length);

/*--------------------------------------------------------------------*\
        Get the geometrical equations for the edge
\*--------------------------------------------------------------------*/
        status = ProEdgeDataGet(p_edge, &gitem_data);
        TEST_CALL_REPORT("ProEdgeDataGet()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);
        if(status == PRO_TK_NO_ERROR)
        {
/*--------------------------------------------------------------------*\
            Dump the edge geometry
\*--------------------------------------------------------------------*/
            ProUtilGeomitemshapeDump(fp, gitem_data);
        }
/*--------------------------------------------------------------------*\
            Edge to NURBS
\*--------------------------------------------------------------------*/
        status = ProEdgeToNURBS(p_edge, &p_curve_data);
        TEST_CALL_REPORT("ProEdgeToNURBS()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);
        if(status == PRO_TK_NO_ERROR)
        {
	    ProTKFprintf(fp, "Edge, translated to NURBS\n");
            ProUtilCurvedataPrint(fp, (char*)"    ", p_curve_data);
            status = ProCurveDataFree(&p_curve_data);
            TEST_CALL_REPORT("ProCurveDataFree()", "ProUtilGeomitemDump()",
                                    status, status != PRO_TK_NO_ERROR);
        }

	status = ProEdgeTessellationGet(p_edge, &vect_list, 
	    NULL, NULL, NULL, &num);
	TEST_CALL_REPORT("ProEdgeTessellationGet()", 
		"ProUtilGeomitemDump()", status, status != PRO_TK_NO_ERROR);
	ProTKFprintf(fp,"Edge, tesselated with %d points\n", num);
	for (i = 0; i < num ; i++)
	{
	    ProTKFprintf(fp,"\tvector[%d] = %6.2f, %6.2f, %6.2f\n", i,
					    vect_list[i][0],
					    vect_list[i][1],
					    vect_list[i][2]);
	}
	
	ProArrayFree((ProArray*)&vect_list); 
	ProTKFprintf(fp,"Edge, UV data\n");
	ProTKFprintf(fp,"\t    t   uv[0]   uv[1]   uvd1[0] uvd1[1]"
	    " uvd2[0] uvd2[1]\n");
	for (i=0; i<=4; i++)
	{
	    t=i*0.25;
	    status = ProEdgeUvdataEval(p_edge, t, uv, uvd1, uvd2);
	    TEST_CALL_REPORT("ProEdgeUvdataEval()", 
		"ProUtilGeomitemDump()", status, status != PRO_TK_NO_ERROR);

	    ProTKFprintf(fp,"\t %4.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",
		t, uv[0][0], uv[0][1], uvd1[0][0], uvd1[0][1], uvd2[0][0],
		uvd2[0][1]);

	    ProTKFprintf(fp,"\t %4.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",
		t, uv[1][0], uv[1][1], uvd1[1][0], uvd1[1][1], uvd2[1][0],
		uvd2[1][1]);
	}

        break;

    case PRO_AXIS :
/*--------------------------------------------------------------------*\
        Get the geometrical equations for the axis (a line)
\*--------------------------------------------------------------------*/
        status = ProAxisInit((ProSolid)model_item.owner, model_item.id, &axis);
        TEST_CALL_REPORT("ProAxisInit()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);

        status = ProAxisToGeomitem((ProSolid)model_item.owner, axis, &geomitem);
        TEST_CALL_REPORT("ProAxisToGeomitem()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);
        status = ProGeomitemToAxis(&geomitem, &axis);
        TEST_CALL_REPORT("ProGeomitemToAxis()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);


        status = ProAxisDataGet(axis, &gitem_data);
        TEST_CALL_REPORT("ProAxisDataGet()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);

        if(status == PRO_TK_NO_ERROR)
        {
/*--------------------------------------------------------------------*\
            Dump the axis geometry
\*--------------------------------------------------------------------*/
            ProUtilGeomitemshapeDump(fp, gitem_data);
        }

/*--------------------------------------------------------------------*\
            Check the parent surface
\*--------------------------------------------------------------------*/
	status = ProAxisSurfaceGet(model_item.owner, axis, &p_surface); 
	TEST_CALL_REPORT("ProAxisSurfaceGet()", "ProTestGeomitemVisAct()",
            status, status!=PRO_TK_NO_ERROR && status != PRO_TK_E_NOT_FOUND);

        if (status == PRO_TK_NO_ERROR)
        {
	    status = ProSurfaceIdGet(p_surface, &id); 
	    TEST_CALL_REPORT("ProAxisSurfaceGet()", 
		"ProTestGeomitemVisAct()", status, status!=PRO_TK_NO_ERROR);
	
	    ProTKFprintf(fp,"\tAxis was created by surface %d\n", id);
        }
        break;
    case PRO_CSYS :
/*--------------------------------------------------------------------*\
        Get the geometry of the CSYS
\*--------------------------------------------------------------------*/
        status = ProCsysInit((ProSolid)model_item.owner,model_item.id,&p_csys);
        TEST_CALL_REPORT("ProCsysInit()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);

        status = ProCsysToGeomitem((ProSolid)model_item.owner, p_csys, &geomitem);
        TEST_CALL_REPORT("ProCsysToGeomitem()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);
        status = ProGeomitemToCsys(&geomitem, &p_csys);
        TEST_CALL_REPORT("ProGeomitemToCsys()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);

        status = ProCsysDataGet(p_csys, &gitem_data);
        TEST_CALL_REPORT("ProCsysDataGet()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);

        if(status == PRO_TK_NO_ERROR)
        {
/*--------------------------------------------------------------------*\
            Dump the geometry of the csys
\*--------------------------------------------------------------------*/
            ProUtilGeomitemshapeDump(fp, gitem_data);
        }
        break;

    case PRO_CURVE :
/*--------------------------------------------------------------------*\
        Get the geometrical equations for the CURVE
\*--------------------------------------------------------------------*/
        status = ProCurveInit((ProSolid)model_item.owner,model_item.id,&p_curve);
        TEST_CALL_REPORT("ProCurveInit()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);

        status = ProCurveToGeomitem((ProSolid)model_item.owner, p_curve, &geomitem);
        TEST_CALL_REPORT("ProCurveToGeomitem()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);
        status = ProGeomitemToCurve(&geomitem, &p_curve);
        TEST_CALL_REPORT("ProGeomitemToCurve()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);

        status = ProCurveLengthEval(p_curve, &length);
        TEST_CALL_REPORT("ProCurveLengthEval()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);
        ProTKFprintf(fp,"Curve length = %6.2f\n\n", length);

/*--------------------------------------------------------------------*\
        Maybe it's an ordinary datum curve
\*--------------------------------------------------------------------*/
        status = ProCurveDataGet(p_curve, &gitem_data);
        TEST_CALL_REPORT("ProCurveDataGet()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);
        if(status == PRO_TK_NO_ERROR)
        {
/*--------------------------------------------------------------------*\
            Dump the geometry of the curve
\*--------------------------------------------------------------------*/
            ProUtilGeomitemshapeDump(fp, gitem_data);
        }

/*--------------------------------------------------------------------*\
        Curve to NURBS
\*--------------------------------------------------------------------*/
        status = ProCurveToNURBS(p_curve, &p_curve_data);
        TEST_CALL_REPORT("ProCurveToNURBS()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);
        if(status == PRO_TK_NO_ERROR)
        {
	    ProTKFprintf(fp, "Curve, translated to NURBS\n");
            ProUtilCurvedataPrint(fp, (char*)"    ", p_curve_data);

            status = ProCurveDataFree(&p_curve_data);
            TEST_CALL_REPORT("ProCurveDataFree()", "ProUtilGeomitemDump()",
                                    status, status != PRO_TK_NO_ERROR);
        }
/*--------------------------------------------------------------------*\
        Maybe it's a composite curve.
\*--------------------------------------------------------------------*/
#ifndef PT_PRODUCTS_BUILD
	status = ProCurveTypeGet(p_curve, &curve_type);
        TEST_CALL_REPORT("ProCurveTypeGet()", "ProUtilGeomitemDump()",
                                    status, status != PRO_TK_NO_ERROR);
	if (curve_type == PRO_ENT_CMP_CRV )
	{
	    status = ProUtilCollectCurveComponents(p_curve, &curvecomps);
	    if (status!=PRO_TK_NO_ERROR)
		break;

	    status = ProArraySizeGet((ProArray)curvecomps, &n);
	    TEST_CALL_REPORT("ProArraySizeGet()", "ProUtilGeomitemDump()",
					status, status != PRO_TK_NO_ERROR);
	    for (i=0; i<n; i++)
	    {
		status = ProCurveIdGet(curvecomps[i].p_owner, &curve_id);
		TEST_CALL_REPORT("ProCurveIdGet()", "ProUtilGeomitemDump()",
					status, status != PRO_TK_NO_ERROR);
		status = ProCurveIdGet(curvecomps[i].p_curve, &comp_crv_id);
		TEST_CALL_REPORT("ProCurveIdGet()", "ProUtilGeomitemDump()",
					status, status != PRO_TK_NO_ERROR);

		ProTKFprintf(fp, "Curve %d, component %d, index %d, flip %d\n",
		    curve_id, comp_crv_id, curvecomps[i].index,
		    curvecomps[i].flip);
	    }
	    status = ProArrayFree((ProArray*)&curvecomps);
	    TEST_CALL_REPORT("ProArrayFree()", "ProUtilGeomitemDump()",
					status, status != PRO_TK_NO_ERROR);
	}  
#endif /* #ifndef PT_PRODUCTS_BUILD */
        break;
    case PRO_POINT :
/*--------------------------------------------------------------------*\
        Get and dump directly the coordinates of the datum point
\*--------------------------------------------------------------------*/
        status = ProPointInit((ProSolid)model_item.owner, model_item.id, &point);
        TEST_CALL_REPORT("ProPointInit()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);

        status = ProPointIdGet(point, &geomitem.id);
        TEST_CALL_REPORT("ProPointIdGet()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);
        status = ProPointToGeomitem((ProSolid)model_item.owner, point, &geomitem);
        TEST_CALL_REPORT("ProPointToGeomitem()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);
        status = ProGeomitemToPoint(&geomitem, &point2);
        TEST_CALL_REPORT("ProGeomitemToPoint()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);
        status = ProPointCoordGet(point, xyz_point);
        TEST_CALL_REPORT("ProPointCoordGet()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);

        ProTKFprintf(fp,"Geometry for datum point = %6.2f, %6.2f, %6.2f\n",
                                xyz_point[0], xyz_point[1], xyz_point[2]);
        break;
    case PRO_QUILT :
#ifndef PT_PRODUCTS_BUILD
        status = ProQuiltInit((ProSolid)model_item.owner, model_item.id, &p_quilt);
        TEST_CALL_REPORT("ProQuiltInit()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);

        status = ProQuiltIdGet(p_quilt, &geomitem.id);
        TEST_CALL_REPORT("ProQuiltIdGet()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);
        status = ProQuiltToGeomitem((ProSolid)model_item.owner, p_quilt, &geomitem);
        TEST_CALL_REPORT("ProQuiltToGeomitem()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);
        status = ProGeomitemToQuilt(&geomitem, &p_quilt);
        TEST_CALL_REPORT("ProGeomitemToQuilt()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);
        ProTKFprintf(fp,"Quilt id %d\n", geomitem.id);
#endif /* #ifndef PT_PRODUCTS_BUILD */
        break;
    case PRO_SURFACE :
/*--------------------------------------------------------------------*\
        Get and dump the area of the surface
\*--------------------------------------------------------------------*/
        status = ProSurfaceInit(model_item.owner, model_item.id, &p_surface);
        TEST_CALL_REPORT("ProSurfaceInit()", "ProUtilGeomitemDump()",
                    status, (status != PRO_TK_NO_ERROR));

        status = ProSurfaceToGeomitem((ProSolid)model_item.owner, p_surface, &geomitem);
        TEST_CALL_REPORT("ProSurfaceToGeomitem()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);
        status = ProGeomitemToSurface(&geomitem, &p_surface);
        TEST_CALL_REPORT("ProGeomitemToSurface()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);

        status = ProSurfaceAreaEval(p_surface, &area);
        TEST_CALL_REPORT("ProSurfaceAreaEval()", "ProUtilGeomitemDump()",
                    status, (status != PRO_TK_NO_ERROR &&
                             status != PRO_TK_OUT_OF_RANGE));
        if(status == PRO_TK_NO_ERROR)
            ProTKFprintf(fp,"Surface area is %6.2f\n\n", area);
/*--------------------------------------------------------------------*\
        Get surface extremes
\*--------------------------------------------------------------------*/
        status = ProUtilCollectSurfaceContours(p_surface, &p_contours);    
        if (status == PRO_TK_NO_ERROR)
        {
            ProArrayFree((ProArray*)&p_contours);
            /* Do not calculate extremes if surface  doesn't have edges */
            dir [0] = dir[1] = dir[2] = 0.7071;
        
            status = ProSurfaceExtremesEval(p_surface, dir, xyz_min, xyz_max);
            TEST_CALL_REPORT("ProSurfaceExtremesEval()",
                "ProUtilGeomitemDump()", status, status != PRO_TK_NO_ERROR);

    
            ProTKFprintf(fp,"Surface extremes (min) %.2f %.2f %.2f\n",
	        xyz_min[0], xyz_min[1], xyz_min[2]);
            ProTKFprintf(fp,"Surface extremes (max) %.2f %.2f %.2f\n\n",
	        xyz_max[0], xyz_max[1], xyz_max[2]);
        }
	status = ProMdlTypeGet(model_item.owner, &mdltype);
        TEST_CALL_REPORT("ProMdlTypeGet()", "ProUtilGeomitemDump()",
					    status, status != PRO_TK_NO_ERROR );

#ifndef PT_PRODUCTS_BUILD
	if (mdltype == PRO_MDL_PART)
	{
	    status = ProSurfaceQuiltGet((ProSolid)model_item.owner ,p_surface, &p_quilt);
	    TEST_CALL_REPORT(" ProSurfaceQuiltGet()", "ProUtilGeomitemDump()",
	    status, status != PRO_TK_NO_ERROR && status != PRO_TK_E_NOT_FOUND);

	    if (status == PRO_TK_NO_ERROR)
		ProTKFprintf(fp, "This surface belong to quilt\n");
	}
#endif /* #ifndef PT_PRODUCTS_BUILD */
/*--------------------------------------------------------------------*\
        Get the geometrical equations of the surface
\*--------------------------------------------------------------------*/
        status = ProSurfaceDataGet(p_surface, &gitem_data);
        TEST_CALL_REPORT("ProSurfaceDataGet()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);

        if(status == PRO_TK_NO_ERROR)
        {
/*--------------------------------------------------------------------*\
            Dump the geometry of the surface
\*--------------------------------------------------------------------*/
            ProUtilGeomitemshapeDump(fp, gitem_data);
        }
/*--------------------------------------------------------------------*\
        Surface to NURBS
\*--------------------------------------------------------------------*/
        status = ProSurfaceToNURBS(p_surface, &p_surf_data);
        TEST_CALL_REPORT("ProSurfaceToNURBS()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);
        if(status == PRO_TK_NO_ERROR)
        {
	    ProTKFprintf(fp, "Surface, translated to NURBS\n");
            ProUtilSurfacedataPrint(fp, (char*)"    ", p_surf_data);

            status = ProSurfaceDataFree(&p_surf_data);
            TEST_CALL_REPORT("ProSurfaceDataFree()", "ProUtilGeomitemDump()",
                                    status, status != PRO_TK_NO_ERROR);
        }

        break;
    default :;
    }
   
    if (gitem_data != NULL)
    {
        status = ProGeomitemdataFree(&gitem_data);
        TEST_CALL_REPORT("ProGeomitemdataFree()", "ProUtilGeomitemDump()",
                                status, status != PRO_TK_NO_ERROR);
    }

   return(0);
}

/*====================================================================*\
    FUNCTION :  ProUtilPointMindist()
    PURPOSE  :  Minimum distance between a point and an edge, curve,
                or surface.
\*====================================================================*/
int ProUtilPointMindist(
    ProVector point,    /* I - Input point in root coords */
    ProSelection *item, /* I - Edge, Curve or Surface     */
    double *distance,   /* O - Minimum distance           */
    double *closest)    /* O - Closest point in root coords */
{
    ProError status;
    ProMatrix transform;
    ProVector local_point;
    double t;
    ProUvParam uv;
    ProCurve p_curve;
    ProEdge p_edge;
    ProSurface p_surface;
    ProAsmcomppath comp_path;
    ProModelitem model_item;

    status = ProSelectionAsmcomppathGet(*item, &comp_path);
    TEST_CALL_REPORT("ProSelectionAsmcomppathGet()", "ProUtilPointMindist()",
                    status, status != PRO_TK_NO_ERROR);

/*--------------------------------------------------------------------*\
    Transform the distance point from root coords to the coords
    local to the selected item.
\*--------------------------------------------------------------------*/
    status = ProAsmcomppathTrfGet(&comp_path, PRO_B_FALSE, transform);
    TEST_CALL_REPORT("ProAsmcomppathTrfGet()", "ProUtilPointMindist()",
                    status, status != PRO_TK_NO_ERROR);
    ProUtilPointTrans(transform, point, local_point);

/*--------------------------------------------------------------------*\
    Calculate the mininum distance
\*--------------------------------------------------------------------*/
    status = ProSelectionModelitemGet(*item, &model_item);
    TEST_CALL_REPORT("ProSelectionModelitemGet()", "ProUtilPointMindist()",
                    status, status != PRO_TK_NO_ERROR);

    switch(model_item.type)
    {
    case PRO_EDGE :
/*--------------------------------------------------------------------*\
        Calculate the value of "t" for the nearest point on the edge
\*--------------------------------------------------------------------*/
        status = ProEdgeInit((ProSolid)model_item.owner, model_item.id, &p_edge);
        TEST_CALL_REPORT("ProEdgeInit()", "ProUtilPointMindist()",
                                        status, status != PRO_TK_NO_ERROR);
         if (status!= PRO_TK_NO_ERROR)
            return (1);

        status = ProEdgeParamEval(p_edge, local_point, &t);
        TEST_CALL_REPORT("ProEdgeParamEval()", "ProUtilPointMindist()",
                                        status, status != PRO_TK_NO_ERROR);
         if (status!= PRO_TK_NO_ERROR)
            return (1);

/*--------------------------------------------------------------------*\
        Calculate the location for that "t" value.
\*--------------------------------------------------------------------*/
        status = ProEdgeXyzdataEval(p_edge, t,
                                        closest, NULL, NULL, NULL);
        TEST_CALL_REPORT("ProEdgeXyzdataEval()", "ProUtilPointMindist()",
                status, status != PRO_TK_NO_ERROR );
         if (status!= PRO_TK_NO_ERROR)
            return (1);

        break;
    case PRO_CURVE :
/*--------------------------------------------------------------------*\
        Calculate the value of "t" for the nearest point on the curve
\*--------------------------------------------------------------------*/
        status = ProCurveInit((ProSolid)model_item.owner,model_item.id,&p_curve);
         if (status!= PRO_TK_NO_ERROR)
            return (1);
        status = ProCurveParamEval(p_curve, local_point, &t);
        TEST_CALL_REPORT("ProCurveParamEval()", "ProUtilPointMindist()",
                                        status, status != PRO_TK_NO_ERROR);
         if (status!= PRO_TK_NO_ERROR)
            return (1);

/*--------------------------------------------------------------------*\
        Calculate the location for that "t" value.
\*--------------------------------------------------------------------*/
        status = ProCurveInit((ProSolid)model_item.owner,model_item.id,&p_curve);
         if (status!= PRO_TK_NO_ERROR)
            return (1);
        status = ProCurveXyzdataEval(p_curve, t,closest, NULL, NULL);
        TEST_CALL_REPORT("ProCurveXyzdataEval()", "ProUtilPointMindist()",
                status, status != PRO_TK_NO_ERROR );
         if (status!= PRO_TK_NO_ERROR)
            return (1);

        break;
    case PRO_SURFACE :
        status = ProSurfaceInit(model_item.owner, model_item.id,
               &p_surface);
        TEST_CALL_REPORT("ProSurfaceInit()", "ProUtilPointMindist()",
                                        status, status != PRO_TK_NO_ERROR);
         if (status!= PRO_TK_NO_ERROR)
            return (1);

/*--------------------------------------------------------------------*\
        Calculate the value of "u" and "v" for the nearest point on
        the surface
\*--------------------------------------------------------------------*/
        status = ProSurfaceParamEval((ProSolid)model_item.owner,
                         p_surface, local_point, uv);
        TEST_CALL_REPORT("ProSurfaceParamEval()", "ProUtilPointMindist()",
                                        status, status != PRO_TK_NO_ERROR);
         if (status!= PRO_TK_NO_ERROR)
            return (1);

/*--------------------------------------------------------------------*\
        Calculate the location for that "uv" value.
\*--------------------------------------------------------------------*/
        status = ProSurfaceXyzdataEval(p_surface, uv,
                                        closest, NULL, NULL, NULL);
        TEST_CALL_REPORT("ProSurfaceXyzdataEval()", "ProUtilPointMindist()",
                status, status != PRO_TK_NO_ERROR );
         if (status!= PRO_TK_NO_ERROR)
            return (1);

        break;
    default :
        return(1);
    }

/*--------------------------------------------------------------------*\
    Transform the closest point back to root coordinates
\*--------------------------------------------------------------------*/
    status = ProAsmcomppathTrfGet(&comp_path, PRO_B_TRUE, transform);
    TEST_CALL_REPORT("ProAsmcomppathTrfGet()", "ProUtilPointMindist()",
                    status, status != PRO_TK_NO_ERROR);
    ProUtilPointTrans(transform, closest, closest);

    *distance = ProUtilPointsDist(point, closest);

    return(0);
}

/*===========================================================================*\
  Function : ProTestGeometryAtPoint
  Purpose  : find what geometry a point is on
\*===========================================================================*/
int ProTestGeometryAtPoint(ProAppData app_data, int b)
{
    Pro3dPnt pnt;
    ProMdl model = ((ProMdl*)app_data)[0];
    ProPart part;
    int i,p_count,edge_no=0,minId,k,l;
    ProSelection *p_sel_arr, select;
    ProError status;
    FILE *fp;
    ProCharLine fname;
    ProModelitem mod_item;
    ProUvParam uv_par;
    double uvpTemp;
    ProMdlType mdltype;
    edgeInfo *edgeInfoCollect;
    edgeInfo edgeInfo_indv;

/*--------------------------------------------------------------------*\
    Find out the model type
\*--------------------------------------------------------------------*/
    status = ProMdlTypeGet(model, &mdltype);
    TEST_CALL_REPORT("ProMdlTypeGet()", "ProTestGeometryAtPoint()",
                                        status, status != PRO_TK_NO_ERROR );

    if (mdltype!=PRO_MDL_PART)
    {
	ProUtilMsgPrint("gen", "TEST %0s", "This function works on part only");
	return (0);
    }

    part = (ProPart)model;
    ProUtilMsgPrint("gen", "TEST %0s", "Enter X coordinate:");
    if (ProUtilDoubleGet(NULL, NULL, &pnt[0])==0)
        return (0);

    ProUtilMsgPrint("gen", "TEST %0s", "Enter Y coordinate:");
    if (ProUtilDoubleGet(NULL, NULL, &pnt[1])==0)
        return (0);

    ProUtilMsgPrint("gen", "TEST %0s", "Enter Z coordinate:");
    if (ProUtilDoubleGet(NULL, NULL, &pnt[2])==0)
        return (0);

    p_count = 0;
    status = ProGeometryAtPointFind(part, pnt, &p_sel_arr, &p_count);
    TEST_CALL_REPORT("ProGeometryAtPointFind()", "ProTestGeometryAtPoint()",
          status, status != PRO_TK_NO_ERROR  && status != PRO_TK_E_NOT_FOUND);

    if ( p_count == 0 || status != PRO_TK_NO_ERROR)
    {
        ProUtilMsgPrint("gen", "TEST %0s", "Point does not lie on geometry");
	return (0);
    }
      else
        ProUtilMsgPrint("gen", "TEST %0s", "Point lies on hilighted geometry");

    ProTestQcrName((ProMdl*)&part, (char*)".pgm", fname);
    if ( (fp = PTApplsUnicodeFopen(fname,"a")) == NULL )
           return(-1);

    ProTKFprintf(fp,"Point %0.2lf, %0.2lf, %0.2lf lies on the following geometry:\n",
              pnt[0],pnt[1],pnt[2]);

    status = ProArrayAlloc (0, sizeof(edgeInfo), 1, (ProArray*)&edgeInfoCollect);
        TEST_CALL_REPORT("ProArrayAlloc()",
            "ProTestGeometryAtPoint()", status, status != PRO_TK_NO_ERROR );

    for (i=0; i<p_count; i++)
    {

        status = ProSelectionModelitemGet(p_sel_arr[i], &mod_item);
        TEST_CALL_REPORT("ProSelectionModelitemGet()", 
	    "ProTestGeometryAtPoint()", status, status != PRO_TK_NO_ERROR );
            
        status = ProSelectionAlloc(NULL, &mod_item, &select);
        TEST_CALL_REPORT("ProSelectionAlloc()", "ProTestGeometryAtPoint()",
                                        status, status != PRO_TK_NO_ERROR );
        
        status = ProSelectionHighlight(select, PRO_COLOR_HIGHLITE);
        TEST_CALL_REPORT("ProSelectionHighlight()", "ProTestGeometryAtPoint()",
                                        status, status != PRO_TK_NO_ERROR );
        
        status = ProSelectionUvParamGet(p_sel_arr[i], uv_par);
        TEST_CALL_REPORT("ProSelectionUvParamGet()",
	    "ProTestGeometryAtPoint()", status, status != PRO_TK_NO_ERROR );

        if ( mod_item.type == PRO_EDGE )
	  {
            edgeInfo_indv.edgeId =mod_item.id;
            edgeInfo_indv.uvparam =uv_par[0];
            ProArrayObjectAdd ((ProArray*)&edgeInfoCollect, edge_no, 1, &edgeInfo_indv);
            edge_no++;
	  }
	
        else 
          {
	    ProTKFprintf(fp,"\tPRO_SURFACE Id [%d] UV parameters: %0.2lf, %0.2lf\n",
		    mod_item.id,uv_par[0],uv_par[1]);
          }
	
    }
    
    if ( mod_item.type == PRO_EDGE )
      {
	if(edge_no>0)
	  {
	    for (k=0; k<=edge_no-1; k++)
	      {
		for (l=k+1; l<edge_no; l++)
		  {
		    if ( edgeInfoCollect[k].edgeId > edgeInfoCollect[l].edgeId)
		      {
			minId =edgeInfoCollect[k].edgeId;
			edgeInfoCollect[k].edgeId = edgeInfoCollect[l].edgeId;
			edgeInfoCollect[l].edgeId = minId;
			
                        uvpTemp = edgeInfoCollect[k].uvparam;
                        edgeInfoCollect[k].uvparam = edgeInfoCollect[l].uvparam;
                        edgeInfoCollect[l].uvparam = uvpTemp; 
		      }
		  }
	      }
	    
	    for (k=0; k<=edge_no-1; k++)
	      {
		
		ProTKFprintf(fp, "\tPRO_EDGE Id[%d] T parameter: %0.2lf\n",edgeInfoCollect[k].edgeId,edgeInfoCollect[k].uvparam); 
	      }
	  }
	else 
	  {
            ProTKFprintf(fp, "\tPRO_EDGE Id[%d] T parameter: %0.2lf\n",edgeInfoCollect[0].edgeId, edgeInfoCollect[0].uvparam);
	    ProTKFprintf(fp, "\n");
	  }
      }
      
    for ( i = 0; i < p_count; i++ ) 
      {
	status = ProSelectionFree(&p_sel_arr[i]);
        TEST_CALL_REPORT("ProSelectionFree()", "ProTestGeometryAtPoint()",
			 status, status != PRO_TK_NO_ERROR );
	
      }
    status = ProArrayFree( (ProArray *) &p_sel_arr );
    TEST_CALL_REPORT("ProArrayFree()", "ProTestGeometryAtPoint()",
		     status, status != PRO_TK_NO_ERROR );
    fclose(fp);
    
    return(0);
}