////////////////////////////////////////
// Start of File: CO1_TMAR.CPP
////////////////////////////////////////

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

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


// Use this ctor to generate a cf_3DTextMarker from three cf_3DPoints:
cf_3DTextMarker::cf_3DTextMarker()

        : cf_Virt3DObj()
{
    // Construct the "default" Marker Line Points:
    this->p_cf_3dpTail = new cf_3DPoint();
    this->p_cf_3dpHead = new cf_3DPoint();
    this->p_cf_3dpText = new cf_3DPoint();
                            // All with x=y=z=0, and CF_BLACK

    // Init the "(virtual) Geometry State":
    this->dTransX = this->dTransY = this->dTransZ = 0.0;
    this->dScaleFacX = this->dScaleFacY = this->dScaleFacZ = 1.0;
                                    // a default init state...

    this->dVirtXMax = this->dVirtYMax = this->dVirtZMax = 0.0;
    this->dVirtXMin = this->dVirtYMin = this->dVirtZMin = 0.0;
                                    // since all points are x=y=z=0.

    // Init run-time drawing attribs:
    this->bDoWeDrawTailLine = FALSE;
    this->bDoWeDrawHeadLine = FALSE;
    bDrawInverted_ = FALSE;
    this->bDoWeDrawTailPoint = FALSE;
    this->bDoWeDrawHeadPoint = FALSE;
 
    // Init label/string member vars:
    this->bWasLabelSet = FALSE;
    this->bDoWeDrawLabel = FALSE;

    this->p_cf_strLabel = NULL;
    this->bWasLabelNewed = FALSE;

    return;

}   // end of default c-tor


//
// Use this ctor to generate a cf_3DTextMarker
// from three cf_3DPoints:
//
cf_3DTextMarker
    ::cf_3DTextMarker(  cf_3DPoint  *p_cf_3dpTailPoint,
                        cf_3DPoint  *p_cf_3dpHeadPoint,
                        cf_3DPoint  *p_cf_3dpTextPoint )
        : cf_Virt3DObj()
{
    // Construct the Marker Line from the ALREADY new()ed
    // (by another "on-site" user object) "3D Point" pointers:
    this->p_cf_3dpTail = p_cf_3dpTailPoint;
    this->p_cf_3dpHead = p_cf_3dpHeadPoint;
    this->p_cf_3dpText = p_cf_3dpTextPoint;
                            // All as the "on-site" USER set them up!...

    // Init the "(virtual) Geometry State":
    this->dTransX = this->dTransY = this->dTransZ = 0.0;
    this->dScaleFacX = this->dScaleFacY = this->dScaleFacZ = 1.0;
                                    // a default init state...

    this->dVirtXMax = this->p_cf_3dpTail->virtXMax();
    this->dVirtXMin = this->p_cf_3dpTail->virtXMin();
    this->dVirtYMax = this->p_cf_3dpTail->virtYMax();
    this->dVirtYMin = this->p_cf_3dpTail->virtYMin();
    this->dVirtZMax = this->p_cf_3dpTail->virtZMax();
    this->dVirtZMin = this->p_cf_3dpTail->virtZMin();
            // Start from the "tail point" as a default...

    if ( this->p_cf_3dpHead->virtXMax() > this->dVirtXMax )
        this->dVirtXMax = this->p_cf_3dpHead->virtXMax();
    if ( this->p_cf_3dpHead->virtXMin() < this->dVirtXMin )
        this->dVirtXMin = this->p_cf_3dpHead->virtXMin();
    if ( this->p_cf_3dpHead->virtYMax() > this->dVirtYMax )
        this->dVirtYMax = this->p_cf_3dpHead->virtYMax();
    if ( this->p_cf_3dpHead->virtYMin() < this->dVirtYMin )
        this->dVirtYMin = this->p_cf_3dpHead->virtYMin();
    if ( this->p_cf_3dpHead->virtZMax() > this->dVirtZMax )
        this->dVirtZMax = this->p_cf_3dpHead->virtZMax();
    if ( this->p_cf_3dpHead->virtZMin() < this->dVirtZMin )
        this->dVirtZMin = this->p_cf_3dpHead->virtZMin();
            // Does the "head point" change anything?...

    if ( this->p_cf_3dpText->virtXMax() > this->dVirtXMax )
        this->dVirtXMax = this->p_cf_3dpText->virtXMax();
    if ( this->p_cf_3dpText->virtXMin() < this->dVirtXMin )
        this->dVirtXMin = this->p_cf_3dpText->virtXMin();
    if ( this->p_cf_3dpText->virtYMax() > this->dVirtYMax )
        this->dVirtYMax = this->p_cf_3dpText->virtYMax();
    if ( this->p_cf_3dpText->virtYMin() < this->dVirtYMin )
        this->dVirtYMin = this->p_cf_3dpText->virtYMin();
    if ( this->p_cf_3dpText->virtZMax() > this->dVirtZMax )
        this->dVirtZMax = this->p_cf_3dpText->virtZMax();
    if ( this->p_cf_3dpText->virtZMin() < this->dVirtZMin )
        this->dVirtZMin = this->p_cf_3dpText->virtZMin();
            // How about the "text point"?...

    // Init run-time drawing attribs:
    this->bDoWeDrawTailLine = FALSE;
    this->bDoWeDrawHeadLine = FALSE;
    bDrawInverted_ = FALSE;
    this->bDoWeDrawTailPoint = FALSE;
    this->bDoWeDrawHeadPoint = FALSE;

    // Init label/string member vars:
    this->bWasLabelSet = FALSE;
    this->bDoWeDrawLabel = FALSE;

    this->p_cf_strLabel = NULL;
    this->bWasLabelNewed = FALSE;

    return;

}   // end of parameterized c-tor


//
// Use this ctor to generate a cf_3DTextMarker 
// from three cf_3DPoints:
//              
cf_3DTextMarker
    ::cf_3DTextMarker(  const   cf_3DPoint  &cr_cf_3dpTailPoint,
                        const   cf_3DPoint  &cr_cf_3dpHeadPoint, 
                        const   cf_3DPoint  &cr_cf_3dpTextPoint )
        : cf_Virt3DObj()
{
    // First, allocate a set of "default" Marker Line Points:
    this->p_cf_3dpTail = new cf_3DPoint();
    this->p_cf_3dpHead = new cf_3DPoint();
    this->p_cf_3dpText = new cf_3DPoint();  
                            // All with x=y=z=0, and CF_BLACK

    // Then, copy the references into our newly allocated points:
    *(this->p_cf_3dpTail) = cr_cf_3dpTailPoint;
    *(this->p_cf_3dpHead) = cr_cf_3dpHeadPoint;
    *(this->p_cf_3dpText) = cr_cf_3dpTextPoint;
                        // Just as the "on-site" USER set them up!...

    // Init the "(virtual) Geometry State":
    this->dTransX = this->dTransY = this->dTransZ = 0.0;
    this->dScaleFacX = this->dScaleFacY = this->dScaleFacZ = 1.0;
                                    // a default init state...

    this->dVirtXMax = this->p_cf_3dpTail->virtXMax();
    this->dVirtXMin = this->p_cf_3dpTail->virtXMin();
    this->dVirtYMax = this->p_cf_3dpTail->virtYMax();
    this->dVirtYMin = this->p_cf_3dpTail->virtYMin();
    this->dVirtZMax = this->p_cf_3dpTail->virtZMax();
    this->dVirtZMin = this->p_cf_3dpTail->virtZMin();
            // Start from the "tail point" as a default...

    if ( this->p_cf_3dpHead->virtXMax() > this->dVirtXMax )
        this->dVirtXMax = this->p_cf_3dpHead->virtXMax();
    if ( this->p_cf_3dpHead->virtXMin() < this->dVirtXMin )
        this->dVirtXMin = this->p_cf_3dpHead->virtXMin();
    if ( this->p_cf_3dpHead->virtYMax() > this->dVirtYMax )
        this->dVirtYMax = this->p_cf_3dpHead->virtYMax();
    if ( this->p_cf_3dpHead->virtYMin() < this->dVirtYMin )
        this->dVirtYMin = this->p_cf_3dpHead->virtYMin();
    if ( this->p_cf_3dpHead->virtZMax() > this->dVirtZMax )
        this->dVirtZMax = this->p_cf_3dpHead->virtZMax();
    if ( this->p_cf_3dpHead->virtZMin() < this->dVirtZMin )
        this->dVirtZMin = this->p_cf_3dpHead->virtZMin();
            // Does the "head point" change anything?...

    if ( this->p_cf_3dpText->virtXMax() > this->dVirtXMax )
        this->dVirtXMax = this->p_cf_3dpText->virtXMax();
    if ( this->p_cf_3dpText->virtXMin() < this->dVirtXMin )
        this->dVirtXMin = this->p_cf_3dpText->virtXMin();
    if ( this->p_cf_3dpText->virtYMax() > this->dVirtYMax )
        this->dVirtYMax = this->p_cf_3dpText->virtYMax();
    if ( this->p_cf_3dpText->virtYMin() < this->dVirtYMin )
        this->dVirtYMin = this->p_cf_3dpText->virtYMin();
    if ( this->p_cf_3dpText->virtZMax() > this->dVirtZMax )
        this->dVirtZMax = this->p_cf_3dpText->virtZMax();
    if ( this->p_cf_3dpText->virtZMin() < this->dVirtZMin )
        this->dVirtZMin = this->p_cf_3dpText->virtZMin();
            // How about the "text point"?...

    // Init run-time drawing attribs:
    this->bDoWeDrawTailLine = FALSE;
    this->bDoWeDrawHeadLine = FALSE;
    bDrawInverted_ = FALSE;
    this->bDoWeDrawTailPoint = FALSE;
    this->bDoWeDrawHeadPoint = FALSE;

    // Init label/string member vars:
    this->bWasLabelSet = FALSE;
    this->bDoWeDrawLabel = FALSE;

    this->p_cf_strLabel = NULL;
    this->bWasLabelNewed = FALSE;

    return;

}   // end of parameterized c-tor 


cf_3DTextMarker
    ::~cf_3DTextMarker() 
{
    // Delete the allocated 3D points:
    if ( this->p_cf_3dpTail != NULL ) delete this->p_cf_3dpTail;
    if ( this->p_cf_3dpHead != NULL ) delete this->p_cf_3dpHead;
    if ( this->p_cf_3dpText != NULL ) delete this->p_cf_3dpText;

    // If we new()ed a Label String -- LOOSE IT!
    if ( this->bWasLabelNewed == TRUE )
        if ( this->p_cf_strLabel != NULL )
            delete this->p_cf_strLabel;
}



cf_3DTextMarker&
    cf_3DTextMarker
        ::operator=( const cf_3DTextMarker& cr_cf_3dtmSource )
{
    // Copy the essential base member var values:
    cf_Virt3DObj::operator=( cr_cf_3dtmSource );

    // "Content copy" the references points into our allocated points:
    *(this->p_cf_3dpTail) = *(cr_cf_3dtmSource.p_cf_3dpTail);
    *(this->p_cf_3dpHead) = *(cr_cf_3dtmSource.p_cf_3dpHead);
    *(this->p_cf_3dpText) = *(cr_cf_3dtmSource.p_cf_3dpText);

    // Copy the (Virtual) Geometry State info:
    this->dVirtXMax     = cr_cf_3dtmSource.dVirtXMax;
    this->dVirtYMax     = cr_cf_3dtmSource.dVirtYMax;
    this->dVirtZMax     = cr_cf_3dtmSource.dVirtZMax;
    this->dVirtXMin     = cr_cf_3dtmSource.dVirtXMin;
    this->dVirtYMin     = cr_cf_3dtmSource.dVirtYMin;
    this->dVirtZMin     = cr_cf_3dtmSource.dVirtZMin;

    this->dTransX       = cr_cf_3dtmSource.dTransX;
    this->dTransY       = cr_cf_3dtmSource.dTransY;
    this->dTransZ       = cr_cf_3dtmSource.dTransZ;

    this->dScaleFacX        = cr_cf_3dtmSource.dScaleFacX;
    this->dScaleFacY        = cr_cf_3dtmSource.dScaleFacY;
    this->dScaleFacZ        = cr_cf_3dtmSource.dScaleFacZ;
                            // Geometry state copied.

    // Copy derived run-time drawing attribs:
    this->bDoWeDrawTailLine     = cr_cf_3dtmSource.bDoWeDrawTailLine;
    this->bDoWeDrawHeadLine     = cr_cf_3dtmSource.bDoWeDrawHeadLine;
    bDrawInverted_              = cr_cf_3dtmSource.bDrawInverted_;
    this->bDoWeDrawTailPoint    = cr_cf_3dtmSource.bDoWeDrawTailPoint;
    this->bDoWeDrawHeadPoint    = cr_cf_3dtmSource.bDoWeDrawHeadPoint;

    // NOW -- Copy (and perhaps allocate with a few new()s )
    // the derived label/string member vars:
    this->bWasLabelSet          = cr_cf_3dtmSource.bWasLabelSet;
    this->bDoWeDrawLabel        = cr_cf_3dtmSource.bDoWeDrawLabel;

    // If the target new()ed its OWN "Label String"
    // object, (i.e. it's NOT using someone else's Label)...
    if ( cr_cf_3dtmSource.bWasLabelNewed == TRUE )
    {
        // Make ourselves ready to do a CONTENT copy (if needed)...
        if ( this->bWasLabelNewed == FALSE )
        {
            this->p_cf_strLabel = new cf_String();
            this->bWasLabelNewed = TRUE;
        }   // Keep track of what we just did (for the d-tor!);

        // ...now we're ready to do a CONTENT copy:
        *(this->p_cf_strLabel)= *(cr_cf_3dtmSource.p_cf_strLabel);
    }
    else
    // The target did NOT new() its own label string -- it's
    // just pointing to someone else's -- let's point there, too!
    {
        this->p_cf_strLabel = cr_cf_3dtmSource.p_cf_strLabel;
        this->bWasLabelNewed = FALSE;
        // Keep track of what we just did (for the d-tor!);
    }

    return *this;
}


void
cf_3DTextMarker::applyGeomXform
                ( cf_Kernel *p_cf_kUseThisKernel )
{
    this->p_cf_3dpTail->applyGeomXform( p_cf_kUseThisKernel );
    this->p_cf_3dpHead->applyGeomXform( p_cf_kUseThisKernel );
    this->p_cf_3dpText->applyGeomXform( p_cf_kUseThisKernel );
}

void
cf_3DTextMarker::applyProjXform
                ( cf_Kernel *p_cf_kUseThisKernel )
{
    this->p_cf_3dpTail->applyProjXform( p_cf_kUseThisKernel );
    this->p_cf_3dpHead->applyProjXform( p_cf_kUseThisKernel );
    this->p_cf_3dpText->applyProjXform( p_cf_kUseThisKernel );
}


void
cf_3DTextMarker::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;

    this->applyTranslateOp( -dSaveXTrans,
                                -dSaveYTrans, -dSaveZTrans );

    // Apply the scale factors to the XYZ coords of the 3D Points:
    this->p_cf_3dpTail
            ->applyScaleOp( dXScaleFactor, dYScaleFactor, dZScaleFactor );
    this->p_cf_3dpHead
            ->applyScaleOp( dXScaleFactor, dYScaleFactor, dZScaleFactor );
    this->p_cf_3dpText
            ->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:
    this->applyTranslateOp( dSaveXTrans,
                                dSaveYTrans, dSaveZTrans );
    return;

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



void
cf_3DTextMarker::applyTranslateOp
                (   double  dXTrans,
                    double  dYTrans,
                    double  dZTrans  )
{
    // Apply the xlations to the XYZ coords of the polyline points.
    this->p_cf_3dpTail->applyTranslateOp( dXTrans, dYTrans, dZTrans );
    this->p_cf_3dpHead->applyTranslateOp( dXTrans, dYTrans, dZTrans );
    this->p_cf_3dpText->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_3DTextMarker::applyTranslateOp(...)




cf_DispAttribs*
cf_3DTextMarker::dispAttribsNewSet()
{
    // Use the base class methodology:
    cf_Virt3DObj::dispAttribsNewSet();

    if ( bWereDispAttribsSet_ == TRUE )
    {
        // Tell our child points to also use this new display attrib object:
        this->p_cf_3dpTail->dispAttribsPointTo( p_cf_datbForDrawOps_ );
        this->p_cf_3dpHead->dispAttribsPointTo( p_cf_datbForDrawOps_ );
        this->p_cf_3dpText->dispAttribsPointTo( p_cf_datbForDrawOps_ );
    }

    return p_cf_datbForDrawOps_;
}


void
cf_3DTextMarker::dispAttribsPointTo
                ( cf_DispAttribs *p_cf_datbTarget )
{
    // Use the base class methodology:
    cf_Virt3DObj::dispAttribsPointTo( p_cf_datbTarget );

    if ( bWereDispAttribsSet_ == TRUE )
    {
        // Tell our child points to also use this new display attrib object:
        this->p_cf_3dpTail->dispAttribsPointTo( p_cf_datbForDrawOps_ );
        this->p_cf_3dpHead->dispAttribsPointTo( p_cf_datbForDrawOps_ );
        this->p_cf_3dpText->dispAttribsPointTo( p_cf_datbForDrawOps_ );
    }

    return;

}   // end of cf_3DTextMarker::dispAttribsSetTo( cf_DispAttribs * )



BOOL
    cf_3DTextMarker
        ::dispLineHead()
            { return this->bDoWeDrawHeadLine; }
void
    cf_3DTextMarker
        ::dispLineHead( BOOL bNewState )
            { this->bDoWeDrawHeadLine = bNewState; }


BOOL
    cf_3DTextMarker
        ::dispLineTail()
            { return this->bDoWeDrawTailLine; }
void
    cf_3DTextMarker
        ::dispLineTail( BOOL bNewState )
            { this->bDoWeDrawTailLine = bNewState; }

BOOL
cf_3DTextMarker::dispInverted()
{
    return( bDrawInverted_ );
}

void
cf_3DTextMarker::dispInverted
                ( BOOL bNewState )
{
    bDrawInverted_ = bNewState;
}


BOOL
    cf_3DTextMarker
        ::dispMarkerHead()
            { return this->bDoWeDrawHeadPoint; }
void
    cf_3DTextMarker
        ::dispMarkerHead( BOOL bNewState )
            { this->bDoWeDrawHeadPoint = bNewState; }


BOOL
    cf_3DTextMarker
        ::dispMarkerTail()
            { return this->bDoWeDrawTailPoint; }
void
    cf_3DTextMarker
        ::dispMarkerTail( BOOL bNewState )
            { this->bDoWeDrawTailPoint = bNewState; }


BOOL
    cf_3DTextMarker
        ::dispText()
            { return this->bDoWeDrawLabel; }

void
    cf_3DTextMarker
        ::dispText( BOOL bNewState )
{
    if ( this->bWasLabelSet == TRUE )
            this->bDoWeDrawLabel = bNewState;
}


void
    cf_3DTextMarker
        ::draw2D( bf_Display *p_bf_dspOutputDisplay )
            { this->draw3D( p_bf_dspOutputDisplay ); }


void
    cf_3DTextMarker
        ::draw3D( bf_Display *p_bf_dspOutputDisplay )
{
    // Construct the polyline to be drawn:
    cf_2DPoint *a_cf_2dpDrawArray = new cf_2DPoint[ 3 ];

    a_cf_2dpDrawArray[ 0 ] = p_cf_3dpTail->screenPoint();
    a_cf_2dpDrawArray[ 1 ] = p_cf_3dpHead->screenPoint();
    a_cf_2dpDrawArray[ 2 ] = p_cf_3dpText->screenPoint();

    // Draw the "tail" and "head" of the polyLine-derived Text Marker:
    this->dispPushPenAttribs( p_bf_dspOutputDisplay );

    if ( this->bDoWeDrawTailLine == TRUE )
        p_bf_dspOutputDisplay->dsp_polyline( &a_cf_2dpDrawArray[ 0 ], 2 );
    if ( this->bDoWeDrawHeadLine == TRUE )
        p_bf_dspOutputDisplay->dsp_polyline( &a_cf_2dpDrawArray[ 1 ], 2 );

    this->dispPopPenAttribs( p_bf_dspOutputDisplay );

    if ( this->bDoWeDrawTailPoint == TRUE )
        p_cf_3dpTail->draw3D( p_bf_dspOutputDisplay );
    if ( this->bDoWeDrawHeadPoint == TRUE )
        p_cf_3dpHead->draw3D( p_bf_dspOutputDisplay );
        // Note that these point objects establish their OWN pen/brush context

    // Clean up:
    delete [] a_cf_2dpDrawArray;
            // .vs. delete [ this->iNumPoints ] a_cf_2dpDrawArray;

    // Position, Construct, & Draw the Text Marker's text label.
    if ( this->bWasLabelSet == FALSE ) return;
    if ( this->bDoWeDrawLabel == FALSE ) return;
    if ( this->p_cf_strLabel->cf_strlen() <= 0 ) return;
        // Don't bother to process if there's nothing to work with:

    // Determine a run-time font-spec for the text, which will be either
    // an (auto-scale) font-spec this object has a pointer to, or we'll
    // just go with whatever font is already selected into the display...
    BOOL        bResetAttribs = FALSE;
    BOOL        bPushedNewFont = FALSE;     // may switch REAL quick!...

    bf_Color   bf_clrSaveOldTextColor;
    bf_Color   bf_clrSaveOldBackColor;    // MAY get used below...

    if ( this->dispIgnorePushFont() == FALSE )
    // ...IF -- we're on our own, and should push our own font!...
    {
        if ( attribTextValid() == TRUE )
        // And ... IF we've got an Auto-Scale Font Spec to work with!...
        {
            bResetAttribs = TRUE;   // So we can restore what we alter...

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

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

            p_bf_dspOutputDisplay->dsp_textColor( bf_clrTextFore );
            p_bf_dspOutputDisplay->dsp_backColor( bf_clrTextBack );

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

            // NOW, (finally), we can push on our output font:
            p_bf_dspOutputDisplay->dsp_pushFont( p_bf_fonOutputFont );
            bPushedNewFont = TRUE;
                    // Voila!  Now a font is pushed on the display
                    // -- for this text marker to use to render its label...

        }   // end of screen for non-null font spec.

    }   // end of screen for using our OWN display attribs.


    // Get the screen point and the text dimensions:
    cf_2DPoint cf_2dpDrawLabelAt = this->p_cf_3dpText->screenPoint();
    if ( bDrawInverted_ ) cf_2dpDrawLabelAt = p_cf_3dpHead->screenPoint();

    cf_2DRect  cf_2drTextDim = p_bf_dspOutputDisplay
                                    ->dsp_getTextRect( *(this->p_cf_strLabel) );

    double  dTextXDim = cf_2drTextDim.width();
    double  dTextYDim = cf_2drTextDim.height();

    double  dCurrAngle = attribTextCurrent()->angleRotationRadians();

    double  dXAngleFactor = cos( dCurrAngle );
    double  dYAngleFactor = sin( dCurrAngle );

    double  dRotatedXDim = (dTextXDim * dXAngleFactor) + (dTextYDim * dYAngleFactor);
    double  dRotatedYDim = (dTextXDim * dYAngleFactor) + (dTextYDim * dXAngleFactor);

    int     iOffsetX = (int) dRotatedXDim;
    int     iOffsetY = (int) dRotatedYDim;

    // See if we need to perform any offsets:
    int iAngleInDegrees = attribTextCurrent()->angleRotationDegrees();
    if ( iAngleInDegrees == 0 )
    {
        if ( attribTextCurrent()->shiftHorzLeftIs() == TRUE )
            cf_2dpDrawLabelAt.x() -= iOffsetX;
        else if ( attribTextCurrent()->shiftHorzRightIs() == TRUE )
            ; // No need to do anything...
        else // default: textAttribCurrent()->shiftHorzCtr() == TRUE
            cf_2dpDrawLabelAt.x() -= (int) ( iOffsetX / 2 );

        if ( attribTextCurrent()->shiftVertUpIs() == TRUE )
            cf_2dpDrawLabelAt.y() -= iOffsetY;
        else if ( attribTextCurrent()->shiftVertDownIs() == TRUE  )
            ; // No need to do anything...
        else // default: attribTextCurrent()->shiftVertCtrIs() == TRUE
            cf_2dpDrawLabelAt.y() -= (int) ( iOffsetY / 2 );
    }
    else if ( iAngleInDegrees < 0 )
    {
        if ( attribTextCurrent()->shiftHorzLeftIs() == TRUE )
            ; // No need to do anything...
        else if ( attribTextCurrent()->shiftHorzRightIs() == TRUE )
            cf_2dpDrawLabelAt.x() -= iOffsetX;
        else // default: textAttribCurrent()->shiftHorzCtr() == TRUE
            cf_2dpDrawLabelAt.x() -= (int) ( iOffsetX / 2 );

        if ( attribTextCurrent()->shiftVertUpIs() == TRUE )
            cf_2dpDrawLabelAt.y() -= iOffsetY;
        else if ( attribTextCurrent()->shiftVertDownIs() == TRUE  )
            ; // no need to do anything...
        else // default: attribTextCurrent()->shiftVertCtrIs() == TRUE
            cf_2dpDrawLabelAt.y() -= (int) ( iOffsetY / 2 );
    }
    else
    {
        if ( attribTextCurrent()->shiftHorzLeftIs() == TRUE )
            cf_2dpDrawLabelAt.x() -= iOffsetX;
        else if ( attribTextCurrent()->shiftHorzRightIs() == TRUE )
            ; // No need to do anything...
        else // default: textAttribCurrent()->shiftHorzCtr() == TRUE
            cf_2dpDrawLabelAt.x() -= (int) ( iOffsetX / 2 );

        if ( attribTextCurrent()->shiftVertUpIs() == TRUE )
            ; // No need to do anything...
        else if ( attribTextCurrent()->shiftVertDownIs() == TRUE  )
            cf_2dpDrawLabelAt.y() += iOffsetY;
        else // default: attribTextCurrent()->shiftVertCtrIs() == TRUE
            cf_2dpDrawLabelAt.y() += (int) ( iOffsetY / 2 );
    }

    // Barf the text out to the display, in the now-current font context!...
    p_bf_dspOutputDisplay->dsp_text(   cf_2dpDrawLabelAt,
                                        *(this->p_cf_strLabel) );
    // Clean up:
    if ( bResetAttribs == TRUE )
    {
        // Restore any display modifications:
        p_bf_dspOutputDisplay->dsp_textColor( bf_clrSaveOldTextColor );
        p_bf_dspOutputDisplay->dsp_backColor( bf_clrSaveOldBackColor );

        // Return any resource allocations:
        if ( bPushedNewFont == TRUE )
            delete p_bf_dspOutputDisplay->dsp_popFont();
    }

    return;
}



char*
cf_3DTextMarker::labelIs()
{
    // Note: how we don't just return the raw pointer...
    return( (char*) (* this->p_cf_strLabel ) );
                    // ... we *force* the conversion op (w/ parends)!
}

void
    cf_3DTextMarker
        ::labelNew( const char *a_cStringForNewLabel )
{
    // Screen to TRY to eliminate bogus values...
    if ( a_cStringForNewLabel != NULL )
    // ...which it MAY or MAY NOT, w.r.t. the skill of a given user...
    {
        // ONLY allocate a new label IF we haven't yet done so!
        if ( this->bWasLabelNewed == FALSE )
        {
            this->p_cf_strLabel = new cf_String();
            this->bWasLabelNewed = TRUE;
        }
        // NOW we're OK to copy the string constant...
        *(this->p_cf_strLabel) = a_cStringForNewLabel;
                                //... to the CURRENTLY ALLOCATED label.
    }
    this->bWasLabelSet = TRUE;
    this->bDoWeDrawLabel = TRUE;
    return;
}


void
    cf_3DTextMarker
        ::labelNew( const double    cdValueForNewLabel,
                    const char      *ca_cFormatString )
{
    // ONLY allocate a new label IF we haven't yet done so!
    if ( this->bWasLabelNewed == FALSE )
    {
        this->p_cf_strLabel = new cf_String();
        this->bWasLabelNewed = TRUE;
    }
    // NOW we're OK to reset the CURRENTLY ALLOCATED label...
    this->p_cf_strLabel->reset();
    this->p_cf_strLabel->cf_append( cdValueForNewLabel, ca_cFormatString );
    this->bWasLabelSet = TRUE;
    this->bDoWeDrawLabel = TRUE;
    return;
}

void
    cf_3DTextMarker
        ::labelNew( const int   ciValueForNewLabel,
                    const char  *ca_cFormatString )
{
    // ONLY allocate a new label IF we haven't yet done so!
    if ( this->bWasLabelNewed == FALSE )
    {
        this->p_cf_strLabel = new cf_String();
        this->bWasLabelNewed = TRUE;
    }
    // NOW we're OK to reset the CURRENTLY ALLOCATED label...
    this->p_cf_strLabel->reset();
    this->p_cf_strLabel->cf_append( ciValueForNewLabel, ca_cFormatString );
    this->bWasLabelSet = TRUE;
    this->bDoWeDrawLabel = TRUE;
    return;
}


BOOL
    cf_3DTextMarker
        ::labelSet()
            { return this->bWasLabelSet; }

void
    cf_3DTextMarker
        ::labelUsing( cf_String *p_cf_strSomeoneElsesLabel )
{
    if ( p_cf_strSomeoneElsesLabel != NULL )
    // ...which it MAY or MAY NOT, w.r.t. the skill of a given user...
    {
        // IF we allocate a string -- it's time to loose it!
        if ( this->bWasLabelNewed == TRUE )
        {
            delete this->p_cf_strLabel;
            this->bWasLabelNewed = FALSE;
        }
        // Point to the other object's string/label:
        this->p_cf_strLabel = p_cf_strSomeoneElsesLabel;

        // Update status vars:
        this->bWasLabelSet = TRUE;
        this->bDoWeDrawLabel = TRUE;
    }
    return;
}


cf_3DPoint*
cf_3DTextMarker::pointToHead()
{
    return this->p_cf_3dpHead;
}

cf_3DPoint*
cf_3DTextMarker::pointToTail()
{
    return this->p_cf_3dpTail;
}

cf_3DPoint*
cf_3DTextMarker::pointToText()
{
    return this->p_cf_3dpText;
}

//
// End of class cf_3DTextMarker Implementation.
//

////////////////////////////////////////
// END of File: CO1_TMAR.CPP
////////////////////////////////////////






