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



/*

This code creates display object on selected surface or curve.

To create display object on surface click on:
TkPart/TkAsm->DisplayObj->Surface
Select surface

To create display object on curve click on:
TkPart/TkAsm->DisplayObj->Curve
Select Curve 
(it will create display object along selected curve and will streach it 
 normal to curve plane by the distance which will be half of curve length).
 
Currently display object API (from ProDispObject.h file) are supported in DLL
mode only. So this file is used to build pt_examples.dll only.

This code supports only two display objects at a time (one on surface and 
 one on curve).

*/


#include "ProToolkit.h"
#include "ProMdl.h"
#include "ProMenu.h"
#include "ProUtil.h"
#include "ProColor.h"
#include "ProGraphic.h"
#include "ProDispObject.h"
#include "ProArray.h"
#include "ProAsmcomp.h"
#include "ProCsys.h"
#include "ProTKRunTime.h"
#include "ProUIMessage.h"
#include "TestError.h"
#include "UtilString.h"

ProDispObject surfDisp_obj = NULL;
ProDispObject curveDisp_obj = NULL;
int *dispobj_keylist1 = NULL, *dispobj_keylist2 = NULL;

int	 ProDispObjectSelectEntitySet( ProType*, ProType );


//    Purpose:	On-button function.  Defines DispObject menu buttons.
int ProTestDispObjectSetMenu( )
{
    ProError		status;
    int			menu_id;
    int			action;
    int			selectionType;
	ProUIMessageButton* buttons;
	ProUIMessageButton result;

    /* Load base menu from file */
    status = ProMenuFileRegister((char*) "DispObject",(char*) "tkdispobject.mnu", &menu_id );
    TEST_CALL_REPORT( "ProMenuFileRegister()", "ProTestEntityDrawMenu()", 
			status, status != PRO_TK_NO_ERROR );

    /* Define menu buttons */
    ProMenubuttonActionSet((char*) "DispObject",(char*) "Surface", 
	(ProMenubuttonAction)ProDispObjectSelectEntitySet, &selectionType, PRO_SURFACE );
    
	ProMenubuttonActionSet((char*) "DispObject",(char*) "Curve",	
	(ProMenubuttonAction)ProDispObjectSelectEntitySet, &selectionType, PRO_CURVE );

    ProMenubuttonActionSet((char*) "DispObject",(char*)"DispObject", 
	(ProMenubuttonAction)ProMenuDelete, NULL, 0 );

    status = ProMenuCreate( PROMENUTYPE_MAIN,(char*) "DispObject", &menu_id );
    TEST_CALL_REPORT( "ProMenuCreate()", "ProTestEntityDrawMenu()", 
			status, status != PRO_TK_NO_ERROR );

    if( status == PRO_TK_NO_ERROR )
    {
		status = ProMenuProcess((char*) "DispObject", &action );
		TEST_CALL_REPORT( "ProMenuProcess()", "ProTestEntityDrawMenu()", 
					status, status != PRO_TK_NO_ERROR );
    }

    return 0;
}


// Creates display object on selected curve
ProError PTTestDispObjectCurve()
{
   ProError status = PRO_TK_NO_ERROR;
   ProMdl model = NULL;
   ProMatrix 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}};
	float normal[3] = {  0.0,   0.0, 1.0};
	int *strip_size;
	ProTriVertex **strip_arr = NULL;
	ProTriVertex *strip = NULL;
	ProSelection *p_sel;
	int i = -1, n_sel = -1, count_pnt = -1, j, offsetVal = 1;
	ProMdl owner;
	ProModelitem modelitem;
	ProCurve curve;
	Pro3dPnt *p_points;
	ProSurfaceAppearanceProps surf_appear;
	ProTriVertex tempTriVertex;
	float x_offset = 0.0, y_offset = 0.0, z_offset = 0.0;
	double curveLen = 0.0, tolerance = 0.0;
	ProMdlType topMdlType;
	ProAsmcomppath pCompPath;
	int *cIdTablel, feat_id = 117;
	ProBoolean isCompPath = PRO_B_FALSE;
	ProModelitem sAsmComp;
	int disobj_winId;
	ProUIMessageButton* buttons;
	ProUIMessageButton result = PRO_UI_MESSAGE_NO;

	if(curveDisp_obj != NULL) // If Display object exist then ask user to keep it or replace witn new one
	{
		ProArrayAlloc (2, sizeof (ProUIMessageButton), 1, (ProArray*)&buttons);
		buttons[0] = PRO_UI_MESSAGE_YES;
		buttons[1] = PRO_UI_MESSAGE_NO;

		status = ProUIMessageDialogDisplay (PROUIMESSAGE_QUESTION, L"Delete existing curve display object",
									L"Code creates only one curve display object at a time. Do you want to delete existing curve display object?", 
									buttons, buttons[1], &result);
		TEST_CALL_REPORT ("ProUIMessageDialogDisplay", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );

		status = ProArrayFree( (ProArray *)&buttons);
		TEST_CALL_REPORT("ProArrayFree", "PTTestDispObjectCurve()", 
			status, status!=PRO_TK_NO_ERROR );

		if(result == PRO_UI_MESSAGE_NO)
			return (PRO_TK_NO_ERROR);
	}

	//Select curve to created display object
	status = ProSelect ((char*)"curve", 1, NULL, NULL, NULL, NULL, &p_sel,
        &n_sel);
    TEST_CALL_REPORT ("ProSelect", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );

	if(status != PRO_TK_NO_ERROR || n_sel <1)
		return status;
		
    status = ProSelectionModelitemGet (p_sel[0], &modelitem);
    TEST_CALL_REPORT ("ProSelectionModelitemGet", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );

	status = ProModelitemMdlGet (&modelitem, &owner);
	TEST_CALL_REPORT ("ProModelitemMdlGet", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );

	status = ProCurveInit ((ProSolid)owner, modelitem.id, &curve);
	TEST_CALL_REPORT ("ProCurveInit", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );

	status = ProCurveLengthEval(curve, &curveLen);
	TEST_CALL_REPORT("ProCurveLengthEval", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );
	offsetVal = curveLen/2;

	// If curve length is small (less than 10), then maximum distance between 
	// the tessellation is reduced otherwise it will be 1.0 
	if (offsetVal < 5)
		tolerance = offsetVal/10.0;
	else
		tolerance = 1.0;

	status = ProCurveTessellationGet (curve, tolerance, &p_points, &count_pnt);
	TEST_CALL_REPORT ("ProCurveTessellationGet", "PTTestDispObjectCurve()", 
				status, status!=PRO_TK_NO_ERROR );

	// Memory allocation for strip arrays
	status = ProArrayAlloc( 1, sizeof(ProTriVertex *), 1, (ProArray *)&strip_arr);
	TEST_CALL_REPORT("ProArrayAlloc", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );
   
	// Memory allocation for first strip array
	status = ProArrayAlloc( 0, sizeof(ProTriVertex), 1, (ProArray *)&(strip_arr[0]));
	TEST_CALL_REPORT("ProArrayAlloc", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );

   // Memory allocation for strip size
	status = ProArrayAlloc( 1, sizeof(int), 1, (ProArray *)&strip_size);
	TEST_CALL_REPORT("ProArrayAlloc", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );

	// checking for curve plane
   	if(count_pnt < 3)
	{
		if(p_points[0][2] == p_points[1][2])
			z_offset = offsetVal;

		else if(p_points[0][1] == p_points[1][1])
			y_offset = offsetVal;
	
		else if(p_points[0][0] == p_points[1][0])
			x_offset = offsetVal;
		
		else
			z_offset = offsetVal;
	}

	else if(count_pnt>=3)
	{
		// Checking Z coord of 3 points (of 1st, middle and last point on curve)
		if((p_points[0][2] == p_points[count_pnt/2][2]) && (p_points[0][2] == p_points[count_pnt-1][2]))
			z_offset = offsetVal;

		// Checking z coord of Y points (of 1st, middle and last point on curve)
		else if((p_points[0][1] == p_points[count_pnt/2][1]) && (p_points[0][1] == p_points[count_pnt-1][1]))
			y_offset = offsetVal;
	
		// Checking X coord of 3 points (of 1st, middle and last point on curve)
		else if((p_points[0][0] == p_points[count_pnt/2][0]) && (p_points[0][0] == p_points[count_pnt-1][0]))
			x_offset = offsetVal;

		else
			z_offset = offsetVal;
	}

	for (i = 0; i <count_pnt; i++ )
	{
			tempTriVertex.pnt[0] = p_points[i][0];
			tempTriVertex.pnt[1] = p_points[i][1];
			tempTriVertex.pnt[2] = p_points[i][2];

			tempTriVertex.norm[0] = 0.0;
			tempTriVertex.norm[1] = 0.0;
			tempTriVertex.norm[2] = 1.0;

			// Adding curve point for dispobj
			status = ProArrayObjectAdd ((ProArray*)&(strip_arr[0]), PRO_VALUE_UNUSED, 1, &tempTriVertex);
			TEST_CALL_REPORT("ProArrayObjectAdd", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );

			// Following code is taking offset curve points at offsetVal distance which is 
			// in normal direction to curve plane
			tempTriVertex.pnt[0] = p_points[i][0] + x_offset;
			tempTriVertex.pnt[1] = p_points[i][1] + y_offset;
			tempTriVertex.pnt[2] = p_points[i][2] + z_offset;

			// Adding offset curve point for dispobj
			status = ProArrayObjectAdd ((ProArray*)&(strip_arr[0]), PRO_VALUE_UNUSED, 1, &tempTriVertex);
			TEST_CALL_REPORT("ProArrayObjectAdd", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );
	}

	strip_size[0] = count_pnt*2;

	status = ProMdlCurrentGet(&model);
	TEST_CALL_REPORT("ProMdlCurrentGet", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );
   
	disobj_winId = 0;
	status = ProMdlWindowGet(model, &disobj_winId);
	TEST_CALL_REPORT("ProMdlWindowGet", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );

	if(result == PRO_UI_MESSAGE_YES)  // Delete existing display object
	{
		status = ProDispObjectDetach( disobj_winId, dispobj_keylist1);
		TEST_CALL_REPORT("ProDispObjectDetach", "PTTestDispObjectCurve()", 
			status, status!=PRO_TK_NO_ERROR );

		status =  ProDispObjectDelete( &curveDisp_obj );
		TEST_CALL_REPORT("ProDispObjectDelete", "PTTestDispObjectCurve()", 
			status, status!=PRO_TK_NO_ERROR );

		status = ProArrayFree( (ProArray *)&dispobj_keylist1);
		TEST_CALL_REPORT("ProArrayFree", "PTTestDispObjectSurf()", 
							status, status!=PRO_TK_NO_ERROR );

		curveDisp_obj = NULL;
	}

	status = ProDispObjectCreate(L"test_curvedisp_obj", PRO_DISP_OBJECT_TWO_SIDED, 
						1, strip_size, strip_arr, &curveDisp_obj);
	TEST_CALL_REPORT("ProDispObjectCreate", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );

	// Setting appearance porperties for display object
	surf_appear.ambient = 0.5;
	surf_appear.shininess = 0.2;
	surf_appear.highlite = 0.1;
	surf_appear.color_rgb[0] = 0.0;
	surf_appear.color_rgb[1] = 0.0;
	surf_appear.color_rgb[2] = 1.0;
	surf_appear.transparency = 0.3;
	surf_appear.diffuse = 0.80;
	surf_appear.highlight_color[0] = 0.10;
	surf_appear.highlight_color[1] = 0.20;
	surf_appear.highlight_color[2] = 0.60;
	surf_appear.reflection = 0.000000;

	status = ProMdlTypeGet(model, &topMdlType);
	TEST_CALL_REPORT("ProMdlTypeGet", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );

	// For top model assembly, checking for selected entities component path
	if(topMdlType == PRO_MDL_ASSEMBLY)
	{
		status = ProSelectionAsmcomppathGet(p_sel[0], &pCompPath);
		TEST_CALL_REPORT("ProSelectionAsmcomppathGet", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );

		if (pCompPath.table_num> 0)
		{
			int arrayCount;

			sAsmComp.type = PRO_FEATURE;
			sAsmComp.id = pCompPath.comp_id_table[pCompPath.table_num-1];
			sAsmComp.owner = owner;

			status = ProArrayAlloc (0, sizeof (int), 1, (ProArray*)&cIdTablel);
			TEST_CALL_REPORT("ProArrayAlloc", "PTTestDispObjectCurve()", 
						status, status!=PRO_TK_NO_ERROR );

			for(arrayCount = 0; arrayCount < pCompPath.table_num; arrayCount++)
			{
				status = ProArrayObjectAdd ((ProArray*)&cIdTablel, 
					PRO_VALUE_UNUSED, 1, &pCompPath.comp_id_table[arrayCount]);
				TEST_CALL_REPORT("ProArrayObjectAdd", "PTTestDispObjectCurve()", 
							status, status!=PRO_TK_NO_ERROR );
			}
			isCompPath = PRO_B_TRUE;
		}
		else
			isCompPath = PRO_B_FALSE;
	}

   if(status == PRO_TK_NO_ERROR)
   {
	   // Attach display object 
      status = ProDispObjectAttach((int)disobj_winId, curveDisp_obj, (isCompPath == PRO_B_TRUE?cIdTablel:NULL), feat_id, transform);
	  TEST_CALL_REPORT("ProDispObjectAttach", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );
  
      surf_appear.color_rgb[0] = 0.0;
      surf_appear.color_rgb[1] = 0.0;
      surf_appear.color_rgb[2] = 1.0;

	status = ProArrayAlloc( 0, sizeof(int), 1, (ProArray *)&dispobj_keylist1);
	TEST_CALL_REPORT("ProArrayAlloc", "PTTestDispObjectCurve()", 
	                 status, status!=PRO_TK_NO_ERROR );

	  if(isCompPath == PRO_B_TRUE)
	  {
		  int arrayCount = -1, ii = -1;

			status = ProArraySizeGet (cIdTablel, &arrayCount);
    		TEST_CALL_REPORT ("ProArraySizeGet()", "PTTestDispObjectCurve()", 
						status, status!=PRO_TK_NO_ERROR );

			for(ii = 0; ii < arrayCount; ii++)
			{
				status = ProArrayObjectAdd ((ProArray*)&dispobj_keylist1, 
						                    PRO_VALUE_UNUSED, 1, &cIdTablel[ii]);
				TEST_CALL_REPORT("ProArrayObjectAdd", "PTTestDispObjectCurve()", 
								  status, status!=PRO_TK_NO_ERROR );
			}
	  }

	  status = ProArrayObjectAdd ((ProArray*)&dispobj_keylist1, 
					PRO_VALUE_UNUSED, 1, &feat_id);
				TEST_CALL_REPORT("ProArrayObjectAdd", "PTTestDispObjectCurve()", 
							status, status!=PRO_TK_NO_ERROR );

	  // Set appearance properties to display object 
      status = ProDispObjectSetSurfaceAppearanceProps( (int)disobj_winId, dispobj_keylist1,surf_appear);
	  TEST_CALL_REPORT("ProDispObjectSetSurfaceAppearanceProps", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );
   }

	/* Call repaint */
	status = ProWindowRepaint( disobj_winId );
	TEST_CALL_REPORT("ProWindowRepaint", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );

	status = ProArrayFree( (ProArray *)&(strip_arr[0]));
	TEST_CALL_REPORT("ProArrayFree", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );

	status = ProArrayFree( (ProArray *)&strip_arr);
	TEST_CALL_REPORT("ProArrayFree", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );
   
	status = ProArrayFree( (ProArray *)&strip_size);
	TEST_CALL_REPORT("ProArrayFree", "PTTestDispObjectCurve()", 
					status, status!=PRO_TK_NO_ERROR );
   
	if(isCompPath == PRO_B_TRUE)
	{
		status = ProArrayFree( (ProArray *)&cIdTablel);
		TEST_CALL_REPORT("ProArrayFree", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
	}

	return status;
}


// Function to create display object on selected surface
ProError PTTestDispObjectSurf()
{
   ProError status = PRO_TK_NO_ERROR;
   ProMdl model = NULL;
   ProMatrix 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}};
	float spiralSurfPtsRem, normal[3] = {  0.0,   0.0, 1.0};
	int *strip_size, spiralSurfPts, reminderVal, facetCount;
	ProTriVertex **strip_arr = NULL;
	ProSurfaceAppearanceProps surf_appear;
	ProMatrix CompMatrix;
	ProSelection *p_sel;
	int i = -1, n_sel = -1, j;
	ProMdl owner;
	ProModelitem modelitem;
	ProCurve curve;
	Pro3dPnt *p_points;
	ProSurface pSurface;
	ProTessellation surfTessellation;
	Pro3dPnt* surfVertices;
	ProVector* surfNormals;
	ProSurfaceTessellationInput inputData;
	ProTriVertex tempTriVertex;
	ProTriangle* pFacets;
	ProMdlType topMdlType;
	ProAsmcomppath pCompPath;
	int *cIdTablel;
	ProBoolean isCompPath = PRO_B_FALSE;
	ProModelitem sAsmComp;
	ProCsys csys;
	ProGeomitemdata* pCsysDataPtr;
	int disobj_winId;
	ProUIMessageButton* buttons2;
	int feat_id = 118;
	ProUIMessageButton result = PRO_UI_MESSAGE_NO;

	if(surfDisp_obj != NULL) // If Display object exist then ask user to keep it or replace witn new one
	{
		ProArrayAlloc (2, sizeof (ProUIMessageButton), 1, (ProArray*)&buttons2);
		buttons2[0] = PRO_UI_MESSAGE_YES;
		buttons2[1] = PRO_UI_MESSAGE_NO;

		status = ProUIMessageDialogDisplay (PROUIMESSAGE_QUESTION, L"Delete existing surface display object",
									L"Code creates only one surface display object at a time. Do you want to delete existing surface display object?", 
									buttons2, buttons2[1], &result);
		TEST_CALL_REPORT ("ProUIMessageDialogDisplay", "PTTestDispObjectSurf()", 
					status, status!=PRO_TK_NO_ERROR);

		status = ProArrayFree( (ProArray *)&buttons2);
		TEST_CALL_REPORT("ProArrayFree", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );

		if(result == PRO_UI_MESSAGE_NO)
			return (PRO_TK_NO_ERROR);
	}

	//Select surface to created display object
	status = ProSelect ((char*)"surface", 1, NULL, NULL, NULL, NULL, &p_sel,
        &n_sel);
    TEST_CALL_REPORT ("ProSelect", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );

	if(status != PRO_TK_NO_ERROR || n_sel <1)
		return status;
		
    status = ProSelectionModelitemGet (p_sel[0], &modelitem);
    TEST_CALL_REPORT ("ProSelectionModelitemGet", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );

	status = ProModelitemMdlGet (&modelitem, &owner);
    TEST_CALL_REPORT ("ProModelitemMdlGet", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
    	
	if(modelitem.type == PRO_SURFACE )
	{
		status = ProSurfaceInit((ProSolid)owner, modelitem.id, &pSurface);
		TEST_CALL_REPORT ("ProSurfaceInit", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
		
		status = ProSurfacetessellationinputAlloc (&inputData);
    	TEST_CALL_REPORT("ProSurfacetessellationinputAlloc", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );

		status = ProSurfacetessellationinputChordheightSet (inputData, PRO_SRFTESS_CHORD_HT_DEFAULT);
    	TEST_CALL_REPORT("ProSurfacetessellationinputChordheightSet", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );

		status = ProSurfacetessellationinputAnglecontrolSet (inputData, 1);
    	TEST_CALL_REPORT("ProSurfacetessellationinputAnglecontrolSet", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
		
		status = ProSurfacetessellationinputStepsizeSet (inputData, 1);
    	TEST_CALL_REPORT("ProSurfacetessellationinputStepsizeSet", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );

			status = ProSurfacetessellationinputUvprojectionSet(inputData, PRO_SRFTESS_DEFAULT_PROJECTION, NULL);
			TEST_CALL_REPORT("ProSurfacetessellationinputUvprojectionSet", "PTTestDispObjectSurf()", 
				status, status!=PRO_TK_NO_ERROR );

		// Getting surface tessellation data
		status = ProSurfaceTessellationGet(pSurface, inputData, &surfTessellation);
		TEST_CALL_REPORT ("ProSurfaceTessellationGet", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
		
		status = ProTessellationVerticesGet(surfTessellation, &surfVertices);
		TEST_CALL_REPORT ("ProTessellationVerticesGet", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
		
		status = ProTessellationNormalsGet(surfTessellation, &surfNormals);
		TEST_CALL_REPORT ("ProTessellationNormalsGet", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
		
		// Getting facets from surface tessellation
		status = ProTessellationFacetsGet(surfTessellation, &pFacets);
		TEST_CALL_REPORT ("ProTessellationNormalsGet", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
		
		status = ProArraySizeGet (pFacets, &facetCount);
    	TEST_CALL_REPORT ("ProArraySizeGet()", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
	}
	else
		return PRO_TK_BAD_INPUTS;

   status = ProArrayAlloc( facetCount, sizeof(ProTriVertex *), 1, (ProArray *)&strip_arr);
   TEST_CALL_REPORT("ProArrayAlloc", "PTTestDispObjectSurf()", 
						status, status!=PRO_TK_NO_ERROR );

   // Each facet is added as a seperate strip so, number of strip arrays (ie strips)
   // is equal to number of facets
   for (i = 0; i < facetCount; i++)
   {
   	   status = ProArrayAlloc( 0, sizeof(ProTriVertex), 1, (ProArray *)&(strip_arr[i]));
	   TEST_CALL_REPORT("ProArrayAlloc", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
   }
   
   status = ProArrayAlloc( facetCount, sizeof(int), 1, (ProArray *)&strip_size);
   TEST_CALL_REPORT("ProArrayAlloc", "PTTestDispObjectSurf()", 
						status, status!=PRO_TK_NO_ERROR );

   for (i = 0; i <facetCount; i++ )
   {
		strip_size[i] = 3;

		for (j = 0; j <3; j++)
		{
			tempTriVertex.pnt[0] = surfVertices[ pFacets[i][j]][0];
			tempTriVertex.pnt[1] = surfVertices[ pFacets[i][j]][1];
			tempTriVertex.pnt[2] = surfVertices[ pFacets[i][j]][2];

			tempTriVertex.norm[0] = surfNormals[ pFacets[i][j]][0];
			tempTriVertex.norm[1] = surfNormals[ pFacets[i][j]][1];
			tempTriVertex.norm[2] = surfNormals[ pFacets[i][j]][2];

			status = ProArrayObjectAdd ((ProArray*)&(strip_arr[i]), PRO_VALUE_UNUSED, 1, &tempTriVertex);
			TEST_CALL_REPORT("ProArrayObjectAdd", "PTTestDispObjectSurf()", 
								status, status!=PRO_TK_NO_ERROR );
		}
	}		

   status = ProMdlCurrentGet(&model);
   TEST_CALL_REPORT("ProMdlCurrentGet", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
   if(status != PRO_TK_NO_ERROR)
      return status;

   disobj_winId = 0;
   status = ProMdlWindowGet(model, &disobj_winId);
   TEST_CALL_REPORT("ProMdlWindowGet", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );

   if(result == PRO_UI_MESSAGE_YES)  // Deletes existing display object
	{
		status = ProDispObjectDetach( disobj_winId, dispobj_keylist2);
		TEST_CALL_REPORT("ProDispObjectDetach", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );

		status =  ProDispObjectDelete( &surfDisp_obj );
		TEST_CALL_REPORT("ProDispObjectDelete", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );

		status = ProArrayFree( (ProArray *)&dispobj_keylist2);
		TEST_CALL_REPORT("ProArrayFree", "PTTestDispObjectSurf()", 
							status, status!=PRO_TK_NO_ERROR );

		surfDisp_obj = NULL;
	}

   // Creates new display object
    status = ProDispObjectCreate(L"test_disp_obj", PRO_DISP_OBJECT_TWO_SIDED, facetCount, strip_size,
                       strip_arr, &surfDisp_obj);
	TEST_CALL_REPORT("ProDispObjectCreate", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );

   // setting appearance porperties for display object
   surf_appear.ambient = 0.5;
   surf_appear.shininess = 0.2;
   surf_appear.highlite = 0.1;
   surf_appear.color_rgb[0] = 0.0;
   surf_appear.color_rgb[1] = 0.0;
   surf_appear.color_rgb[2] = 1.0;
   surf_appear.transparency = 0.5;
   surf_appear.diffuse = 0.80;
   surf_appear.highlight_color[0] = 0.10;
   surf_appear.highlight_color[1] = 0.20;
   surf_appear.highlight_color[2] = 0.60;
   surf_appear.reflection = 0.000000;

   if(status == PRO_TK_NO_ERROR)
   {
		status = ProMdlTypeGet(model, &topMdlType);
		TEST_CALL_REPORT("ProMdlTypeGet", "PTTestDispObjectSurf()", 
						status, status!=PRO_TK_NO_ERROR );

		if(topMdlType == PRO_MDL_ASSEMBLY)
		{
			// Getting component path
			status = ProSelectionAsmcomppathGet(p_sel[0], &pCompPath);
			TEST_CALL_REPORT("ProSelectionAsmcomppathGet", "PTTestDispObjectSurf()", 
						status, status!=PRO_TK_NO_ERROR );

			if (pCompPath.table_num> 0)
			{
				int arrayCount;

				sAsmComp.type = PRO_FEATURE;
				sAsmComp.id = pCompPath.comp_id_table[pCompPath.table_num-1];
				sAsmComp.owner = owner;

				status = ProArrayAlloc (0, sizeof (int), 1, (ProArray*)&cIdTablel);
				TEST_CALL_REPORT("ProArrayAlloc", "PTTestDispObjectSurf()", 
							status, status!=PRO_TK_NO_ERROR );

				// Getting component ID table
				for(arrayCount = 0; arrayCount < pCompPath.table_num; arrayCount++)
				{
					status = ProArrayObjectAdd ((ProArray*)&cIdTablel, 
						PRO_VALUE_UNUSED, 1, &pCompPath.comp_id_table[arrayCount]);
					TEST_CALL_REPORT("ProArrayObjectAdd", "PTTestDispObjectSurf()", 
								status, status!=PRO_TK_NO_ERROR );
				}
				isCompPath = PRO_B_TRUE;
			}
			else
				isCompPath = PRO_B_FALSE;
		}

	  // Attaching display object
      status = ProDispObjectAttach((int)disobj_winId, surfDisp_obj, (isCompPath == PRO_B_TRUE?cIdTablel:NULL), feat_id, transform);
	  TEST_CALL_REPORT("ProDispObjectAttach", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
	  
      surf_appear.color_rgb[0] = 0.0;
      surf_appear.color_rgb[1] = 0.0;
      surf_appear.color_rgb[2] = 1.0;

	  status = ProArrayAlloc( 0, sizeof(int), 1, (ProArray *)&dispobj_keylist2);
	  TEST_CALL_REPORT("ProArrayAlloc", "PTTestDispObjectSurf()", 
						status, status!=PRO_TK_NO_ERROR );

	  if(isCompPath == PRO_B_TRUE)
	  {
		  int arrayCount = -1, ii = -1;

			status = ProArraySizeGet (cIdTablel, &arrayCount);
    		TEST_CALL_REPORT ("ProArraySizeGet()", "PTTestDispObjectSurf()", 
						status, status!=PRO_TK_NO_ERROR );

			for(ii = 0; ii < arrayCount; ii++)
			{
				status = ProArrayObjectAdd ((ProArray*)&dispobj_keylist2, 
						                    PRO_VALUE_UNUSED, 1, &cIdTablel[ii]);
				TEST_CALL_REPORT("ProArrayObjectAdd", "PTTestDispObjectSurf()", 
								  status, status!=PRO_TK_NO_ERROR );
			}
	  }

	  status = ProArrayObjectAdd ((ProArray*)&dispobj_keylist2, 
					PRO_VALUE_UNUSED, 1, &feat_id);
				TEST_CALL_REPORT("ProArrayObjectAdd", "PTTestDispObjectSurf()", 
							status, status!=PRO_TK_NO_ERROR );

	  // Setting appearance properties on display object
      status = ProDispObjectSetSurfaceAppearanceProps( (int)disobj_winId, dispobj_keylist2, surf_appear);
	  TEST_CALL_REPORT("ProDispObjectSetSurfaceAppearanceProps", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
   }

   // Call repaint 
   status = ProWindowRepaint( disobj_winId);
   TEST_CALL_REPORT("ProWindowRepaint", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
 
    for(i =0; i < facetCount; i++)
   {
	   for (j= 0; j<3; j++)
	   {
			status = ProArrayFree( (ProArray *)&(strip_arr[i]));
			TEST_CALL_REPORT("ProArrayFree", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
		}
   }	

   status = ProArrayFree( (ProArray *)&strip_arr);
   TEST_CALL_REPORT("ProArrayFree", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
   
   status = ProArrayFree( (ProArray *)&strip_size);
   TEST_CALL_REPORT("ProArrayFree", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
   
   if(modelitem.type == PRO_SURFACE)
   {
	   status = ProArrayFree( (ProArray *)&surfVertices);
	   TEST_CALL_REPORT("ProArrayFree", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
	   
	   status = ProArrayFree( (ProArray *)&surfNormals);
	   TEST_CALL_REPORT("ProArrayFree", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
	}

	if(isCompPath == PRO_B_TRUE)
	{
		status = ProArrayFree( (ProArray *)&cIdTablel);
		TEST_CALL_REPORT("ProArrayFree", "PTTestDispObjectSurf()", 
			status, status!=PRO_TK_NO_ERROR );
	}

	return PRO_TK_NO_ERROR;
}


// Creates display object on selected curve/surface
int ProDispObjectSelectEntitySet( ProType* p_disobjSelEntity, ProType disobjSelEntity )
{
    ProError		status;

	// Create display object along selected curve
	if(disobjSelEntity == PRO_CURVE)
	{
		status =  PTTestDispObjectCurve();
		TEST_CALL_REPORT("PTTestDispObjectCurve", "ProDispObjectSelectEntitySet()", 
			status, status!=PRO_TK_NO_ERROR );

	    return 0;
	}

	// Create display object on selected surface
	else if(disobjSelEntity == PRO_SURFACE)
	{
		status =  PTTestDispObjectSurf();
		TEST_CALL_REPORT("PTTestDispObjectSurf", "ProDispObjectSelectEntitySet()", 
			status, status!=PRO_TK_NO_ERROR );

		return 0;
	}

    status = ProMenuDelete();
    TEST_CALL_REPORT( "ProMenuDelete()", "ProDispObjectSelectEntitySet()", 
			status, status!=PRO_TK_NO_ERROR );

    return 0;
}