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


/*--------------------------------------------------------------------*\
Pro/TOOLKIT includes
\*--------------------------------------------------------------------*/
#include <ProToolkit.h>
#include <ProAnalysis.h>
#include <ProModelitem.h>
#include <ProMessage.h>
#include <ProArray.h>
#include <ProPoint.h>
#include <ProDtmPnt.h>
#include <ProUtil.h>

/*--------------------------------------------------------------------*\
Application includes
\*--------------------------------------------------------------------*/
#include "TestError.h"
#include "TestAnalysis.h"
#include "TestDimension.h"

#include "UtilMath.h"
#include "UtilMatrix.h"

/*====================================================================*\
FUNCTION : ProTestSectionCsysFind()
PURPOSE  : 
\*====================================================================*/
int ProTestSectionCsysFind(
    ProSection section,
    ProVector origin,
    ProVector x,
    ProVector y)
{
    int *ids, n_ids, i;
    Pro2dEntdef *entity;
    ProMatrix matrix;

    ProSectionLocationGet(section, matrix);

    ProSectionEntityIdsGet(section, &ids, &n_ids);
    for(i=0;i<n_ids;i++)
    {
        ProSectionEntityGet(section, ids[i], &entity);
        if(entity->type != PRO_2D_COORD_SYS)
            continue;
        
        origin[0] = ((Pro2dCoordSysdef*)entity)->pnt[0];
        origin[1] = ((Pro2dCoordSysdef*)entity)->pnt[1];
        origin[2] = 0.0;
        ProPntTrfEval(origin, matrix, origin);

        x[0]=1.0;
        x[1]=x[2]=0.0;
        ProVectorTrfEval(x, matrix, x);

        y[0]=y[2]=0.0;
        y[1]=1.0;
        ProVectorTrfEval(y, matrix, y);
        return(1);
    }
    return(0);
}

/*====================================================================*\
FUNCTION : ProTestCurvePlaneGet()
PURPOSE  : 
\*====================================================================*/
int ProTestCurvePlaneGet(
    ProFeature *feature,
    ProVector origin,
    ProVector x,
    ProVector y)
{
    ProElempathItem items[4];
    ProElempath epath;
    ProValue value;
    ProValueData vdata;
    ProGeomitem geomitem;
    ProFeattype ftype;
    ProGeomitemdata *gdata;
    ProSection section;
    ProError err;

    err = ProFeatureTypeGet (feature, &ftype);
    TEST_CALL_REPORT ("ProFeatureTypeGet()",
        "ProTestCurvePlaneGet()", err, err != PRO_TK_NO_ERROR);
    if(ftype != PRO_FEAT_CURVE)
        return(0);

    items[0].type = PRO_ELEM_PATH_ITEM_TYPE_ID;
    items[0].path_item.elem_id = PRO_E_STD_SECTION;
    items[1].type = PRO_ELEM_PATH_ITEM_TYPE_ID;
    items[1].path_item.elem_id = PRO_E_SKETCHER;
    err = ProElempathAlloc(&epath);
    TEST_CALL_REPORT ("ProElempathAlloc()",
        "ProTestCurvePlaneGet()", err, err != PRO_TK_NO_ERROR);
    err = ProElempathDataSet(epath, items, 2);
    TEST_CALL_REPORT ("ProElempathDataSet()",
        "ProTestCurvePlaneGet()", err, err != PRO_TK_NO_ERROR);
    err = ProFeatureElemValueGet(feature, epath, &value);
    TEST_CALL_REPORT ("ProElempathDataSet()",
        "ProTestCurvePlaneGet()", err, err != PRO_TK_NO_ERROR);
    if (err != PRO_TK_NO_ERROR)
        return(0);

    err = ProValueDataGet(value, &vdata);
    TEST_CALL_REPORT ("ProElempathDataSet()",
        "ProTestCurvePlaneGet()", err, err != PRO_TK_NO_ERROR);
    if (err != PRO_TK_NO_ERROR)
        return(0);

    section = (ProSection)vdata.v.p;

    err = ProElempathFree (&epath);
    err = ProValueFree (value);
    if(!ProTestSectionCsysFind(section, origin, x, y))
        return(0);

    return(1);
}

/*====================================================================*\
FUNCTION : ProTestCurvewrapUiAction()
PURPOSE  : Callback for UI action of analysis feature
\*====================================================================*/
ProError ProTestCurvewrapUiAction(
    ProAnalysis analysis)
{
    ProSelection *sel;
    ProError err = PRO_TK_NO_ERROR;
    int n_sel;
    ProFeature feature;
    ProModelitem modelitem;
    Curvewrapdata_t *data;
    ProPoint p;
    ProDtmpntType ptype;
    ProVector origin, x, y;

    TEST_CALL_REPORT ("ProAnalysisUiAction()", 
        "ProTestCurvewrapUiAction()", err, err != PRO_TK_NO_ERROR);

    err = ProAnalysisInfoGet(analysis, (ProAppData*)&data);
    TEST_CALL_REPORT ("ProAnalysisInfoGet()", 
        "ProTestCurvewrapUiAction()", err, err != PRO_TK_NO_ERROR);

    if (err != PRO_TK_NO_ERROR)
        return (PRO_TK_GENERAL_ERROR);

    ProMessageDisplay (msgfil, (char *)"USER Select sketched datum curve");
    while (1)
    {
        if (ProSelect((char *)"feature",1,NULL,NULL,NULL,NULL,&sel, &n_sel) !=
            PRO_TK_NO_ERROR || n_sel < 0)
            return(PRO_TK_NO_ERROR);
        err = ProSelectionModelitemGet(sel[0], &feature);
        TEST_CALL_REPORT ("ProSelectionModelitemGet()", 
            "ProTestCurvewrapUiAction()", err, err != PRO_TK_NO_ERROR);

        if(!ProTestCurvePlaneGet(&feature, origin, x, y))
            ProMessageDisplay (msgfil,
                (char *)"USER That is not a sketched curve. Select again");
        else
            break;
    }
    memcpy(&data->curve, &feature, sizeof(ProFeature));

    ProMessageDisplay(msgfil,(char *)"USER Select a point on a surface to wrap onto");
    while(1)
    {
        if(ProSelect((char *)"point",1,NULL,NULL,NULL,NULL,&sel, &n_sel) !=
            PRO_TK_NO_ERROR || n_sel < 0)
            return(PRO_TK_NO_ERROR);
        err = ProSelectionModelitemGet(sel[0], &modelitem);
	TEST_CALL_REPORT ("ProSelectionModelitemGet()", 
            "ProTestCurvewrapUiAction()", err, err != PRO_TK_NO_ERROR);
        err = ProPointInit((ProSolid)modelitem.owner, modelitem.id, &p);
        TEST_CALL_REPORT ("ProPointInit()", 
            "ProTestCurvewrapUiAction()", err, err != PRO_TK_NO_ERROR);

        if(!ProTestPointPtypeGet((ProSolid)modelitem.owner, p, &ptype) ||
                        ptype != PRO_DTMPNT_TYPE_ON_SURF)
            ProMessageDisplay (msgfil,
                (char *)"USER That is not a point on surf. Select again"); 
        else
            break;
    }
    memcpy(&data->point, &modelitem, sizeof(ProModelitem));

    ProMessageDisplay(msgfil,(char *)"USER Enter rotation angle|||0.0");
    err = ProMessageDoubleRead(NULL, &data->angle);
    if(err == PRO_TK_MSG_USER_QUIT)
        return(PRO_TK_GENERAL_ERROR);
    if(err != PRO_TK_NO_ERROR)
        data->angle = 0.0;

    return(PRO_TK_NO_ERROR);
}


/*====================================================================*\
FUNCTION : ProTestCurvewarpDimsAction()
PURPOSE  : Create dimentions
\*====================================================================*/
ProError ProTestCurvewrapDimsAction(
    ProAnalysis analysis,
    double **dims)
{
    Curvewrapdata_t *data;
    ProError err = PRO_TK_NO_ERROR;

    TEST_CALL_REPORT ("ProAnalysisDimsAction()", 
        "ProTestCurvewrapDimsAction()", err, err != PRO_TK_NO_ERROR);

    err = ProAnalysisInfoGet(analysis, (ProAppData*)&data);
    TEST_CALL_REPORT ("ProAnalysisInfoGet()", 
        "ProTestCurvewrapDimsAction()", err, err != PRO_TK_NO_ERROR);
    if (err != PRO_TK_NO_ERROR)
        return(PRO_TK_NO_ERROR);

    err = ProArrayObjectAdd ((ProArray*)dims, PRO_VALUE_UNUSED, 1,
        &data->angle);
    TEST_CALL_REPORT ("ProArrayObjectAdd()", 
        "ProTestCurvewrapDimsAction()", err, err != PRO_TK_NO_ERROR);

    err = ProArrayObjectAdd ((ProArray*)dims, PRO_VALUE_UNUSED, 1,
        &data->offset);
    TEST_CALL_REPORT ("ProArrayObjectAdd()", 
        "ProTestCurvewrapDimsAction()", err, err != PRO_TK_NO_ERROR);

    return(PRO_TK_NO_ERROR);
}


/*====================================================================*\
FUNCTION : ProTestCurvewarpInfoallocAction()
PURPOSE  : Callback to allocate application data needed to describe
		the analysis feature
\*====================================================================*/
ProError ProTestCurvewrapInfoallocAction(
    ProAnalysis analysis)
{
    Curvewrapdata_t *data;
    ProError err = PRO_TK_NO_ERROR;

    TEST_CALL_REPORT ("ProAnalysisInfoallocAction()", 
        "ProTestCurvewrapInfoallocAction()", err, err != PRO_TK_NO_ERROR);   

    data = (Curvewrapdata_t*)calloc(1, sizeof(Curvewrapdata_t));
    data->offset = 0.0;
    data->curve.id = -1;
    data->point.id = -1;
    err = ProAnalysisInfoSet(analysis, data);
    TEST_CALL_REPORT ("ProAnalysisInfoSet()", 
        "ProTestCurvewrapInfoallocAction()", err, err != PRO_TK_NO_ERROR); 

    return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
FUNCTION : ProTestCurvewrapInfofreeAction()
PURPOSE  : Callback to free the application data
\*====================================================================*/
ProError ProTestCurvewrapInfofreeAction(
    ProAnalysis analysis)
{
    Curvewrapdata_t *data;
    int n_curves, c;
    ProError err = PRO_TK_NO_ERROR;

    TEST_CALL_REPORT ("ProAnalysisInfofreeAction()", 
        "ProTestCurvewrapInfofreeAction()", err, err != PRO_TK_NO_ERROR);

    err = ProAnalysisInfoGet (analysis, (ProAppData*)&data);
    TEST_CALL_REPORT ("ProAnalysisInfoGet()", 
        "ProTestCurvewrapInfofreeAction()", err, err != PRO_TK_NO_ERROR);
    if (err != PRO_TK_NO_ERROR)
        return(PRO_TK_NO_ERROR);
    
    if (data->curves != NULL)
      {
	err = ProArraySizeGet (data->curves, &n_curves);
	TEST_CALL_REPORT ("ProArraySizeGet()", "ProTestCurvewrapInfofreeAction()", err, err != PRO_TK_NO_ERROR);

	for (c = 0; c < n_curves; c++)
	  {
	    ProCurvedataFree (data->curves [c].curve);
	  }

	ProArrayFree ((ProArray*)&data->curves);
      }
    
    free(data);
 
    err = ProAnalysisInfoSet(analysis, NULL);
    TEST_CALL_REPORT ("ProAnalysisInfoGet()", 
        "ProTestCurvewrapInfofreeAction()", err, err != PRO_TK_NO_ERROR);

    return(PRO_TK_NO_ERROR);
}


/*====================================================================*\
FUNCTION : ProTestCurvewarpCompcheckAction()
PURPOSE  : Callback to tell Pro/E whether computation can be performed
		in this analysis feature
\*====================================================================*/
ProError ProTestCurvewrapCompcheckAction(
    ProAnalysis analysis)
{
    Curvewrapdata_t *data;
    ProError err = PRO_TK_NO_ERROR;

    TEST_CALL_REPORT ("ProAnalysisComputecheckAction()", 
        "ProTestCurvewrapCompcheckAction()", err, err != PRO_TK_NO_ERROR);
    
    err = ProAnalysisInfoGet(analysis, (ProAppData*)&data);
    TEST_CALL_REPORT ("ProAnalysisInfoGet()", 
        "ProTestCurvewrapCompcheckAction()", err, err != PRO_TK_NO_ERROR);
    if (err != PRO_TK_NO_ERROR)
        return(PRO_TK_NO_ERROR);
    if(data->curve.id < 0 || data->point.id < 0)
        return(PRO_TK_GENERAL_ERROR);
    return(PRO_TK_NO_ERROR);
}


/*====================================================================*\
FUNCTION : ProTestCurvewarpComputeAction()
PURPOSE  : Callback to perform the analysis feature computation
\*====================================================================*/
ProError ProTestCurvewrapComputeAction(
    ProAnalysis analysis)
{
    Curvewrapdata_t *data;
    double radians, cosine, sine;
    ProVector origin, x, y, z, pos, der1[2];
    ProMatrix from_plane, to_plane;
    ProGeomitem *curves;
    ProGeomitemdata *gdata;
    int n_curves, c, p, i, size;
    ProCurve curve;
    ProSurfcurvedata surf_curve;
    ProCurvedata *spline;
    ProSelection point_sel;
    ProPoint point;
    ProUvParam uv;
    double xscale, yscale, t;
    ProError err = PRO_TK_NO_ERROR;
    ProBoolean is_inactive;
    ProSurface surface;
    int degree, num_knots, num_pnts;
    double *params, *weights;
    ProPoint3d *c_pnts;

    TEST_CALL_REPORT ("ProAnalysisComputeAction()", 
        "ProTestCurvewrapComputeAction()", err, err != PRO_TK_NO_ERROR);
    
    err = ProAnalysisInfoGet(analysis, (ProAppData*)&data);
    TEST_CALL_REPORT ("ProAnalysisInfoGet()", 
        "ProTestCurvewrapComputeAction()", err, err != PRO_TK_NO_ERROR);
    if (err != PRO_TK_NO_ERROR)
        return(PRO_TK_NO_ERROR);

    ProTestCurvePlaneGet(&data->curve, origin, x, y);
    ProUtilVectorCross(x, y, z);
    ProMatrixInit(x, y, z, origin, from_plane);
    ProUtilMatrixInvert(from_plane, to_plane);

    err = ProSelectionAlloc(NULL, &data->point, &point_sel);
    TEST_CALL_REPORT ("ProSelectionAlloc()", 
        "ProTestCurvewrapComputeAction()", err, err != PRO_TK_NO_ERROR);
    ProTestPointSrfGet(point_sel, &surface);
    ProSelectionFree (&point_sel);

    err = ProPointInit((ProSolid)data->point.owner, data->point.id, &point);
    TEST_CALL_REPORT ("ProPointInit()", 
        "ProTestCurvewrapComputeAction()", err, err != PRO_TK_NO_ERROR);
    err = ProPointCoordGet(point, pos);
    TEST_CALL_REPORT ("ProPointCoordGet()", 
        "ProTestCurvewrapComputeAction()", err, err != PRO_TK_NO_ERROR);

    pos[1] += data->offset;
    
    err = ProSurfaceParamEval((ProSolid)data->point.owner, surface, pos, uv);
    TEST_CALL_REPORT ("ProSurfaceParamEval()", 
        "ProTestCurvewrapComputeAction()", err, err != PRO_TK_NO_ERROR);
    err = ProSurfaceXyzdataEval (surface, uv, NULL, der1, 
        NULL, NULL);
    TEST_CALL_REPORT ("ProSurfaceXyzdataEval()", 
        "ProTestCurvewrapComputeAction()", err, err != PRO_TK_NO_ERROR);
    xscale = 1.0/ProUtilVectorLength(der1[0]);
    yscale = 1.0/ProUtilVectorLength(der1[1]);

    err = ProUtilCollectFeatureGeomitems (&data->curve, PRO_CURVE, &curves);
    if (err != PRO_TK_NO_ERROR)
        return PRO_TK_USER_ABORT;

    err = ProArraySizeGet (curves, &n_curves);
    TEST_CALL_REPORT ("ProArraySizeGet()", 
        "ProTestCurvewrapComputeAction()", err, err != PRO_TK_NO_ERROR);

    err = ProArrayAlloc (0, sizeof(ProSurfcurvedata), 1, 
        (ProArray*)&data->curves);
    TEST_CALL_REPORT ("ProArrayAlloc()", 
        "ProTestCurvewrapComputeAction()", err, err != PRO_TK_NO_ERROR);

    for (c = 0; c < n_curves; c++)
    {
        err = ProCurvedataAlloc (&spline);
        TEST_CALL_REPORT ("ProCurvedataAlloc()", 
            "ProTestCurvewrapComputeAction()", err, err != PRO_TK_NO_ERROR);

        err = ProGeomitemIsInactive (&curves[c], &is_inactive);
        TEST_CALL_REPORT ("ProGeomitemIsInactive()",
            "ProTestCurvewrapComputeAction()", err, err != PRO_TK_NO_ERROR);
        if (is_inactive == PRO_B_TRUE)
            continue;

        err = ProGeomitemdataGet(&curves[c], &gdata);
        TEST_CALL_REPORT ("ProGeomitemdataGet()", 
            "ProTestCurvewrapComputeAction()", err, err != PRO_TK_NO_ERROR);

        switch(gdata->data.p_curve_data->line.type)
        {
        case PRO_ENT_LINE :
            spline->spline.num_points = 2;
            spline->spline.type = PRO_ENT_SPLINE;
            ProArrayAlloc (2, sizeof(double), 1, 
                (ProArray*)&spline->spline.par_arr);
            ProArrayAlloc (2, sizeof(ProVector), 1, 
                (ProArray*)&spline->spline.tan_arr);
            ProArrayAlloc (2, sizeof(ProVector), 1, 
                (ProArray*)&spline->spline.pnt_arr);
            spline->spline.par_arr[0] = 0.0;
            spline->spline.par_arr[1] = 1.0;
            memcpy(spline->spline.pnt_arr[0], 
                gdata->data.p_curve_data->line.end1,
                sizeof(ProVector));
            memcpy(spline->spline.pnt_arr[1], 
                gdata->data.p_curve_data->line.end2,
                sizeof(ProVector));
            ProUtilVectorDiff(spline->spline.pnt_arr[1], 
                spline->spline.pnt_arr[0],
                spline->spline.tan_arr[0]);
            ProUtilVectorNormalize(spline->spline.tan_arr[0], 
                spline->spline.tan_arr[0]);
            ProUtilVectorCopy(spline->spline.tan_arr[0], 
                spline->spline.tan_arr[1]);
            break;
        case PRO_ENT_ARC :
            spline->spline.num_points = 6;
            spline->spline.type = PRO_ENT_SPLINE;
            ProArrayAlloc (spline->spline.num_points, sizeof(double), 1, 
                (ProArray*)&spline->spline.par_arr);
            ProArrayAlloc(spline->spline.num_points, sizeof(ProVector), 1, 
                (ProArray*)&spline->spline.tan_arr);
            ProArrayAlloc(spline->spline.num_points, sizeof(ProVector), 1, 
                (ProArray*)&spline->spline.pnt_arr);
            for(i=0;i<6;i++)
            {
                t= 0.2 * i;
                spline->spline.par_arr[i] = t;
                err = ProCurveInit((ProSolid)curves[c].owner, curves[c].id, &curve);
                TEST_CALL_REPORT ("ProCurveInit()",
                    "ProTestCurvewrapComputeAction()",
                    err, err != PRO_TK_NO_ERROR);
                err = ProCurveXyzdataEval(curve, t, spline->spline.pnt_arr[i],
                    spline->spline.tan_arr[i], NULL);
                TEST_CALL_REPORT ("ProCurveXyzdataEval()",
                    "ProTestCurvewrapComputeAction()",
                    err, err != PRO_TK_NO_ERROR);
            }
            break;
        case PRO_ENT_SPLINE :
            spline->spline.num_points = 
                gdata->data.p_curve_data->spline.num_points;
            spline->spline.type = PRO_ENT_SPLINE;
            ProArrayAlloc (spline->spline.num_points, sizeof(double), 1, 
                (ProArray*)&spline->spline.par_arr);
            ProArrayAlloc(spline->spline.num_points, sizeof(ProVector), 1, 
                (ProArray*)&spline->spline.tan_arr);
            ProArrayAlloc(spline->spline.num_points, sizeof(ProVector), 1, 
                (ProArray*)&spline->spline.pnt_arr);
            for (p = 0; p < gdata->data.p_curve_data->spline.num_points; p++)
            {
                memcpy (spline->spline.pnt_arr[p], 
                    gdata->data.p_curve_data->spline.pnt_arr[p],
                    sizeof(ProVector));
                spline->spline.par_arr[p] = 
                    gdata->data.p_curve_data->spline.par_arr[p];
            }
            break;
        case PRO_ENT_B_SPLINE :
            err = ProBsplinedataGet (gdata->data.p_curve_data,
                &degree, &params, &weights, &c_pnts, &num_knots, &num_pnts);
            TEST_CALL_REPORT ("ProBsplinedataGet()",
                "ProTestCurvewrapComputeAction()",
                err, err != PRO_TK_NO_ERROR);
            err = ProBsplinedataInit (degree, params, weights, c_pnts,
                num_knots, num_pnts, spline);
            TEST_CALL_REPORT ("ProBsplinedataInit()",
                "ProTestCurvewrapComputeAction()",
                err, err != PRO_TK_NO_ERROR);
            break;
        default: continue;
        }

        radians = TWOPI * data->angle / 360.0;
        sine = sin(radians);
        cosine = cos(radians);
        if (gdata->data.p_curve_data->line.type == PRO_ENT_B_SPLINE)
	{
            for (p = 0; p < spline->b_spline.num_c_points; p++)
            {
                if (spline->b_spline.weights != NULL)
	        {
                    spline->b_spline.c_pnts[p][0] /= 
                        spline->b_spline.weights[p];
                    spline->b_spline.c_pnts[p][1] /= 
                        spline->b_spline.weights[p];
                    spline->b_spline.c_pnts[p][2] /= 
                        spline->b_spline.weights[p];
		} 
                
                err = ProPntTrfEval (spline->b_spline.c_pnts[p], to_plane, 
                    spline->b_spline.c_pnts[p]);
                TEST_CALL_REPORT ("ProPntTrfEval()",
                    "ProTestCurvewrapComputeAction()",
                    err, err != PRO_TK_NO_ERROR);
                spline->b_spline.c_pnts[p][0] = 
                    cosine * spline->b_spline.c_pnts[p][0] +
                    sine   * spline->b_spline.c_pnts[p][1];
                spline->b_spline.c_pnts[p][1] = 
                    -sine  * spline->b_spline.c_pnts[p][0] +
                    cosine * spline->b_spline.c_pnts[p][1];
                spline->b_spline.c_pnts[p][0] *= xscale;
                spline->b_spline.c_pnts[p][1] *= yscale;
                spline->b_spline.c_pnts[p][0] += uv[0];
                spline->b_spline.c_pnts[p][1] += uv[1];

                if (spline->b_spline.weights != NULL)
	        {
                    spline->b_spline.c_pnts[p][0] *= 
                        spline->b_spline.weights[p];
                    spline->b_spline.c_pnts[p][1] *= 
                        spline->b_spline.weights[p];
                    spline->b_spline.c_pnts[p][2] *= 
                        spline->b_spline.weights[p];
		}
            }
        }
        else
	{
            for (p = 0; p < spline->spline.num_points; p++)
            {
                err = ProPntTrfEval (spline->spline.pnt_arr[p], to_plane, 
                    spline->spline.pnt_arr[p]);
                TEST_CALL_REPORT ("ProPntTrfEval()",
                    "ProTestCurvewrapComputeAction()",
                    err, err != PRO_TK_NO_ERROR);
                spline->spline.pnt_arr[p][0] = 
                    cosine * spline->spline.pnt_arr[p][0] +
                    sine   * spline->spline.pnt_arr[p][1];
                spline->spline.pnt_arr[p][1] = 
                    -sine  * spline->spline.pnt_arr[p][0] +
                    cosine * spline->spline.pnt_arr[p][1];
                spline->spline.pnt_arr[p][0] *= xscale;
                spline->spline.pnt_arr[p][1] *= yscale;
                spline->spline.pnt_arr[p][0] += uv[0];
                spline->spline.pnt_arr[p][1] += uv[1];

                err = ProVectorTrfEval (spline->spline.tan_arr[p], to_plane, 
                    spline->spline.tan_arr[p]);
                TEST_CALL_REPORT ("ProVectorTrfEval()",
                    "ProTestCurvewrapComputeAction()",
                    err, err != PRO_TK_NO_ERROR);
                spline->spline.tan_arr[p][0] = 
                    cosine * spline->spline.pnt_arr[p][0] +
                    sine   * spline->spline.pnt_arr[p][1];
                spline->spline.tan_arr[p][1] = 
                    -sine  * spline->spline.pnt_arr[p][0] +
                    cosine * spline->spline.pnt_arr[p][1];
                spline->spline.tan_arr[p][0] *= xscale;
                spline->spline.tan_arr[p][1] *= yscale;
            }

        }

        err = ProSurfcurvedataInit (surface, spline, 
            (ProCurvedata*)&surf_curve);
        TEST_CALL_REPORT ("ProSurfcurvedataInit()",
            "ProTestCurvewrapComputeAction()",
            err, err != PRO_TK_NO_ERROR);
	err = ProCurvedataMemoryFree (spline);

        err = ProArrayObjectAdd ((ProArray*)&data->curves, PRO_VALUE_UNUSED, 1,
            &surf_curve);
        TEST_CALL_REPORT ("ProArrayObjectAdd()",
            "ProTestCurvewrapComputeAction()",
            err, err != PRO_TK_NO_ERROR);

        err = ProGeomitemdataFree(&gdata);
        TEST_CALL_REPORT ("ProGeomitemdataFree()",
            "ProTestCurvewrapComputeAction()",
            err, err != PRO_TK_NO_ERROR);
    }

    err = ProArrayFree ((ProArray*)&curves);

    return(PRO_TK_NO_ERROR);
}


/*====================================================================*\
FUNCTION : ProTestCurvewarpDisplayAction()
PURPOSE  : Callback to display the results of the analysis computation
\*====================================================================*/
ProError ProTestCurvewrapDisplayAction(
    ProAnalysis analysis)
{
    Curvewrapdata_t *data;
    int n_curves, c, p;
    ProVector pos;
    ProError err = PRO_TK_NO_ERROR;
    ProPoint3d point;

    TEST_CALL_REPORT ("ProAnalysisDisplayAction()", 
        "ProTestCurvewrapDisplayAction()", err, err != PRO_TK_NO_ERROR);
    
    err = ProAnalysisInfoGet(analysis, (ProAppData*)&data);
    if (err != PRO_TK_NO_ERROR)
        return(PRO_TK_NO_ERROR);

    err = ProArraySizeGet(data->curves, &n_curves);
    TEST_CALL_REPORT ("ProArraySizeGet()", 
        "ProTestCurvewrapDisplayAction()", err, err != PRO_TK_NO_ERROR);
    for (c = 0; c < n_curves; c++)
    {
        if (data->curves[c].curve->line.type == PRO_ENT_B_SPLINE)
        {
            for (p = 0; p < data->curves[c].curve->b_spline.num_c_points; p++)
            {
                point[0] = data->curves[c].curve->b_spline.c_pnts[p][0];
                point[1] = data->curves[c].curve->b_spline.c_pnts[p][1];
                point[2] = data->curves[c].curve->b_spline.c_pnts[p][2];
                if (data->curves[c].curve->b_spline.weights != NULL)
		{
                    point[0] /= data->curves[c].curve->b_spline.weights[p];
                    point[1] /= data->curves[c].curve->b_spline.weights[p];
                    point[2] /= data->curves[c].curve->b_spline.weights[p];
                }
                err = ProSurfaceXyzdataEval (data->curves[c].surface,
                    point,
                    pos, NULL, NULL, NULL);
                TEST_CALL_REPORT ("ProSurfaceXyzdataEval()", 
                    "ProTestCurvewrapDisplayAction()", 
                    err, err != PRO_TK_NO_ERROR);
                
                if (p == 0)
                    ProGraphicsPenPosition(pos);
                else
                    ProGraphicsLineDraw(pos);
	    }
	}
        else
	{
            for (p = 0; p < data->curves[c].curve->spline.num_points; p++)
            {
                err = ProSurfaceXyzdataEval (data->curves[c].surface,
                    data->curves[c].curve->spline.pnt_arr[p],
                    pos, NULL, NULL, NULL);
                TEST_CALL_REPORT ("ProSurfaceXyzdataEval()", 
                    "ProTestCurvewrapDisplayAction()", 
                    err, err != PRO_TK_NO_ERROR);
	   
                if (p == 0)
                    ProGraphicsPenPosition(pos);
                else
                    ProGraphicsLineDraw(pos);
	    }
        }
    }
    return(PRO_TK_NO_ERROR);
}


/*====================================================================*\
FUNCTION : ProTestCurvewarpOutputAction()
PURPOSE  : Callback to write textual information about the result of
		the computation
\*====================================================================*/
ProError ProTestCurvewrapOutputAction(
    ProAnalysis analysis,
    ProLine **lines)
{
    ProError err = PRO_TK_NO_ERROR;

    TEST_CALL_REPORT ("ProAnalysisOutputAction()", 
        "ProTestCurvewrapOutputAction()", err, err != PRO_TK_NO_ERROR);
    return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
FUNCTION : ProTestCurvewarpSavecheckAction()
PURPOSE  : Callback to tell Pro/E whether the analysis application
		data can be saved
\*====================================================================*/
ProError ProTestCurvewrapSavecheckAction(
    ProAnalysis analysis)
{
    ProError err = PRO_TK_NO_ERROR;
    
    TEST_CALL_REPORT ("ProAnalysisSavecheckAction()", 
        "ProTestCurvewrapSavecheckAction()", err, err != PRO_TK_NO_ERROR);
    return(PRO_TK_NO_ERROR);
}


/*====================================================================*\
FUNCTION : ProTestCurvewarpInfosaveAction()
PURPOSE  : Callback to tell Pro/E what element references are required
		by the analysis feature
\*====================================================================*/
ProError ProTestCurvewrapInfosaveAction(
    ProAnalysis analysis,
    ProFeature *feature,
    ProSelection **references)
{
    Curvewrapdata_t *data;
    ProSelection sel;
    ProError err = PRO_TK_NO_ERROR;

    TEST_CALL_REPORT ("ProAnalysisInfosaveAction()", 
        "ProTestCurvewrapInfosaveAction()", err, err != PRO_TK_NO_ERROR);

    err = ProAnalysisInfoGet (analysis, (ProAppData*)&data);
    TEST_CALL_REPORT ("ProAnalysisInfoGet()", 
        "ProTestCurvewrapInfosaveAction()", err, err != PRO_TK_NO_ERROR);
    if (err != PRO_TK_NO_ERROR)
        return(PRO_TK_NO_ERROR);

    ProSelectionAlloc(NULL, &data->curve, &sel);
    ProArrayObjectAdd((ProArray*)references, -1, 1, &sel);
    ProSelectionAlloc(NULL, &data->point, &sel);
    ProArrayObjectAdd((ProArray*)references, -1, 1, &sel);

    return(PRO_TK_NO_ERROR);
}


/*====================================================================*\
FUNCTION : ProTestCurvewarpInforetrieveAction()
PURPOSE  : Callback to get the references Pro/E has stored with the
		analysis feature
\*====================================================================*/
ProError ProTestCurvewrapInforetrieveAction(
    ProAnalysis analysis,
    ProFeature *feature,
    ProSelection *references)
{
    Curvewrapdata_t *data;
    int n_dims;
    ProDimension *p_dims;
    ProError err = PRO_TK_NO_ERROR;

    TEST_CALL_REPORT ("ProAnalysisInforetrieveAction()", 
        "ProTestCurvewrapInforetrieveAction()", 
        err, err != PRO_TK_NO_ERROR);
    
    err = ProAnalysisInfoGet(analysis, (ProAppData*)&data);
    TEST_CALL_REPORT ("ProAnalysisInfoGet()", 
        "ProTestCurvewrapInforetrieveAction()", 
        err, err != PRO_TK_NO_ERROR);
    if (err != PRO_TK_NO_ERROR)
        return(PRO_TK_NO_ERROR);

    ProSelectionModelitemGet(references[0], &data->curve);
    ProSelectionModelitemGet(references[1], &data->point);

/*--------------------------------------------------------------------*\
    If the feature has a dimension, take its value as the offset
\*--------------------------------------------------------------------*/
    err = ProTestFeatureDimensionsCollect (feature, &p_dims);
    err = ProArraySizeGet ((ProArray)p_dims, &n_dims);

    if(n_dims > 0)
    {
        double dim_value;
        err = ProDimensionValueGet(&p_dims[0], &dim_value);
        data->angle = dim_value;
        err = ProDimensionValueGet(&p_dims[1], &dim_value);
        data->offset = dim_value;

    }

    return(PRO_TK_NO_ERROR);
}


/*====================================================================*\
FUNCTION : ProTestCurvewarpInfocopyAction()
PURPOSE  : Copy information
\*====================================================================*/
ProError ProTestCurvewrapInfocopyAction(
    ProAnalysis from,
    ProAnalysis to)
{
    Curvewrapdata_t *fdata, *tdata;
    int n_curves, c;
    ProError err = PRO_TK_NO_ERROR;

    TEST_CALL_REPORT ("ProAnalysisInfocopyAction()", 
        "ProTestCurvewrapInfocopyAction()", 
        err, err != PRO_TK_NO_ERROR);
   
    err = ProAnalysisInfoGet (from, (ProAppData*)&fdata);
    TEST_CALL_REPORT ("ProAnalysisInfoGet()", 
        "ProTestCurvewrapInfocopyAction()", 
        err, err != PRO_TK_NO_ERROR);
    if (err != PRO_TK_NO_ERROR)
        return(PRO_TK_GENERAL_ERROR);
    err = ProAnalysisInfoGet (to  , (ProAppData*)&tdata);
    TEST_CALL_REPORT ("ProAnalysisInfoGet()", 
        "ProTestCurvewrapInfocopyAction()", 
        err, err != PRO_TK_NO_ERROR);
    if (err != PRO_TK_NO_ERROR)
        return(PRO_TK_GENERAL_ERROR);

    memcpy(&tdata->curve, &fdata->curve, sizeof(ProFeature));
    memcpy(&tdata->point, &fdata->point, sizeof(ProFeature));
    tdata->angle = fdata->angle;
    tdata->offset = fdata->offset;

    return(PRO_TK_NO_ERROR);
}

/*====================================================================*\
FUNCTION : ProTestCurvewarpResultAction()
PURPOSE  : Callback to give Pro/E the feature parameters and geometry
		that the analysis feature must contain
\*====================================================================*/
ProError ProTestCurvewrapResultAction(
    ProAnalysis analysis,
    ProBoolean names_only,
    ProAnalysisParameter **parameters,
    ProAnalysisGeomitem  **geometry)
{
    ProAnalysisParameter param;
    ProAnalysisGeomitem geomitem;
    ProSurface surface;
    ProCurvedata *curves_data;
    Curvewrapdata_t *data;
    int n_geoms, n_shapes, g, s, n_curves, c, p;
    ProCharName buff;
    ProError err = PRO_TK_NO_ERROR;
    double *par_arr;
    ProPoint3d *pnt_arr;
    ProPoint3d *tan_arr;
    int num;

    TEST_CALL_REPORT ("ProAnalysisResultAction()", 
        "ProTestCurvewrapResultAction()", 
        err, err != PRO_TK_NO_ERROR);
    
    err = ProAnalysisInfoGet(analysis, (ProAppData*)&data);
    TEST_CALL_REPORT ("ProAnalysisInfoGet()", 
        "ProTestCurvewrapResultAction()", 
        err, err != PRO_TK_NO_ERROR);
    if (err != PRO_TK_NO_ERROR)
        return(PRO_TK_GENERAL_ERROR);

/*--------------------------------------------------------------------*\
TEMP PARAMETER JUST TO MAKE SURE THE ENTITY GETS CREATED
\*--------------------------------------------------------------------*/
    ProStringToWstring(param.name, (char *)"TESTPARAM");
    param.create = PRO_B_TRUE;
    ProStringToWstring(param.description, (char *)"This is my test parameter");
    ProArrayAlloc(1, sizeof(ProParamvalue), 1, (ProArray*)&param.values);
    param.values[0].type = PRO_PARAM_DOUBLE;
    param.values[0].value.d_val=99.9;
    ProArrayObjectAdd((ProArray*)parameters, -1, 1, &param);

    ProStringToWstring(geomitem.name, (char *)"SURF_CURVE");
    geomitem.create = PRO_B_TRUE;
    geomitem.type = PRO_ANALYSIS_CURVE;
    if (!names_only)
    {
        ProArraySizeGet (data->curves, &n_curves);
        ProArrayAlloc (n_curves, sizeof(ProAnalysisEntity), 1, 
            (ProArray*)&geomitem.shapes);
        for (c = 0; c < n_curves; c++)
        {
            err = ProCurvedataAlloc (&geomitem.shapes[c].curve);
            TEST_CALL_REPORT ("ProCurvedataAlloc()",
                "ProTestCurvewrapResultAction()", err, 
                err != PRO_TK_NO_ERROR);
            
            err = ProSurfcurvedataGet ((ProCurvedata*)&data->curves[c], 
                &surface, &curves_data);
            TEST_CALL_REPORT ("ProSurfcurvedataGet()",
                "ProTestCurvewrapResultAction()", err, 
                err != PRO_TK_NO_ERROR);
            if (err != PRO_TK_NO_ERROR)
                return PRO_TK_GENERAL_ERROR;

            err = ProSurfcurvedataInit (surface, curves_data,
                geomitem.shapes[c].curve);
            TEST_CALL_REPORT ("ProSurfcurvedataInit()",
                "ProTestCurvewrapResultAction()", err, 
                err != PRO_TK_NO_ERROR);

	    err = ProCurvedataMemoryFree ( curves_data ) ;
            TEST_CALL_REPORT ("ProCurvedataFree()",
                "ProTestCurvewrapResultAction()", err, 
                err != PRO_TK_NO_ERROR);

        }
    }

    err = ProArrayObjectAdd ((ProArray*)geometry, PRO_VALUE_UNUSED, 1, 
        &geomitem);
    TEST_CALL_REPORT ("ProArrayObjectAdd()",
        "ProTestCurvewrapResultAction()", err, 
        err != PRO_TK_NO_ERROR);

    return(PRO_TK_NO_ERROR);
}