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


/*---------------------- Pro/Toolkit Includes ------------------------*/
#include "ProToolkit.h"
#include "ProMdl.h"
#include "ProModelitem.h"
#include "ProSelection.h"
#include "ProMessage.h"
#include "ProMenu.h"
#include "ProSurface.h"
#include "ProCsys.h"
#include "ProFeature.h"
#include "ProDisplist.h"
#include "ProGraphic.h"
#include "ProXsec.h"

#include "UtilMatrix.h"
/*---------------------- Application Includes ------------------------*/
#include "UtilMath.h"

/*------------------------- Global Data -----------------------------*/
static ProName msgfil;

/*---------------------- Function Prototypes -------------------------*/
int user_Neutral_Axis();
void UsrPolylineDraw();

/*====================================================================*
Function : user_Neutral_Axis()
Purpose  : Example for Calculating the Mass Properties of Cross Sections 
\*====================================================================*/
int user_Neutral_Axis()
{
    ProError status;
    ProPart part;
    int n_sel;
    ProSelection *sel;
    ProModelitem surface_modelitem, csys_modelitem;
    ProSurface surface;
    ProSrftype stype;
    ProPoint3d finish, normal, pos, cross, xpos, cog;
    ProUvParam uv;
    double dist, absdist, offset;
    ProCsys csys;
    ProGeomitemdata *csys_geomdata;
    ProCsysdata *csys_data;
    ProMatrix transf, nulltransf;
    ProName w_csys_name, w_name;
    int n_steps, id=-1, surf_id;
    ProXsec xsec;
    ProDimension dimension;
    ProMassProperty  mprop;
    ProPoint3d points[100];
    int n_points=0;
    ProFeature feature;
    ProFeatureDeleteOptions *delete_opts = 0;
    int *feat_ids = NULL;

    ProStringToWstring(msgfil,"msg_ugxsec.txt");
    ProMdlCurrentGet((ProMdl*)&part);

/*-----------------------------------------------------------*\
    Select a starting plane for the cross section.
\*-----------------------------------------------------------*/
    ProMessageDisplay(msgfil, "USER Pick the start plane");
    status = ProSelect("face", 1, NULL, NULL, NULL, NULL, &sel, &n_sel);
    if(status != PRO_TK_NO_ERROR || n_sel < 1)
        return(0);

    ProSelectionModelitemGet(sel[0], &surface_modelitem);
    ProSurfaceInit(part, surface_modelitem.id, &surface);
    ProSurfaceTypeGet(surface, &stype);
    if(stype != PRO_SRF_PLANE)
	return(0);

/*-----------------------------------------------------------*\
    Select a finish point.
\*-----------------------------------------------------------*/
    ProMessageDisplay(msgfil, "USER Pick the end position");
    status = ProSelect("face,edge", 1, NULL, NULL, NULL, NULL, &sel, &n_sel);
    if(status != PRO_TK_NO_ERROR || n_sel < 1)
        return(0);
    ProSelectionPoint3dGet(sel[0], finish);

/*-----------------------------------------------------------*\
    Get the geometry of the start plane.
\*-----------------------------------------------------------*/
    uv[0]=uv[1]=0.0;
    ProSurfaceXyzdataEval(surface, uv, pos, NULL, NULL, normal);
    dist = ProUtilPointPlaneDist(finish, pos, normal);

/*-----------------------------------------------------------*\
    Select a Csys Datum whose X and Y are parallel to the
    start plane.
\*-----------------------------------------------------------*/
    ProMessageDisplay(msgfil, "USER Pick the csys");
    while (1)
    {
	status = ProSelect("csys", 1, NULL, NULL, NULL, NULL, &sel, &n_sel);
	if(status != PRO_TK_NO_ERROR || n_sel < 1)
            return(0);
	ProSelectionModelitemGet(sel[0], &csys_modelitem);
	ProCsysInit(part, csys_modelitem.id, &csys);
	ProCsysDataGet(csys, &csys_geomdata);
	csys_data = csys_geomdata->data.p_csys_data;

        ProUtilVectorCross(normal, csys_data->z_vector, cross);
        if (fabs(ProUtilVectorLength(cross)) > EPSM6)
            ProMessageDisplay(msgfil, "USER Csys has wrong orientation");
        else
            break;
    }

/*-----------------------------------------------------------*\
    Get the name and location of the coordinate system.
\*-----------------------------------------------------------*/
    ProMatrixInit(csys_data->x_vector,
		  csys_data->y_vector,
		  csys_data->z_vector,
		  csys_data->origin, transf);
    ProModelitemNameGet(&csys_modelitem, w_csys_name);

/*-----------------------------------------------------------*\
    Get the number of steps in the analysis.
\*-----------------------------------------------------------*/
    ProMessageDisplay(msgfil, "USER Number of steps [QUIT] : ");
    if(ProMessageIntegerRead(NULL, &n_steps) != PRO_TK_NO_ERROR)
        return(0);

/*-----------------------------------------------------------*\
    Create an initial cross section half-way down.
\*-----------------------------------------------------------*/
    ProStringToWstring(w_name, "ZZZ");
    status = ProSurfaceIdGet (surface, &surf_id);
    status =  ProXsecParallelCreate((ProSolid)part, w_name, surf_id, dist / 2.0, 
                                    &xsec, &dimension);
/*-----------------------------------------------------------*\
    Step from start plane to finish.
\*-----------------------------------------------------------*/
    absdist = fabs(dist);
    for (offset = 0.0; offset <= absdist; offset += 
         absdist / n_steps)
    {
/*-----------------------------------------------------------*\
        Modify the cross-sectional offset dimension to move
        it to the right position.
\*-----------------------------------------------------------*/
       ProDimensionValueSet(&dimension, offset);
/*-----------------------------------------------------------*\
        Regenerate the cross section, and calculate the
        mass properties.
\*-----------------------------------------------------------*/
       status = ProSolidRegenerate((ProSolid)part, PRO_REGEN_NO_FLAGS);
       status = ProXsecRegenerate(&xsec);
        status = ProXsecMassPropertyCompute(&xsec, w_csys_name, &mprop);
        if (PRO_TK_NO_ERROR != status)
            continue;
/*-----------------------------------------------------------*\
        Transform the COG to model coordinates.
\*-----------------------------------------------------------*/
        ProPntTrfEval(mprop.center_of_gravity, transf, cog);

/*-----------------------------------------------------------*\
        Shift the cross COG from the XY-plane of the
        coordinate system to the plane of the cross section.
\*-----------------------------------------------------------*/
        xpos[0] = pos[0] - normal[0] * offset;
        xpos[1] = pos[1] - normal[1] * offset;
        xpos[2] = pos[2] - normal[2] * offset;

        ProUtilPlaneLineX(xpos, normal, cog, normal, cog);
        ProUtilVectorCopy (cog, points[n_points++]);
    }

/*-----------------------------------------------------------*\
    Delete the cross section and the owning feature (a datum 
    plane).
\*-----------------------------------------------------------*/
    ProDimensionFeatureGet (&dimension, &feature);
    status = ProXsecDelete(&xsec);

    status = ProArrayAlloc(1,sizeof(ProFeatureDeleteOptions),
        1, (ProArray*)&delete_opts);

    delete_opts[0] = PRO_FEAT_DELETE_CLIP;

    status = ProArrayAlloc(1,sizeof(int),
        1, (ProArray*)&feat_ids);

    feat_ids[0] = feature.id;

    ProFeatureWithoptionsDelete(part, feat_ids, 
      delete_opts, PRO_REGEN_NO_FLAGS);

    status = ProArrayFree((ProArray*)&delete_opts);
    status = ProArrayFree((ProArray*)&feat_ids);


/*-----------------------------------------------------------*\
    Display the line of the COG as a 3D list of vectors.
\*-----------------------------------------------------------*/
    ProDisplist3dCreate(id, UsrPolylineDraw, points,
         &n_points, NULL, NULL, NULL, NULL);
    ProUtilMatrixCopy(NULL, nulltransf);
    ProDisplist3dDisplay(id++, nulltransf);
    ProWindowRepaint(-1);

    return (0);
}

/*===========================================================*\
    Function to draw a polyline, with arguments suitable 
    for acting as a callback to ProDisplist3dCreate()
\*===========================================================*/
void UsrPolylineDraw(
    ProPoint3d *points,
    int *n_points)
{
    ProColor old_color, warning_color;
	
	warning_color.method = PRO_COLOR_METHOD_TYPE;
	warning_color.value.type = PRO_COLOR_WARNING;
	
	ProGraphicsColorModify (&warning_color, &old_color);
	    
    ProGraphicsPolylineDraw(points, *n_points);
    
	ProGraphicsColorModify(&old_color, NULL);
}