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


/*--------------------------------------------------------------------*\
Pro/TOOLKIT includes
\*--------------------------------------------------------------------*/
#include "ProToolkit.h"
#include "ProObjects.h"
#include "ProGraphic.h"
#include "ProMdl.h"
#include "ProMenu.h"
#include "ProMessage.h"
#include "ProSolid.h"
#include "ProUtil.h"
/*--------------------------------------------------------------------*\
C System includes
\*--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*\
Application includes
\*--------------------------------------------------------------------*/
#include "TestError.h"
#include "TestFiletypes.h"
#include "UtilFiles.h"
#include "UtilMessage.h"
#include "UtilString.h"
#include <PTApplsUnicodeUtils.h>
#include <ProTKRunTime.h>
#include <ProModelitem.h>
#include <ProSurface.h>
/*--------------------------------------------------------------------*\
Application macros
\*--------------------------------------------------------------------*/
#define SOLID_FILE ".sld"
/*--------------------------------------------------------------------*\
Application data types
\*--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*\
Application global/external data
\*--------------------------------------------------------------------*/

ProError ProTestRayIntersectionCompute(  ProSolid		p_solid,
                                         FILE    		*fp );
    

/*====================================================================*\
  Function : ProTestSolidFunc()
  Purpose  : to test some functions
\*====================================================================*/
int ProTestSolidFunc()
{
    ProError status;
    ProSolid solid, solid2;
    ProMdl   model;
    ProMdlType model_type;
    ProMdlName name;
    ProCharLine string;
    ProAccuracyType a_type;
    ProMassProperty mass_prop;
    Pro3dPnt outline[2];
    static ProMatrix matrix={{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}};
    double accuracy;
    int p_id;
    FILE *fp;
    ProSolidOutlExclTypes excl[1] = {PRO_OUTL_EXC_NOT_USED};

    status  =  ProMdlCurrentGet(&model);
    TEST_CALL_REPORT("ProMdlCurrentGet()", "ProTestSolidFunc()", 
	    status, status != PRO_TK_NO_ERROR && status != PRO_TK_BAD_CONTEXT);
    if (status !=  PRO_TK_NO_ERROR) 
	return (0);

    status = ProMdlTypeGet(model, &model_type);
    TEST_CALL_REPORT("ProMdlTypeGet()", "ProTestSolidFunc()", 
					    status, status != PRO_TK_NO_ERROR);
    if (model_type != PRO_MDL_PART && model_type != PRO_MDL_ASSEMBLY)
	return (0);
    status = ProMdlMdlnameGet(model, name);
    TEST_CALL_REPORT("ProMdlMdlnameGet()", "ProTestSolidFunc()", 
					    status, status != PRO_TK_NO_ERROR);
    ProTestQcrName(&model, (char *)SOLID_FILE, string);
    
    fp = (FILE *)PTApplsUnicodeFopen (string, "w");
    ProTKFprintf(fp, "File %s\n\n", string);

    ProTKFprintf(fp, "Model %s.%s\n", ProWstringToString(string, name),
		model_type == PRO_MDL_PART ? "prt" : "asm");
#ifndef PT_PRODUCTS_BUILD
    status = ProSolidMdlnameInit(name, (ProMdlfileType)model_type, &solid);
    TEST_CALL_REPORT("ProSolidMdlnameInit()", "ProTestSolidFunc()", 
					    status, status != PRO_TK_NO_ERROR);
    status = ProSolidAccuracyGet(solid, &a_type, &accuracy);
    TEST_CALL_REPORT("ProSolidAccuracyGet()", "ProTestSolidFunc()", 
					    status, status != PRO_TK_NO_ERROR);
    ProTKFprintf(fp, "Accuracy %10.6f\n", accuracy);
    accuracy /= 2;
    status = ProSolidAccuracySet(solid, a_type, accuracy);
    TEST_CALL_REPORT("ProSolidAccuracySet()", "ProTestSolidFunc()", 
					    status, status != PRO_TK_NO_ERROR);
    status = ProSolidRegenerate(solid, PRO_REGEN_NO_FLAGS);
    TEST_CALL_REPORT("ProSolidRegenerate()", "ProTestSolidFunc()", 
					    status, status != PRO_TK_NO_ERROR);
    status = ProSolidAccuracyGet(solid, &a_type, &accuracy);
    TEST_CALL_REPORT("ProSolidAccuracyGet()", "ProTestSolidFunc()", 
					    status, status != PRO_TK_NO_ERROR);
    ProTKFprintf(fp, "Accuracy %10.6f\n\n", accuracy);
#endif /* #ifndef PT_PRODUCTS_BUILD */

    status = ProSolidMassPropertyGet(solid, NULL, &mass_prop);
    TEST_CALL_REPORT("ProSolidMassPropertyGet()", "ProTestSolidFunc()", 
					    status, status != PRO_TK_NO_ERROR);
    ProTKFprintf(fp, "Mass properties\n");
    ProTKFprintf(fp, "Volume = %f\n", mass_prop.volume);
    ProTKFprintf(fp, "Surface area = %f\n",  mass_prop.surface_area);
    ProTKFprintf(fp, "Density = %f\n",  mass_prop.density);
    ProTKFprintf(fp, "Mass = %f\n",  mass_prop.mass);
    ProTKFprintf(fp, "Center of gravity with respect to default CSYS\n");
    ProTKFprintf(fp, "X Y Z    %f  %f  %f\n",  mass_prop.center_of_gravity[0],
		mass_prop.center_of_gravity[1], mass_prop.center_of_gravity[2]);
    ProTKFprintf(fp, "Inertia at Center of gravity with respect to default CSYS\n");  
    ProTKFprintf(fp, "Inertia tensor\n");
    ProTKFprintf(fp, "Ixx Ixy Ixz   %f  %f  %f\n",
		mass_prop.coor_sys_inertia_tensor[0][0],
		mass_prop.coor_sys_inertia_tensor[0][1],
		mass_prop.coor_sys_inertia_tensor[0][2]);
    ProTKFprintf(fp, "Iyx Iyy Iyz   %f  %f  %f\n",
		mass_prop.coor_sys_inertia_tensor[1][0],
		mass_prop.coor_sys_inertia_tensor[1][1],
		mass_prop.coor_sys_inertia_tensor[1][2]);
    ProTKFprintf(fp, "Izx Izy Izz   %f  %f  %f\n",
		mass_prop.coor_sys_inertia_tensor[2][0],
		mass_prop.coor_sys_inertia_tensor[2][1],
		mass_prop.coor_sys_inertia_tensor[2][2]);
    ProTKFprintf(fp, "Principal moments of inertia\n");
    ProTKFprintf(fp, "I1  I2  I3    %f  %f  %f\n",mass_prop.principal_moments[0],
	    mass_prop.principal_moments[1],mass_prop.principal_moments[2]);
    ProTKFprintf(fp, "Rotation matrix from default orientation to principal axes\n");
    ProTKFprintf(fp, "              %f  %f  %f\n",mass_prop.principal_axes[0][0],
	     mass_prop.principal_axes[0][1], mass_prop.principal_axes[0][2]);
    ProTKFprintf(fp, "              %f  %f  %f\n",mass_prop.principal_axes[1][0],
	     mass_prop.principal_axes[1][1], mass_prop.principal_axes[1][2]);
    ProTKFprintf(fp, "              %f  %f  %f\n",mass_prop.principal_axes[2][0],
    	     mass_prop.principal_axes[2][1], mass_prop.principal_axes[2][2]);


    status = ProSolidOutlineGet(solid, outline);
    TEST_CALL_REPORT("ProSolidOutlineGet()", "ProTestSolidFunc()", 
					    status, status != PRO_TK_NO_ERROR);
    ProTKFprintf(fp, "\nOutline :\n");
    ProTKFprintf(fp, "\t%f  %f  %f\n", outline[0][0], outline[0][1], outline[0][2]);
    ProTKFprintf(fp, "\t%f  %f  %f\n", outline[1][0], outline[1][1], outline[1][2]);

    status = ProSolidOutlineCompute(solid, matrix, excl, 1, outline);
    TEST_CALL_REPORT("ProSolidOutlineCompute()", "ProTestSolidFunc()", 
					    status, status != PRO_TK_NO_ERROR);
    ProTKFprintf(fp, "\nOutline :\n");
    ProTKFprintf(fp, "\t%f  %f  %f\n", outline[0][0], outline[0][1], outline[0][2]);
    ProTKFprintf(fp, "\t%f  %f  %f\n", outline[1][0], outline[1][1], outline[1][2]);
    
    status = ProSolidToPostfixId(solid, &p_id);
    TEST_CALL_REPORT("ProSolidToPostfixId()", "ProTestSolidFunc()", 
					    status, status != PRO_TK_NO_ERROR);
    ProTKFprintf(fp, "\nPostfix id = %d\n", p_id);
    status = ProPostfixIdToSolid(p_id, &solid2);
    TEST_CALL_REPORT("ProPostfixIdToSolid()", "ProTestSolidFunc()", 
					    status, status != PRO_TK_NO_ERROR);
    ProTKFprintf(fp, "PostfixId to Solid %s\n", solid == solid2 ? "Ok" : "Error");

    ProTestRayIntersectionCompute( solid, fp );

    fclose(fp);
    return (0);
}
   


/*====================================================================*\
  Function : ProTestRayIntersectionCompute()
  Purpose  : ProSolidRayIntersectionCompute test
\*====================================================================*/
ProError ProTestRayIntersectionCompute( 
    ProSolid		p_solid,
    FILE		*fp
)
{
    ProError		status;
    int			i;
    ProRay 		ray;
    ProSelection 	*p_sel;
    int 		n_sel;
    ProPoint3d 		point;
    ProColor	old_color;
	ProColor	letter_color, highlite_color, drawing_color;


    ray.start_point[0] = ray.start_point[1] = ray.start_point[2] = 0.0;
    for( i=0; i<3; i++ )
    {
	ProUtilMsgPrint( "gen", "TEST %0s", 
		"Enter the start point coord [0.0]: " );
        status = ProMessageDoubleRead( NULL, ray.start_point+i );
	TEST_CALL_REPORT( "ProMessageDoubleRead()",
         	"ProTestSolidFunc()", status, status != PRO_TK_NO_ERROR );
	if( status != PRO_TK_NO_ERROR )
	    return PRO_TK_USER_ABORT;

	ProGraphicsCircleDraw( ray.start_point, 0.1 );
        TEST_CALL_REPORT( "ProGraphicsCircleDraw()",
            "ProTestSolidFunc()", PRO_TK_NO_ERROR, 0 );
    }

    ray.dir_vector[0] = ray.dir_vector[1] = ray.dir_vector[2] = 0.0;
    for( i=0; i<3; i++ )
    {
        ProUtilMsgPrint( "gen", "TEST %0s",
                "Enter the dir vector coord [0.0]: " );
        status = ProMessageDoubleRead( NULL, ray.dir_vector+i );
        TEST_CALL_REPORT( "ProMessageDoubleRead()",
                "ProTestSolidFunc()", status, status != PRO_TK_NO_ERROR );
        if( status != PRO_TK_NO_ERROR )
            return PRO_TK_USER_ABORT;

        ProGraphicsPenPosition( ray.start_point );
        TEST_CALL_REPORT( "ProGraphicsPenPosition()",
            "ProTestSolidFunc()", PRO_TK_NO_ERROR, 0 );

        ProGraphicsLineDraw( ray.dir_vector );
        TEST_CALL_REPORT( "ProGraphicsLineDraw()",
            "ProTestSolidFunc()", PRO_TK_NO_ERROR, 0 );
    }

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

    status = ProSolidRayIntersectionCompute( p_solid, 0.0, &ray, 
	&p_sel, &n_sel );
    TEST_CALL_REPORT( "ProSolidRayIntersectionCompute()", 
	"ProTestSolidFunc()", status, status != PRO_TK_NO_ERROR );
	
	letter_color.method = PRO_COLOR_METHOD_TYPE;
	letter_color.value.type = PRO_COLOR_LETTER;

    status = ProGraphicsColorModify( &letter_color, &old_color );
    TEST_CALL_REPORT( "ProGraphicsColorModify()",
        "ProTestSolidFunc()", status, status != PRO_TK_NO_ERROR );

    for( i=0; i<n_sel; i++ )
    {
        status = ProSelectionPoint3dGet( p_sel[i], point );
	TEST_CALL_REPORT( "ProSelectionPoint3dGet()",
            "ProTestSolidFunc()", status, status != PRO_TK_NO_ERROR );

	ProGraphicsCircleDraw( point, 0.1 );
        TEST_CALL_REPORT( "ProSelectionPoint3dGet()",
            "ProTestSolidFunc()", PRO_TK_NO_ERROR, 0 );

        ProGraphicsPenPosition( ray.start_point );
        TEST_CALL_REPORT( "ProGraphicsPenPosition()",
            "ProTestSolidFunc()", PRO_TK_NO_ERROR, 0 );

        ProGraphicsLineDraw( point );
        TEST_CALL_REPORT( "ProGraphicsLineDraw()",
            "ProTestSolidFunc()", PRO_TK_NO_ERROR, 0 );
    }

    highlite_color.method = PRO_COLOR_METHOD_TYPE;
	highlite_color.value.type = PRO_COLOR_HIGHLITE;

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

    ProGraphicsCircleDraw( ray.start_point, 0.1 );
    TEST_CALL_REPORT( "ProGraphicsCircleDraw()",
        "ProTestSolidFunc()", PRO_TK_NO_ERROR, 0 );

    drawing_color.method = PRO_COLOR_METHOD_TYPE;
	drawing_color.value.type = PRO_COLOR_DRAWING;

    status = ProGraphicsColorModify( &drawing_color, &old_color );		
    TEST_CALL_REPORT( "ProGraphicsColorModify()",
        "ProTestSolidFunc()", status, status != PRO_TK_NO_ERROR );

    /* Write the ray data to the file */
    if( fp != NULL )
    {
	ProTKFprintf( fp, "\n!   Ray Intersection Data\n" );
        ProTKFprintf( fp, "Ray start point: %f %f %f\n", 
		ray.start_point[0], ray.start_point[1], ray.start_point[2] ); 
        ProTKFprintf( fp, "Ray vector dir: %f %f %f\n",
                ray.dir_vector[0], ray.dir_vector[1], ray.dir_vector[2] );

        ProTKFprintf( fp, "Ray intersection points:\n" );
    	
	for( i=0; i<n_sel; i++ )
    	{
            status = ProSelectionPoint3dGet( p_sel[i], point );
            TEST_CALL_REPORT( "ProSelectionPoint3dGet()",
            	"ProTestSolidFunc()", status, status != PRO_TK_NO_ERROR );
	    ProTKFprintf( fp, "%f %f %f\n", point[0], point[1], point[2] );
	}
    }


    return PRO_TK_NO_ERROR;
}
 
/*====================================================================*\
  Function : ProTestRayIntersectionCompute()
  Purpose  : ProSolidRayIntersectionCompute test
\*====================================================================*/
int ProTestSolidProject()
{
    ProError status;
    ProMdl owner;
    ProSurface surface;
    ProUvParam uv_point;
    double tolerance;
    Pro3dPnt xyz;
    ProSelection *p_sel;
    int n_sel, id;
    ProSrftype type;
    FILE *qcr_fp;
    ProUtilCname fname;
    ProModelitem srf_modelitem;
   
    ProUtilMsgPrint ( "gen", "TEST %0s", "Enter tolerance" );
    status = ProMessageDoubleRead (NULL, &tolerance);
    TEST_CALL_REPORT( "ProMessageDoubleRead()",
        "ProTestSolidProject()", status, status != PRO_TK_NO_ERROR );
    if(status != PRO_TK_NO_ERROR) 
        return(0);
  
    ProUtilMsgPrint ( "gen", "TEST %0s", "Select surface" );
    status = ProSelect ((char*)"surface", 1, NULL, NULL, NULL, NULL, &p_sel,
        &n_sel);
    TEST_CALL_REPORT( "ProSelect()",
        "ProTestSolidProject()", status, status != PRO_TK_NO_ERROR );
    if (status != PRO_TK_NO_ERROR || n_sel != 1)
        return (0);
    status = ProSelectionModelitemGet (p_sel[0], &srf_modelitem);
    TEST_CALL_REPORT( "ProSelectionModelitemGet()",
        "ProTestSolidProject()", status, status != PRO_TK_NO_ERROR );
    status = ProModelitemMdlGet (&srf_modelitem, &owner);
    TEST_CALL_REPORT( "ProModelitemMdlGet()",
        "ProTestSolidProject()", status, status != PRO_TK_NO_ERROR );
        
    ProTestQcrName(&owner, (char*)".prj", fname);
    qcr_fp = (FILE *)PTApplsUnicodeFopen(fname,"a");
    
    status = ProSelectionPoint3dGet(p_sel[0], xyz);
    TEST_CALL_REPORT( "ProSelectionPoint3dGet()",
        "ProTestSolidProject()", status, status != PRO_TK_NO_ERROR );
    status= ProSolidProjectPoint ((ProSolid)owner, xyz, tolerance, &surface, 
        uv_point);
    TEST_CALL_REPORT( "ProSolidProjectPoint()",
        "ProTestSolidProject()", status, status != PRO_TK_NO_ERROR );
        
    status = ProSurfaceIdGet(surface, &id);
    TEST_CALL_REPORT( "ProSurfaceIdGet()",
        "ProTestSolidProject()", status, status != PRO_TK_NO_ERROR );
    status = ProSurfaceTypeGet(surface, &type);
    TEST_CALL_REPORT( "ProSurfaceTypeGet()",
        "ProTestSolidProject()", status, status != PRO_TK_NO_ERROR );
    
    ProTKFprintf(qcr_fp, "\n Surface : type: %d, id: %d", type, id);
    ProTKFprintf(qcr_fp, "\n UV_param : uv_point[1] = %f, uv_point[2] = %f", 
            uv_point[0], uv_point[1]);
    fclose(qcr_fp);
    
    return(0);
}