/* Copyright (c) 2024 PTC Inc. and/or Its Subsidiary Companies. All Rights Reserved. */ /*--------------------------------------------------------------------*\ Pro/TOOLKIT includes \*--------------------------------------------------------------------*/ #include "ProToolkit.h" #include "ProMenu.h" #include "ProSelection.h" #include "ProModelitem.h" #include "ProMdl.h" #include "ProArray.h" #include "ProUtil.h" #include "ProAnimate.h" #include "ProTKRunTime.h" /*--------------------------------------------------------------------*\ Pro/DEVELOP includes \*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*\ C System includes \*--------------------------------------------------------------------*/ #include <math.h> /*--------------------------------------------------------------------*\ Application includes \*--------------------------------------------------------------------*/ #include "TestError.h" #include "TestAnimation.h" #include "UtilMessage.h" #include "UtilString.h" #include "UtilCollect.h" /*--------------------------------------------------------------------*\ Macros \*--------------------------------------------------------------------*/ #define ANI_OBJECT( i, f ) (ani_obj_seq[i].anims[f]) #define PI (3.1451) #define MAX_FRAMES_NUM 30 /*--------------------------------------------------------------------*\ Data types \*--------------------------------------------------------------------*/ /*---------------------------------------------------------------*\ This structure contains information about animation objects associated with the model. Macro ANI_OBJECT(i,f) is used to get animation object handle (ProAnimObj) of the model i in the frame f. \*---------------------------------------------------------------*/ typedef struct tag_AniObjectInstance { ProMdl model; /* Handle to the animated model */ ProAsmcomppath comp_path; /* Component path of the object */ ProAnimObj anims[ MAX_FRAMES_NUM ]; /* Array of the ani objs */ } AniObjectInstance; /*--------------------------------------------------------------------*\ Application global/external data \*--------------------------------------------------------------------*/ static AniObjectInstance* ani_obj_seq = NULL; /* Array of of ani objs */ static int n_objects = 0; /* Current number of ani objs */ #if 0 static ProAnimFrame frames[ MAX_FRAMES_NUM ]; /* Animation frames */ #endif static ProAnimFrame *frames; /* Animation frames */ static int n_frames; /* Current number of frames */ /*---------------------------------------------------------------------*\ Functions declaration \*---------------------------------------------------------------------*/ ProError ProUtilSelectedMdlGet( ProSelection* , ProMdl* ); ProError ProUtilAniObjectSelect( char option[], ProSelection**, AniObjectInstance* ); ProBoolean ProUtilMdlEqual( ProMdl, ProMdl ); int ProUtilAniObjectFind( ProArray, AniObjectInstance ); ProError ProUtilAniObjectInstanceInit( ProSelection**, AniObjectInstance* ); ProError ProTestBatchAnimAct( ProAnimFrame, int, ProAppData ); void ProUtilRotX( double angle, ProMatrix mx ); /*---------------------------------------------------------------------*\ Function: ProTestAnimation() Purpose: Top-level function. Initialize some data, create and run ANIMATION menu, then free used resources. Returns: 0 - success; -1 - error. Now ignored. \*---------------------------------------------------------------------*/ int ProTestAnimation( void* p_dummy, int int_dummy ) { ProError status; int menu_id; /* The identifier of the created menu */ int action; /* Init the array of animation objects */ n_objects = 0; status = ProArrayAlloc( 0, sizeof(AniObjectInstance), 1, (ProArray *)&ani_obj_seq ); TEST_CALL_REPORT( "ProArrayAlloc()", "ProTestAnimation()", status, status != PRO_TK_NO_ERROR ); if( status != PRO_TK_NO_ERROR ) return -1; /* Init the array of animation frames */ n_frames = 0; status = ProArrayAlloc( 0, sizeof(ProAnimFrame), 1, (ProArray *)&frames ); TEST_CALL_REPORT( "ProArrayAlloc()", "ProTestAnimation()", status, status != PRO_TK_NO_ERROR ); if( status != PRO_TK_NO_ERROR ) return -1; status = ProArraySizeSet( (ProArray *)&frames, MAX_FRAMES_NUM ); TEST_CALL_REPORT( "ProArraySizeSet()", "ProTestAnimation()", status, status != PRO_TK_NO_ERROR ); if( status != PRO_TK_NO_ERROR ) return -1; /*-----------------------------*\ Create new menu ANIMATION \*-----------------------------*/ /* Load base menu from file */ status = ProMenuFileRegister((char *)"Animation", (char *)"tkanim.mnu", &menu_id ); TEST_CALL_REPORT( "ProMenuFileRegister()", "ProTestAnimation()", status, status != PRO_TK_NO_ERROR ); /* Define menu buttons */ ProMenubuttonActionSet((char *)"Animation", (char *)"Create", (ProMenubuttonAction)ProTestAnimframeCreate, NULL, 0 ); ProMenubuttonActionSet((char *)"Animation", (char *)"Delete", (ProMenubuttonAction)ProTestAnimframeDelete, NULL, 0 ); ProMenubuttonActionSet((char *)"Animation", (char *)"AddObject", (ProMenubuttonAction)ProTestAniObjectAdd, NULL, 0 ); ProMenubuttonActionSet((char *)"Animation", (char *)"DeleteObject", (ProMenubuttonAction)ProTestSelAniObjectDelete, NULL, 0 ); ProMenubuttonActionSet((char *)"Animation", (char *)"PlaySingle", (ProMenubuttonAction)ProTestSingleAnimation, NULL, 0 ); ProMenubuttonActionSet((char *)"Animation", (char *)"PlayBatch", (ProMenubuttonAction)ProTestBatchAnimation, NULL, 0 ); ProMenubuttonActionSet((char *)"Animation", (char *)"Animation", (ProMenubuttonAction)ProMenuDelete, NULL, 0 ); /*-----------------------*\ Run menu ANIMATION \*-----------------------*/ status = ProMenuCreate( PROMENUTYPE_MAIN, (char *)"Animation", &menu_id ); TEST_CALL_REPORT( "ProMenuCreate()", "ProTestAnimation()", status, status != PRO_TK_NO_ERROR ); if( status == PRO_TK_NO_ERROR ) { status = ProMenuProcess( (char *)"Animation", &action ); TEST_CALL_REPORT( "ProMenuProcess()", "ProTestAnimation()", status, status != PRO_TK_NO_ERROR ); } status = ProArrayFree( (ProArray *)&ani_obj_seq ); TEST_CALL_REPORT( "ProArrayFree()", "ProTestAnimation()", status, status != PRO_TK_NO_ERROR ); n_objects = 0; status = ProArrayFree( (ProArray *)&frames ); TEST_CALL_REPORT( "ProArrayFree()", "ProTestAnimation()", status, status != PRO_TK_NO_ERROR ); n_frames = 0; return 0; } /*---------------------------------------------------------------------*\ Function: ProTestAnimframeCreate() Purpose: On-button function. Initialize frames sequence structure. Returns: 0 - success; -1 - error. Now ignored. \*---------------------------------------------------------------------*/ int ProTestAnimframeCreate( void* p_dummy, int int_dummy ) { ProError status; int i; ProMatrix m_frame_view = { {1.0, 0.0, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0} }; ProVector v_x = {1.0, 0.0, 0.0}; ProVector v_y = {0.0, 1.0, 0.0}; ProVector v_z = {0.0, 0.0, 1.0}; ProPoint3d origin = {0.0, 0.0, 1.0}; /* Check animation frames */ if( n_frames > 0 ) { ProUtilMsgPrint( "gen", "TEST %0s", "Animation already exists" ); return -1; } /* Get a number of frames */ ProUtilMsgPrint( "gen", "TEST %0s", "Enter a number of frames: " ); if( !ProUtilIntGet( NULL, NULL, &n_frames ) ) n_frames = MAX_FRAMES_NUM; if( n_frames > MAX_FRAMES_NUM ) n_frames = MAX_FRAMES_NUM; /* Init the frame view matrix */ status = ProMatrixInit( v_x, v_y, v_z, origin, m_frame_view ); TEST_CALL_REPORT( "ProMatrixInit()", "ProTestAnimframeCreate()", status, status != PRO_TK_NO_ERROR ); /* Initialize the frames */ for( i=0; i<n_frames; i++ ) { status = ProAnimframeCreate( m_frame_view, &(frames[i]) ); TEST_CALL_REPORT( "ProAnimframeCreate()", "ProTestAnimframeCreate()", status, status != PRO_TK_NO_ERROR ); if( status != PRO_TK_NO_ERROR ) return -1; } return 0; /* Upon success */ } /*---------------------------------------------------------------------*\ Function: ProTestAnimframeDelete() Purpose: On-button function. Remove animation objects from the frames, delete animation frames and free an array of the handles of the frames. Returns: 0 - success; -1 - error. Now ignored. Note: Arguments are ignored. \*---------------------------------------------------------------------*/ int ProTestAnimframeDelete( void* p_dummy, int int_dummy ) { ProError status; int i; /* Check animation frames */ if( n_frames < 1 ) return -1; /* Delete the animation objects */ for( i=n_objects-1; i>=0; i-- ) ProTestAniObjectDelete( i ); /* Delete animation frames */ for( i=0; i<n_frames; i++ ) { status = ProAnimframeDelete( frames[i] ); TEST_CALL_REPORT( "ProAnimframeDelete()", "ProTestAnimframeDelete()", status, status != PRO_TK_NO_ERROR ); } n_frames = 0; return 0; } /*---------------------------------------------------------------------*\ Function: ProTestAniObjectAdd() Purpose: On-button function. Select an animation object and add it to the animation frames. Returns: 0 - success; -1 - error. Now ignored. Note: Arguments are ignored. \*---------------------------------------------------------------------*/ int ProTestAniObjectAdd( void* p_dummy, int int_dummy ) { ProError status; ProSelection* p_selection; AniObjectInstance ani_object; /* Created animation object */ int i_frame; double angle; double add_angle; ProMode mode; ProMatrix m_transform = { {1.0, 0.0, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0} }; /* Check animation frames */ if( n_frames < 1 ) { ProUtilMsgPrint( "gen", "TEST %0s", "First, create an animation" ); return -1; } /* Select ONE element to animate */ status = ProUtilAniObjectSelect( (char *)"prt_or_asm", &p_selection, &ani_object ); if( status == PRO_TK_USER_ABORT ) return -1; if( status != PRO_TK_E_NOT_FOUND ) { /* User have selected already animated object */ ProUtilMsgPrint( "gen", "TEST %0s", "The item is already animated" ); return -1; } /* Insert object to the array of the animated elements */ status = ProArrayObjectAdd( (ProArray *)&ani_obj_seq, 0, 1, (void*)&ani_object ); TEST_CALL_REPORT( "ProArrayObjectAdd()", "ProTestAniObjectAdd()", status, status != PRO_TK_NO_ERROR ); if( status == PRO_TK_NO_ERROR ) n_objects++; else return -1; status = ProModeCurrentGet(&mode); TEST_CALL_REPORT( "ProModeCurrentGet()", "ProTestAniObjectAdd()", status, status != PRO_TK_NO_ERROR ); if (mode == PRO_MODE_ASSEMBLY) { /* Retrieve the transformation matrix */ status = ProAsmcomppathTrfGet( &ani_obj_seq[0].comp_path, PRO_B_TRUE, m_transform ); TEST_CALL_REPORT( "ProAsmcomppathTrfGet()", "ProTestAniObjectAdd()", status, status != PRO_TK_NO_ERROR ); /* Assign the transformation matrix. Used for test only */ status = ProAsmcomppathTrfSet( &ani_obj_seq[0].comp_path, PRO_B_TRUE, m_transform ); TEST_CALL_REPORT( "ProAsmcomppathTrfSet()", "ProTestAniObjectAdd()", status, status != PRO_TK_NO_ERROR ); } /* Init rotate angle */ angle = 0.0; add_angle = 360.0 / (double)n_frames; /* Create animation objects and add it to the frames */ for( i_frame=0; i_frame<n_frames; i_frame++ ) { /* Add rotation to the transformation matrix */ angle += add_angle; ProUtilRotX( angle, m_transform ); /* Create an animation object... */ status = ProAnimobjectCreate( *p_selection, m_transform, &ANI_OBJECT(0, i_frame) ); TEST_CALL_REPORT( "ProAnimobjectCreate()", "ProTestAniObjectAdd()", status, status != PRO_TK_NO_ERROR ); if( status != PRO_TK_NO_ERROR ) return -1; /* ...and add it to the frame */ status = ProAnimframeObjAdd( frames[i_frame], ANI_OBJECT(0, i_frame) ); TEST_CALL_REPORT( "ProAnimframeObjAdd()", "ProTestAniObjectAdd()", status, status != PRO_TK_NO_ERROR ); if( status != PRO_TK_NO_ERROR ) return -1; } return 0; } /*---------------------------------------------------------------------*\ Function: ProTestSelAniObjectDelete() Purpose: On-button function. Select ani object and delete it. Returns: 0 - success; -1 - error. Now ignored. Note: Arguments are ignored. \*---------------------------------------------------------------------*/ int ProTestSelAniObjectDelete( void* p_dummy, int int_dummy ) { ProSelection* p_selection; int i_obj; /* Select an animation object */ i_obj = ProUtilAniObjectSelect( (char *)"prt_or_asm", &p_selection, NULL ); if( i_obj < PRO_TK_NO_ERROR ) { ProUtilMsgPrint( "gen", "TEST %0s", "Invalid selection" ); return -1; } /* Delete specified animation object */ if( ProTestAniObjectDelete( i_obj ) != PRO_TK_NO_ERROR ) return -1; else return 0; } /*---------------------------------------------------------------------*\ Function: ProTestAniObjectDelete() Purpose: Delete specified animation object and removes it from the array.. Returns: 0 - success; -1 - error. Now ignored. Note: Arguments are ignored. \*---------------------------------------------------------------------*/ int ProTestAniObjectDelete( int i_obj ) /* (In) The object index in the sequence of the ani objects */ { ProError status; int i_frame; /* Check index */ if( (i_obj < 0) || (i_obj >= n_objects) ) return -1; /* Delete the animation objects */ for( i_frame=0; i_frame<n_frames; i_frame++ ) { /* Remove the animation object from the frame */ status = ProAnimframeObjRemove( frames[i_frame], ANI_OBJECT(i_obj, i_frame) ); TEST_CALL_REPORT( "ProAnimframeObjRemove()", "ProTestAniObjectDelete()", status, status != PRO_TK_NO_ERROR ); /* Delete the animation object */ status = ProAnimobjectDelete( ANI_OBJECT(i_obj, i_frame) ); TEST_CALL_REPORT( "ProAnimobjectDelete()", "ProTestAniObjectDelete()", status, status != PRO_TK_NO_ERROR ); } /* Remove the animation object from the array */ status = ProArrayObjectRemove( (ProArray *)&ani_obj_seq, i_obj, 1 ); TEST_CALL_REPORT( "ProArrayObjectRemove()", "ProTestAniObjectDelete()", status, status != PRO_TK_NO_ERROR ); if( status == PRO_TK_NO_ERROR ) n_objects--; else return -1; return 0; } /*---------------------------------------------------------------------*\ Function: ProTestSingleAnimationAct() Purpose: This is the generic function for visiting animation objects. Returns: 1 - success; Note: I also use this function as a filter one. \*---------------------------------------------------------------------*/ ProError ProTestSingleAnimAct( ProAnimObj ani_object, /* (In) The handle to the animation object */ ProAppData app_data ) /* (In) The pointer to the frame number */ { TEST_CALL_REPORT ("ProAnimObjAct()","ProTestSingleAnimAct()", PRO_TK_NO_ERROR, 0); if( app_data != NULL ) { ProTKPrintf( "Single frame %d, object %X\n", *(int*)app_data, ani_object ); } return PRO_TK_NO_ERROR; } /*---------------------------------------------------------------------*\ Function: ProTestSingleAnimation() Purpose: On-button function. Returns: 0 - success; -1 - error. Now ignored. Note: Arguments are ignored. \*---------------------------------------------------------------------*/ int ProTestSingleAnimation( void* p_dummy, int int_dummy ) { ProError status; ProSingleAnim single_animation; int i_frame; int i_obj; ProAnimObj *anim_objects; int anim_obj_num, i; /* Check animation frames */ if( n_frames < 1 ) { ProUtilMsgPrint( "gen", "TEST %0s", "First, create an animation" ); return -1; } /* At least one animation object must exist */ if( n_objects < 1 ) { ProUtilMsgPrint( "gen", "TEST %0s", "First, add objects to animate" ); return -1; } /* Initialize an animation in single mode. */ status = ProSingleAnimationInit( ani_obj_seq[0].model, frames[0], &single_animation ); TEST_CALL_REPORT( "ProSingleAnimationInit()", "ProTestSingleAnimation()", status, status != PRO_TK_NO_ERROR ); if( status != PRO_TK_NO_ERROR ) return -1; /* Play back the animation frame by frame */ for( i_frame=0; i_frame<n_frames; i_frame++ ) { /* Play back the frame */ status = ProSingleAnimationPlay( single_animation, frames[i_frame] ); TEST_CALL_REPORT( "ProSingleAnimationPlay()", "ProTestSingleAnimation()", status, status != PRO_TK_NO_ERROR ); if( status != PRO_TK_NO_ERROR ) return -1; } /* Visit objects in the frames */ puts( "Visit objects in the frames:" ); for( i_frame=0; i_frame<n_frames; i_frame++ ) for( i_obj=0; i_obj<n_objects; i_obj++ ) { status = ProUtilCollectAnimObjects (frames[i_frame], &anim_objects); if (status == PRO_TK_NO_ERROR) { status = ProArraySizeGet ((ProArray)anim_objects, &anim_obj_num); TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestSingleAnimation()", status, status != PRO_TK_NO_ERROR ); for (i = 0; i < anim_obj_num; i++) { status = ProTestSingleAnimAct (anim_objects[i], (ProAppData)&i_frame); } status = ProArrayFree ((ProArray*)&anim_objects); TEST_CALL_REPORT( "ProArrayFree()", "ProTestSingleAnimation()", status, status != PRO_TK_NO_ERROR ); } } /* Clear the data generated for single mode animation.*/ status = ProSingleAnimationClear( single_animation ); TEST_CALL_REPORT( "ProSingleAnimationClear()", "ProTestSingleAnimation()", status, status != PRO_TK_NO_ERROR ); if( status != PRO_TK_NO_ERROR ) return -1; return 0; } /*---------------------------------------------------------------------*\ Function: ProTestAnimFrameAct() Purpose: This is the generic function for visiting animation objects. Returns: 1 - success; \*---------------------------------------------------------------------*/ ProError ProTestAnimFrameAct( ProAnimFrame ani_frame, /* (In) The handle to the animation frame */ ProAppData app_data ) /* (In) The pointer to the frame number */ { TEST_CALL_REPORT ("ProAnimFrameAct()", "ProTestAnimFrameAct()", PRO_TK_NO_ERROR, 0); if( app_data != NULL ) { ProTKPrintf( "Movie frame %d: %X\n", *(int*)app_data, ani_frame ); } return PRO_TK_NO_ERROR; } /*---------------------------------------------------------------------*\ Function: ProTestBatchAnimAct() Purpose: This is the generic function for callbacks in the middle of a batch animation. Returns: PRO_TK_NO_ERROR - success; Note: \*---------------------------------------------------------------------*/ ProError ProTestBatchAnimAct( ProAnimFrame animation_frame, int frame_no, ProAppData app_data ) { TEST_CALL_REPORT ("ProBatchAnimAct()", "ProTestBatchAnimAct()", PRO_TK_NO_ERROR, 0); ProTKPrintf( "Batch frame %d\n", frame_no ); return PRO_TK_NO_ERROR; } /*---------------------------------------------------------------------*\ Function: ProTestBatchAnimation() Purpose: On-button function. Returns: 0 - success; -1 - error. Now ignored. Note: Arguments are ignored. \*---------------------------------------------------------------------*/ int ProTestBatchAnimation( void* p_dummy, int int_dummy ) { ProError status; ProAnimMovie animation_movie; int i_frame; ProAnimFrame *anim_frames; int anim_frm_num; int i; /* Check animation frames */ if( n_frames < 1 ) { ProUtilMsgPrint( "gen", "TEST %0s", "First, create an animation" ); return -1; } /* Check the number of the objects to be abimated */ if( n_objects < 1 ) { ProUtilMsgPrint( "gen", "TEST %0s", "First, add objects to animate" ); return -1; } /* Create an animation movie */ status = ProAnimmovieCreate( ani_obj_seq[0].model, &animation_movie ); TEST_CALL_REPORT( "ProAnimmovieCreate()", "ProTestBatchAnimation()", status, status != PRO_TK_NO_ERROR ); if( status != PRO_TK_NO_ERROR ) return -1; /* Add frames to the movie */ for( i_frame=0; i_frame<n_frames; i_frame++ ) { status = ProAnimmovieFrameAdd( animation_movie, frames[i_frame] ); TEST_CALL_REPORT( "ProAnimmovieFrameAdd()", "ProTestBatchAnimation()", status, status != PRO_TK_NO_ERROR ); if( status != PRO_TK_NO_ERROR ) return -1; } /* Visit animation frames in the movie */ /* status = ProAnimmovieFrameVisit( animation_movie, (ProAnimFrameAct)ProTestAnimFrameAct, (ProAnimFrameAct)ProTestAnimFrameFilter, NULL ); TEST_CALL_REPORT( "ProAnimmovieFrameVisit()", "ProTestBatchAnimation()", status, status != PRO_TK_NO_ERROR );*/ status = ProUtilCollectAnimFrames (animation_movie, &anim_frames); if (status == PRO_TK_NO_ERROR) { status = ProArraySizeGet ((ProArray)anim_frames, &anim_frm_num); TEST_CALL_REPORT( "ProArraySizeGet()", "ProTestBatchAnimation()", status, status != PRO_TK_NO_ERROR ); for (i = 0; i < anim_frm_num; i++) { status = ProTestAnimFrameAct (anim_frames[i], (ProAppData)NULL); } status = ProArrayFree ((ProArray*)&anim_frames); TEST_CALL_REPORT( "ProArrayFree()", "ProTestBatchAnimation()", status, status != PRO_TK_NO_ERROR ); } /* Allow spinning */ ProAnimmovieSpinflagSet(animation_movie, PRO_B_TRUE); /* Start a batch animation process */ status = ProBatchAnimationStart( animation_movie, (ProBatchAnimAct)ProTestBatchAnimAct, NULL ); TEST_CALL_REPORT( "ProBatchAnimationStart()", "ProTestBatchAnimation()", status, status != PRO_TK_NO_ERROR && status != PRO_TK_GENERAL_ERROR); /* Remove frames from the movie */ for( i_frame=0; i_frame<n_frames; i_frame++ ) { status = ProAnimmovieFrameRemove( animation_movie, frames[i_frame] ); TEST_CALL_REPORT( "ProAnimmovieFrameRemove()", "ProTestBatchAnimation()", status, status != PRO_TK_NO_ERROR ); } /* remove movie */ status = ProAnimmovieDelete( animation_movie ); TEST_CALL_REPORT( "ProAnimmovieDelete()", "ProTestBatchAnimation()", status, status != PRO_TK_NO_ERROR ); if( status != PRO_TK_NO_ERROR ) return -1; return 0; } /*---------------------------------------------------------------------*\ Function: ProUtilSelectedMdlGet() Purpose: Retrieves a handle of the model from the selection object. Returns: PRO_TK_NO_ERROR - The function successfully get the model name. PRO_TK_GENERAL_ERROR - Error. Note: \*---------------------------------------------------------------------*/ ProError ProUtilSelectedMdlGet( ProSelection* p_selection, ProMdl* p_model ) { ProError status; ProModelitem model_item; /* Check out the input parameters */ if( !p_selection || !p_model ) return PRO_TK_GENERAL_ERROR; /* Get the model item from a selection object. */ status = ProSelectionModelitemGet( *p_selection, &model_item ); TEST_CALL_REPORT( "ProSelectionModelitemGet()", "ProUtilSelectedMdlGet()", status, status != PRO_TK_NO_ERROR ); if( status == PRO_TK_NO_ERROR ) { /* Retrieve the model the owns the specified item. */ status = ProModelitemMdlGet( &model_item, p_model ); TEST_CALL_REPORT( "ProModelitemMdlGet()", "ProUtilSelectedMdlGet()", status, status != PRO_TK_NO_ERROR ); if( status == PRO_TK_NO_ERROR ) return PRO_TK_NO_ERROR; } return PRO_TK_GENERAL_ERROR; } /*---------------------------------------------------------------------*\ Function: ProUtilMdlEqual() Purpose: Compares two models. Returns: PRO_B_TRUE - The models are equal. PRO_B_FALSE - The models are different. Note: Here I compare models names, types and ids although possibly it's enough to use only the types and ids. \*---------------------------------------------------------------------*/ ProBoolean ProUtilMdlEqual( ProMdl model1, ProMdl model2 ) { ProError status; ProMdlName name1; ProMdlName name2; ProType type1; ProType type2; int id1; int id2; /* Get and compare types of the models. */ status = ProMdlTypeGet( model1, (ProMdlType *)&type1 ); TEST_CALL_REPORT( "ProMdlTypeGet()", "ProUtilMdlEqual()", status, status != PRO_TK_NO_ERROR ); status = ProMdlTypeGet( model2, (ProMdlType *)&type2 ); TEST_CALL_REPORT( "ProMdlTypeGet()", "ProUtilMdlEqual()", status, status != PRO_TK_NO_ERROR ); if( type1 != type2 ) return PRO_B_FALSE; /* Get and compare ids of the models. */ status = ProMdlIdGet( model1, &id1 ); TEST_CALL_REPORT( "ProMdlIdGet()", "ProUtilMdlEqual()", status, status != PRO_TK_NO_ERROR ); status = ProMdlIdGet( model2, &id2 ); TEST_CALL_REPORT( "ProMdlIdGet()", "ProUtilMdlEqual()", status, status != PRO_TK_NO_ERROR ); if( id1 != id2 ) return PRO_B_FALSE; /* Get and compare names of the models. */ status = ProMdlMdlnameGet( model1, name1 ); TEST_CALL_REPORT( "ProMdlMdlnameGet()", "ProUtilMdlEqual()", status, status != PRO_TK_NO_ERROR ); status = ProMdlMdlnameGet( model2, name2 ); TEST_CALL_REPORT( "ProMdlMdlnameGet()", "ProUtilMdlEqual()", status, status != PRO_TK_NO_ERROR ); if( ProUtilWstrCmp( name1, name2 ) != 0 ) return PRO_B_FALSE; return PRO_B_TRUE; } /*---------------------------------------------------------------------*\ Function: ProUtilAsmcomppathEqual() Purpose: Compares two component pathes. Returns: PRO_B_TRUE - The pathes are equal. PRO_B_FALSE - The pathes are different. Note: \*---------------------------------------------------------------------*/ ProBoolean ProUtilAsmcomppathEqual( ProAsmcomppath path1, ProAsmcomppath path2 ) { int i; /* Compare owners handles and number of the component ids */ if( (path1.owner != path2.owner) || (path1.table_num != path2.table_num) ) return PRO_B_FALSE; /* Compare path ids */ for( i=0; i<path1.table_num; i++ ) if( path1.comp_id_table[i] != path2.comp_id_table[i] ) return PRO_B_FALSE; return PRO_B_TRUE; } /*---------------------------------------------------------------------*\ Function: ProUtilAniObjectSelect() Purpose: Select an animation object. Returns: If the element is successfuly selected and found in the array index is returned. PRO_TK_E_NOT_FOUND - The selected element is not an animation object. PRO_TK_USER_ABORT - Selection was interrupted by a user. Note: When I used ProSelection* p_selection calling ProSelect with &p_selection... \*---------------------------------------------------------------------*/ ProError ProUtilAniObjectSelect( char option[], /* (In) The selection filter. */ ProSelection** p_selection, /* (Out) The pointer to selected item */ AniObjectInstance* p_ani_object ) /* (Out) Animation object to initialize. Can be NULL */ { ProError status; int n_selected = 0; /* Actual number of sections made. */ AniObjectInstance ani_object; /* Check arguments */ if( !p_selection ) return PRO_TK_USER_ABORT; ProUtilMsgPrint( "gen", "TEST %0s", "Select an object" ); /* Select ONE object. */ status = ProSelect( option, 1, NULL, NULL, NULL, NULL, p_selection, &n_selected ); TEST_CALL_REPORT( "ProSelect()", "ProUtilAniObjectSelect()", status, status != PRO_TK_NO_ERROR ); if( (status != PRO_TK_NO_ERROR) || (n_selected != 1) ) return PRO_TK_USER_ABORT; if( p_ani_object == NULL ) p_ani_object = &ani_object; /* Use ProSelection data to init the animation object */ if( ProUtilAniObjectInstanceInit( p_selection, p_ani_object ) != PRO_TK_NO_ERROR ) return PRO_TK_USER_ABORT; /* Try to find out the selected object among array of the animation objects */ return (ProError) ProUtilAniObjectFind( ani_obj_seq, *p_ani_object ); } /*---------------------------------------------------------------------*\ Function: ProUtilAniObjectFind() Purpose: Find specified animation object (AniObjectInstance) in the array. Returns: Note: Animation objects are compared using ProMdl data and ProAsmcomppath data. Animation object handles (ProAnimObj) are not used. \*---------------------------------------------------------------------*/ int ProUtilAniObjectFind( ProArray array, /* (In) An array of the animation objects */ AniObjectInstance ani_object ) /* (In) The animation objects to looking for */ { ProError status; int n_ani_objects = 0; /* Variable to get the size of the array of the animation objects */ int i; /* Get the current size of the array. */ status = ProArraySizeGet( array, &n_ani_objects ); TEST_CALL_REPORT( "ProArraySizeGet()", "ProUtilAniObjectFind()", status, status != PRO_TK_NO_ERROR ); if( status != PRO_TK_NO_ERROR ) return PRO_TK_E_NOT_FOUND; /* Try to find out the name of the selected object among array of the animation objects */ for( i=0; i<n_ani_objects; i++ ) if( (ProUtilMdlEqual( ((AniObjectInstance*)array)[i].model, ani_object.model ) == PRO_B_TRUE ) && (ProUtilAsmcomppathEqual( ((AniObjectInstance*)array)[i].comp_path, ani_object.comp_path ) == PRO_B_TRUE ) ) return i; /* The specified object is not found */ return PRO_TK_E_NOT_FOUND; } /*---------------------------------------------------------------------*\ Function: ProUtilAniObjectInstanceInit() Purpose: Initialize the AniObjectInstance structure using ProSelection object. Returns: PRO_TK_NO_ERROR - success; PRO_TK_GENERAL_ERROR - error Note: \*---------------------------------------------------------------------*/ ProError ProUtilAniObjectInstanceInit( ProSelection** p_selection, /* (In) The pointer to selected item */ AniObjectInstance* p_ani_object ) /* (Out) Animation object to init */ { ProError status; /* Get a model from the selection */ if( ProUtilSelectedMdlGet( *p_selection, &(p_ani_object->model) ) != PRO_TK_NO_ERROR ) return PRO_TK_GENERAL_ERROR; /* Get a component path of the model */ status = ProSelectionAsmcomppathGet( **p_selection, &(p_ani_object->comp_path) ); TEST_CALL_REPORT( "ProSelectionAsmcomppathGet()", "ProUtilAniObjectInstanceInit()", status, status != PRO_TK_NO_ERROR ); if( status != PRO_TK_NO_ERROR ) return PRO_TK_GENERAL_ERROR; return PRO_TK_NO_ERROR; } /*---------------------------------------------------------------------*\ Function: ProUtilRotX() Purpose: Add x rotation values to the transformation matrix. Returns: None Note: Only the rotation components of the matrix are modified. \*---------------------------------------------------------------------*/ void ProUtilRotX( double angle, /* (In) The rotation angle */ ProMatrix mx ) /* (Out) The transformation matrix */ { mx[0][0] = 1.0; mx[0][1] = mx[0][2] = mx[1][0] = mx[2][0] = 0.0; mx[1][1] = mx[2][2] = cos( angle * PI / 180.0); mx[1][2] = sin( angle * PI / 180.0); mx[2][1] = - mx[1][2]; }