//////////////////////////////////////
// START of File: CE2_COLM.CPP
//////////////////////////////////////

//===================================================================
//
// COPYRIGHT NOTICE:  This code is protected by Copyright!
//
// Copyright (c) 1994, 1995, 1996, 1997 by DPC Technology.
// All rights reserved. 
//
// See files "cf_copyr.h" and "cf_licen.h" for details of 
// copyright and license specifications, and contact information.
//
//===================================================================


//
// Include this source file's header file:
// and any additional neccessary include statements.
//
#include	<cf_api/bf_defs.h>
#include    <cf_api/ce2_colm.hpp> 

class       cf_XYZ;
class       cf_DataGroup;
#include    <cf_api/c1_dgrou.hpp>
            // We'll access the data groups/items in our Chart Model..

class       cf_3DPoint;
class       cf_3DPolygon;
#include    <cf_api/co1_pgon.hpp>
            // We'll build 2D Polygons for the 2D Columns...
    
//-------------------------------
// Implement class cf_eng_Col2D:
//-------------------------------
cf_eng_Col2D::cf_eng_Col2D()

    :   cf_eng_CartXYZ( CF_TYPE_COLUMN, CF_DISP_2D )

{
    disp2D3DMode( CF_DISP_2D );           // Make it a 2D Chart!...

    // The BASE chart engine class will have instantiated
    // ALL the possible Grid/Tick Series to NULL...
    // The DERIVED chart engine classes MUST set 
    // the series that they specifically want to be ON!...
    this->initGridTickSeries();
            // cf_engCartXYZ-derived charts can use either
            // the "default" XYZ/Cartesian method, which
            // activates the BOTTOM X-Axis as a "domain"
            // axis, and the LEFT Y-Axis as a "range over
            // chart model Y-Vals" axis, or define their
            // OWN version to over-ride the virtual XYZ/
            // Cartesian method...
}

cf_eng_Col2D
    ::~cf_eng_Col2D() 
        {}

void    
cf_eng_Col2D::updateYValsOnNatNs
            ( cf_ChartModel *p_cf_cmodlDataSource )
//
//==============================================
// OK -- the PLAN is the SAME as for 
// BAR Charts -- Just "turned sideways" !!!:
//==============================================
//
/*        

  (Range)
        |
        |
        |  +
        |  + &
        |  +*&  *  +*&
        |  +*& +*& +*&
      0-|__+*&_+*&_+*&_ [ ... ] ___(Domain)
        |   |   |   !           |
        0   1   2   3           N  

        ( continued on Natural N Indices)
         
 */
{
    // We will pull data from the chart with these vars:
    cf_DataGroup    *p_cf_dgAccessGroup = NULL;
    cf_XYZ          *p_cf_xyzAccessItem = NULL;
    double          dUserYVal = 0.0;

    // We will generate "Virtual 2D Bar Points/Polygons" 
    // for each of the Chart's Data Items with these vars:
    cf_3DPoint      cf_3dpTemp( 0.0, 0.0, 0.0 );
    cf_3DPolygon    *p_cf_3dpgNewGon = NULL;
                    // After new()-ed and configured, this storage
                    // will get passed to our dyna-array of ptrs...

    // Count the number of Active Groups:
    int     iStartAt = p_cf_cmodlDataSource->dataGroupsStartAt();
    int     iEndAt = p_cf_cmodlDataSource->dataGroupsEndAt();
    int     iNumGroups = iEndAt - iStartAt;
    int     iNumItemsPerPosit = iNumGroups + 2;
            // Cause each group will have a trailing space...
    
    // Calc the space required for each item:
    double  dSpacePerPosit = 1.0;
    double  dSpacePerItem = dSpacePerPosit / iNumItemsPerPosit;
    double  dItemHalfSpace = dSpacePerItem / 2.0;
                // Note that iNumItemsPerPosit should NEVER == 0.0! 

    // Compute the max number of axis items to iterate over:
    int iNumActiveInGroup = 0;
    int iNumDomainAxisItems = 0;
    for ( i = iStartAt; i <= iEndAt; i++ )
    {
        p_cf_dgAccessGroup = p_cf_cmodlDataSource->activateGroupUserData( i );
        iNumActiveInGroup = p_cf_dgAccessGroup->numItems();
        if ( iNumActiveInGroup > iNumDomainAxisItems ) 
                iNumDomainAxisItems = iNumActiveInGroup;
    }           // We now have our iteration limit...

    //
    //--------------------------------------------------
    // Loop over each axis index which represents the
    // indexed values from our collection of groups:
    //--------------------------------------------------
    //
    double  dPlaceItemAt 
                = 0.5 + dItemHalfSpace;
                // Set the spot to (start to) lay down items:
                
    for ( i = 1; i <= iNumDomainAxisItems; i++ )
    {
        //--------------------------------------------------------  
        // Loop over the (available) groups to generate polygons:
        //--------------------------------------------------------  
        for ( j = iStartAt; j <= iEndAt; j++ )  // (D-group indices)
        {
            // Get data values and construct 3D Points that
            // define bar/col/stack vertices:
            p_cf_dgAccessGroup  // Grab a group...
                = p_cf_cmodlDataSource->activateGroupUserData( j );
            p_cf_xyzAccessItem  // Then an item....
                = p_cf_dgAccessGroup->activateXYZValAt( i );
            dUserYVal = p_cf_xyzAccessItem->y();
                // ... whose Y value will define a "length/height"...

            // New a polygon -- note that we wait till AFTER we have
            // a data group activated so we can use VALID disp attribs!
            p_cf_3dpgNewGon 
                = new cf_3DPolygon( p_cf_dgAccessGroup->dispAttribs() );
                // (which will become a bar/col/stack/etc):
                
            // Construct the "leading edge":
            cf_3dpTemp.dataXYZ( dPlaceItemAt, 0.0, 0.0 );
            p_cf_3dpgNewGon->addPoint( cf_3dpTemp );

            cf_3dpTemp.dataXYZ( dPlaceItemAt, dUserYVal, 0.0 );
            p_cf_3dpgNewGon->addPoint( cf_3dpTemp );

            dPlaceItemAt += dSpacePerItem;
                        // bump along to the trailing edge...
            
            // Construct the "trailing edge":
            cf_3dpTemp.dataXYZ( dPlaceItemAt, dUserYVal, 0.0 );
            p_cf_3dpgNewGon->addPoint( cf_3dpTemp );

            cf_3dpTemp.dataXYZ( dPlaceItemAt, 0.0, 0.0 );
            p_cf_3dpgNewGon->addPoint( cf_3dpTemp );

            // Done with this polygon -- don't loose it!
            this->addSpaceObject( p_cf_3dpgNewGon );

        }   // end of for-loop over Data Groups

        // Lay down a trailing space AFTER the grouped items:
        dPlaceItemAt += dSpacePerItem;

    }   // end of for-loop over iNumCurrentItems

    return;
    
}   // end of cf_eng_Col2D::updateYValsOnNatNs()



void    
cf_eng_Col2D::updateYValsAtIntIs
            ( cf_ChartModel *p_cf_cmodlDataSource )
//
//==============================================
// OK -- the PLAN is the SAME as for 
// BAR Charts -- Just "turned sideways" !!!:
//==============================================
//
/*        
     (Range)
           |
           |
           +
           + &
           +*&  *  +*&
           +*& +*& +*&
           +*&_+*&_+*&_ [ ... ] ___(Domain)
           |   |   !           |
           0   1   2           I  

        ( continued on Natural I Indices)

 */
{
    // We will pull data from the chart with these vars:
    cf_DataGroup    *p_cf_dgAccessGroup = NULL;
    cf_XYZ          *p_cf_xyzAccessItem = NULL;
    double      dUserYVal = 0.0;

    // We will generate "Virtual 2D Bar Points/Polygons" 
    // for each of the Chart's Data Items with these vars:
    cf_3DPoint      cf_3dpTemp( 0.0, 0.0, 0.0 );
    cf_3DPolygon    *p_cf_3dpgNewGon = NULL;
                    // After new()-ed and configured, this storage
                    // will get passed to our dyna-array of ptrs...

    // Count the number of Active Groups:
    int     iStartAt = p_cf_cmodlDataSource->dataGroupsStartAt();
    int     iEndAt = p_cf_cmodlDataSource->dataGroupsEndAt();
    int     iNumGroups = iEndAt - iStartAt;
    int     iNumItemsPerPosit = iNumGroups + 1;
            // Unlike Natural N Indices, these group will
            // have NO leading or trailing space...
    
    // Calc the space required for each item:
    double  dSpacePerPosit = 1.0;
    double  dSpacePerItem = dSpacePerPosit / iNumItemsPerPosit;
    double  dItemHalfSpace = dSpacePerItem / 2.0;
                // Note that iNumItemsPerPosit should NEVER == 0.0! 

    // Compute the max number of axis items to iterate over:
    int iNumActiveInGroup = 0;
    int iNumDomainAxisItems = 0;
    for ( i = iStartAt; i <= iEndAt; i++ )
    {
        p_cf_dgAccessGroup = p_cf_cmodlDataSource->activateGroupUserData( i );
        iNumActiveInGroup = p_cf_dgAccessGroup->numItems();
        if ( iNumActiveInGroup > iNumDomainAxisItems ) 
                iNumDomainAxisItems = iNumActiveInGroup;
    }           // We now have our iteration limit...

    //
    //--------------------------------------------------
    // Loop over each axis index which represents the
    // indexed values from our collection of groups:
    //--------------------------------------------------
    //
    double  dPlaceItemAt = 0.0;
                // Set the spot to (start to) lay down items:
                
    for ( i = 1; i <= iNumDomainAxisItems; i++ )
    {
        //--------------------------------------------------------  
        // Loop over the (available) groups to generate polygons:
        //--------------------------------------------------------  
        for ( j = iStartAt; j <= iEndAt; j++ )  // (D-group indices)
        {
            // Get data values and construct 3D Points that
            // define bar/col/stack vertices:
            p_cf_dgAccessGroup  // Grab a group...
                = p_cf_cmodlDataSource->activateGroupUserData( j );
            p_cf_xyzAccessItem  // Then an item....
                = p_cf_dgAccessGroup->activateXYZValAt( i );
            dUserYVal = p_cf_xyzAccessItem->y();
                // ... whose Y value will define a "length/height"...

            // New a polygon -- note that we wait till AFTER we have
            // a data group activated so we can use VALID disp attribs!
            p_cf_3dpgNewGon 
                = new cf_3DPolygon( p_cf_dgAccessGroup->dispAttribs() );
                // (which will become a bar/col/stack/etc):
                
            // Construct the "leading edge":
            cf_3dpTemp.dataXYZ( dPlaceItemAt, 0.0, 0.0 );
            p_cf_3dpgNewGon->addPoint( cf_3dpTemp );

            cf_3dpTemp.dataXYZ( dPlaceItemAt, dUserYVal, 0.0 );
            p_cf_3dpgNewGon->addPoint( cf_3dpTemp );

            dPlaceItemAt += dSpacePerItem;
                        // bump along to the trailing edge...
            
            // Construct the "trailing edge":
            cf_3dpTemp.dataXYZ( dPlaceItemAt, dUserYVal, 0.0 );
            p_cf_3dpgNewGon->addPoint( cf_3dpTemp );

            cf_3dpTemp.dataXYZ( dPlaceItemAt, 0.0, 0.0 );
            p_cf_3dpgNewGon->addPoint( cf_3dpTemp );

            // Done with this polygon -- don't loose it!
            this->addSpaceObject( p_cf_3dpgNewGon );

        }   // end of for-loop over Data Groups

    }   // end of for-loop over iNumCurrentItems

    return;

}   // end of cf_eng_Col2D::updateYValsAtIntIs()

//
// END of class cf_eng_Col2D Implementation
//

//////////////////////////////////////
// END of File: CE2_COLM.CPP
//////////////////////////////////////

