/******************************************************************************
             Copyright (c) 1999 Unigraphics Solutions, Inc.
                       Unpublished - All Rights Reserved

*******************************************************************************/
/* This example demonstrates the UF_EVAL api for lines and arcs.
Some of the UF_EVAL routines operate on an evaluator
independent of type while others are type dependent.  No longer use
UF_CURVE_ask_curve_struct ( ),
UF_CURVE_ask_curve_struct_data ( ) and
UF_CURVE_free_curve_struct ( )
*/

#include <stdio.h>
#include <uf_object_types.h>
#include <uf_curve.h>
#include <uf_eval.h>
#include <uf_modl.h>
#include <uf_part.h>
#include <uf_so.h>
#include <uf.h>
#define UF_CALL( X ) ( report ( __FILE__, __LINE__, #X, ( X ) ) )
static void show_edge_points(UF_EVAL_p_t eval, int n_pts);
/*---------------------------------------------------------------*/
static int report ( char *file, int line, char *call, int irc )
{
    if ( irc )
    {
        char message [ 132 + 1 ];
        printf ( "%s, line %d:  %s\n", file, line, call );
        UF_get_fail_message ( irc, message ) ?
            printf ( "    error %d\n", irc ) :
            printf ( "    error %d:  %s\n", irc, message );
    }
    return irc;
}
/*---------------------------------------------------------------*/
int ufusr_ask_unload ( void )
{
    return UF_UNLOAD_IMMEDIATELY;
}
/*---------------------------------------------------------------*/
/* ARGSUSED */
extern void ufusr ( char *param, int *retcod, int param_len )
{
    tag_t line;
    tag_t arc;
    tag_t edge;
    tag_t edges [ 3 ];
    UF_EVAL_p_t line_evaluator;
    UF_EVAL_p_t arc_evaluator;
    UF_EVAL_p_t edge_evaluator;
    UF_CALL ( UF_initialize ( ) );
    /*  
        Create new part "ufd_eval.prt".
        
        Close part if it already exists.
    */
    {
        tag_t part = UF_PART_ask_part_tag ( "ufd_eval.prt" );
        if ( part != NULL_TAG )
        {
            UF_CALL ( UF_PART_close ( part, 0, 1 ) );
        }
        UF_CALL ( UF_PART_new ( "ugd_eval.prt", 
                                UF_PART_ENGLISH, 
                                &part ) );
    }
    /* 
        Create block and get edges. 
    */
    {
        double  origin [ ] = { 0.0, 0.0, 0.0 };
        char   *sizes  [ ] = { "1", "1", "1" };
        tag_t block_feature;
            
        UF_CALL ( UF_MODL_create_block1 ( UF_NULLSIGN, 
                                          origin, 
                                          sizes, 
                                          &block_feature ) );
        {
            uf_list_p_t edge_list;
            UF_CALL ( UF_MODL_ask_feat_edges ( block_feature, 
                                               &edge_list ) );
            
            UF_CALL ( UF_MODL_ask_list_item ( edge_list, 
                                              1, 
                                              &edge ) );
            edges [ 0 ] = edge;
            edges [ 1 ] = edge;
            UF_CALL ( UF_MODL_ask_list_item ( edge_list, 
                                              0, 
                                              &edges [ 2 ] ) );
            UF_CALL ( UF_MODL_delete_list ( &edge_list ) );
        }
}
    /*  
        Create smart line.
    */
    UF_CALL ( UF_SO_create_curve_extract 
              ( 
                  edge, 
                  UF_SO_update_after_modeling, 
                  edge,
                  UF_line_type, /* enforce line type */
                  0,            /* no subtype to enforce */
                  NULL_TAG,
                  &line 
              ) );
        
    /*  
        Create smart arc.
    */
    {
        int i;
        tag_t points [ 3 ];
        for ( i = 0; i < 3; i++ )
        {
            char *strings [  ] = { "center=1.0", 
                                   "start=0.0", 
                                   "end=1.0" };
            tag_t exps    [ 3 ];
            tag_t scalars [ 3 ];
            UF_CALL ( UF_MODL_create_exp_tag ( strings [ i ], 
                                               &exps [ i ] ) );
            UF_CALL ( UF_SO_create_scalar_exp 
                      ( 
                          exps [ i ],
                          UF_SO_update_after_modeling, 
                          exps [ i ], 
                          &scalars [ i ]
                    ) );
            UF_CALL ( UF_SO_create_point_on_curve 
                      (
                          edges [ i ],
                          UF_SO_update_after_modeling, 
                          edges [ i ],
                          scalars [ i ], 
                          &points [ i ]
                    ) );
        }
        UF_CALL ( UF_SO_create_arc_center_2_pnts 
                 ( 
                      points [ 0 ], 
                      UF_SO_update_after_modeling,
                      points, 
                      &arc 
                  ) );
    }
        
    /* 
       Smart objects are created as invisible objects by 
       default.  UF_SO_set_visibility_option ( ) can be 
       used to make them visible in the graphics window.
    */
    UF_CALL ( UF_SO_set_visibility_option ( line, 
                                            UF_SO_visible ) );
    UF_CALL ( UF_SO_set_visibility_option ( arc,  
                                            UF_SO_visible ) );
    /*  
        Get line/arc/edge evaluators.
    */
    UF_CALL ( UF_EVAL_initialize ( line, &line_evaluator ) );
    UF_CALL ( UF_EVAL_initialize ( arc,  &arc_evaluator ) );
    UF_CALL ( UF_EVAL_initialize ( edge, &edge_evaluator ) );
    show_edge_points(line_evaluator, 10);
    show_edge_points(arc_evaluator, 10);
    show_edge_points(edge_evaluator, 10);
    /*  
        Get line/arc/edge data.
    */
    {
        UF_EVAL_line_t line_data;
        UF_EVAL_arc_t  arc_data;
        UF_EVAL_line_t edge_data;
        UF_CALL ( UF_EVAL_ask_line ( line_evaluator, 
                                     &line_data ) );
        UF_CALL ( UF_EVAL_ask_arc  ( arc_evaluator,  
                                     &arc_data ) );
        UF_CALL ( UF_EVAL_ask_line ( edge_evaluator,  
                                     &edge_data ) );
    }
    /*  
        Check line/arc/edge periodicity.
    */
    {
        logical is_periodic;
        
        UF_CALL ( UF_EVAL_is_periodic ( line_evaluator, 
                                        &is_periodic ) );
        UF_CALL ( UF_EVAL_is_periodic ( arc_evaluator,  
                                        &is_periodic ) );
        UF_CALL ( UF_EVAL_is_periodic ( edge_evaluator,  
                                        &is_periodic ) );
    }
/*  
        Evaluate line/arc/edge.
*/
    {
        double limits [ 2 ];        
        double mid_t;
        double point [ 3 ];
        double derivative [ 3 ];
        double tangent [ 3 ];
        double normal [ 3 ];
        double binormal [ 3 ];
        UF_CALL ( UF_EVAL_ask_limits ( line_evaluator, limits ) );
        mid_t = ( limits [ 1 ] + limits [ 0 ] ) / 2.0;
        UF_CALL ( UF_EVAL_evaluate ( line_evaluator, 
                                     1, 
                                     mid_t, 
                                     point, 
                                     derivative ) );
                  
        UF_CALL ( UF_EVAL_evaluate_unit_vectors ( line_evaluator, 
                                                  mid_t, 
                                                  point, 
                                                  tangent, 
                                                  normal, 
                                                  binormal ) );
        UF_CALL ( UF_EVAL_ask_limits ( arc_evaluator, limits ) );
        mid_t = ( limits [ 1 ] + limits [ 0 ] ) / 2.0;
        
        UF_CALL ( UF_EVAL_evaluate ( arc_evaluator, 
                                     1, 
                                     mid_t, 
                                     point, 
                                     derivative ) );
        
        UF_CALL ( UF_EVAL_evaluate_unit_vectors ( arc_evaluator, 
                                                  mid_t, 
                                                  point, 
                                                  tangent, 
                                                  normal, 
                                                  binormal ) );
        UF_CALL ( UF_EVAL_ask_limits ( edge_evaluator, limits ) );
        mid_t = ( limits [ 1 ] + limits [ 0 ] ) / 2.0;
        UF_CALL ( UF_EVAL_evaluate ( edge_evaluator, 
                                     1, 
                                     mid_t, 
                                     point, 
                                     derivative ) );
        UF_CALL ( UF_EVAL_evaluate_unit_vectors ( edge_evaluator, 
                                                  mid_t, 
                                                  point, 
                                                  tangent, 
                                                  normal, 
                                                  binormal ) );
    }
    /*  
        Check line/arc/edge equality of evaluators.
    */
    {
        logical is_equal;
        UF_EVAL_p_t line_evaluator_copy;
        UF_CALL ( UF_EVAL_copy ( line_evaluator,
                                 &line_evaluator_copy ) );
        UF_CALL ( UF_EVAL_is_equal ( line_evaluator,
                                     line_evaluator_copy,
                                     &is_equal ) );
        UF_CALL ( UF_EVAL_free ( line_evaluator_copy ) );
        UF_CALL ( UF_EVAL_is_equal ( line_evaluator, 
                                     arc_evaluator, 
                                     &is_equal ) );
        UF_CALL ( UF_EVAL_is_equal ( line_evaluator, 
                                     edge_evaluator, 
                                     &is_equal ) );
    }
    /*  
        Check line/arc/edge type.
    */
    {
        logical is_line;
        logical is_arc;
        UF_CALL ( UF_EVAL_is_line ( line_evaluator, &is_line ) );
        UF_CALL ( UF_EVAL_is_arc  ( line_evaluator, &is_arc ) );
        UF_CALL ( UF_EVAL_is_arc  ( arc_evaluator,  &is_arc ) );
        UF_CALL ( UF_EVAL_is_line ( arc_evaluator,  &is_line ) );
        UF_CALL ( UF_EVAL_is_arc  ( edge_evaluator, &is_arc ) );
        UF_CALL ( UF_EVAL_is_line ( edge_evaluator, &is_line ) );
    }
    UF_CALL ( UF_EVAL_free ( line_evaluator ) );
    UF_CALL ( UF_EVAL_free ( arc_evaluator ) );
    UF_CALL ( UF_EVAL_free ( edge_evaluator ) );
    UF_CALL ( UF_terminate ( ) );
}

/* This function will disply n_pts equally spaced along the
   input curve.
*/
static void show_edge_points(UF_EVAL_p_t eval, int n_pts)
{
    int ii;
    double limits[2], p, point[3], end_parameter, start_parameter;
    UF_OBJ_disp_props_t
        attrib = { 1, UF_OBJ_WHITE, UF_OBJ_NOT_BLANKED, UF_OBJ_WIDTH_NORMAL,
            UF_OBJ_FONT_SOLID, FALSE};

    UF_CALL(UF_EVAL_ask_limits(eval, limits));
    printf ( "limit0 = %f\n", limits[0] );
    printf ( "limit1 = %f\n", limits[1] );
    start_parameter = limits[0];
    end_parameter = limits[1];

    for (ii = 0; ii < n_pts; ii++)
    {
        p =start_parameter + ii*((end_parameter - start_parameter)/(n_pts - 1));
        printf ( "evaluate = %f\n", p );
        UF_CALL(UF_EVAL_evaluate(eval, 0, p, point, NULL));
        UF_CALL(UF_DISP_display_temporary_point(NULL_TAG,
            UF_DISP_USE_ACTIVE_PLUS, point, &attrib, UF_DISP_POINT));
    }

}
