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


/*------------------------------------------------------------------*\
Pro/Toolkit includes
\*------------------------------------------------------------------*/
#include <ProToolkit.h>
#include <ProObjects.h>
#include <ProFeature.h>
#include <ProDimension.h>
#include <ProAxis.h>
#include <ProUtil.h>
#include <ProSolid.h>
#include <ProMessage.h>
#include <ProAnnotation.h>
/*------------------------------------------------------------------*\
Application includes 
\*------------------------------------------------------------------*/
#include <TestError.h>
#include <UtilMath.h>

typedef struct  
{
  ProVector vector;        /* The direction that the dimension should
			      be parallel to */
  ProBoolean found;        /* Flag signalling if any matching 
			      dimensions were found. */
  ProDimension dim_found;  /* May be used if visiting in an attempt 
			      to locate a certain dimension */
} DimByVector;


/*==================================================================*\
FUNCTION : UserDimensionFilterByVector()
PURPOSE  : Find linear dimensions oriented parallel to vector (a filter 
           action)
\*==================================================================*/
ProError UserDimensionFilterByVector (ProDimension* dim,
				      ProAppData appdata)
{
  ProDimlocation dimloc;
  ProDimensiontype type;  
  ProPoint3d arrow_1, arrow_2;
  int i;
  ProError status;
  ProVector dimvector;
  double dotproduct;
  DimByVector* data = (DimByVector*) appdata;

/*------------------------------------------------------------------*\
    Continue only for linear dimensions
\*------------------------------------------------------------------*/
  ProDimensionTypeGet (dim, &type);
  if (type != PRODIMTYPE_LINEAR)
    return (PRO_TK_CONTINUE);
  
/*------------------------------------------------------------------*\
    Extract the location of the arrows of the dimension
\*------------------------------------------------------------------*/
  status = ProDimensionLocationGet (dim, NULL, NULL, &dimloc);
  if (status != PRO_TK_NO_ERROR)
    return (PRO_TK_CONTINUE);

  ProDimlocationArrowsGet (dimloc, arrow_1, arrow_2);
  ProDimlocationFree (dimloc);

/*------------------------------------------------------------------*\
    Construct, validate, and normalize the dimension direction vector
\*------------------------------------------------------------------*/
  for (i = 0; i < 3; i++)
    dimvector [i] = arrow_2 [i] - arrow_1 [i];

  if (ProUtilVectorLength (dimvector) < EPSM6 )
    return (PRO_TK_CONTINUE);

  ProUtilVectorNormalize (dimvector, dimvector);

/*------------------------------------------------------------------*\
    Check if the angle between the vectors is 0 or 180 degrees
\*------------------------------------------------------------------*/
  dotproduct = ProUtilVectorDot (data->vector, dimvector);

  if (fabs (fabs (dotproduct) - 1.0) < EPSM6 )
    {
      data->found = PRO_B_TRUE;
      return (PRO_TK_NO_ERROR);
    }
  else
    return (PRO_TK_CONTINUE);
}

/*==================================================================*\
FUNCTION : UserDimensionShow()
PURPOSE  : Show the given dimension (a visit action)
\*==================================================================*/
ProError UserDimensionShow (ProDimension* dim, 
			    ProError error_status,
			    ProAppData appdata)
{
  ProAnnotationShow ( (ProAnnotation*)dim, NULL, NULL);

  return (PRO_TK_NO_ERROR);
}

/*==================================================================*\
FUNCTION : UserDimensionsByDirectionShow()
PURPOSE  : Highlight linear dimensions in the feature that are 
           oriented parallel to a given vector.
\*==================================================================*/
ProError UserDimensionsByDirectionShow(ProSolid solid, 
				       ProFeature* feature, 
				       ProVector vector)
{
  DimByVector data;
  ProError status;
  ProFileName msg_file;

  ProStringToWstring(msg_file, "msg_ugfund.txt");

  memcpy (data.vector, vector, sizeof (ProVector));
  data.found = PRO_B_FALSE;

  if (feature != NULL)
    {
/*------------------------------------------------------------------*\
    Visit all feature dimensions.
\*------------------------------------------------------------------*/
      status = ProFeatureDimensionVisit (feature,
					 UserDimensionShow,
					 UserDimensionFilterByVector,
					 (ProAppData)&data);  
    }
  else
    {
/*------------------------------------------------------------------*\
    Visit all model dimensions.
\*------------------------------------------------------------------*/
      status = ProSolidDimensionVisit (solid,
				       PRO_B_FALSE,
				       UserDimensionShow,
				       UserDimensionFilterByVector,
					 &data);  
    }

/*------------------------------------------------------------------*\
   Return based on the success of the visit.
\*------------------------------------------------------------------*/
  if (status != PRO_TK_NO_ERROR || data.found == PRO_B_FALSE)
    {
      ProMessageDisplay(msg_file, "USER %0s F", 
			"No dimensions found parallel to the supplied direction."); 
      return (PRO_TK_E_NOT_FOUND);
    }
  else
    {
      ProMessageDisplay(msg_file, "USER %0s F", 
			"Showing dimensions parallel to the supplied direction."); 

      return(PRO_TK_NO_ERROR); 
    }
}

/*==================================================================*\
FUNCTION : UserDimensionsByAxisDirectionShow()
PURPOSE  : Highlight model or feature dimensions parallel to a 
           selected axis.
\*==================================================================*/
ProError UserDimensionsByAxisDirectionShow ()
{
  ProError status;
  ProSelection* sels;
  int n_sels = -1;
  ProFileName msg_file;      
  ProSolid input_solid_ptr;
  ProFeature* input_feat_ptr;
  ProFeature feature;
  ProModelitem axis_item;
  ProAxis axis;
  ProGeomitemdata* axis_data;
  ProVector dirvector;
  int i;

  ProStringToWstring(msg_file, "msg_ugfund.txt") ;

/*------------------------------------------------------------------*\
  Prompt to select the context
\*------------------------------------------------------------------*/
  ProMessageDisplay(msg_file, "USER %0s F", 
		    "Select the feature for locating dimensions.  <CANCEL> to locate dimensions in the current model."); 

  status = ProSelect ("feature", 1, NULL, NULL, NULL, NULL, 
		      &sels, &n_sels);
  if (status == PRO_TK_USER_ABORT)
    {
      ProMdlCurrentGet ((ProMdl)&input_solid_ptr);
      input_feat_ptr = NULL;
    }
  else if (status != PRO_TK_NO_ERROR || n_sels < 1)
    {
      return (PRO_TK_USER_ABORT);
    }
  else
    {
      ProSelectionModelitemGet (sels [0], &feature);

      input_solid_ptr = NULL;
      input_feat_ptr = &feature;
    }

/*------------------------------------------------------------------*\
  Prompt to select the axis
\*------------------------------------------------------------------*/
 ProMessageDisplay(msg_file, "USER %0s F", 
		    "Select the axis for orientation of the dimensions."); 

  status = ProSelect ("axis", 1, NULL, NULL, NULL, NULL, &sels, &n_sels);
  if (status != PRO_TK_NO_ERROR || n_sels < 1)
    {
      return (PRO_TK_USER_ABORT);
    }
  
/*------------------------------------------------------------------*\
  Extract the direction vector of the axis
\*------------------------------------------------------------------*/
  ProSelectionModelitemGet (sels [0], &axis_item);  
  ProGeomitemToAxis (&axis_item, &axis);
  ProAxisDataGet (axis, &axis_data);
    
  for (i = 0; i < 3; i ++)
    dirvector [i] = axis_data->data.p_curve_data->line.end2 [i] -
      axis_data->data.p_curve_data->line.end1 [i];

  ProUtilVectorNormalize (dirvector, dirvector);

  ProGeomitemdataFree (&axis_data);

/*------------------------------------------------------------------*\
  Show the dimensions
\*------------------------------------------------------------------*/
  UserDimensionsByDirectionShow (input_solid_ptr, input_feat_ptr, dirvector);

  return PRO_TK_NO_ERROR;
}