/***********************************************************************/
/* Open Visualization Data Explorer                                    */
/* (C) Copyright IBM Corp. 1989,1999                                   */
/* ALL RIGHTS RESERVED                                                 */
/* This code licensed under the                                        */
/*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
/***********************************************************************/
/*
 * $Header: /home/gda/dxcvs/dx/src/exec/dxmods/showposition.c,v 1.4 1999/05/10 15:45:30 gda Exp $
 */

#include <dxconfig.h>


#include <stdlib.h>
#include <string.h>
#include <dx/dx.h>
#include <_helper_jea.h>
#include <_getfield.h>

#define  DEFAULT_COLOR  DXRGB(1.0,1.0,1.0)


#define  NEWBIT(n)      ((Pointer)DXAllocateLocalZero((((n)+31)/32)*4))
#define  SETBIT(a,i,v)  (((unsigned int*)(a))[((i)/32)]|=((v)<<((i)&31)))
#define  GETBIT(a,i)    (1&(((unsigned int*)(a))[((i)/32)]>>((i)&31)))


/* The following function resides in the file: showboundary.m */
extern
Array _dxf_resample_array
          ( component_info comp,  int dep_ref,
            int Nin,   int Nout,
            int *push, int *pull );



static
Field show_positions_every ( Field input, float every )
{
    int         i, j;
    float       float_items;
    int         validcount, newitems;
    Array       array      = NULL;
    int         *pull      = NULL;
    int         *aux       = NULL;
    array_info  p_info     = NULL;
    field_info  input_info = NULL;
    component_info    comp = NULL;
    InvalidComponentHandle
                  i_handle = NULL;

    if ( ERROR == ( i_handle = DXCreateInvalidComponentHandle
                                   ( (Object)input, NULL, "positions" ) ) )
         goto error;

    validcount = DXGetValidCount ( i_handle );

    if ( ( float_items = (float)validcount / every ) < 1.0 )
        float_items = 1.0;

    newitems = (int)float_items;

    if ( ( ERROR == ( pull = (int*) DXAllocate ( newitems * sizeof(int) ) ) ) ||
         ( ERROR == ( aux =  (int*) NEWBIT     ( validcount )             ) ) )
        goto error;

    if ( 0 != DXGetInvalidCount ( i_handle ) )
        for ( i=0; i<newitems; )
        {
            j = random() % validcount;

            if ( DXIsElementValidSequential ( i_handle, j ) &&
                 ( 0 == GETBIT ( aux, j ) ) )
                { pull[i++] = j; SETBIT ( aux, j, 1 ); }
        }
    else
        for ( i=0; i<newitems; )
        {
            j = random() % validcount;

            if ( 0 == GETBIT ( aux, j ) )
                { pull[i++] = j; SETBIT ( aux, j, 1 ); }
        }

    DXFree  ( (Pointer) aux );
    DXFreeInvalidComponentHandle ( i_handle );
    i_handle = NULL;  
    aux      = NULL;  

    if ( !DXSetComponentValue ( input, "invalid positions", NULL )
         ||
         ( ERROR == ( input_info = _dxf_InMemory ( input ) ) ) )
        goto error;

    p_info = (array_info) &(input_info->std_comps[(int)POSITIONS]->array);

    for ( i=0, comp=input_info->comp_list;
          i<input_info->comp_count;
          i++, comp++ )
        if ( ( NULL  != comp->std_attribs[(int)DEP]        ) &&
             ( ERROR != comp->std_attribs[(int)DEP]->value ) &&
             ( 0 == strcmp ( comp->std_attribs[(int)DEP]->value, "positions" )))
        {
            if ( ( ERROR == ( array = _dxf_resample_array
                                         ( comp, 1, p_info->items, newitems,
                                           NULL, pull ) ) )
                 ||
                 !DXSetComponentValue
                      ( input_info->field, comp->name, (Object)array ) )
                goto error;
        }

    if ( !_dxf_FreeInMemory ( input_info ) )
        goto error;

    return input;

    error:
        DXFreeInvalidComponentHandle ( i_handle );
        DXASSERT ( DXGetError() != ERROR_NONE );
        return ERROR; 
}



static
Field show_positions ( Field input, char *data, int size )
{
    int    i, j;
    Field  output = NULL;
    Object t  = NULL;
    char   *r = NULL;

    static char *relations[]  = { "dep", "ref", "der", NULL };
    static char *removables[] = { "connections", "normals", "faces", "loops",
                                  "invalid connections", "edges", NULL };

    DXASSERTGOTO ( input != NULL );
    DXASSERTGOTO ( ( data != NULL ) && ( size == sizeof(float) ) );
    DXASSERTGOTO ( DXGetObjectClass ( (Object)input ) == CLASS_FIELD );

    if ( DXEmptyField ( input ) ) return NULL;

    /*
     * 1/ Remove "connections".
     *        Renderability will default to a by points method.
     * 2/ (New) Remove "normals" component.
     * 3/ Remove any components that reference these components.
     * 4/ Ensure that "colors" exist.
     */

    if ( !DXExists ( (Object) input, "positions" ) )
        DXErrorGoto
            ( ERROR_INVALID_DATA, "No \"positions\" component in field" )

    if ( ERROR == ( output = (Field) DXCopy ( (Object)input, COPY_STRUCTURE ) ))
        goto error;


    /* Special scan to keep ChangedComponentStructure from deleting positions */

    for ( i=0; relations[i] != NULL; i++ )
    {
        if ( ( NULL != ( t = DXGetComponentAttribute
                                 ( output, "positions", relations[i] ) ) )
             &&
             ( ERROR == ( r = DXGetString ( (String) t ) ) ) )
            goto error;

        if ( t != NULL ) 
            for ( j=0; removables[j] != NULL; j++ )
                if ( 0 == strcmp ( r, removables[j] ) )
                    if ( !DXSetComponentAttribute
                              ( output, "positions", relations[i], NULL ) )
                        goto error;
                    else
                        DXWarning
                          ( "#4415", "positions", relations[i], removables[j] );
                /* `%s' component has unusual `%s' attribute: `%s'.  removing */
    }


    for ( i=0; removables[i] != NULL; i++ )

        if ( DXDeleteComponent ( output, removables[i] ) )
        {
            if ( !DXChangedComponentStructure ( output, removables[i] ) )
                goto error;
        }
        else if ( DXGetError() != ERROR_NONE )
            goto error;

    if ( *((float *) data) != 1.0 )
        if ( !show_positions_every ( output, *((float *) data) ) )
            goto error;

    if ( !_dxf_SetDefaultColor  ( output, DEFAULT_COLOR )
         ||
         !_dxf_SetFuzzAttribute ( output, 2 ) ) 
        goto error;

    return output;

    error:
        DXDelete ( (Object) output );

        DXASSERT ( DXGetError() != ERROR_NONE );
        return ERROR; 
}



extern
int
m_ShowPositions ( Object *in, Object *out )
{
    float every;

#define I_input  in[0]
#define I_every  in[1]
#define O_output out[0]

    if ( I_every == NULL ) every = 1.0;
    else
        if ( !DXExtractFloat ( I_every, &every ) || ( every < 1.0 ) )
            DXErrorGoto3
                ( ERROR_INVALID_DATA,
                  "#10121",
                  /* %s must be a scalar value greater than or equal to %g */
                  "parameter 'every'", 1.0 );

    if ( ( ERROR == ( O_output = DXProcessParts
                                    ( I_input, show_positions,
                                      /* args, size, copy, preserve */
                                      (Pointer)&every, sizeof(float), 1, 1 ) ) )
         ||
         ( DXGetError() != ERROR_NONE ) )
        goto error;

    return OK;

    error:
        if ( O_output != NULL ) DXDelete ( O_output );

        O_output = NULL;

        DXASSERT ( DXGetError() != ERROR_NONE );
        return ERROR;
}
