////////////////////////////////////////
// Start of File: CO1_GTS.CPP
////////////////////////////////////////

//=============================================================================
// Copyright (c) 1994-1997 by DPC Technology Corporation. All rights reserved.
//=============================================================================

#include	<cf_api/bf_defs.h>
#include    <cf_api/co1_gts.hpp>

#include    <math.h>        // For polar grid/tick marking ops below...

//==============================================================
// Implement the Chart Framework "cf_3DGridTickSeries" class:
//==============================================================
cf_3DGridTickSeries
    ::cf_3DGridTickSeries( cf_ChartEngine *p_cf_engINowBelongTo )
        : cf_Virt3DObj()
{
    //-----------------------------------------------------
    // Keep a pointer to the engine which owns us:
    //-----------------------------------------------------
    p_cf_engParentEngine_ = p_cf_engINowBelongTo;
    this->bIsActive = TRUE;

    enumCurrAxisType_ = CF_AXIS_UNDEFINED;

    //-----------------------------------------------------
    // Init the state of the "Dynamic Array" Vars:
    //-----------------------------------------------------
    this->da_p_cf_3dtmMarkerArray.growBy( 25 );
    this->iNumMarkAllocs = 0;

    //------------------------------------------------
    // Init the state of the "Axis Label" Text Marker:
    //------------------------------------------------
    p_cf_3dtmAxisLabel_ = new cf_3DTextMarker();
    p_cf_3dtmAxisLabel_->attribTextNew();
    p_cf_3dtmAxisLabel_->attribTextCurrent()->preferFontToProjRectPct( 5.0 );
    p_cf_3dtmAxisLabel_->attribTextCurrent()->colorTextBack
                            ( p_cf_engParentEngine_->dispColorBackground() );

    //--------------------------------------------------------
    // Init the "Virtual Geometry State" of this collection:
    //--------------------------------------------------------
    this->dVirtXMax = this->dVirtYMax = this->dVirtZMax = 0.0;
    this->dVirtXMin = this->dVirtYMin = this->dVirtZMin = 0.0;
            // Scaling Range info init'ed.

    this->dTransX = this->dTransY = this->dTransZ = 0.0;
    this->dScaleFacX = this->dScaleFacY = this->dScaleFacZ = 1.0;
            // Geometry State init'ed.

    //-------------------------------------------------
    // Init our "Target Engine Dimensions" state vars:
    //-------------------------------------------------
    this->dEngVirtXMin = this->dEngVirtYMin = this->dEngVirtZMin = 0.0;
    this->dEngVirtXMax = this->dEngVirtYMax = this->dEngVirtZMax = 0.0;
                        // The "scale-into" VIRTUAL ranges...

    this->dEngDataXMin = this->dEngDataYMin = this->dEngDataZMin = 0.0;
    this->dEngDataXMax = this->dEngDataYMax = this->dEngDataZMax = 0.0;
                        // The applicable DATA range...

    this->dEngVirtXDim = this->dEngVirtYDim = this->dEngVirtZDim = 0.0;
    this->dEngDataXDim = this->dEngDataYDim = this->dEngDataZDim = 0.0;
                        // Calc'ed dimensions used to generate grid/
                        // tick markers to fit the current engine...
                        //
                        // These are set by subsequent calls to the
                        // gatherEngineDataVirtRanges() member method
                        // below -- AFTER the engine has been properly
                        // configured with calls to config3DBoxETC()
                        // and a measureDataMinMax(), etc...

    //-----------------------------------------------------
    // Create a SHARED "Display Attribute" object that ALL
    // the markers in this series will SHARE:
    //-----------------------------------------------------
    dispAttribsNewSet();
            // Now dispAttribsCurrent() calls will be valid, AND
            // the virtual d-tor will know to delete the object.

    //-----------------------------------------------------
    // Create an Auto-Scale Font Spec to use for the markers:
    //-----------------------------------------------------
    attribTextNew();
    attribTextCurrent()->preferFontToProjRectPct( 4.0 );
    attribTextCurrent()->colorTextFore( CF_BLACK );
    attribTextCurrent()->colorTextBack
                        ( p_cf_engParentEngine_->dispColorBackground() );

    //-----------------------------------------------------
    // Init a set of common/shared attributes to use in
    // this series of markers:
    //-----------------------------------------------------
    this->dTickSizeRatio = 0.03;

    //------------------------------------
    // Init "engine update method" vars:
    //------------------------------------
    this->bUseDomainItems = FALSE;
    this->bUseDataGroupsList = FALSE;
    this->bUseDataRange = FALSE;
    this->bUseDataRangeSums = FALSE;
    this->bUseRangeValues = FALSE;
    this->bUseRangeValSums = FALSE;

    this->bUsePrefModelDomainFactor = TRUE;
    this->bUsePrefModelRangeFactor = TRUE;

    this->iPrefModelDomainFactor = 10;
    this->iPrefModelRangeFactor = 10;

    this->iFreqTicksToDomainItems = 1;
    this->dFreqTicksToRangeValues = 1.0;

    this->iFreqGridsToTicks = 0;
    this->iFreqTextsToTicks = 1;
    iFreqMajorToMinor_ = 1;
    enumCurrTickSize_ = CF_TICK_MAJOR;

    this->bDispForceMaxTickText = FALSE;
    this->bDispForceMinTickText = FALSE;

    this->bDispWithHiddenTicks = FALSE;
    bDispWithInvertedTicks_ = FALSE;

    this->p_cf_3dtmMaxTick = NULL;  // Any newly added mark will be a
    this->p_cf_3dtmMinTick = NULL;  // candidate for these to point to...

}   // end of BASE class c-tor.


cf_3DGridTickSeries
    ::~cf_3DGridTickSeries()
{
    if ( p_cf_3dtmAxisLabel_ != NULL ) delete p_cf_3dtmAxisLabel_;

    for ( int i = 1; i <= this->iNumMarkAllocs; i++ )
        delete ( ( cf_3DTextMarker*) this->da_p_cf_3dtmMarkerArray[ i ] );
}


//-------------------------------------------------------------
// These protected member methods creates a new grid/tick mark
// from the 3 cf_3DPoint* params and makes the new grid/tick
// mark match this owning grid/tick series's attributes:
//-------------------------------------------------------------
cf_3DTextMarker*
    cf_3DGridTickSeries
        ::addAxisMarker(    cf_3DPoint  *p_cf_3dpTailPoint,
                            cf_3DPoint  *p_cf_3dpHeadPoint,
                            cf_3DPoint  *p_cf_3dpTextPoint )
{
    // Create a new text-marker and add its address into 
    // our dynamic array of pointers to text-markers
    this->iNumMarkAllocs++;
    cf_3DTextMarker *p_cf_3dtmNewMarker
                    = new cf_3DTextMarker(  p_cf_3dpTailPoint,
                                            p_cf_3dpHeadPoint,
                                            p_cf_3dpTextPoint );
    this->da_p_cf_3dtmMarkerArray[ iNumMarkAllocs ]
                                            = p_cf_3dtmNewMarker;

    // Now, make this new grid/tick mark match this
    // owning grid/tick series's attributes:
    p_cf_3dtmNewMarker->dispAttribsPointTo( dispAttribsCurrent() );
    p_cf_3dtmNewMarker->attribTextUsing( attribTextCurrent() );

    // Tell this new text-marker NOT to try to use its own ASFS!
    p_cf_3dtmNewMarker->dispIgnorePushFont( TRUE );

    if ( this->bDispWithHiddenTicks == TRUE )
        p_cf_3dtmNewMarker->dispLineHead( FALSE );

    // Now set the geometry state of this new marker
    // to match this owner/parent grid/tick/series:
    p_cf_3dtmNewMarker
        ->applyScaleOp(this->dScaleFacX,this->dScaleFacY,this->dScaleFacZ);
    p_cf_3dtmNewMarker
        ->applyTranslateOp( this->dTransX, this->dTransY, this->dTransZ );

    return p_cf_3dtmNewMarker;

}   // end of addAxisMarker(... 3 points ...)




void
cf_3DGridTickSeries::applyDataUpdate
                    ( cf_ChartModel *p_cf_cmodlDataSource )
{
    // Get rid of any old stuff:
    reset();

    // Does the user really want us to do anything?
    if ( bIsActive == FALSE ) return;

    // Setup Display and Text-Attribs:
    cf_DataGroup    *p_dgAttrib = NULL;
    BOOL            bFoundAttribGroup = TRUE;
    switch ( enumCurrAxisType_ )
    {
        case CF_AXIS_X_BACK:
                p_dgAttrib = p_cf_cmodlDataSource->activateGroupAxis( CF_AXIS_X_BACK );
                break;

        case CF_AXIS_X_BOTTOM:
                p_dgAttrib = p_cf_cmodlDataSource->activateGroupAxis( CF_AXIS_X_BOTTOM );
                break;

        case CF_AXIS_Y_BACK:
                p_dgAttrib = p_cf_cmodlDataSource->activateGroupAxis( CF_AXIS_Y_BACK );
                break;

        case CF_AXIS_Y_LEFT:
                p_dgAttrib = p_cf_cmodlDataSource->activateGroupAxis( CF_AXIS_Y_LEFT );
                break;

        case CF_AXIS_Z_BOTTOM:
                p_dgAttrib = p_cf_cmodlDataSource->activateGroupAxis( CF_AXIS_Z_BOTTOM );
                break;

        case CF_AXIS_Z_LEFT:
                p_dgAttrib = p_cf_cmodlDataSource->activateGroupAxis( CF_AXIS_Z_LEFT );
                break;

        case CF_AXIS_POLAR_FLOOR:
                p_dgAttrib = p_cf_cmodlDataSource->activateGroupAxis( CF_AXIS_POLAR_FLOOR );
                break;

        case CF_AXIS_UNDEFINED:
        case CF_AXIS_CUSTOM:
        default:
                bFoundAttribGroup = FALSE;
                break;
    }

    if ( bFoundAttribGroup == TRUE )
    {
        dispAttribsPointTo( p_dgAttrib->dispAttribs() );
        attribTextUsing( p_dgAttrib->textAttribs() );
    }

    // Gather (data and virtual) dimension params neccessary to
    // convert the raw user-data DATA value into a VIRTUAL value:
    cf_3DGridTickSeries::gatherEngineDataVirtRanges();
            // Note that we use the COMMON BASE class implementation!
            // See the Caveat/Note in this method's body above!...

    // Only make auto-updates IF the user has set them up!
    if ( this->bUseDataGroupsList == TRUE )
    {
        updateFromDataGroupsList( p_cf_cmodlDataSource );
    }
    if ( this->bUseDomainItems == TRUE )
    {
        updateFromDomainItems( p_cf_cmodlDataSource );
    }
    else if ( this->bUseDataRange == TRUE )
    {
        updateOverDataRange( p_cf_cmodlDataSource );
        if ( this->bUseRangeValues == TRUE )
            updateFromRangeValues( p_cf_cmodlDataSource );
    }
    else if ( this->bUseDataRangeSums == TRUE )
    {
        updateOverDataRangeSums( p_cf_cmodlDataSource );
        if ( this->bUseRangeValSums == TRUE )
            updateFromRangeValSums( p_cf_cmodlDataSource );
    }
    else if ( this->bUseRangeValues == TRUE )
    {
        updateFromRangeValues( p_cf_cmodlDataSource );
        // only if everything else up to now was not called!...
    }
    else if ( this->bUseRangeValSums == TRUE )
    {
        updateFromRangeValSums( p_cf_cmodlDataSource );
        // only if everything else up to now was not called!...
    }

}



void
    cf_3DGridTickSeries
        ::applyGeomXform( cf_Kernel  *p_cf_kUseThisKernel )
{
    // Apply the xform to the grid/tick mark line's vertices:
    for ( int i = 1; i <= this->iNumMarkAllocs; i++ ) 
        ( (cf_3DTextMarker*) this->da_p_cf_3dtmMarkerArray[ i ] )
                                ->applyGeomXform( p_cf_kUseThisKernel );
    // Then xform the label:
    p_cf_3dtmAxisLabel_->applyGeomXform( p_cf_kUseThisKernel );
    return;
}

void
    cf_3DGridTickSeries
        ::applyProjXform( cf_Kernel *p_cf_kUseThisKernel )
{
    // Apply the xform to the grid/tick mark line's vertices:
    for ( int i = 1; i <= this->iNumMarkAllocs; i++ ) 
        ( (cf_3DTextMarker*) this->da_p_cf_3dtmMarkerArray[ i ] )
                                ->applyProjXform( p_cf_kUseThisKernel );
    // Then xform the label:
    p_cf_3dtmAxisLabel_->applyProjXform( p_cf_kUseThisKernel );
    return;
}



// SCALE the cf_3DGridTickSeries's VIRTUAL Coordinates.
void
    cf_3DGridTickSeries
        ::applyScaleOp( double dXScaleFactor,
                        double dYScaleFactor,
                        double dZScaleFactor )
{
    // In order to "properly" scale this object, we
    // need to translate it back to its original coords.
    double  dSaveXTrans = this->dTransX;
    double  dSaveYTrans = this->dTransY;
    double  dSaveZTrans = this->dTransZ;
    
    this->applyTranslateOp( -dSaveXTrans, 
                                -dSaveYTrans, 
                                    -dSaveZTrans );
    
    // Apply the scale factors to the XYZ coords of 
    // the cf_Virt3DObj's components.
    for ( int i = 1; i <= this->iNumMarkAllocs; i++ ) 
        ( (cf_3DTextMarker*) this->da_p_cf_3dtmMarkerArray[ i ] )
            ->applyScaleOp( dXScaleFactor, dYScaleFactor, dZScaleFactor );
            
    // Then scale the label:
    p_cf_3dtmAxisLabel_
            ->applyScaleOp( dXScaleFactor, dYScaleFactor, dZScaleFactor );

    // Update this object's "history":
    this->dScaleFacX = this->dScaleFacX * dXScaleFactor;
    this->dScaleFacY = this->dScaleFacY * dYScaleFactor;
    this->dScaleFacZ = this->dScaleFacZ * dZScaleFactor;

    this->dVirtXMax = this->dVirtXMax * dXScaleFactor;
    this->dVirtXMin = this->dVirtXMin * dXScaleFactor;
    this->dVirtYMax = this->dVirtYMax * dYScaleFactor;
    this->dVirtYMin = this->dVirtYMin * dYScaleFactor;
    this->dVirtZMax = this->dVirtZMax * dZScaleFactor;
    this->dVirtZMin = this->dVirtZMin * dZScaleFactor;

    // Update our translation counters, so we can always
    // reverse-calc the Initial XYZ coords of the object.
//    this->dTransX = this->dTransX * dXScaleFactor;
  //  this->dTransY = this->dTransY * dYScaleFactor;
    //this->dTransZ = this->dTransZ * dZScaleFactor;

    // Now put our re-scaled object "back" where it was:
    this->applyTranslateOp( dSaveXTrans,
                                dSaveYTrans,
                                    dSaveZTrans );
    return;

}   // end of cf_3DGridTickSeries::applyScaleOp(...)


void
    cf_3DGridTickSeries
        ::applyTranslateOp( double  dXTrans,
                            double  dYTrans,
                            double  dZTrans )
{
    // Apply the xlations to the XYZ coords of the
    // grid/tick mark polyline's points.
    for ( int i = 1; i <= this->iNumMarkAllocs; i++ )
        ( (cf_3DTextMarker*) this->da_p_cf_3dtmMarkerArray[ i ] )
                ->applyTranslateOp( dXTrans, dYTrans, dZTrans );

    // Then xlate the label:
    p_cf_3dtmAxisLabel_
            ->applyTranslateOp( dXTrans, dYTrans, dZTrans );

    // Update our translation counters, so we can always
    // reverse-calc the Initial XYZ coords of the object.
    this->dTransX = this->dTransX + dXTrans;
    this->dTransY = this->dTransY + dYTrans;
    this->dTransZ = this->dTransZ + dZTrans;

    this->dVirtXMax = this->dVirtXMax + dXTrans;
    this->dVirtXMin = this->dVirtXMin + dXTrans;
    this->dVirtYMax = this->dVirtYMax + dYTrans;
    this->dVirtYMin = this->dVirtYMin + dYTrans;
    this->dVirtZMax = this->dVirtZMax + dZTrans;
    this->dVirtZMin = this->dVirtZMin + dZTrans;
    return;

}   // end of cf_3DGridTickSeries::applyTranslateOp(...)



void
cf_3DGridTickSeries::colorBack
                    ( const bf_Color &cr_bf_clrNewVal )
{
    attribTextCurrent()->colorTextBack( cr_bf_clrNewVal );
    p_cf_3dtmAxisLabel_->attribTextCurrent()->colorTextBack( cr_bf_clrNewVal );
}



// We can choose to disregard tick freqs and
// force the display of max/min ticks:
BOOL
    cf_3DGridTickSeries
        ::dispForceMaxTickText()
            { return this->bDispForceMaxTickText; }
void
    cf_3DGridTickSeries
        ::dispForceMaxTickText( BOOL bNewState )
            { this->bDispForceMaxTickText = bNewState; }

BOOL
    cf_3DGridTickSeries
        ::dispForceMinTickText()
            { return this->bDispForceMinTickText; }
void
    cf_3DGridTickSeries
        ::dispForceMinTickText( BOOL bNewState )
            { this->bDispForceMinTickText = bNewState; }


// This will generate ticks, so the user can show
// text markers, grids, etc, but will set the "tick"
// part of the grid/tick/text marker OFF.
BOOL
    cf_3DGridTickSeries
        ::dispWithHiddenTicks()
            { return this->bDispWithHiddenTicks; }
void
    cf_3DGridTickSeries
        ::dispWithHiddenTicks( BOOL bNewState )
{
    this->bDispWithHiddenTicks = bNewState;

    for ( int i = 1; i <= this->iNumMarkAllocs; i++ )
        ( (cf_3DTextMarker*) this->da_p_cf_3dtmMarkerArray[ i ] )
                        ->dispLineHead( !(this->bDispWithHiddenTicks) );
    return;
}



BOOL
cf_3DGridTickSeries::dispWithInvertedTicks()
{
    return( bDispWithInvertedTicks_ );
}


void
cf_3DGridTickSeries::dispWithInvertedTicks( BOOL bNewState )
{
    bDispWithInvertedTicks_ = bNewState;
}


//
//-------------------------------------------------
// DRAW this cf_3DGridTickSeries on a bf_Display.
//-------------------------------------------------
//
void
    cf_3DGridTickSeries
        ::draw2D( bf_Display *p_bf_dspOutputDisplay )
            { this->draw3D( p_bf_dspOutputDisplay ); }
void
    cf_3DGridTickSeries
        ::draw3D( bf_Display *p_bf_dspOutputDisplay )
{
    // Are we SERIOUS about this?...
    if ( !this->bIsActive ) return;
                // ...then don't incur font calculation overhead!

    // Save info on current text color, since we may wanna change it...
    bf_Color   bf_clrSaveOldTextColor
                = p_bf_dspOutputDisplay->dsp_textColor();
    bf_Color   bf_clrSaveOldBackColor
                = p_bf_dspOutputDisplay->dsp_backColor();

    // Set up the output display Text/Letter & Text/Background Colors:
    bf_Color   bf_clrTextLetterColor = attribTextCurrent()->colorTextFore();
    bf_Color   bf_clrTextBackgroundColor = attribTextCurrent()->colorTextBack();

    p_bf_dspOutputDisplay->dsp_textColor( bf_clrTextLetterColor );
    p_bf_dspOutputDisplay->dsp_backColor( bf_clrTextBackgroundColor );

    //--------------------------------------
    // Calculate an auto-scaled font spec:
    //--------------------------------------
    bf_FontSpec    dspOutputFontSpec
                    = attribTextCurrent()->calcFontSpec( p_bf_dspOutputDisplay );
    bf_Font        *p_donOutputFont
                    = new bf_Font( dspOutputFontSpec );

    // NOW, (finally), we can push on the output font we chose:
    p_bf_dspOutputDisplay->dsp_pushFont( p_donOutputFont );
                //
                // Voila!  Now a zFont is pushed on the display
                // -- one that each of the cf3DGritTickMarks
                // in this cf_3DGridTickSeries can use to draw
                // its little label...
                //

    // We'll use the cf_3DTextMarker::draw3D() member method
    // which ASSUMES we will push on the appropriate font, pen,
    // brush, etc., to draw with:
    this->dispPushPenAttribs( p_bf_dspOutputDisplay );
    this->dispPushBrushAttribs( p_bf_dspOutputDisplay );

    // Prepare to resolve "stagger-up/down and/or down/up" situations:
    cf_TextAttribs  cf_tatbShiftedUp;
    cf_TextAttribs  cf_tatbShiftedDown;
    cf_tatbShiftedUp.shiftVertUp();
    cf_tatbShiftedDown.shiftVertDown();

    // Draw the individual data points/markers -- NOTE that
    // because the individual markers has their useOwnerAttributes()
    // set to FALSE, each mark will NOT push/pop a font spec,
    // but will instead use the one that WE push/pop right here...
    for ( int i = 1; i <= this->iNumMarkAllocs; i++ )
    {
        // Should we alternately stagger first down, then up?
        if ( attribTextCurrent()->staggerDownUpIs() == TRUE )
            if ( ( i % 2 ) == 0 )
                ( (cf_3DTextMarker*) da_p_cf_3dtmMarkerArray[ i ] )
                                    ->attribTextUsing( &cf_tatbShiftedUp );
            else
                ( (cf_3DTextMarker*) da_p_cf_3dtmMarkerArray[ i ] )
                                    ->attribTextUsing( &cf_tatbShiftedDown );

        // Should we alternately stagger first up, then down?
        if ( attribTextCurrent()->staggerUpDownIs() == TRUE )
            if ( ( i % 2 ) == 0 )
                ( (cf_3DTextMarker*) da_p_cf_3dtmMarkerArray[ i ] )
                                    ->attribTextUsing( &cf_tatbShiftedDown );
            else
                ( (cf_3DTextMarker*) da_p_cf_3dtmMarkerArray[ i ] )
                                    ->attribTextUsing( &cf_tatbShiftedUp );

        // With any possible staggering resolved, render the mark
        ( (cf_3DTextMarker*) this->da_p_cf_3dtmMarkerArray[ i ] )
                                    ->draw3D( p_bf_dspOutputDisplay );

        // Make sure the mark's text-attribute is reset and valid!
        ( (cf_3DTextMarker*) da_p_cf_3dtmMarkerArray[ i ] )
                                    ->attribTextUsing( attribTextCurrent() );
    }

    // Finish by drawing the axis label "on top of" anything else:
    p_cf_3dtmAxisLabel_->draw3D( p_bf_dspOutputDisplay );

    // Restore any display modifications:
    p_bf_dspOutputDisplay->dsp_textColor( bf_clrSaveOldTextColor );
    p_bf_dspOutputDisplay->dsp_backColor( bf_clrSaveOldBackColor );

    // Return any resource allocations:
    this->dispPopBrushAttribs( p_bf_dspOutputDisplay );
    this->dispPopPenAttribs( p_bf_dspOutputDisplay );
    delete p_bf_dspOutputDisplay->dsp_popFont();

    return;

}   // end of cf_3DGridTickSeries::draw3D( bf_Display* )


//-----------------------------------------
// Manipulate grid/tick/text frequencies:
//-----------------------------------------
void
cf_3DGridTickSeries::freqTicksFromDomainFactor
                    (   cf_ChartModel *p_cf_cmodlDataSource,
                        int iDivideDomainItemsBy )
{
    // Screen and correct bogus parameter values:
    if ( iDivideDomainItemsBy <= 0 )
    {
        this->iPrefModelDomainFactor = 0;
        this->iFreqTicksToDomainItems = 0;
    }
    else // apply the user's choice of domain division factor
    {
        this->iPrefModelDomainFactor = iDivideDomainItemsBy;

        // Get info on the extent of the current domain:
        cf_DataGroup    *p_cf_dgDomainItems
                        = p_cf_cmodlDataSource->accessDomainItems();
        #ifdef CF_ASSERT_DVALS
        assert( this->iPrefModelDomainFactor > 0 );
        #endif
        this->iFreqTicksToDomainItems
            = (int)( p_cf_dgDomainItems->numItems()
                                    / this->iPrefModelDomainFactor );
        // Correct things if we go TOO far...
        if ( this->iFreqTicksToDomainItems < 1 ) 
                    this->iFreqTicksToDomainItems = 1;
    }
    //...and make a note that (any future) updates will use this factor... 
    this->bUsePrefModelDomainFactor = TRUE;
    return;
}

void
    cf_3DGridTickSeries
        ::freqTicksToDomainItems( int   iEveryHowManyItems )
{ 
    // Set the new DIRECT frequency...
    this->iFreqTicksToDomainItems = iEveryHowManyItems;

    //...and make a note that (any future) updates will
    // use this frequency, NOT the range factor... 
    this->bUsePrefModelDomainFactor = FALSE;
    return;
}

int 
    cf_3DGridTickSeries
        ::freqTicksToDomainItems()
            { return this->iFreqTicksToDomainItems; }

void
cf_3DGridTickSeries::freqTicksFromRangeFactor
                    (   cf_ChartModel   *p_cf_cmodlDataSource,
                        int             iDivideDataRangeBy  )
{
    // Screen and correct bogus parameter values:
    if ( iDivideDataRangeBy < 0 )
    {
        this->iPrefModelRangeFactor = 0;
        this->dFreqTicksToRangeValues = 0.0;
    }
    else // apply the user's choice of range division factor
    {
        this->iPrefModelRangeFactor = iDivideDataRangeBy;
        double dCurrRangeExtent = p_cf_cmodlDataSource->dataYValuesExtent();

        this->dFreqTicksToRangeValues = ( dCurrRangeExtent /
                            ( (double) this->iPrefModelRangeFactor ) );
                            // which (due to screen) will NOT == 0!
    }
    //...and make a note that (any future) updates will use this factor...
    this->bUsePrefModelRangeFactor = TRUE;
    return;
}

void
cf_3DGridTickSeries::freqTicksFromRangeSumFactor
                    (   cf_ChartModel   *p_cf_cmodlDataSource,
                        int             iDivideRangeSumsBy  )
{
    // Screen and correct bogus parameter values:
    if ( iDivideRangeSumsBy < 0 )
    {
        this->iPrefModelRangeFactor = 0;
        this->dFreqTicksToRangeValues = 0.0;    
    }
    else // apply the user's choice of range division factor
    {
        this->iPrefModelRangeFactor = iDivideRangeSumsBy;
        double dCurrRangeExtent = p_cf_cmodlDataSource->dataYValSumsExtent();

        this->dFreqTicksToRangeValues = ( dCurrRangeExtent /
                            ( (double) this->iPrefModelRangeFactor ) );
                            // which (due to screen) will NOT == 0!
    }
    //...and make a note that (any future) updates will use this factor...
    this->bUsePrefModelRangeFactor = TRUE;
    return;
}

void
    cf_3DGridTickSeries
        ::freqTicksToRangeValues( double    dIntervalOverData )
{ 
    // Set the new DIRECT frequency
    this->dFreqTicksToRangeValues = dIntervalOverData;
    //...and make a note that (any future) updates will
    // use this frequency, NOT the range factor...
    this->bUsePrefModelRangeFactor = FALSE;
    return;
}

double  
    cf_3DGridTickSeries
        ::freqTicksToRangeValues()
            { return this->dFreqTicksToRangeValues; }


void
    cf_3DGridTickSeries
        ::freqGridsToTicks( int iEveryHowManyTicks )
{
    // Assign grid/tick freq -- and compensate for bogus values:
    this->iFreqGridsToTicks = iEveryHowManyTicks;
    if ( this->iFreqGridsToTicks < 0 ) this->iFreqGridsToTicks = 0;

    // Update the "draw grid" status of any existing text markers:
    cf_3DTextMarker *p_cf_3dtmTarget = NULL;
    int iGridsToTicksAccum = this->iFreqGridsToTicks;

    for ( int i = 1; i <= this->iNumMarkAllocs; i++ )
    {
        p_cf_3dtmTarget = ( (cf_3DTextMarker*)
                            this->da_p_cf_3dtmMarkerArray[ i ] );

        if ( ( this->iFreqGridsToTicks > 0 )
            && ( ++iGridsToTicksAccum >= this->iFreqGridsToTicks ) )
        {
            p_cf_3dtmTarget->dispLineTail( TRUE );
            iGridsToTicksAccum = 0;
        }   // Note the (in-expression ++ op) !
        else
            p_cf_3dtmTarget->dispLineTail( FALSE );
    }
    return;
}

int
    cf_3DGridTickSeries
        ::freqGridsToTicks()
            { return this->iFreqGridsToTicks; }

void
    cf_3DGridTickSeries
        ::freqTextsToTicks( int iEveryHowManyTicks )
{
    // Assign text/tick freq -- and compensate for bogus values:
    this->iFreqTextsToTicks = iEveryHowManyTicks;
    if ( this->iFreqTextsToTicks < 0 ) this->iFreqTextsToTicks = 0;

    // Update the "draw grid" status of any existing text markers:
    cf_3DTextMarker *p_cf_3dtmTarget = NULL;
    int iTextsToTicksAccum = this->iFreqTextsToTicks;

    for ( int i = 1; i <= this->iNumMarkAllocs; i++ )
    {
        p_cf_3dtmTarget = ( (cf_3DTextMarker*) 
                            this->da_p_cf_3dtmMarkerArray[ i ] );

        if ( ( this->iFreqTextsToTicks > 0 )
            && ( ++iTextsToTicksAccum >= this->iFreqTextsToTicks ) )
        {
            p_cf_3dtmTarget->dispText( TRUE );
            iTextsToTicksAccum = 0;
        }   // Note the (in-expression ++ op) !
        else
            p_cf_3dtmTarget->dispText( FALSE );
    }
    return;
}

int
    cf_3DGridTickSeries
        ::freqTextsToTicks()
            { return this->iFreqTextsToTicks; }



void
cf_3DGridTickSeries::freqMajorToMinorTicks( int   iEveryHowManyTicks )
{
    iFreqMajorToMinor_ = iEveryHowManyTicks;
    enumCurrTickSize_ = CF_TICK_MAJOR;
                        // Alternates based on Major/Minor-Freq
}

int
cf_3DGridTickSeries::freqMajorToMinorTicks()
{
    return( iFreqMajorToMinor_ );
}


// Gather (data and virtual) dimension params neccessary to
// convert the raw user-data DATA value into a VIRTUAL value:
void
    cf_3DGridTickSeries
        ::gatherEngineDataVirtRanges()
{
    // NOTE: We are assuming that the parent engine completed a
    // p_cf_engParentEngine_->measureDataMinMax();
    // operation before we make these calls!
    this->dEngVirtXMin  = p_cf_engParentEngine_->measuredVirtXRangeMin();
    this->dEngVirtXMax  = p_cf_engParentEngine_->measuredVirtXRangeMax();
    this->dEngVirtYMin  = p_cf_engParentEngine_->measuredVirtYRangeMin();
    this->dEngVirtYMax  = p_cf_engParentEngine_->measuredVirtYRangeMax();
    this->dEngVirtZMin  = p_cf_engParentEngine_->measuredVirtZRangeMin();
    this->dEngVirtZMax  = p_cf_engParentEngine_->measuredVirtZRangeMax();
                        // The "scale-into" VIRTUAL ranges...

    this->dEngDataXMin  = p_cf_engParentEngine_->measuredDataXRangeMin();
    this->dEngDataXMax  = p_cf_engParentEngine_->measuredDataXRangeMax();
    this->dEngDataYMin  = p_cf_engParentEngine_->measuredDataYRangeMin();
    this->dEngDataYMax  = p_cf_engParentEngine_->measuredDataYRangeMax();
    this->dEngDataZMin  = p_cf_engParentEngine_->measuredDataZRangeMin();
    this->dEngDataZMax  = p_cf_engParentEngine_->measuredDataZRangeMax();
                        // The applicable DATA range...

    this->dEngVirtXDim  = this->dEngVirtXMax - this->dEngVirtXMin;
    this->dEngVirtYDim  = this->dEngVirtYMax - this->dEngVirtYMin;
    this->dEngVirtZDim  = this->dEngVirtZMax - this->dEngVirtZMin;

    this->dEngDataXDim  = this->dEngDataXMax - this->dEngDataXMin;
    this->dEngDataYDim  = this->dEngDataYMax - this->dEngDataYMin;
    this->dEngDataZDim  = this->dEngDataZMax - this->dEngDataZMin;
                        // Calc dimensions used to generate grid/
                        // tick markers to fit the current engine...
    return;
}

//-----------------
// On/Off? Status:
//-----------------
BOOL
    cf_3DGridTickSeries::
        isActive()  
            { return this->bIsActive; }
BOOL
    cf_3DGridTickSeries::
        isActive( BOOL bNewState )
            { return( this->bIsActive = bNewState ); }


//----------------------------------------------------------
// This Virtual member method is REALLY implemented 
// in the DERIVED objects' member methods...
//----------------------------------------------------------
cf_3DTextMarker*
cf_3DGridTickSeries::markAxisAt
                    (   double,     /* dAtUserVal */
                        cf_TickSize /* enumTickSize */ )
{
    // We REALLY want the DERIVED member method to be invoked !!!
    return NULL;
}

cf_3DTextMarker*
    cf_3DGridTickSeries
        ::markAxisAt(   double      dAtUserVal,
                        double      dValueForLabel,
                        cf_TickSize enumTickSize  )
{
    // We're trading-off more function call overhead here
    // for less lines of code and greater maintanability...
    cf_3DTextMarker *p_cf_3dtmNewMarker = this->markAxisAt( dAtUserVal, enumTickSize );
                                // Using the DERIVED member method(s) !!!

    p_cf_3dtmNewMarker->labelNew(   dValueForLabel,
                                    attribTextCurrent()->formatNumPrefer() );
    p_cf_3dtmNewMarker->dispText( TRUE );
    return p_cf_3dtmNewMarker;
}

cf_3DTextMarker*
cf_3DGridTickSeries::markAxisAt
                    (   double      dAtUserVal,
                        const char  *a_cStringForLabel,
                        cf_TickSize enumTickSize  )
{
    // We're trading-off more function call overhead here
    // for less lines of code and greater maintanability...
    cf_3DTextMarker *p_cf_3dtmNewMarker = this->markAxisAt( dAtUserVal, enumTickSize );
                                // Using the DERIVED member method(s) !!!

    // Now use the string ptr (if appropriate) for a label:
    if ( a_cStringForLabel != NULL )
    {
        p_cf_3dtmNewMarker->labelNew( a_cStringForLabel );
        p_cf_3dtmNewMarker->dispText( TRUE );
    }

    return p_cf_3dtmNewMarker;
}


//------------------------------------------
// Manipulate the Axis "Label" Text marker:
//------------------------------------------
cf_3DTextMarker*
    cf_3DGridTickSeries
        ::markerLabel()
            { return p_cf_3dtmAxisLabel_; }
BOOL
    cf_3DGridTickSeries
        ::markerLabelDispHead()
            { return p_cf_3dtmAxisLabel_->dispLineHead(); }
void
    cf_3DGridTickSeries
        ::markerLabelDispHead( BOOL bNewState )
            { p_cf_3dtmAxisLabel_->dispLineHead( bNewState ); }
BOOL
    cf_3DGridTickSeries
        ::markerLabelDispTail()
            { return p_cf_3dtmAxisLabel_->dispLineTail(); }
void
    cf_3DGridTickSeries
        ::markerLabelDispTail( BOOL bNewState )
            { p_cf_3dtmAxisLabel_->dispLineTail( bNewState ); }
BOOL
    cf_3DGridTickSeries
        ::markerLabelDispText()
            { return p_cf_3dtmAxisLabel_->dispText(); }
void
    cf_3DGridTickSeries
        ::markerLabelDispText( BOOL bNewState )
            { p_cf_3dtmAxisLabel_->dispText( bNewState ); }


char* 
    cf_3DGridTickSeries
        ::markerLabelIs()
            { return p_cf_3dtmAxisLabel_->labelIs(); }
void            
    cf_3DGridTickSeries
        ::markerLabelNew( const char *p_csStringForNewLabel )
    { p_cf_3dtmAxisLabel_->labelNew( p_csStringForNewLabel); }

void
    cf_3DGridTickSeries
        ::markerLabelNew( double    dValueForNewLabel )
    { p_cf_3dtmAxisLabel_->labelNew( dValueForNewLabel); }

BOOL
    cf_3DGridTickSeries
        ::markerLabelSet()
            { return p_cf_3dtmAxisLabel_->labelSet(); }
void
    cf_3DGridTickSeries
        ::markerLabelUsing( cf_String *p_cf_strSomeoneElsesLabel )
    { p_cf_3dtmAxisLabel_->labelUsing( p_cf_strSomeoneElsesLabel); }


BOOL
    cf_3DGridTickSeries
        ::markerLabelPositHead( double  dPctWidthFromCtr,
                                double  dPctHeightFromCtr,
                                double  dPctDepthFromCtr )
{ 
    BOOL bStatus = FALSE;   // Init to ERROR state to be safe...
    if ( p_cf_3dtmAxisLabel_ != NULL )
    {   // We'll reset the active marker's HEAD point:
        cf_3DPoint *p_cf_3dpTargetPoint = p_cf_3dtmAxisLabel_->pointToHead();

        bStatus = p_cf_engParentEngine_
                            ->positPointAt( p_cf_3dpTargetPoint,
                                            dPctWidthFromCtr,
                                            dPctHeightFromCtr,
                                            dPctDepthFromCtr );
    }
    return bStatus; // Which (hopefully) is now TRUE!...
}

BOOL
    cf_3DGridTickSeries
        ::markerLabelPositTail( double  dPctWidthFromCtr,
                                double  dPctHeightFromCtr,
                                double  dPctDepthFromCtr )
{
    BOOL bStatus = FALSE;   // Init to ERROR state to be safe...

    if ( p_cf_3dtmAxisLabel_ != NULL )
    {   // We'll reset the active marker's TAIL point:
        cf_3DPoint *p_cf_3dpTargetPoint = p_cf_3dtmAxisLabel_->pointToTail();
        bStatus = p_cf_engParentEngine_
                            ->positPointAt( p_cf_3dpTargetPoint,
                                            dPctWidthFromCtr,
                                            dPctHeightFromCtr,
                                            dPctDepthFromCtr );
    }
    return bStatus; // Which (hopefully) is now TRUE!...
}

BOOL
    cf_3DGridTickSeries
        ::markerLabelPositText( double  dPctWidthFromCtr,
                                double  dPctHeightFromCtr,
                                double  dPctDepthFromCtr )
{
    BOOL bStatus = FALSE;   // Init to ERROR state to be safe...

    if ( p_cf_3dtmAxisLabel_ != NULL )
    {   // We'll reset the active marker's TEXT point:
        cf_3DPoint  *p_cf_3dpTargetPoint = p_cf_3dtmAxisLabel_->pointToText();
        bStatus = p_cf_engParentEngine_
                    ->positPointAt( p_cf_3dpTargetPoint,
                                    dPctWidthFromCtr,
                                    dPctHeightFromCtr,
                                    dPctDepthFromCtr );
    }
    return bStatus; // Which (hopefully) is now TRUE!...
}


int
    cf_3DGridTickSeries
        ::numMarks()
            { return this->iNumMarkAllocs; }
    
void
    cf_3DGridTickSeries
        ::on()
            { this->bIsActive = TRUE; }
void
    cf_3DGridTickSeries
        ::off()
            { this->bIsActive = FALSE; }


void
    cf_3DGridTickSeries
        ::preferTickSizeRatio( double dPreferredPercentVal )
        { this->dTickSizeRatio = (dPreferredPercentVal / 100.0); }


void    
    cf_3DGridTickSeries
        ::reset()
{ 
    // First, get RID of ANY allocated text/markers we new()ed!
    for ( int i = 1; i <= this->iNumMarkAllocs; i++ )
        delete ( (cf_3DTextMarker*) this->da_p_cf_3dtmMarkerArray[ i ] );
    this->iNumMarkAllocs = 0;

    this->p_cf_3dtmMaxTick = NULL;  // Any newly added mark will be a
    this->p_cf_3dtmMinTick = NULL;  // candidate for these to point to...

    return;
}


//-------------------------------------------------------------------
// Make any DATA/RANGE-DEPENDENT (from the Data Model) Range Marks:
//-------------------------------------------------------------------
void
    cf_3DGridTickSeries
        ::updateDataRange(  double  dWithinRangeMin,
                            double  dWithinRangeMax )
{
    // Look before leaping into this routine!
    if ( this->dFreqTicksToRangeValues <= 0.0 ) return;

    //-------------------------------------------------------------
    // Generate Axis Grid/Tick Marks over the range of user Y-Vals
    //-------------------------------------------------------------
    cf_3DTextMarker *p_cf_3dtmOnValue = NULL;

    int     iGridsToTicksAccum = iFreqGridsToTicks;
    int     iTextsToTicksAccum = iFreqTextsToTicks;
    int     iMajorToMinorAccum = iFreqMajorToMinor_;
            // We'll use these local-scoped vars to (re)set
            // grid/tick text-marker attributes

    //=====================================
    // First mark any positive data-range:
    //=====================================
    double  dMarkAt = 0.0;
    BOOL    bMarkedOrigin = FALSE;

    if ( dWithinRangeMax > 0.0 )
    {
        //--------------------------------------------------------------
        // Make the first mark at the origin or the data-range minimum:
        //--------------------------------------------------------------
        if ( dWithinRangeMin > 0.0 )
            dMarkAt = dWithinRangeMin;
        else
            bMarkedOrigin = TRUE;

        p_cf_3dtmOnValue = this->markAxisAt( dMarkAt, dMarkAt, CF_TICK_MAJOR );
        if ( ( ++iMajorToMinorAccum ) >= iFreqMajorToMinor_ ) iMajorToMinorAccum = 0;

        // Set up default grid/tick/text characteristics:
        p_cf_3dtmOnValue->dispLineHead( TRUE );
        p_cf_3dtmOnValue->dispLineTail( FALSE );
        p_cf_3dtmOnValue->dispText( FALSE );

        if ( bDispWithHiddenTicks == TRUE ) p_cf_3dtmOnValue->dispLineHead( FALSE );

        if ( ( iFreqTextsToTicks > 0 ) && ( ++iTextsToTicksAccum >= iFreqTextsToTicks ) )
        {
            p_cf_3dtmOnValue->dispText( TRUE );
            iTextsToTicksAccum = 0;
        }   // Note the (in-expression ++ op) !

        if ( ( iFreqGridsToTicks > 0 ) && ( ++iGridsToTicksAccum >= iFreqGridsToTicks ) )
        {
            p_cf_3dtmOnValue->dispLineTail( TRUE );
            iGridsToTicksAccum = 0;
        }   // Note the (in-expression ++ op) !


        //----------------------------------------------
        // Continue by marking any positive data-range:
        //----------------------------------------------
        while ( dMarkAt < dWithinRangeMax )
        {
            // Consider the (next) grid/tick mark -- AND...
            dMarkAt += this->dFreqTicksToRangeValues;

            // If we have NOT reached the range limit...
            if ( ( dMarkAt < dWithinRangeMax )
                    && ( dMarkAt >= dWithinRangeMin ) )
            {
                // Shall we create a Major, or Minor Tick?
                enumCurrTickSize_ = CF_TICK_MINOR;
                if ( ( iFreqMajorToMinor_ >= 1 ) && ( ++iMajorToMinorAccum >= iFreqMajorToMinor_ ) )
                {
                    enumCurrTickSize_ = CF_TICK_MAJOR;
                    if ( ( iMajorToMinorAccum ) >= iFreqMajorToMinor_ ) iMajorToMinorAccum = 0;
                }

                // Make the mark:
                p_cf_3dtmOnValue = this->markAxisAt( dMarkAt, dMarkAt, enumCurrTickSize_ );

                // Now set grid/tick/text characteristics:
                p_cf_3dtmOnValue->dispLineHead( TRUE );
                p_cf_3dtmOnValue->dispLineTail( FALSE );
                p_cf_3dtmOnValue->dispText( FALSE );// i.e. the default.
                                // the default state.

                if ( this->bDispWithHiddenTicks == TRUE )
                    p_cf_3dtmOnValue->dispLineHead( FALSE );

                if ( ( this->iFreqTextsToTicks > 0 )
                    && ( ++iTextsToTicksAccum >= this->iFreqTextsToTicks ) )
                {
                    p_cf_3dtmOnValue->dispText( TRUE );
                    iTextsToTicksAccum = 0;
                }   // Note the (in-expression ++ op) !

                if ( ( this->iFreqGridsToTicks > 0 )
                    && ( ++iGridsToTicksAccum >= this->iFreqGridsToTicks ) )
                {
                    p_cf_3dtmOnValue->dispLineTail( TRUE );
                    iGridsToTicksAccum = 0;
                }   // Note the (in-expression ++ op) !

            }   // end of screen for mark within limits:
        }   // end of loop UP-TO positive range limit

        //----------------------------------------------------------------
        // Finish by Marking and setting the attribs for the range limit:
        //----------------------------------------------------------------
        enumCurrTickSize_ = CF_TICK_MINOR; // Create a Major, or Minor Tick?
        if ( ( iFreqMajorToMinor_ >= 1 ) && ( ++iMajorToMinorAccum >= iFreqMajorToMinor_ ) )
        {
            enumCurrTickSize_ = CF_TICK_MAJOR;
            if ( ( iMajorToMinorAccum ) >= iFreqMajorToMinor_ ) iMajorToMinorAccum = 0;
        }

        this->p_cf_3dtmMaxTick = this->markAxisAt( dWithinRangeMax, dWithinRangeMax, enumCurrTickSize_ );

        // Now set grid/tick/text characteristics:
        this->p_cf_3dtmMaxTick->dispLineHead( TRUE );
        this->p_cf_3dtmMaxTick->dispLineTail( FALSE );
        this->p_cf_3dtmMaxTick->dispText( FALSE );

        if ( bDispWithHiddenTicks == TRUE ) p_cf_3dtmMaxTick->dispLineHead( FALSE );

        if ( ( iFreqTextsToTicks > 0 ) && ( ++iTextsToTicksAccum >= iFreqTextsToTicks ) )
        {
            p_cf_3dtmMaxTick->dispText( TRUE );
            iTextsToTicksAccum = 0;
        }

        if ( ( this->iFreqGridsToTicks > 0 )
            && ( ++iGridsToTicksAccum >= this->iFreqGridsToTicks ) )
        {
            this->p_cf_3dtmMaxTick->dispLineTail( TRUE );
            iGridsToTicksAccum = 0;
        }

        // Shall we FORCE this Max Tick to display Text?
        if ( bDispForceMaxTickText == TRUE ) p_cf_3dtmMaxTick->dispText( TRUE );

    }   // Pos range (and the pos range limit) now marked.


    //============================================
    // Finish by marking any negative data-range:
    //===========================================
    dMarkAt = 0.0;
    iGridsToTicksAccum = iFreqGridsToTicks;
    iTextsToTicksAccum = iFreqTextsToTicks;
    iMajorToMinorAccum = iFreqMajorToMinor_;    // Reset the accumulators!

    if ( dWithinRangeMin < 0 )
    {
        if ( bMarkedOrigin == TRUE )
        {
            if ( ( ++iMajorToMinorAccum ) >= iFreqMajorToMinor_ ) iMajorToMinorAccum = 0;
            if ( ( ++iGridsToTicksAccum ) >= iFreqGridsToTicks ) iGridsToTicksAccum = 0;
            if ( ( ++iTextsToTicksAccum ) >= iFreqTextsToTicks ) iTextsToTicksAccum = 0;
        }
        else
        {
            //----------------------------------------------------------------
            // Make the first mark at the origin or the data-range (neg) max:
            //----------------------------------------------------------------
            if ( dWithinRangeMax < 0.0 )  dMarkAt = dWithinRangeMax;

            enumCurrTickSize_ = CF_TICK_MINOR; // Create a Major, or Minor Tick?
            if ( ( iFreqMajorToMinor_ >= 1 ) && ( ++iMajorToMinorAccum >= iFreqMajorToMinor_ ) )
            {
                enumCurrTickSize_ = CF_TICK_MAJOR;
                if ( ( iMajorToMinorAccum ) >= iFreqMajorToMinor_ ) iMajorToMinorAccum = 0;
            }

            p_cf_3dtmOnValue = this->markAxisAt( dMarkAt, dMarkAt, CF_TICK_MAJOR );

            // Set up default grid/tick/text characteristics:
            p_cf_3dtmOnValue->dispLineHead( TRUE );
            p_cf_3dtmOnValue->dispLineTail( FALSE );
            p_cf_3dtmOnValue->dispText( FALSE );

            if ( bDispWithHiddenTicks == TRUE ) p_cf_3dtmOnValue->dispLineHead( FALSE );

            if ( ( iFreqTextsToTicks > 0 ) && ( ++iTextsToTicksAccum >= iFreqTextsToTicks ) )
            {
                p_cf_3dtmOnValue->dispText( TRUE );
                iTextsToTicksAccum = 0;
            }   // Note the (in-expression ++ op) !

            if ( ( iFreqGridsToTicks > 0 ) && ( ++iGridsToTicksAccum >= iFreqGridsToTicks ) )
            {
                p_cf_3dtmOnValue->dispLineTail( TRUE );
                iGridsToTicksAccum = 0;
            }   // Note the (in-expression ++ op) !
        }

        //----------------------------------------------
        // Continue by marking any negative data-range:
        //----------------------------------------------
        while ( dMarkAt > dWithinRangeMin )
        {
            // Consider the (next) grid/tick mark -- AND...
            dMarkAt -= this->dFreqTicksToRangeValues;

            // If we have NOT reached the range limit...
            if ( ( dMarkAt > dWithinRangeMin )
                    && ( dMarkAt <= dWithinRangeMax ) )
            {
                // Shall we create a Major, or Minor Tick?
                enumCurrTickSize_ = CF_TICK_MINOR;
                if ( ( iFreqMajorToMinor_ >= 1 ) && ( ++iMajorToMinorAccum >= iFreqMajorToMinor_ ) )
                {
                    enumCurrTickSize_ = CF_TICK_MAJOR;
                    if ( ( iMajorToMinorAccum ) >= iFreqMajorToMinor_ ) iMajorToMinorAccum = 0;
                }

                // Make the mark:
                p_cf_3dtmOnValue = this->markAxisAt( dMarkAt, dMarkAt, enumCurrTickSize_ );

                // Now set grid/tick/text characteristics:
                p_cf_3dtmOnValue->dispLineHead( TRUE );
                p_cf_3dtmOnValue->dispLineTail( FALSE );
                p_cf_3dtmOnValue->dispText( FALSE );// i.e. the default.
                                // the default state.

                if ( this->bDispWithHiddenTicks == TRUE )
                    p_cf_3dtmOnValue->dispLineHead( FALSE );

                if ( ( this->iFreqTextsToTicks > 0 )
                    && ( ++iTextsToTicksAccum >= this->iFreqTextsToTicks ) )
                {
                    p_cf_3dtmOnValue->dispText( TRUE );
                    iTextsToTicksAccum = 0;
                }   // Note the (in-expression ++ op) !

                if ( ( this->iFreqGridsToTicks > 0 )
                    && ( ++iGridsToTicksAccum >= this->iFreqGridsToTicks ) )
                {
                    p_cf_3dtmOnValue->dispLineTail( TRUE );
                    iGridsToTicksAccum = 0;
                }   // Note the (in-expression ++ op) !

            }   // end of screen for mark within limits:
        }   // end of loop DOWN-TO negative range limit


        // Mark and set the attribs for the range limit:

        // Shall we create a Major, or Minor Tick?
        enumCurrTickSize_ = CF_TICK_MINOR;
        if ( ( iFreqMajorToMinor_ >= 1 ) && ( ++iMajorToMinorAccum >= iFreqMajorToMinor_ ) )
        {
            enumCurrTickSize_ = CF_TICK_MAJOR;
            if ( ( iMajorToMinorAccum ) >= iFreqMajorToMinor_ ) iMajorToMinorAccum = 0;
        }

        // Make the mark:
        this->p_cf_3dtmMinTick
                = this->markAxisAt( dWithinRangeMin, dWithinRangeMin, enumCurrTickSize_ );

        // Now set grid/tick/text characteristics:
        this->p_cf_3dtmMinTick->dispLineHead( TRUE );
        this->p_cf_3dtmMinTick->dispLineTail( FALSE );
        this->p_cf_3dtmMinTick->dispText( FALSE );// i.e. the default.
                            // the default state.

        if ( this->bDispWithHiddenTicks == TRUE )
            this->p_cf_3dtmMinTick->dispLineHead( FALSE );

        if ( ( this->iFreqTextsToTicks > 0 )
            && ( ++iTextsToTicksAccum >= this->iFreqTextsToTicks ) )
        {
            this->p_cf_3dtmMinTick->dispText( TRUE );
            iTextsToTicksAccum = 0;
        }   // Note the (in-expression ++ op) !

        if ( ( this->iFreqGridsToTicks > 0 )
            && ( ++iGridsToTicksAccum >= this->iFreqGridsToTicks ) )
        {
            this->p_cf_3dtmMinTick->dispLineTail( TRUE );
            iGridsToTicksAccum = 0;
        }   // Note the (in-expression ++ op) !

        // Shall we FORCE this Min Tick to display Text?
        if ( this->bDispForceMinTickText == TRUE )
                this->p_cf_3dtmMinTick->dispText( TRUE );

    }   // Neg range (and the neg range limit) now marked.

    return;

}   // end of cf_3DGridTickSeries::updateDataRange( min, max )


void
cf_3DGridTickSeries::updateFromDataGroupsList
                    ( cf_ChartModel *p_cf_cmodlDataSource )
{
    // Get information on the current list of data-groups:
    cf_DataGroup *p_cf_dgGroupsList = p_cf_cmodlDataSource->accessGroupsList();
    int iNumItems = p_cf_dgGroupsList->numItems();

    int iGridsToTicksAccum = this->iFreqGridsToTicks;
    int iTextsToTicksAccum = this->iFreqTextsToTicks;

    for ( int i = 1; i <= iNumItems; i ++ )
    {
        // We will use the domain item to generate our tick-mark:
        cf_XYZ *p_cf_xyzAccessItem = p_cf_dgGroupsList->activateXYZValAt( i );

        // place the grid/tick at the specified axis location...
        double dIndexValue = p_cf_xyzAccessItem->z();
        cf_3DTextMarker *p_cf_3dtmFromItem = this->markAxisAt( dIndexValue, enumCurrTickSize_ );

        //... and either RE_USE the label/string from the model...
        if ( p_cf_xyzAccessItem->labelSet() == TRUE )
            p_cf_3dtmFromItem->labelUsing( p_cf_xyzAccessItem->labelIs() );
        else    // or generate a NEW value mark:
            p_cf_3dtmFromItem->labelNew( dIndexValue );

        // Now set grid/tick/text characteristics:
        p_cf_3dtmFromItem->dispLineHead( TRUE );
        p_cf_3dtmFromItem->dispLineTail( FALSE );
        p_cf_3dtmFromItem->dispText( FALSE );

        if ( this->bDispWithHiddenTicks == TRUE )
            p_cf_3dtmFromItem->dispLineHead( FALSE );

        if ( ( this->iFreqTextsToTicks > 0 )
            && ( ++iTextsToTicksAccum >= this->iFreqTextsToTicks ) )
        {
            p_cf_3dtmFromItem->dispText( TRUE );
            iTextsToTicksAccum = 0;
        }   // Note the (in-expression ++ op) !

        if ( ( this->iFreqGridsToTicks > 0 )
            && ( ++iGridsToTicksAccum >= this->iFreqGridsToTicks ) )
        {
            p_cf_3dtmFromItem->dispLineTail( TRUE );
            iGridsToTicksAccum = 0;
        }   // Note the (in-expression ++ op) !

    }

}   // end of cf_3DGridTickSeries::updateFromDataGroupsList( model* )




void
cf_3DGridTickSeries::updateFromDomainItems
                    ( cf_ChartModel *p_cf_cmodlDataSource )
{
    // Look before leaping into this routine!
    if ( this->iFreqTicksToDomainItems <= 0 ) return;

    // Get information on the current domain:
    cf_DataGroup *p_cf_dgDomainItems = p_cf_cmodlDataSource->accessDomainItems();

    int iNumDomainItems = p_cf_dgDomainItems->numItems();

    // Try NOT to cram TOO many ticks into the base line:
    if ( this->bUsePrefModelDomainFactor == TRUE )
        this->freqTicksFromDomainFactor(    p_cf_cmodlDataSource,
                                            this->iPrefModelDomainFactor );

    //------------------------------------------------
    // Generate Axis Grid/Tick Marks that ATTEMPT
    // to RE-USE the parent model's EXISTING labels:
    //------------------------------------------------
    cf_XYZ              *p_cf_xyzAccessItem = NULL;
    double              dIndexValue = 0.0;
    cf_3DTextMarker     *p_cf_3dtmFromItem = NULL;

    int iGridsToTicksAccum = this->iFreqGridsToTicks;
    int iTextsToTicksAccum = this->iFreqTextsToTicks;
    int iMajorToMinorAccum = iFreqMajorToMinor_;

    for ( int i = 1; i <= iNumDomainItems; i += this->iFreqTicksToDomainItems )
    {
        // We will use the domain item to generate our tick-mark:
        p_cf_xyzAccessItem = p_cf_dgDomainItems->activateXYZValAt( i );

        // Init the tick-mark value according to the current index mode:
        if ( p_cf_cmodlDataSource->dataIndexMethod() == CF_INDEX_USR_X )
            dIndexValue = p_cf_xyzAccessItem->x();
        else if ( p_cf_cmodlDataSource->dataIndexMethod() == CF_INDEX_INT_I )
            dIndexValue = (double) ( i - 1 );
        else
            dIndexValue = (double) i;
            // because the dataIndexMethod() == CF_INDEX_NAT_N

        // Shall we create a Major, or Minor Tick?
        enumCurrTickSize_ = CF_TICK_MINOR;
        if ( ( iFreqMajorToMinor_ >= 1 ) && ( ++iMajorToMinorAccum >= iFreqMajorToMinor_ ) )
        {
            enumCurrTickSize_ = CF_TICK_MAJOR;
            if ( ( iMajorToMinorAccum ) >= iFreqMajorToMinor_ ) iMajorToMinorAccum = 0;
        }

        // Make the mark:
        p_cf_3dtmFromItem = this->markAxisAt( dIndexValue, enumCurrTickSize_ );

        //... and either RE_USE the label/string from the model...
        if ( p_cf_xyzAccessItem->labelSet() == TRUE )
            p_cf_3dtmFromItem->labelUsing( p_cf_xyzAccessItem->labelIs() );
        else    // or generate a NEW value mark:
            p_cf_3dtmFromItem->labelNew( dIndexValue );

        // Now set grid/tick/text characteristics:
        p_cf_3dtmFromItem->dispLineHead( TRUE );
        p_cf_3dtmFromItem->dispLineTail( FALSE );
        p_cf_3dtmFromItem->dispText( FALSE );// i.e. the default.
                        // the default state.

        if ( this->bDispWithHiddenTicks == TRUE )
            p_cf_3dtmFromItem->dispLineHead( FALSE );

        if ( ( this->iFreqTextsToTicks > 0 )
            && ( ++iTextsToTicksAccum >= this->iFreqTextsToTicks ) )
        {
            p_cf_3dtmFromItem->dispText( TRUE );
            iTextsToTicksAccum = 0;
        }   // Note the (in-expression ++ op) !

        if ( ( this->iFreqGridsToTicks > 0 )
            && ( ++iGridsToTicksAccum >= this->iFreqGridsToTicks ) )
        {
            p_cf_3dtmFromItem->dispLineTail( TRUE );
            iGridsToTicksAccum = 0;
        }   // Note the (in-expression ++ op) !
    }

    // Integer-I Bar/Col/Stack-Charts *MAY* require an extra tick-mark!
    if ( p_cf_cmodlDataSource->dataIndexMethod() == CF_INDEX_INT_I )
        if ( p_cf_engParentEngine_->chartTypeBarColStackIs() == TRUE )
        {
            if ( iNumDomainItems > p_cf_dgDomainItems->dataXMax() )
            {
                // Shall we create a Major, or Minor Tick?
                enumCurrTickSize_ = CF_TICK_MINOR;
                if ( ( iFreqMajorToMinor_ >= 1 ) && ( ++iMajorToMinorAccum >= iFreqMajorToMinor_ ) )
                {
                    enumCurrTickSize_ = CF_TICK_MAJOR;
                    if ( ( iMajorToMinorAccum ) >= iFreqMajorToMinor_ ) iMajorToMinorAccum = 0;
                }

                // Make the mark:
                p_cf_3dtmFromItem = this->markAxisAt( iNumDomainItems, enumCurrTickSize_ );
                p_cf_3dtmFromItem->dispLineHead( TRUE );
                p_cf_3dtmFromItem->labelNew( iNumDomainItems );
            }
        }

    // Shall we force the Max Tick to display Text?
    if ( this->bDispForceMaxTickText == TRUE )
        if ( p_cf_3dtmFromItem != NULL )
            p_cf_3dtmFromItem->dispText( TRUE );

    // Re-set our main axis-label according to the data-group:
/*
    cf_DataGroup *p_cf_dgForTitle
                    = p_cf_cmodlDataSource->accessDomainItems();
    this->markerLabelUsing( p_cf_dgForTitle->labelIs() );
  */

}   // end of cf_3DGridTickSeries::updateFromDomainItems()



//------------------------------------------------------------
// Make any USER-SPECIFIED (from the Data Model) Range Marks:
//------------------------------------------------------------
void
cf_3DGridTickSeries::updateFromRangeValues
                    ( cf_ChartModel *p_cf_cmodlDataSource )
{
    // Get the current chart data-value ranges:
    double  dWithinRangeMax
            = p_cf_cmodlDataSource->dataYValuesMax();
            //= p_cf_engParentEngine_->measuredDataYRangeMax();

    double  dWithinRangeMin
            = p_cf_cmodlDataSource->dataYValuesMin();
            //= p_cf_engParentEngine_->measuredDataYRangeMin();

    // Try NOT to cram TOO many ticks into the base line:
    if ( this->bUsePrefModelRangeFactor == TRUE )
        this->freqTicksFromRangeFactor( p_cf_cmodlDataSource,
                                        this->iPrefModelRangeFactor );

    // We'll use these vars to examine/update data groups,
    // individual data items/values, and grid/tick marks...
    cf_DataGroup    *p_cf_dgRangeItems
                    = p_cf_cmodlDataSource->accessRangeValues();

    cf_XYZ          *p_cf_xyzAccessItem = NULL;
    double          dMarkAt = 0.0;
    cf_3DTextMarker *p_cf_3dtmOnValue = NULL;

    // Is there anything there?
    int iNumRangeItems = p_cf_dgRangeItems->numItems();
    if ( iNumRangeItems > 0 )
    {
        //...then render it!
        cf_XYZ  *p_cf_xyzAccessItem = NULL;
        int     iGridsToTicksAccum = this->iFreqGridsToTicks;
        int     iTextsToTicksAccum = this->iFreqTextsToTicks;
        int     iMajorToMinorAccum = iFreqMajorToMinor_;

        for ( int i = 1; i <= iNumRangeItems; i++ )
        {
            // Is it WITHIN our current range limits?
            p_cf_xyzAccessItem = p_cf_dgRangeItems->activateXYZValAt( i );
            dMarkAt = p_cf_xyzAccessItem->y();

            if ( ( dWithinRangeMin <= dMarkAt )
                && ( dMarkAt <= dWithinRangeMax ) )
            {
                // place the grid/tick at the specified axis location...

                // Shall we create a Major, or Minor Tick?
                enumCurrTickSize_ = CF_TICK_MINOR;
                if ( ( iFreqMajorToMinor_ >= 1 ) && ( ++iMajorToMinorAccum >= iFreqMajorToMinor_ ) )
                {
                    enumCurrTickSize_ = CF_TICK_MAJOR;
                    if ( ( iMajorToMinorAccum ) >= iFreqMajorToMinor_ ) iMajorToMinorAccum = 0;
                }

                // Make the mark:
                p_cf_3dtmOnValue = this->markAxisAt( dMarkAt, enumCurrTickSize_ );

                //... and RE USE any label/string from the model...
                if ( p_cf_xyzAccessItem->labelSet() == TRUE )
                    p_cf_3dtmOnValue
                            ->labelUsing( p_cf_xyzAccessItem->labelIs() );
                else    // or generate a NEW value mark:
                    p_cf_3dtmOnValue->labelNew( dMarkAt );

                // Now set grid/tick/text characteristics:
                p_cf_3dtmOnValue->dispLineHead( TRUE );
                p_cf_3dtmOnValue->dispLineTail( FALSE );
                p_cf_3dtmOnValue->dispText( FALSE );// i.e. the default.

                if ( this->bDispWithHiddenTicks == TRUE )
                    p_cf_3dtmOnValue->dispLineHead( FALSE );

                if ( ( this->iFreqTextsToTicks > 0 )
                    && ( ++iTextsToTicksAccum >= this->iFreqTextsToTicks ) )
                {
                    p_cf_3dtmOnValue->dispText( TRUE );
                    iTextsToTicksAccum = 0;
                }   // Note the (in-expression ++ op) !

                if ( ( this->iFreqGridsToTicks > 0 )
                    && ( ++iGridsToTicksAccum >= this->iFreqGridsToTicks ) )
                {
                    p_cf_3dtmOnValue->dispLineTail( TRUE );
                    iGridsToTicksAccum = 0;
                }   // Note the (in-expression ++ op) !

            }   // Dome with making a mark.
        }   // Done with the for-loop.
    }   // Done making any USER-SPECIFIED Range Marks:

    // Re-set our main axis-label according to the data-group:
/*
    cf_DataGroup *p_cf_dgForTitle
                    = p_cf_cmodlDataSource->accessRangeValues();
    this->markerLabelUsing( p_cf_dgForTitle->labelIs() );
 */
}   // end of cf_3DGridTickSeries::updateFromRangeValues()


void
cf_3DGridTickSeries::updateFromRangeValSums
                    ( cf_ChartModel *p_cf_cmodlDataSource )
{
    // Get the current chart data-value ranges:
    double  dWithinRangeMax
                = p_cf_cmodlDataSource->dataYValSumsMax();
    double  dWithinRangeMin
                = p_cf_cmodlDataSource->dataYValSumsMin();

    // Try NOT to cram TOO many ticks into the base line:
    if ( this->bUsePrefModelRangeFactor == TRUE )
        this->freqTicksFromRangeSumFactor(  p_cf_cmodlDataSource,
                                            this->iPrefModelRangeFactor );

    // We'll use these vars to examine/update data groups,
    // individual data items/values, and grid/tick marks...
    cf_DataGroup    *p_cf_dgRangeItems
                    = p_cf_cmodlDataSource->accessRangeValues();

    cf_XYZ          *p_cf_xyzAccessItem = NULL;
    double          dMarkAt = 0.0;
    cf_3DTextMarker *p_cf_3dtmOnValue = NULL;

    // Is there anything there?
    int iNumRangeItems = p_cf_dgRangeItems->numItems();
    if ( iNumRangeItems > 0 )
    {
        //...then render it!
        cf_XYZ  *p_cf_xyzAccessItem = NULL;
        int     iGridsToTicksAccum = this->iFreqGridsToTicks;
        int     iTextsToTicksAccum = this->iFreqTextsToTicks;
        int     iMajorToMinorAccum = iFreqMajorToMinor_;

        for ( int i = 1; i <= iNumRangeItems; i++ )
        {
            // Is it WITHIN our current range limits?
            p_cf_xyzAccessItem = p_cf_dgRangeItems->activateXYZValAt( i );
            dMarkAt += p_cf_xyzAccessItem->y();

            if ( ( dWithinRangeMin <= dMarkAt )
                && ( dMarkAt <= dWithinRangeMax ) )
            {
                // place the grid/tick at the specified axis location...

                // Shall we create a Major, or Minor Tick?
                enumCurrTickSize_ = CF_TICK_MINOR;
                if ( ( iFreqMajorToMinor_ >= 1 ) && ( ++iMajorToMinorAccum >= iFreqMajorToMinor_ ) )
                {
                    enumCurrTickSize_ = CF_TICK_MAJOR;
                    if ( ( iMajorToMinorAccum ) >= iFreqMajorToMinor_ ) iMajorToMinorAccum = 0;
                }

                // Make the mark:
                p_cf_3dtmOnValue = this->markAxisAt( dMarkAt, enumCurrTickSize_ );

                //... and RE USE any label/string from the model...
                if ( p_cf_xyzAccessItem->labelSet() == TRUE )
                    p_cf_3dtmOnValue
                            ->labelUsing( p_cf_xyzAccessItem->labelIs() );
                else    // or generate a NEW value mark:
                    p_cf_3dtmOnValue->labelNew( dMarkAt );

                // Now set grid/tick/text characteristics:
                p_cf_3dtmOnValue->dispLineHead( TRUE );
                p_cf_3dtmOnValue->dispLineTail( FALSE );
                p_cf_3dtmOnValue->dispText( FALSE );// i.e. the default.

                if ( this->bDispWithHiddenTicks == TRUE )
                    p_cf_3dtmOnValue->dispLineHead( FALSE );

                if ( ( this->iFreqTextsToTicks > 0 )
                    && ( ++iTextsToTicksAccum >= this->iFreqTextsToTicks ) )
                {
                    p_cf_3dtmOnValue->dispText( TRUE );
                    iTextsToTicksAccum = 0;
                }   // Note the (in-expression ++ op) !

                if ( ( this->iFreqGridsToTicks > 0 )
                    && ( ++iGridsToTicksAccum >= this->iFreqGridsToTicks ) )
                {
                    p_cf_3dtmOnValue->dispLineTail( TRUE );
                    iGridsToTicksAccum = 0;
                }   // Note the (in-expression ++ op) !

            }   // Dome with making a mark.
        }   // Done with the for-loop.
    }   // Done making any USER-SPECIFIED Range Marks:

    // Re-set our main axis-label according to the data-group:
/*
    cf_DataGroup *p_cf_dgForTitle
                    = p_cf_cmodlDataSource->accessRangeValues();
    this->markerLabelUsing( p_cf_dgForTitle->labelIs() );
  */
}   // end of cf_3DGridTickSeries::updateFromRangeValSums()



//------------------------------------------------------
// Make any AUTOMATIC Range Marks (from the Data Model):
//------------------------------------------------------
void
cf_3DGridTickSeries::updateOverDataRange
                    ( cf_ChartModel *p_cf_cmodlDataSource )
{
    // Get the current chart data-value ranges:
    double  dCurrentRangeMax
            = p_cf_cmodlDataSource->dataYValuesMax();
            //= p_cf_engParentEngine_->measuredDataYRangeMax();

    double  dCurrentRangeMin
            = p_cf_cmodlDataSource->dataYValuesMin();
            //= p_cf_engParentEngine_->measuredDataYRangeMin();

    // Try NOT to cram TOO many ticks into the base line:
    if ( this->bUsePrefModelRangeFactor == TRUE )
        this->freqTicksFromRangeFactor( p_cf_cmodlDataSource,
                                        this->iPrefModelRangeFactor );

    // Make any DATA/RANGE-DEPENDENT (from the Data Model) Range Marks:
    this->updateDataRange( dCurrentRangeMin, dCurrentRangeMax );

    // Re-set our main axis-label according to the data-group:
/*
    cf_DataGroup *p_cf_dgForTitle
                    = p_cf_cmodlDataSource->accessRangeValues();
    this->markerLabelUsing( p_cf_dgForTitle->labelIs() );
  */
}   // end of cf_3DGridTickSeries::updateOverDataRange()

void
cf_3DGridTickSeries::updateOverDataRangeSums
                    ( cf_ChartModel *p_cf_cmodlDataSource )
{
    // Get the current chart data-value ranges:
    double  dCurrentRangeMax
            = p_cf_cmodlDataSource->dataYValSumsMax();
            //= p_cf_engParentEngine_->measuredDataYRangeMax();

    double  dCurrentRangeMin
            = p_cf_cmodlDataSource->dataYValSumsMin();
            //= p_cf_engParentEngine_->measuredDataYRangeMin();

    // Try NOT to cram TOO many ticks into the base line:
    if ( this->bUsePrefModelRangeFactor == TRUE )
        this->freqTicksFromRangeSumFactor(  p_cf_cmodlDataSource,
                                            this->iPrefModelRangeFactor );

    // Make any DATA/RANGE-DEPENDENT (from the Data Model) Range Marks:
    this->updateDataRange( dCurrentRangeMin, dCurrentRangeMax );

    // Re-set our main axis-label according to the data-group:
/*
    cf_DataGroup *p_cf_dgForTitle
                    = p_cf_cmodlDataSource->accessRangeValues();
    this->markerLabelUsing( p_cf_dgForTitle->labelIs() );
  */
}   // end of cf_3DGridTickSeries::updateOverDataRangeSums()



//------------------------------
// Manipulate update behaviors:
//------------------------------
BOOL
cf_3DGridTickSeries::useDataGroupsListIs()
                    { return this->bUseDataGroupsList; }
BOOL
cf_3DGridTickSeries::useDataRangeIs()
                    { return this->bUseDataRange; }
BOOL
cf_3DGridTickSeries::useDataRangeSumsIs()
                    { return this->bUseDataRangeSums; }
BOOL
cf_3DGridTickSeries::useDomainItemsIs()
                    { return this->bUseDomainItems; }
BOOL
cf_3DGridTickSeries::useRangeValuesIs()
                    { return this->bUseRangeValues; }
BOOL
cf_3DGridTickSeries::useRangeValSumsIs()
                    { return this->bUseRangeValSums; }


void
cf_3DGridTickSeries::useNoUpdateSource()
{
    this->bUseDataGroupsList = FALSE;
    this->bUseDataRange     = FALSE;
    this->bUseDataRangeSums = FALSE;
    this->bUseDomainItems   = FALSE;
    this->bUseRangeValues   = FALSE;
    this->bUseRangeValSums  = FALSE;
    return;
}


void
cf_3DGridTickSeries::useDataGroupsList
                    ( BOOL bNewState )
{
    this->bUseDataGroupsList = bNewState;

    if ( this->bUseDataGroupsList == TRUE )
    {   // Update mutual exculsions!
        this->bUseDataRange     = FALSE;
        this->bUseDataRangeSums = FALSE;
        this->bUseDomainItems   = FALSE;
        this->bUseRangeValues   = FALSE;
        this->bUseRangeValSums  = FALSE;
    }
    return;
}


void
cf_3DGridTickSeries::useDataRange
                    ( BOOL bNewState )
{
    this->bUseDataRange = bNewState;

    if ( this->bUseDataRange == TRUE )
    {   // Update mutual exculsions!
        this->bUseDomainItems   = FALSE;
        this->bUseDataRangeSums = FALSE;
        this->bUseDataGroupsList = FALSE;
    }
    return;
}

void
cf_3DGridTickSeries::useDataRangeSums
                    ( BOOL bNewState )
{
    this->bUseDataRangeSums = bNewState;

    if ( this->bUseDataRangeSums == TRUE )
    {   // Update mutual exculsions!
        this->bUseDomainItems = FALSE;
        this->bUseDataRange   = FALSE;
        this->bUseDataGroupsList = FALSE;
    }
    return;
}



void
cf_3DGridTickSeries::useDomainItems
                    ( BOOL bNewState )
{
    this->bUseDomainItems = bNewState;

    if ( this->bUseDomainItems == TRUE )
    {   // Also update mutual exculsions!
        this->bUseDataRange     = FALSE;
        this->bUseDataRangeSums = FALSE;
        this->bUseRangeValues   = FALSE;
        this->bUseRangeValSums  = FALSE;
        this->bUseDataGroupsList = FALSE;
    }
}


void
cf_3DGridTickSeries::useRangeValues
                    ( BOOL bNewState )
{
    this->bUseRangeValues = bNewState;

    if ( this->bUseRangeValues == TRUE )
    {   // Update mutual exculsions!
        this->bUseDataRangeSums = FALSE;
        this->bUseDomainItems   = FALSE;
        this->bUseRangeValSums  = FALSE;
        this->bUseDataGroupsList = FALSE;
    }

}

void
cf_3DGridTickSeries::useRangeValSums
                    ( BOOL bNewState )
{
    this->bUseRangeValSums = bNewState;

    if ( this->bUseRangeValSums == TRUE )
    {   // update mutual exculsions!
        this->bUseDataRange   = FALSE;
        this->bUseDomainItems = FALSE;
        this->bUseRangeValues = FALSE;
        this->bUseDataGroupsList = FALSE;
    }
}


//-----------------------------------------------------
// End of class cf_3DGridTickSeries Implementation:
//-----------------------------------------------------

//=========================================================
// Implement specialized derivations of the
// Chart Framework "Grid/Tick Mark Series" BASE class
// (above) which have specific behaviors:
//=========================================================

//--------------------------------------------------------------
// Implement a specialized derivation of the "Grid/Tick
// Mark Series" BASE class with specific behavior for
// the Upper X-Axis:
//--------------------------------------------------------------
cf_3DGTS_AutoMarkBackFaceX
    ::cf_3DGTS_AutoMarkBackFaceX( cf_ChartEngine *p_cf_engINowBelongTo )
        : cf_3DGridTickSeries( p_cf_engINowBelongTo )
{
    enumCurrAxisType_ = CF_AXIS_X_BACK;
    //p_cf_3dtmAxisLabel_->labelNew( "[back-face X-Axis]" );
/*
    p_cf_3dtmAxisLabel_->attribTextCurrent()->shiftHorzRight();
    this->markerLabelPositText( -100.0,     // pct "WidthFromCtr"
                                 120.0,     // pct "HeightFromCtr"
                                -100.0 );   // pct "DepthFromCtr"
    attribTextCurrent()->shiftVertUp();
    */
}

cf_3DGTS_AutoMarkBackFaceX
    ::~cf_3DGTS_AutoMarkBackFaceX()
        {}

cf_3DTextMarker*
cf_3DGTS_AutoMarkBackFaceX::markAxisAt
                        (   double      dAtUserVal,
                            cf_TickSize enumTickSize  )
{
    // Compute scale params neccessary to convert the RAW
    // user-DATA parameter into a VIRTUAL tick mark value:
    double  dScaleFactor = 1.0;  // Start with a harmless default.

    if ( fabs( this->dEngDataXDim ) > CF_NUM_ZERO_IF_LT )
            dScaleFactor = this->dEngVirtXDim / this->dEngDataXDim;
            // Then see if it's OK to modify.

    if ( fabs( this->dScaleFacX ) > CF_NUM_ZERO_IF_LT )
            dScaleFactor = dScaleFactor / this->dScaleFacX;
            // Compensate for the scaled state of THIS object!

    // Create and Initialize defining points for the mark:
    double  dVirtualAxisValue = - this->dEngDataXMin * dScaleFactor
                                    +  dAtUserVal * dScaleFactor;
                                    // according to the current virt/
                                    // data scale ratios of the chart.

    double  dVirtGridLength = this->dEngVirtYDim;
    double  dVirtTickLength = this->dEngVirtYDim * this->dTickSizeRatio;
    if ( bDispWithInvertedTicks_ ) dVirtTickLength = - dVirtTickLength;
    if ( enumTickSize == CF_TICK_MINOR ) dVirtTickLength = dVirtTickLength / 2.0;

    cf_3DPoint  *p_cf_3dpNewTailPoint
                = new cf_3DPoint(   dVirtualAxisValue,
                                    0.0,
                                    0.0 );
    cf_3DPoint  *p_cf_3dpNewHeadPoint
                = new cf_3DPoint(   dVirtualAxisValue,
                                    dVirtGridLength,
                                    0.0 );
    cf_3DPoint  *p_cf_3dpNewTextPoint
                = new cf_3DPoint(   dVirtualAxisValue,
                                    dVirtGridLength + dVirtTickLength,
                                    0.0 );

    // Create a new grid/tick mark in the dynamic array of
    // grid/tick marks, and match its attributes to this
    // grid/tick series'es attributes:
    cf_3DTextMarker *p_cf_3dtmNewMarker
                    = cf_3DGridTickSeries
                        ::addAxisMarker(    p_cf_3dpNewTailPoint,
                                            p_cf_3dpNewHeadPoint,
                                            p_cf_3dpNewTextPoint );
                    // Using the UNIFORM BASE CLASS METHOD !!!

    p_cf_3dtmNewMarker->dispInverted( bDispWithInvertedTicks_ );

    // Return a pointer to the new text marker so the
    // caller can make further mods to it if needed...
    return p_cf_3dtmNewMarker;

}   // end of cf_3DGTS_AutoMarkBackFaceX::markAxisAt(...)
    // End of class cf_3DGTS_AutoMarkBackFaceX implementation.



//--------------------------------------------------------------
// Implement a specialized derivation of the "Grid/Tick
// Mark Series" BASE class with specific behavior for
// the Lower X-Axis:
//--------------------------------------------------------------
cf_3DGTS_AutoMarkBottomFaceX
    ::cf_3DGTS_AutoMarkBottomFaceX( cf_ChartEngine *p_cf_engINowBelongTo )
        : cf_3DGridTickSeries( p_cf_engINowBelongTo )
{
    enumCurrAxisType_ = CF_AXIS_X_BOTTOM;
    // Set up the series attribs:
    // p_cf_3dtmAxisLabel_->labelNew( "[bottom-face X-Axis]" );
/*
    p_cf_3dtmAxisLabel_->attribTextCurrent()->shiftHorzCtr();
    p_cf_3dtmAxisLabel_->attribTextCurrent()->shiftVertDown();
    this->markerLabelPositText(  -50.0,     // pct "WidthFromCtr"
                                -125.0,     // pct "HeightFromCtr"
                                 100.0 );   // pct "DepthFromCtr"
    attribTextCurrent()->shiftVertDown();
    */
}

cf_3DGTS_AutoMarkBottomFaceX
    ::~cf_3DGTS_AutoMarkBottomFaceX()
        {}

cf_3DTextMarker*
cf_3DGTS_AutoMarkBottomFaceX::markAxisAt
                        (   double      dAtUserVal,
                            cf_TickSize enumTickSize  )
{
    // Compute scale params neccessary to convert the RAW
    // user-DATA parameter into a VIRTUAL tick mark value:
    double  dScaleFactor = 1.0;  // Start with a harmless default.

    #ifdef CF_ASSERT_DVALS
    assert( fabs( this->dEngDataXDim ) > CF_NUM_ZERO_IF_LT );
    assert( fabs( this->dScaleFacX ) > CF_NUM_ZERO_IF_LT );
    #endif

    if ( fabs( this->dEngDataXDim ) > CF_NUM_ZERO_IF_LT )
            dScaleFactor = this->dEngVirtXDim / this->dEngDataXDim;
            // Then see if it's OK to modify.

    if ( fabs( this->dScaleFacX ) > CF_NUM_ZERO_IF_LT )
            dScaleFactor = dScaleFactor / this->dScaleFacX;
            // Compensate for the scaled state of THIS object!

    // Create and Initialize defining points for the mark:
    double  dVirtualAxisValue = - this->dEngDataXMin * dScaleFactor
                                    +  dAtUserVal * dScaleFactor;
                                    // according to the current virt/
                                    // data scale ratios of the chart.

    double  dVirtGridLength = this->dEngVirtZDim;
    double  dVirtTickLength = this->dEngVirtYDim * this->dTickSizeRatio;
    if ( bDispWithInvertedTicks_ ) dVirtTickLength = - dVirtTickLength;
    if ( enumTickSize == CF_TICK_MINOR ) dVirtTickLength = dVirtTickLength / 2.0;

    cf_3DPoint  *p_cf_3dpNewTailPoint
                = new cf_3DPoint(   dVirtualAxisValue,
                                    0.0,
                                    0.0 );
    cf_3DPoint  *p_cf_3dpNewHeadPoint
                = new cf_3DPoint(   dVirtualAxisValue,
                                    0.0,
                                    dVirtGridLength );
    cf_3DPoint  *p_cf_3dpNewTextPoint
                = new cf_3DPoint(   dVirtualAxisValue,
                                    - dVirtTickLength,
                                    dVirtGridLength );

    // Create a new grid/tick mark in the dynamic array of
    // grid/tick marks, and match its attributes to this
    // grid/tick series'es attributes:
    cf_3DTextMarker *p_cf_3dtmNewMarker
                    = cf_3DGridTickSeries
                        ::addAxisMarker(    p_cf_3dpNewTailPoint,
                                            p_cf_3dpNewHeadPoint,
                                            p_cf_3dpNewTextPoint );
                    // Using the UNIFORM BASE CLASS METHOD !!!

    p_cf_3dtmNewMarker->dispInverted( bDispWithInvertedTicks_ );

    // Return a pointer to the new text marker so the
    // caller can make further mods to it if needed...
    return p_cf_3dtmNewMarker;

}   // end of cf_3DGTS_AutoMarkBottomFaceX::markAxisAt(...)
    // End of class cf_3DGTS_AutoMarkBottomFaceX implementation.


//--------------------------------------------------------------
// Implement a specialized derivation of the "Grid/Tick
// Mark Series" BASE class with specific behavior for
// the Left Y-Axis:
//--------------------------------------------------------------
cf_3DGTS_AutoMarkLeftFaceY
    ::cf_3DGTS_AutoMarkLeftFaceY( cf_ChartEngine *p_cf_engINowBelongTo )
        : cf_3DGridTickSeries( p_cf_engINowBelongTo )
{
    enumCurrAxisType_ = CF_AXIS_Y_LEFT;
    // Set up the label for this GTS:
    //p_cf_3dtmAxisLabel_->labelNew( "[left-face Y-Axis]" );
/*
    this->markerLabelPositText( -120.0,     // pct "WidthFromCtr"
                                -100.0,     // pct "HeightFromCtr"
                                 110.0 );   // pct "DepthFromCtr"

    // Set up the series attribs:
    this->useDataRange( TRUE );
    this->useRangeValues( TRUE );

    attribTextCurrent()->shiftHorzLeft();

    this->iFreqGridsToTicks = 2;
    this->iFreqTextsToTicks = 1;

    // Place the Axis Label according to most widely-used context:
    p_cf_3dtmAxisLabel_->attribTextCurrent()->angleRotationPrefer( 90 );
//  p_cf_3dtmAxisLabel_->attribTextCurrent()->textShiftHorzLeft();
            // Run the Y-axis label vertically UPWARDS, But use a LEFT
            // displacement, in case rotation does not work correctly.
*/
}

cf_3DGTS_AutoMarkLeftFaceY
    ::~cf_3DGTS_AutoMarkLeftFaceY()
        {}


cf_3DTextMarker*
cf_3DGTS_AutoMarkLeftFaceY::markAxisAt
                        (   double      dAtUserVal,
                            cf_TickSize enumTickSize  )
{
    // Compute scale params neccessary to convert the RAW
    // user-DATA parameter into a VIRTUAL tick mark value:
    double  dScaleFactor = 1.0;  // Start with a harmless default.

    if ( fabs( this->dEngDataYDim ) > CF_NUM_ZERO_IF_LT )
            dScaleFactor = this->dEngVirtYDim / this->dEngDataYDim;
            // Then see if it's OK to modify.

    if ( fabs( this->dScaleFacY ) > CF_NUM_ZERO_IF_LT )
            dScaleFactor = dScaleFactor / this->dScaleFacY;
            // Compensate for the scaled state of THIS object!

    // Create and Initialize defining points for the mark:
    double  dVirtualAxisValue = - this->dEngDataYMin * dScaleFactor
                                    +  dAtUserVal * dScaleFactor;
                                    // according to the current virt/
                                    // data scale ratios of the chart.

    double  dVirtGridLength = this->dEngVirtZDim;
    double  dVirtTickLength = this->dEngVirtXDim * this->dTickSizeRatio;
    if ( bDispWithInvertedTicks_ ) dVirtTickLength = - dVirtTickLength;
    if ( enumTickSize == CF_TICK_MINOR ) dVirtTickLength = dVirtTickLength / 2.0;

    cf_3DPoint  *p_cf_3dpNewTailPoint
                = new cf_3DPoint(   0.0,
                                    dVirtualAxisValue,
                                    0.0 );
    cf_3DPoint  *p_cf_3dpNewHeadPoint
                = new cf_3DPoint(   0.0,
                                    dVirtualAxisValue,
                                    dVirtGridLength );
    cf_3DPoint  *p_cf_3dpNewTextPoint
                = new cf_3DPoint(   - dVirtTickLength,
                                    dVirtualAxisValue,
                                    dVirtGridLength );

    // Create a new grid/tick mark in the dynamic array of
    // grid/tick marks, and match its attributes to this
    // grid/tick series'es attributes:
    cf_3DTextMarker *p_cf_3dtmNewMarker
                    = cf_3DGridTickSeries
                        ::addAxisMarker(    p_cf_3dpNewTailPoint,
                                            p_cf_3dpNewHeadPoint,
                                            p_cf_3dpNewTextPoint );
                    // Using the UNIFORM BASE CLASS METHOD !!!

    p_cf_3dtmNewMarker->dispInverted( bDispWithInvertedTicks_ );

    // Return a pointer to the new text marker so the
    // caller can make further mods to it if needed...
    return p_cf_3dtmNewMarker;

}   // end of cf_3DGTS_AutoMarkLeftFaceY::markAxisAt(...)
    // End of class cf_3DGTS_AutoMarkLeftFaceY implementation.


//--------------------------------------------------------------
// Implement a specialized derivation of the "Grid/Tick
// Mark Series" BASE class with specific behavior for
// the Right Y-Axis:
//--------------------------------------------------------------
cf_3DGTS_AutoMarkBackFaceY
    ::cf_3DGTS_AutoMarkBackFaceY( cf_ChartEngine *p_cf_engINowBelongTo )
        : cf_3DGridTickSeries( p_cf_engINowBelongTo )
{
    enumCurrAxisType_ = CF_AXIS_Y_BACK;
    //p_cf_3dtmAxisLabel_->labelNew( "[back-face Y-Axis]" );
/*
    this->markerLabelPositText(  125.0,     // pct "WidthFromCtr"
                                  50.0,     // pct "HeightFromCtr"
                                -100.0 );   // pct "DepthFromCtr"

    attribTextCurrent()->shiftHorzRight();

    // Place the Axis Label:
    p_cf_3dtmAxisLabel_->attribTextCurrent()->shiftHorzRight();
    p_cf_3dtmAxisLabel_->attribTextCurrent()->angleRotationPrefer( -90 );
            // run the Y-axis label vertically DOWNWARDS, But use
            // use the RIGHT displacement, which lines things up right.
*/
}

cf_3DGTS_AutoMarkBackFaceY
    ::~cf_3DGTS_AutoMarkBackFaceY()
        {}

cf_3DTextMarker*
cf_3DGTS_AutoMarkBackFaceY::markAxisAt
                        (   double      dAtUserVal,
                            cf_TickSize enumTickSize  )
{
    // Compute scale params neccessary to convert the RAW
    // user-DATA parameter into a VIRTUAL tick mark value:
    double  dScaleFactor = 1.0;  // Start with a harmless default.

    if ( fabs( this->dEngDataYDim ) > CF_NUM_ZERO_IF_LT )
            dScaleFactor = this->dEngVirtYDim / this->dEngDataYDim;
            // Then see if it's OK to modify.

    if ( fabs( this->dScaleFacY ) > CF_NUM_ZERO_IF_LT )
            dScaleFactor = dScaleFactor / this->dScaleFacY;
            // Compensate for the scaled state of THIS object!

    // Create and Initialize defining points for the mark:
    double  dVirtualAxisValue = - this->dEngDataYMin * dScaleFactor
                                    +  dAtUserVal * dScaleFactor;
                                    // according to the current virt/
                                    // data scale ratios of the chart.

    double  dVirtGridLength = this->dEngVirtXDim;
    double  dVirtTickLength = this->dEngVirtXDim * this->dTickSizeRatio;
    if ( bDispWithInvertedTicks_ ) dVirtTickLength = - dVirtTickLength;
    if ( enumTickSize == CF_TICK_MINOR ) dVirtTickLength = dVirtTickLength / 2.0;

    cf_3DPoint  *p_cf_3dpNewTailPoint
                = new cf_3DPoint(   0.0,
                                    dVirtualAxisValue,
                                    0.0 );
    cf_3DPoint  *p_cf_3dpNewHeadPoint
                = new cf_3DPoint(   dVirtGridLength,
                                    dVirtualAxisValue,
                                    0.0 );
    cf_3DPoint  *p_cf_3dpNewTextPoint
                = new cf_3DPoint(   dVirtGridLength + dVirtTickLength,
                                    dVirtualAxisValue,
                                    0.0 );

    // Create a new grid/tick mark in the dynamic array of
    // grid/tick marks, and match its attributes to this
    // grid/tick series'es attributes:
    cf_3DTextMarker *p_cf_3dtmNewMarker
                    = cf_3DGridTickSeries
                        ::addAxisMarker(    p_cf_3dpNewTailPoint,
                                            p_cf_3dpNewHeadPoint,
                                            p_cf_3dpNewTextPoint );
                    // Using the UNIFORM BASE CLASS METHOD !!!

    p_cf_3dtmNewMarker->dispInverted( bDispWithInvertedTicks_ );

    // Return a pointer to the new text marker so the
    // caller can make further mods to it if needed...
    return p_cf_3dtmNewMarker;

}   // end of cf_3DGTS_AutoMarkBackFaceY::markAxisAt(...)
    // End of class cf_3DGTS_AutoMarkBackFaceY implementation.



//--------------------------------------------------------------
// Implement a specialized derivation of the "Grid/Tick
// Mark Series" BASE class with specific behavior for
// the Left Z-Axis:
//--------------------------------------------------------------
cf_3DGTS_AutoMarkLeftFaceZ
    ::cf_3DGTS_AutoMarkLeftFaceZ( cf_ChartEngine *p_cf_engINowBelongTo )
        : cf_3DGridTickSeries( p_cf_engINowBelongTo )
{
    enumCurrAxisType_ = CF_AXIS_Z_LEFT;
    //p_cf_3dtmAxisLabel_->labelNew( "[left-face Z-Axis]" );
/*
    p_cf_3dtmAxisLabel_->attribTextCurrent()->shiftHorzLeft();
    this->markerLabelPositText( -120.0,     // pct "WidthFromCtr"
                                 120.0,     // pct "HeightFromCtr"
                                -100.0 );   // pct "DepthFromCtr"

    attribTextCurrent()->shiftVertUp();
    attribTextCurrent()->shiftHorzLeft();
    */
}

cf_3DGTS_AutoMarkLeftFaceZ
    ::~cf_3DGTS_AutoMarkLeftFaceZ()
        {}

cf_3DTextMarker*
cf_3DGTS_AutoMarkLeftFaceZ::markAxisAt
                        (   double      dAtUserVal,
                            cf_TickSize enumTickSize  )
{
    // Compute scale params neccessary to convert the RAW
    // user-DATA parameter into a VIRTUAL tick mark value:
    double  dScaleFactor = 1.0;  // Start with a harmless default.

    #ifdef CF_ASSERT_DVALS
    assert( this->dEngDataZDim > CF_NUM_ZERO_IF_LT );
    assert( this->dScaleFacZ > CF_NUM_ZERO_IF_LT );
    #endif

    if ( fabs( this->dEngDataZDim ) > CF_NUM_ZERO_IF_LT )
            dScaleFactor = this->dEngVirtZDim / this->dEngDataZDim;
            // Then see if it's OK to modify.

    if ( fabs( this->dScaleFacZ ) > CF_NUM_ZERO_IF_LT )
            dScaleFactor = dScaleFactor / this->dScaleFacZ;
            // Compensate for the scaled state of THIS object!

    // Create and Initialize defining points for the mark:
    double  dVirtualAxisValue = - this->dEngDataZMin * dScaleFactor
                                    +  dAtUserVal * dScaleFactor;
                                    // according to the current virt/
                                    // data scale ratios of the chart.

    double  dVirtGridLength = this->dEngVirtYDim;
    double  dVirtTickLength = this->dEngVirtXDim * this->dTickSizeRatio;
    if ( bDispWithInvertedTicks_ ) dVirtTickLength = - dVirtTickLength;
    if ( enumTickSize == CF_TICK_MINOR ) dVirtTickLength = dVirtTickLength / 2.0;

    cf_3DPoint  *p_cf_3dpNewTailPoint
                = new cf_3DPoint(   0.0,
                                    0.0,
                                    dVirtualAxisValue );
    cf_3DPoint  *p_cf_3dpNewHeadPoint
                = new cf_3DPoint(   0.0,
                                    dVirtGridLength,
                                    dVirtualAxisValue );
    cf_3DPoint  *p_cf_3dpNewTextPoint
                = new cf_3DPoint(   - dVirtTickLength,
                                    dVirtGridLength,
                                    dVirtualAxisValue );

    // Create a new grid/tick mark in the dynamic array of
    // grid/tick marks, and match its attributes to this
    // grid/tick series'es attributes:
    cf_3DTextMarker *p_cf_3dtmNewMarker
                    = cf_3DGridTickSeries
                        ::addAxisMarker(    p_cf_3dpNewTailPoint,
                                            p_cf_3dpNewHeadPoint,
                                            p_cf_3dpNewTextPoint );
                    // Using the UNIFORM BASE CLASS METHOD !!!

    p_cf_3dtmNewMarker->dispInverted( bDispWithInvertedTicks_ );

    // Return a pointer to the new text marker so the
    // caller can make further mods to it if needed...
    return p_cf_3dtmNewMarker;

}   // end of cf_3DGTS_AutoMarkLeftFaceZ::markAxisAt(...)
    // End of class cf_3DGTS_AutoMarkLeftFaceZ implementation.


//--------------------------------------------------------------
// Implement a specialized derivation of the "Grid/Tick
// Mark Series" BASE class with specific behavior for
// the Right Z-Axis:
//--------------------------------------------------------------
cf_3DGTS_AutoMarkBottomFaceZ
    ::cf_3DGTS_AutoMarkBottomFaceZ( cf_ChartEngine *p_cf_engINowBelongTo )
        : cf_3DGridTickSeries( p_cf_engINowBelongTo )
{
    enumCurrAxisType_ = CF_AXIS_Z_BOTTOM;
    //p_cf_3dtmAxisLabel_->labelNew( "[bottom-face Z-Axis]" );
/*
    p_cf_3dtmAxisLabel_->attribTextCurrent()->shiftHorzRight();
    this->markerLabelPositText(  120.0,     // pct "WidthFromCtr"
                                -120.0,     // pct "HeightFromCtr"
                                 100.0 );   // pct "DepthFromCtr"

    attribTextCurrent()->shiftVertDown();
    attribTextCurrent()->shiftHorzRight();
    */
}

cf_3DGTS_AutoMarkBottomFaceZ
    ::~cf_3DGTS_AutoMarkBottomFaceZ()
        {}


cf_3DTextMarker*
cf_3DGTS_AutoMarkBottomFaceZ::markAxisAt
                        (   double      dAtUserVal,
                            cf_TickSize enumTickSize  )
{
    // Compute scale params neccessary to convert the RAW
    // user-DATA parameter into a VIRTUAL tick mark value:
    double  dScaleFactor = 1.0;  // Start with a harmless default.

    #ifdef CF_ASSERT_DVALS
    assert( fabs( this->dEngDataZDim ) > CF_NUM_ZERO_IF_LT );
    assert( fabs( this->dScaleFacZ ) > CF_NUM_ZERO_IF_LT );
    #endif

    if ( fabs( this->dEngDataZDim ) > CF_NUM_ZERO_IF_LT )
            dScaleFactor = this->dEngVirtZDim / this->dEngDataZDim;
            // Then see if it's OK to modify.

    if ( fabs( this->dScaleFacZ ) > CF_NUM_ZERO_IF_LT )
            dScaleFactor = dScaleFactor / this->dScaleFacZ;
            // Compensate for the scaled state of THIS object!

    // Create and Initialize defining points for the mark:
    double  dVirtualAxisValue = - this->dEngDataZMin * dScaleFactor
                                    +  dAtUserVal * dScaleFactor;
                                    // according to the current virt/
                                    // data scale ratios of the chart.

    double  dVirtGridLength = this->dEngVirtXDim;
    double  dVirtTickLength = this->dEngVirtXDim * this->dTickSizeRatio;
    if ( bDispWithInvertedTicks_ ) dVirtTickLength = - dVirtTickLength;
    if ( enumTickSize == CF_TICK_MINOR ) dVirtTickLength = dVirtTickLength / 2.0;

    cf_3DPoint  *p_cf_3dpNewTailPoint
                = new cf_3DPoint(   0.0,
                                    0.0,
                                    dVirtualAxisValue );
    cf_3DPoint  *p_cf_3dpNewHeadPoint
                = new cf_3DPoint(   dVirtGridLength,
                                    0.0,
                                    dVirtualAxisValue );
    cf_3DPoint  *p_cf_3dpNewTextPoint
                = new cf_3DPoint(   dVirtGridLength + dVirtTickLength,
                                    0.0,
                                    dVirtualAxisValue );

    // Create a new grid/tick mark in the dynamic array of
    // grid/tick marks, and match its attributes to this
    // grid/tick series'es attributes:
    cf_3DTextMarker *p_cf_3dtmNewMarker
                    = cf_3DGridTickSeries
                        ::addAxisMarker(    p_cf_3dpNewTailPoint,
                                            p_cf_3dpNewHeadPoint,
                                            p_cf_3dpNewTextPoint );
                    // Using the UNIFORM BASE CLASS METHOD !!!

    p_cf_3dtmNewMarker->dispInverted( bDispWithInvertedTicks_ );

    // Return a pointer to the new text marker so the
    // caller can make further mods to it if needed...
    return p_cf_3dtmNewMarker;

}   // end of cf_3DGTS_AutoMarkBottomFaceZ::markAxisAt(...)
    // End of class cf_3DGTS_AutoMarkBottomFaceZ implementation.



//--------------------------------------------------------------
// Implement a specialized derivation of the "Grid/Tick
// Mark Series" BASE class with specific behavior for
// the Polar-Axis on the Z-Floor of the chart:
//--------------------------------------------------------------
cf_3DGTS_AutoMarkPolarFloor
    ::cf_3DGTS_AutoMarkPolarFloor( cf_ChartEngine *p_cf_engINowBelongTo )
        : cf_3DGridTickSeries( p_cf_engINowBelongTo )
{
    enumCurrAxisType_ = CF_AXIS_POLAR_FLOOR;
    //p_cf_3dtmAxisLabel_->labelNew( "[Polar Axis]" );
/*
    this->markerLabelPositText(   0.0,      // pct "WidthFromCtr"
                                110.0,      // pct "HeightFromCtr"
                                  0.0 );    // pct "DepthFromCtr"

    attribTextCurrent()->shiftVertDown();
    */
}


cf_3DGTS_AutoMarkPolarFloor
    ::~cf_3DGTS_AutoMarkPolarFloor()
        {}


cf_3DTextMarker*
cf_3DGTS_AutoMarkPolarFloor::markAxisAt
                        (   double      dAtUserVal,
                            cf_TickSize enumTickSize  )
        // Note that in this implementation, param
        // dAtUserVal is a RADIAN value.

{
    // Calc current 3D Box geometry values for
    // Cartesian-to-Polar cordinate conversion:
    double  dCurrentRadius = this->dEngVirtXMax;
    double  dTickRadius = dCurrentRadius
                            + dCurrentRadius * this->dTickSizeRatio;

    // Create and Initialize defining points for the mark:
    double  dXOrigin = p_cf_engParentEngine_->measuredVirtXOrigin();
    double  dYOrigin = p_cf_engParentEngine_->measuredVirtYOrigin();
    double  dZOrigin = p_cf_engParentEngine_->measuredVirtZOrigin();

    double  dPieEdgeVirtX = dCurrentRadius * cos( dAtUserVal );
    double  dPieEdgeVirtZ = - dCurrentRadius * sin( dAtUserVal );

    double  dTickEndVirtX = dTickRadius * cos( dAtUserVal );
    double  dTickEndVirtZ = - dTickRadius * sin( dAtUserVal );
                // NB: The negative sign is d*mn important!

    cf_3DPoint  *p_cf_3dpPolarOrigin
                = new cf_3DPoint(   dXOrigin,
                                    dYOrigin,
                                    dZOrigin );

    cf_3DPoint  *p_cf_3dpPiesEdge
                = new cf_3DPoint(   dPieEdgeVirtX,
                                    dYOrigin,
                                    dPieEdgeVirtZ );

    cf_3DPoint  *p_cf_3dpNewTextPoint
                = new cf_3DPoint(   dTickEndVirtX,
                                    dYOrigin,
                                    dTickEndVirtZ );

    // Create a new grid/tick mark in the dynamic array of
    // grid/tick marks, and match its attributes to this
    // grid/tick series'es attributes:
    cf_3DTextMarker *p_cf_3dtmNewMarker
                    = cf_3DGridTickSeries
                        ::addAxisMarker(    p_cf_3dpPolarOrigin,
                                            p_cf_3dpPiesEdge,
                                            p_cf_3dpNewTextPoint );
    // Return a pointer to the new text marker so the
    // caller can make further mods to it if needed...
    return p_cf_3dtmNewMarker;

}   // end of cf_3DGTS_AutoMarkPolarFloor::markAxisAt( radian,... )
    // End of class cf_3DGTS_AutoMarkPolarFloor implementation.


////////////////////////////////////////
// End of File: CO1_GTS.CPP
////////////////////////////////////////

