////////////////////////////////////////
// Start of File: CO1_TMS.CPP
////////////////////////////////////////

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

//
// Include this source file's header file:
//
#include	<cf_api/bf_defs.h>
#include    <cf_api/co1_tms.hpp> 
            // relative to the IDE's (global) include path: ~/cfrz
 
//
//=============================================
// Implement the cf_3DTextMarkerSeries object:
//=============================================
//
cf_3DTextMarkerSeries::cf_3DTextMarkerSeries
                    ( cf_ChartEngine *p_cf_engINowBelongTo )

    :   cf_Virt3DObj(),
    		dTransX(0), dTransY(0), dTransZ(0),
    		dVirtXMax(0), dVirtYMax(0), dVirtZMax(0),
    		dVirtXMin(0), dVirtYMin(0), dVirtZMin(0)
{
    p_cf_engParent_ = p_cf_engINowBelongTo;

    da_p_cf_3dtmMarkerArray_.growBy( 25 );
    iNumMarkAllocs_ = 0;
    bIsActive_ = TRUE;

    // Init the "active marker" pointer to a KNOWN state:
    p_cf_3dtmActiveMarker_ = NULL; // Until set by activateMark( int )

}   // end of c-tor.


cf_3DTextMarkerSeries::
    ~cf_3DTextMarkerSeries()
{
    // Get RID of ANY allocated text/markers we new()ed!
    for ( int i = 1; i <= iNumMarkAllocs_; i++ )
        delete ( ( cf_3DTextMarker*) da_p_cf_3dtmMarkerArray_[ i ] );
}   // end of d-tor.



cf_3DTextMarker*
    cf_3DTextMarkerSeries
        ::activateMarker( int iMarkerNumber )
{
    // Screen (and correct to default value) for bogus index values:
    int iGetMarkerNumber = iMarkerNumber;

    if ( ( iGetMarkerNumber < 1 )
        || ( iGetMarkerNumber > iNumMarkAllocs_ ) )
            // IGNORE their bogus index request...
            iGetMarkerNumber = 1;
            //...and give them something we actually HAVE!

    // Wait a second... do we HAVE something to give?...
    if ( iNumMarkAllocs_ < 1 )
        // WHOOPS!  Then we had BETTER correct this!
        addTextMarker();
            // makes a "default" (tail=head=text=0,0,0) marker.

    // OK... we should be good-to-go with either the user's
    // ORIGINALLY indexed request, or with our "ignore-the-
    // user's-index-request" text-marker at index one:
    p_cf_3dtmActiveMarker_ = ( (cf_3DTextMarker*)
                da_p_cf_3dtmMarkerArray_[ iGetMarkerNumber ] );

    return  p_cf_3dtmActiveMarker_;
}

//---------------------------------------------------------
// Allow the user to over-ride the default positioning
// of the Head, Tail and Text of the Text Marker, and
// specify a new position as an X/Y projection away from
// the projected CENTER of the chart.  Positive OR
// negative percentages are allowed.
//---------------------------------------------------------
BOOL
    cf_3DTextMarkerSeries
        ::activeMarkerPositHead(    double  dPctWidthFromCtr,
                                    double  dPctHeightFromCtr,
                                    double  dPctDepthFromCtr )
{
    BOOL bStatus = FALSE;   // Init to ERROR state to be safe...

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

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

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



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

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

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

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



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

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


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

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



//----------------------------------------------
// Add a "default" 3D-text-marker (with the
// tail, head, and text points at 0,0,0, and
// return a pointer to this new marker.
//----------------------------------------------
cf_3DTextMarker*    
    cf_3DTextMarkerSeries
        ::addTextMarker()
{
    cf_3DPoint  *p_cf_3dpTail = new cf_3DPoint( 0, 0, 0 );
    cf_3DPoint  *p_cf_3dpHead = new cf_3DPoint( 0, 0, 0 );
    cf_3DPoint  *p_cf_3dpText = new cf_3DPoint( 0, 0, 0 );

    addTextMarker( p_cf_3dpTail, p_cf_3dpHead, p_cf_3dpText );
    // which sets p_cf_3dtmActiveMarker_ = p_cf_3dtmNewMarker;

    return p_cf_3dtmActiveMarker_;
}

//----------------------------------------------
// Add a "user-specified" 3D-text-marker and
// return a pointer to this new marker.
//----------------------------------------------
cf_3DTextMarker*
    cf_3DTextMarkerSeries
        ::addTextMarker(    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
    iNumMarkAllocs_++;
    cf_3DTextMarker *p_cf_3dtmNewMarker
                    = new cf_3DTextMarker(  p_cf_3dpTailPoint,
                                            p_cf_3dpHeadPoint,
                                            p_cf_3dpTextPoint );

    p_cf_3dtmNewMarker->attribTextUsing( attribTextCurrent() );

    da_p_cf_3dtmMarkerArray_[ iNumMarkAllocs_ ] = p_cf_3dtmNewMarker;

    return ( p_cf_3dtmActiveMarker_ = p_cf_3dtmNewMarker );

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



//----------------------------------------------
// Add a "user-specified" (with tail and head
// points at 0,0,0, and the text-point posit
// as a percentage projection away from the
// center of the chart-engine's 3D-box.
//----------------------------------------------
cf_3DTextMarker*    
    cf_3DTextMarkerSeries
        ::addTextMarker(    double  dPctWidthFromCtr,
                            double  dPctHeightFromCtr,
                            double  dPctDepthFromCtr )
{
    cf_3DPoint  *p_cf_3dpTail = new cf_3DPoint( 0, 0, 0 );
    cf_3DPoint  *p_cf_3dpHead = new cf_3DPoint( 0, 0, 0 );
    cf_3DPoint  *p_cf_3dpText = new cf_3DPoint( 0, 0, 0 );

    addTextMarker( p_cf_3dpTail, p_cf_3dpHead, p_cf_3dpText );
    // which sets p_cf_3dtmActiveMarker_ = p_cf_3dtmNewMarker;

    p_cf_engParent_
            ->positPointAt(   p_cf_3dpText,
                                dPctWidthFromCtr,
                                    dPctHeightFromCtr,
                                        dPctDepthFromCtr );
    return p_cf_3dtmActiveMarker_;
}




void
cf_3DTextMarkerSeries::applyDataUpdate
                    ( cf_ChartModel *p_cf_cmodlDataSource )
{
    reset();
    for ( int i = 1; i <= p_cf_cmodlDataSource->labelLegendCount(); i++ )
    {
        // Define the TEXT point position -- as a dimension percentage:
        cf_DataGroup *p_dgLabelLegend = p_cf_cmodlDataSource->activateGroupLegend( i );
        cf_XYZ  *p_xyzPositPercentData = p_dgLabelLegend->activateXYZValAt( 1 );
        cf_3DTextMarker *p_cf_3dtmNewLegend
                        = addTextMarker(    p_xyzPositPercentData->x(),
                                            p_xyzPositPercentData->y(),
                                            p_xyzPositPercentData->z() );

        // Label the marker point and set its attributes:
        p_cf_3dtmNewLegend->labelUsing( p_dgLabelLegend->labelIs() );
        p_cf_3dtmNewLegend->dispAttribsPointTo( p_dgLabelLegend->dispAttribs() );
        p_cf_3dtmNewLegend->attribTextUsing( p_dgLabelLegend->textAttribs() );
    }
}



//----------------------------------------------------------
// Use the Given Chart Framework Kernel to apply Geometry/
// Projection Transformations to this cf_3DGridTickSeries:
//----------------------------------------------------------
void
    cf_3DTextMarkerSeries
        ::applyGeomXform( cf_Kernel  *p_cf_kUseThisKernel )
{
    // Apply the xform to the text marker line's vertices:
    for ( int i = 1; i <= iNumMarkAllocs_; i++ )
        ( (cf_3DTextMarker*) da_p_cf_3dtmMarkerArray_[ i ] )
                                ->applyGeomXform( p_cf_kUseThisKernel );
                // Note that we do not perform DSORT update ops 
    return;     // as in class cf_3DPointSeries...
}

void
    cf_3DTextMarkerSeries
        ::applyProjXform( cf_Kernel *p_cf_kUseThisKernel ) 
{
    // Apply the xform to the text marker line's vertices:
    for ( int i = 1; i <= iNumMarkAllocs_; i++ )
        ( (cf_3DTextMarker*) da_p_cf_3dtmMarkerArray_[ i ] )
                                ->applyProjXform( p_cf_kUseThisKernel );
    return;
}


//---------------------------------------------------------
// SCALE the cf_3DTextMarkerSeries's VIRTUAL Coordinates.
//---------------------------------------------------------
void
    cf_3DTextMarkerSeries
        ::applyScaleOp( double dXScaleFactor,
                        double dYScaleFactor, 
                        double dZScaleFactor )
{
    // In order to "properly" scale this object, we
    // need to translate it back to it's original coords.
    double  dSaveXTrans = this->dTransX;
    double  dSaveYTrans = this->dTransY;
    double  dSaveZTrans = this->dTransZ;
    
    applyTranslateOp( -dSaveXTrans, -dSaveYTrans, -dSaveZTrans );

    // Apply the xform to the text marker line's vertices:
    for ( int i = 1; i <= iNumMarkAllocs_; i++ )
        ( (cf_3DTextMarker*) da_p_cf_3dtmMarkerArray_[ i ] )
                                            ->applyScaleOp( dXScaleFactor,
                                                            dYScaleFactor,
                                                            dZScaleFactor );
    // Update this cf_Virt3DObj'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;

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

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



//------------------------------------------------------------
// TRANSLATE the cf_3DTextMarkerSeries's VIRTUAL Coordinates.
//------------------------------------------------------------
void
    cf_3DTextMarkerSeries
        ::applyTranslateOp( double  dXTrans,
                            double  dYTrans,
                            double  dZTrans  )
{
    // Apply the xform to the text marker line's vertices:
    for ( int i = 1; i <= iNumMarkAllocs_; i++ )
        ( (cf_3DTextMarker*) da_p_cf_3dtmMarkerArray_[ i ] )
                                        ->applyTranslateOp( dXTrans,
                                                            dYTrans,
                                                            dZTrans );
    // Update our translation counters, so we can always
    // reverse-calc the Initial XYZ coords of the polyline.
    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_3DTextMarkerSeries::applyTranslateOp(...)


//----------------------------------------------------------------
// (re)set text back color for any active (auto-scale) font spec:
//----------------------------------------------------------------
void
    cf_3DTextMarkerSeries
        ::colorBack( const bf_Color &cr_bf_clrNewVal )
{
    for ( int i = 1; i <= iNumMarkAllocs_; i++ )
        ( (cf_3DTextMarker*) da_p_cf_3dtmMarkerArray_[ i ] )
                    ->attribTextCurrent()->colorTextBack( cr_bf_clrNewVal );
}


//---------------------------------------------------
// DRAW this cf_3DTextMarkerSeries on a bf_Display.
//---------------------------------------------------
void
cf_3DTextMarkerSeries::draw2D
                    ( bf_Display *p_bf_dspOutputDisplay )
{
    draw3D( p_bf_dspOutputDisplay );
}

void
cf_3DTextMarkerSeries::draw3D
                    ( bf_Display *p_bf_dspOutputDisplay )
{
    // Don't incur font calculation overhead unless we're serious about this!
    if ( bIsActive_ != TRUE ) return;

    // We'll use the cf_3DTextMarker::draw3D() member method
    // which lets EACH cf_3DTextMarker object push onto the
    // display its own appropriate font, pen, etc., to draw with:
    for ( int i = 1; i <= iNumMarkAllocs_; i++ )
        ( (cf_3DTextMarker*) da_p_cf_3dtmMarkerArray_[ i ] )
                                        ->draw3D( p_bf_dspOutputDisplay );
}


//-------------------------------
// Get/set activation status:
//-------------------------------
BOOL
cf_3DTextMarkerSeries::isActive()
{
    return bIsActive_;
}

BOOL
cf_3DTextMarkerSeries::isActive
                    ( BOOL bNewState )
{
    return( bIsActive_ = bNewState );
}


//----------------------------------------------------------
// Allow users to create new text markers placed at a
// specific location within an chart engine's 3D space:
//----------------------------------------------------------
cf_3DTextMarker*
cf_3DTextMarkerSeries::markerValueAt
                    (   double  dPctWidthFromCtr,
                        double  dPctHeightFromCtr,
                        double  dPctDepthFromCtr,
                        double  dValueForLabel )
{
    // Create a new text-marker and add its address into
    // our dynamic array of pointers to text-markers
    cf_3DTextMarker *p_cf_3dtmNewMarker
                    = addTextMarker(  new cf_3DPoint,
                                            new cf_3DPoint,
                                            new cf_3DPoint );
    // Set the new text marker's attributes:
    p_cf_3dtmActiveMarker_ = p_cf_3dtmNewMarker;
    p_cf_3dtmActiveMarker_->labelNew( dValueForLabel );
    activeMarkerPositText(    dPctWidthFromCtr,
                                    dPctHeightFromCtr,
                                    dPctDepthFromCtr );
    // We be done!
    return  p_cf_3dtmActiveMarker_;
}

cf_3DTextMarker*
    cf_3DTextMarkerSeries
        ::markerLabelAt(    double  dPctWidthFromCtr,
                            double  dPctHeightFromCtr,
                            double  dPctDepthFromCtr,
                            const char  *a_cStringForLabel )
{
    // Create a new text-marker and add its address into
    // our dynamic array of pointers to text-markers
    cf_3DTextMarker *p_cf_3dtmNewMarker
                    = addTextMarker(  new cf_3DPoint,
                                            new cf_3DPoint,
                                            new cf_3DPoint );
    // Set the new text marker's attributes:
    p_cf_3dtmActiveMarker_ = p_cf_3dtmNewMarker;
    p_cf_3dtmActiveMarker_->labelNew( a_cStringForLabel );
    activeMarkerPositText(    dPctWidthFromCtr,
                                    dPctHeightFromCtr,
                                    dPctDepthFromCtr );
    // We be done!
    return  p_cf_3dtmActiveMarker_;
}


int
    cf_3DTextMarkerSeries
        ::numMarks()
            { return iNumMarkAllocs_; }

void
    cf_3DTextMarkerSeries
        ::on()
            { bIsActive_ = TRUE; }

void
    cf_3DTextMarkerSeries
        ::off()
            { bIsActive_ = FALSE; }

void
cf_3DTextMarkerSeries::reset()
{
    for ( int i = 1; i <= iNumMarkAllocs_; i++ )
        delete ( ( cf_3DTextMarker*) da_p_cf_3dtmMarkerArray_[ i ] );
    iNumMarkAllocs_ = 0;
}
//-----------------------------------------------------
// End of cf_3DTextMarkerSeries object implementation.
//-----------------------------------------------------


//=============================================================
// Implement the Chart Framework "Title Marker Manager" class.
//============================================================
cf_TitleMarkerMgr::cf_TitleMarkerMgr
                ( cf_ChartEngine *p_cf_engINowBelongTo )

    :   cf_3DTextMarkerSeries( p_cf_engINowBelongTo )
{
    // Init ALL the title text marker pointers to a KNOWN (and testable) state:
    p_cf_3dtmTitle_         = NULL;
    p_cf_3dtmSubTitle_      = NULL;

    p_cf_3dtmXAxisBackFace_     = NULL;
    p_cf_3dtmXAxisBottomFace_   = NULL;
    p_cf_3dtmYAxisLeftFace_     = NULL;
    p_cf_3dtmYAxisBackFace_     = NULL;
    p_cf_3dtmZAxisLeftFace_     = NULL;
    p_cf_3dtmZAxisBottomFace_   = NULL;
    p_cf_3dtmPolarFloor_        = NULL;

}


cf_TitleMarkerMgr::~cf_TitleMarkerMgr()
{
}




void
cf_TitleMarkerMgr::applyDataUpdate
                    ( cf_ChartModel *p_cf_cmodlDataSource )
{
    reset();

    cf_DataGroup    *p_dgAccessInfo = NULL;
    cf_XYZ          *p_xyzPositPercentData = NULL;
    cf_3DTextMarker *p_cf_3dtmNewMarker = NULL;

    cf_3DGridTickSeries *p_cf_3dgtsBorrow = NULL;
    cf_3DTextMarker     *p_cf_3dtmBorrow = NULL;

    bf_Color        bf_clrGroup = CF_BLACK;

    //if ( p_cf_cmodlDataSource->labelTitleIs( CF_TITLE_MAIN ) == TRUE )
    {
        p_dgAccessInfo = p_cf_cmodlDataSource->labelTitleData( CF_TITLE_MAIN );
        p_xyzPositPercentData = p_dgAccessInfo->activateXYZValAt( 1 );

        p_cf_3dtmNewMarker = addTextMarker( p_xyzPositPercentData->x(),
                                            p_xyzPositPercentData->y(),
                                            p_xyzPositPercentData->z() );
        p_cf_3dtmNewMarker->labelUsing( p_dgAccessInfo->labelIs() );
        p_cf_3dtmNewMarker->dispAttribsPointTo( p_dgAccessInfo->dispAttribs() );
        p_cf_3dtmNewMarker->attribTextUsing( p_dgAccessInfo->textAttribs() );
        p_cf_3dtmTitle_ = p_cf_3dtmNewMarker;
    }

    //if ( p_cf_cmodlDataSource->labelTitleIs( CF_TITLE_SUB ) == TRUE )
    {
        p_dgAccessInfo = p_cf_cmodlDataSource->labelTitleData( CF_TITLE_SUB );
        p_xyzPositPercentData = p_dgAccessInfo->activateXYZValAt( 1 );
        p_cf_3dtmNewMarker = addTextMarker( p_xyzPositPercentData->x(),
                                            p_xyzPositPercentData->y(),
                                            p_xyzPositPercentData->z() );
        p_cf_3dtmNewMarker->labelUsing( p_dgAccessInfo->labelIs() );
        p_cf_3dtmNewMarker->dispAttribsPointTo( p_dgAccessInfo->dispAttribs() );
        p_cf_3dtmNewMarker->attribTextUsing( p_dgAccessInfo->textAttribs() );
        p_cf_3dtmSubTitle_ = p_cf_3dtmNewMarker;
    }

    p_cf_3dgtsBorrow = p_cf_engParent_->axis_X_BottomFace();
    //if ( p_cf_3dgtsBorrow->isActive() == TRUE )
    {
        p_cf_3dtmBorrow = p_cf_3dgtsBorrow->markerLabel();
        p_dgAccessInfo = p_cf_cmodlDataSource->activateGroupAxisLabel( CF_AXIS_X_BOTTOM );

        p_cf_3dtmBorrow->labelUsing( p_dgAccessInfo->labelIs() );
        p_cf_3dtmBorrow->dispAttribsPointTo( p_dgAccessInfo->dispAttribs() );
        p_cf_3dtmBorrow->attribTextUsing( p_dgAccessInfo->textAttribs() );

        p_xyzPositPercentData = p_dgAccessInfo->activateXYZValAt( 1 );
        p_cf_3dgtsBorrow->markerLabelPositText( p_xyzPositPercentData->x(),
                                                p_xyzPositPercentData->y(),
                                                p_xyzPositPercentData->z() );
        p_cf_3dtmXAxisBackFace_ = p_cf_3dtmBorrow;
    }

    //if ( p_cf_cmodlDataSource->labelAxisIs( CF_AXIS_X_BACK ) == TRUE )
    {
        p_cf_3dgtsBorrow = p_cf_engParent_->axis_X_BackFace();
        p_cf_3dtmBorrow = p_cf_3dgtsBorrow->markerLabel();

        p_dgAccessInfo = p_cf_cmodlDataSource->labelAxisData( CF_AXIS_X_BACK );
        p_cf_3dtmBorrow->labelUsing( p_dgAccessInfo->labelIs() );
        p_cf_3dtmBorrow->dispAttribsPointTo( p_dgAccessInfo->dispAttribs() );
        p_cf_3dtmBorrow->attribTextUsing( p_dgAccessInfo->textAttribs() );

        p_xyzPositPercentData = p_dgAccessInfo->activateXYZValAt( 1 );
        p_cf_3dgtsBorrow->markerLabelPositText( p_xyzPositPercentData->x(),
                                                p_xyzPositPercentData->y(),
                                                p_xyzPositPercentData->z() );
        p_cf_3dtmXAxisBottomFace_ = p_cf_3dtmBorrow;
    }

    //if ( p_cf_cmodlDataSource->labelAxisIs( CF_AXIS_Y_LEFT ) == TRUE )
    {
        p_cf_3dgtsBorrow = p_cf_engParent_->axis_Y_LeftFace();
        p_cf_3dtmBorrow = p_cf_3dgtsBorrow->markerLabel();

        p_dgAccessInfo = p_cf_cmodlDataSource->labelAxisData( CF_AXIS_Y_LEFT );
        p_cf_3dtmBorrow->labelUsing( p_dgAccessInfo->labelIs() );
        p_cf_3dtmBorrow->dispAttribsPointTo( p_dgAccessInfo->dispAttribs() );
        p_cf_3dtmBorrow->attribTextUsing( p_dgAccessInfo->textAttribs() );

        p_xyzPositPercentData = p_dgAccessInfo->activateXYZValAt( 1 );
        p_cf_3dgtsBorrow->markerLabelPositText( p_xyzPositPercentData->x(),
                                                p_xyzPositPercentData->y(),
                                                p_xyzPositPercentData->z() );
        p_cf_3dtmYAxisLeftFace_ = p_cf_3dtmBorrow;
    }

    //if ( p_cf_cmodlDataSource->labelAxisIs( CF_AXIS_Y_BACK ) == TRUE )
    {
        p_cf_3dgtsBorrow = p_cf_engParent_->axis_Y_BackFace();
        p_cf_3dtmBorrow = p_cf_3dgtsBorrow->markerLabel();

        p_dgAccessInfo = p_cf_cmodlDataSource->labelAxisData( CF_AXIS_Y_BACK );
        p_cf_3dtmBorrow->labelUsing( p_dgAccessInfo->labelIs() );
        p_cf_3dtmBorrow->dispAttribsPointTo( p_dgAccessInfo->dispAttribs() );
        p_cf_3dtmBorrow->attribTextUsing( p_dgAccessInfo->textAttribs() );

        p_xyzPositPercentData = p_dgAccessInfo->activateXYZValAt( 1 );
        p_cf_3dgtsBorrow->markerLabelPositText( p_xyzPositPercentData->x(),
                                                p_xyzPositPercentData->y(),
                                                p_xyzPositPercentData->z() );
        p_cf_3dtmYAxisBackFace_ = p_cf_3dtmBorrow;
    }

    //if ( p_cf_cmodlDataSource->labelAxisIs( CF_AXIS_Z_BOTTOM ) == TRUE )
    {
        p_cf_3dgtsBorrow = p_cf_engParent_->axis_Z_BottomFace();
        p_cf_3dtmBorrow = p_cf_3dgtsBorrow->markerLabel();

        p_dgAccessInfo = p_cf_cmodlDataSource->labelAxisData( CF_AXIS_Z_BOTTOM );
        p_cf_3dtmBorrow->labelUsing( p_dgAccessInfo->labelIs() );
        p_cf_3dtmBorrow->dispAttribsPointTo( p_dgAccessInfo->dispAttribs() );
        p_cf_3dtmBorrow->attribTextUsing( p_dgAccessInfo->textAttribs() );

        p_xyzPositPercentData = p_dgAccessInfo->activateXYZValAt( 1 );
        p_cf_3dgtsBorrow->markerLabelPositText( p_xyzPositPercentData->x(),
                                                p_xyzPositPercentData->y(),
                                                p_xyzPositPercentData->z() );
        p_cf_3dtmZAxisBottomFace_ = p_cf_3dtmBorrow;
    }

    //if ( p_cf_cmodlDataSource->labelAxisIs( CF_AXIS_Z_LEFT ) == TRUE )
    {
        p_cf_3dgtsBorrow = p_cf_engParent_->axis_Z_LeftFace();
        p_cf_3dtmBorrow = p_cf_3dgtsBorrow->markerLabel();

        p_dgAccessInfo = p_cf_cmodlDataSource->labelAxisData( CF_AXIS_Z_LEFT );
        p_cf_3dtmBorrow->labelUsing( p_dgAccessInfo->labelIs() );
        p_cf_3dtmBorrow->dispAttribsPointTo( p_dgAccessInfo->dispAttribs() );
        p_cf_3dtmBorrow->attribTextUsing( p_dgAccessInfo->textAttribs() );

        p_xyzPositPercentData = p_dgAccessInfo->activateXYZValAt( 1 );
        p_cf_3dgtsBorrow->markerLabelPositText( p_xyzPositPercentData->x(),
                                                p_xyzPositPercentData->y(),
                                                p_xyzPositPercentData->z() );
        p_cf_3dtmZAxisLeftFace_ = p_cf_3dtmBorrow;
    }

    //if ( p_cf_cmodlDataSource->labelAxisIs( CF_AXIS_POLAR_FLOOR ) == TRUE )
    {
        p_cf_3dgtsBorrow = p_cf_engParent_->axis_Polar_Floor();
        p_cf_3dtmBorrow = p_cf_3dgtsBorrow->markerLabel();

        p_dgAccessInfo = p_cf_cmodlDataSource->labelAxisData( CF_AXIS_POLAR_FLOOR );
        p_cf_3dtmBorrow->labelUsing( p_dgAccessInfo->labelIs() );
        p_cf_3dtmBorrow->dispAttribsPointTo( p_dgAccessInfo->dispAttribs() );
        p_cf_3dtmBorrow->attribTextUsing( p_dgAccessInfo->textAttribs() );

        p_xyzPositPercentData = p_dgAccessInfo->activateXYZValAt( 1 );
        p_cf_3dgtsBorrow->markerLabelPositText( p_xyzPositPercentData->x(),
                                                p_xyzPositPercentData->y(),
                                                p_xyzPositPercentData->z() );
        p_cf_3dtmPolarFloor_ = p_cf_3dtmBorrow;
    }

}   // end of cf_TitleMarkerMgr::applyDataUpdate( cf_ChartModel * )


//---------------------------------------------------
// DRAW this cf_3DTextMarkerSeries on a bf_Display.
//---------------------------------------------------
void
cf_TitleMarkerMgr::draw2D
                ( bf_Display *p_bf_dspOutputDisplay )
{
    draw3D( p_bf_dspOutputDisplay );
}

void
cf_TitleMarkerMgr::draw3D
                ( bf_Display *p_bf_dspOutputDisplay )
{
    // Draw any allocated title markers:
    if ( p_cf_3dtmTitle_ != NULL )
        p_cf_3dtmTitle_->draw3D( p_bf_dspOutputDisplay );
    if ( p_cf_3dtmSubTitle_ != NULL )
        p_cf_3dtmSubTitle_->draw3D( p_bf_dspOutputDisplay );

    // RE-draw any shared axis title markers:
    if ( p_cf_3dtmXAxisBackFace_ != NULL )
        p_cf_3dtmXAxisBackFace_->draw3D( p_bf_dspOutputDisplay );
    if ( p_cf_3dtmXAxisBottomFace_ != NULL )
        p_cf_3dtmXAxisBottomFace_->draw3D( p_bf_dspOutputDisplay );
    if ( p_cf_3dtmYAxisLeftFace_ != NULL )
        p_cf_3dtmYAxisLeftFace_->draw3D( p_bf_dspOutputDisplay );
    if ( p_cf_3dtmYAxisBackFace_ != NULL )
        p_cf_3dtmYAxisBackFace_->draw3D( p_bf_dspOutputDisplay );
    if ( p_cf_3dtmZAxisLeftFace_ != NULL )
        p_cf_3dtmZAxisLeftFace_->draw3D( p_bf_dspOutputDisplay );
    if ( p_cf_3dtmZAxisBottomFace_ != NULL )
        p_cf_3dtmZAxisBottomFace_->draw3D( p_bf_dspOutputDisplay );
    if ( p_cf_3dtmPolarFloor_ != NULL )
        p_cf_3dtmPolarFloor_->draw3D( p_bf_dspOutputDisplay );
}

cf_3DTextMarker*
cf_TitleMarkerMgr::markerTitle()
{   // If we don't yet have one...
    if( p_cf_3dtmTitle_ == NULL )
    {   // Make One !
        p_cf_3dtmTitle_ = markerLabelAt( 0.0, 120.0, -120.0,  "Chart Title" );
        // ... give it attributes!
        p_cf_3dtmTitle_->dispAttribsNewSet();
        p_cf_3dtmTitle_->attribTextNew();
    }
    // OK, so we've now got something to point to!...
    return ( p_cf_3dtmActiveMarker_ = p_cf_3dtmTitle_ );
}


cf_3DTextMarker*
cf_TitleMarkerMgr::markerSubTitle()
{   // If we don't yet have one...
    if( p_cf_3dtmSubTitle_ == NULL )
    {   // Make One !
        p_cf_3dtmSubTitle_ = markerLabelAt( 0.0, 118.0, 0.0,
                                              "(optional sub-title)" );
        // ... give it attributes!
        p_cf_3dtmSubTitle_->dispAttribsNewSet();
        p_cf_3dtmSubTitle_->attribTextNew();
    }
    // OK, so we've now got something to point to!...
    return ( p_cf_3dtmActiveMarker_ = p_cf_3dtmSubTitle_ );
}

cf_3DTextMarker*
cf_TitleMarkerMgr::markerAxis_X_BackFace()
{   // If we don't yet have one...
    if( p_cf_3dtmXAxisBackFace_ == NULL )
        // Do NOT make one -- just POINT to the one we want!
        p_cf_3dtmXAxisBackFace_ = p_cf_engParent_->axis_X_BackFace()->markerLabel();

    // OK, so we've now got something to point to!...
    return ( p_cf_3dtmActiveMarker_ = p_cf_3dtmXAxisBackFace_ );
}

cf_3DTextMarker*
cf_TitleMarkerMgr::markerAxis_X_BottomFace()
{   // If we don't yet have one...
    if( p_cf_3dtmXAxisBottomFace_ == NULL )
        // Do NOT make one -- just POINT to the one we want!
        p_cf_3dtmXAxisBottomFace_ = p_cf_engParent_->axis_X_BottomFace()->markerLabel();
    // OK, so we've now got something to point to!...
    return ( p_cf_3dtmActiveMarker_ = p_cf_3dtmXAxisBottomFace_ );
}

cf_3DTextMarker*
cf_TitleMarkerMgr::markerAxis_Y_LeftFace()
{   // If we don't yet have one...
    if( p_cf_3dtmYAxisLeftFace_ == NULL )
        // Do NOT make one -- just POINT to the one we want!
        p_cf_3dtmYAxisLeftFace_ = p_cf_engParent_->axis_Y_LeftFace()->markerLabel();

    // OK, so we've now got something to point to!...
    return ( p_cf_3dtmActiveMarker_ = p_cf_3dtmYAxisLeftFace_ );
}

cf_3DTextMarker*
cf_TitleMarkerMgr::markerAxis_Y_BackFace()
{   // If we don't yet have one...
    if( p_cf_3dtmYAxisBackFace_ == NULL )
        // Do NOT make one -- just POINT to the one we want!
        p_cf_3dtmYAxisBackFace_ = p_cf_engParent_->axis_Y_BackFace()->markerLabel();

    // OK, so we've now got something to point to!...
    return ( p_cf_3dtmActiveMarker_ = p_cf_3dtmYAxisBackFace_ );
}




cf_3DTextMarker*
cf_TitleMarkerMgr::markerAxis_Z_LeftFace()
{   // If we don't yet have one...
    if( p_cf_3dtmZAxisLeftFace_ == NULL )
        // Do NOT make one -- just POINT to the one we want!
        p_cf_3dtmZAxisLeftFace_ = p_cf_engParent_->axis_Z_LeftFace()->markerLabel();

    // OK, so we've now got something to point to!...
    return ( p_cf_3dtmActiveMarker_ = p_cf_3dtmZAxisLeftFace_ );
}

cf_3DTextMarker*
cf_TitleMarkerMgr::markerAxis_Z_BottomFace()
{   // If we don't yet have one...
    if( p_cf_3dtmZAxisBottomFace_ == NULL )
        // Do NOT make one -- just POINT to the one we want!
        p_cf_3dtmZAxisBottomFace_  = p_cf_engParent_->axis_Z_BottomFace()->markerLabel();

    // OK, so we've now got something to point to!...
    return ( p_cf_3dtmActiveMarker_ = p_cf_3dtmZAxisBottomFace_ );
}

cf_3DTextMarker*
cf_TitleMarkerMgr::markerAxis_Polar_Floor()
{   // If we don't yet have one...
    if( p_cf_3dtmPolarFloor_ == NULL )
        // Do NOT make one -- just POINT to the one we want!
        p_cf_3dtmPolarFloor_  = p_cf_engParent_->axis_Polar_Floor()->markerLabel();

    // OK, so we've now got something to point to!...
    return ( p_cf_3dtmActiveMarker_ = p_cf_3dtmPolarFloor_ );
}


void
cf_TitleMarkerMgr::reset()
{
    cf_3DTextMarkerSeries::reset();

    // Init ALL the title text marker pointers to a KNOWN (and testable) state:
    p_cf_3dtmTitle_            = NULL;
    p_cf_3dtmSubTitle_         = NULL;

    p_cf_3dtmXAxisBackFace_    = NULL;
    p_cf_3dtmXAxisBottomFace_  = NULL;
    p_cf_3dtmYAxisLeftFace_    = NULL;
    p_cf_3dtmYAxisBackFace_   = NULL;
    p_cf_3dtmZAxisLeftFace_    = NULL;
    p_cf_3dtmZAxisBottomFace_  = NULL;

    p_cf_3dtmPolarFloor_       = NULL;
}

//-----------------------------------------------------
// End of cf_TitleMarkerMgr object implementation.
//-----------------------------------------------------

////////////////////////////////////////
// End of File: CO1_TMS.CPP
////////////////////////////////////////

