////////////////////////////////////////
// START of File: CO1_TLIN.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_tlin.hpp> 
            // relative to the IDE's (global) include path: ~/cfrz

#include    <math.h>   
            // We'll need the std math lib for geometric/trig functions.

//
// Default c-tor
//              
cf_3DTextLine
    ::cf_3DTextLine( const char *a_cUserLabel )
        :cf_3DPolyLine()
{
    //
    // Init applicable member vars:
    //
    this->bIsActive = FALSE;
    this->cf_strLineLabel = a_cUserLabel;
    this->p_cf_asfsForLabel = new cf_AutoScaleFontSpec();
    this->p_cf_asfsForLabel->preferFontToProjRectPct( 3.0 );
    this->bDoWeDrawLabel = FALSE;
    this->bDoWeDrawLine = FALSE;
    
    this->bUseDispBackColor = TRUE;

    this->bHorizShiftLeft = FALSE;
    this->bHorizShiftRight = FALSE;
    this->bHorizCentered = TRUE;
    
    this->bVertShiftUp = FALSE;
    this->bVertShiftDown = FALSE;
    this->bVertCentered = TRUE;

    //
    // Construct a "Default" Text Line:
    //
    cf_3DPoint      cf_3dpLineCtor( 0, 0, 0 );
    cf_3DPolyLine::addPoint( cf_3dpLineCtor );
    cf_3dpLineCtor.dataX( 100 );
    cf_3DPolyLine::addPoint( cf_3dpLineCtor );


}   // end of c-tor( Using NO points)




cf_3DTextLine
    ::~cf_3DTextLine() 
        {}

cf_AutoScaleFontSpec*
    cf_3DTextLine
        ::autoScaleFontSpec()
            { return this->p_cf_asfsForLabel; }
    
void    
    cf_3DTextLine
        ::autoScaleFontSpec( cf_AutoScaleFontSpec *p_cf_asfsUseThisSpec )
        { *(this->p_cf_asfsForLabel) = *(p_cf_asfsUseThisSpec ); }



//
// A cf_3DTextLine needs to draw its label along the screen
// projection of its line, so we need to calc this angle.
//
// The return value here is an int which is the font orientation
// angle in 10ths of degrees, as per zApp spec.
//
int
    cf_3DTextLine
        ::calcFontOrientation() 
{
    if ( this->bIsActive !=  TRUE ) return 0;

    double  dAngleInRadians;
            // Gets the aTan angle between the head and tail points.
    
    int     iAngleInTenths;
            // Font Angle values will be in tenths of degrees.

    //
    // Screen for bogosities.
    //                      
    if ( cf_3DPolyLine::numPoints() != 2 ) return 0;

    //
    // Set up an aTan function between the head and tail points:
    //  
    cf_3DPoint  cf_3dpPoint1, cf_3dpPoint2;
    cf_2DPoint     cf_2dpPoint1, cf_2dpPoint2;
    cf_3dpPoint1 = cf_3DPolyLine::getPoint( 1 );
    cf_3dpPoint2 = cf_3DPolyLine::getPoint( 2 );
    cf_2dpPoint1 = cf_3dpPoint1.screenPoint();
    cf_2dpPoint2 = cf_3dpPoint2.screenPoint();
    
    double  dDeltaY 
            = (double) 
            ( cf_2dpPoint2.y() - cf_2dpPoint1.y() );
    double  dDeltaX 
            = (double) 
            ( cf_2dpPoint2.x() - cf_2dpPoint1.x() );
    
    dAngleInRadians = - atan2( dDeltaY, dDeltaX );

    //debug( "(int)dAngleInRadians = %d ", (int)(dAngleInRadians * 1000) );
    
    iAngleInTenths 
                = ((int) (dAngleInRadians / CF_PI_OVER_180) ) * 10;
    
    //debug( "iAngleInTenths = %d ", iAngleInTenths );
        
    return( iAngleInTenths );
    
}   // end of cf_3DTextLine::calcFontOrientation() 



BOOL
    cf_3DTextLine
        ::colorUsingDispBack()
            { return this->bUseDispBackColor; }
        
void
    cf_3DTextLine
        ::colorUsingDispBack( BOOL bNewState )
            { this->bUseDispBackColor = bNewState; }



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


void
    cf_3DTextLine
        ::draw3D( bf_Display *p_bf_dspOutputDisplay )
{
    if ( this->bIsActive != TRUE ) return;

    //
    // Drawing "the line" is really more of a distraction... but:
    //
    if ( this->bDoWeDrawLine == TRUE )
        cf_3DPolyLine::draw3D( p_bf_dspOutputDisplay );

    //
    // Don't incur font calculation overhead unless
    // we're serious about this!...
    //
    if ( this->bDoWeDrawLabel != TRUE ) return;

    //
    // 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... and ROTATED (whoo-hoo!) font spec:
    //
    int iDisplayAtAngle = this->calcFontOrientation();
    /*
    this->p_cf_asfsForLabel->displayAtAngle(    p_bf_dspOutputDisplay,
                                                iDisplayAtAngle );
      */                                                
    bf_FontSpec    dspOutputFontSpec
                    = this->p_cf_asfsForLabel 
                        ->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 );

    //
    // ...and Position, Construct, & Draw the Text Line's Label:
    //
    if ( this->cf_strLineLabel.cf_strlen() > 0 )
    // Don't bother to process if there's nothing to work with:
    {
        //
        // Break Down this Text Line's Coordinates:
        //
        cf_3DPoint  cf_3dpHead = this->getPoint( 1 );
        cf_2DPoint cf_2dpHead = cf_3dpHead.screenPoint();
        int iHeadX = cf_2dpHead.x();
        int iHeadY = cf_2dpHead.y();

        cf_3DPoint  cf_3dpTail = this->getPoint( 2 );
        cf_2DPoint cf_2dpTail = cf_3dpTail.screenPoint();
        int iTailX = cf_2dpTail.x();
        int iTailY = cf_2dpTail.y();

        //
        // Get the Text's "Display Text-Box Dimensions":
        //
        cf_2DRect  cf_2drTextDim 
                        = p_bf_dspOutputDisplay
                            ->dsp_getTextRect( this->cf_strLineLabel );

        int iTextBoxWidth = cf_2drTextDim.width();
        int iTextBoxHeight = cf_2drTextDim.height();

        //
        // Calc any necessary text-box offsets:
        //
        int iTextBoxWidthShift = 0;
        int iTextBoxHeightShift = 0;

        if ( this->bHorizShiftLeft == TRUE )
            iTextBoxWidthShift = 0;
        else if ( this->bHorizShiftRight == TRUE )
            iTextBoxWidthShift = iTextBoxWidth;
        else    // this->bHorizCentered == TRUE; default 
            iTextBoxWidthShift = iTextBoxWidth / 2;
        
        if ( this->bVertShiftUp == TRUE )
            iTextBoxHeightShift = iTextBoxHeight;
        else if ( this->bVertShiftDown == TRUE )
            iTextBoxHeightShift = 0;
        else    // this->bVertCentered == TRUE; default 
            iTextBoxHeightShift = iTextBoxHeight / 2;

        //
        // Set up an aTan function between the head and tail points:
        //  
        double  dDeltaY = (double) ( iTailY - iHeadY );
        double  dDeltaX = (double) ( iTailX - iHeadX );
        double  dAngleInRadians = - atan2( dDeltaY, dDeltaX );
                // Gets the aTan angle between the head and tail points.

        //
        // Calc Delta Xs & Ys from the Text Box offsets
        // in the context of the current line angle:
        //
        double  dTextBoxWidthDeltaX
                = (double) iTextBoxWidthShift * cos( dAngleInRadians );

        double  dTextBoxWidthDeltaY
                = (double) iTextBoxWidthShift * sin( dAngleInRadians );

        double  dTextBoxHeightDeltaX
                = (double) iTextBoxHeightShift * sin( dAngleInRadians );

        double  dTextBoxHeightDeltaY
                = (double) iTextBoxHeightShift * cos( dAngleInRadians );

        int     iTextBoxDeltaX 
                = (int) ( dTextBoxWidthDeltaX + dTextBoxHeightDeltaX );

        int     iTextBoxDeltaY 
                = (int) ( dTextBoxWidthDeltaY + dTextBoxHeightDeltaY );

        //
        // Figure where we will actually draw the text box at:
        //
        cf_2DPoint cf_2dpDrawLabelAt;
                    
        if ( this->bHorizShiftLeft == TRUE )
        {
            // Use the HEAD of the line
            cf_2dpDrawLabelAt  = cf_3dpHead.screenPoint();
        }
        else if ( this->bHorizShiftRight == TRUE )
        {
            // Use the TAIL of the line
            cf_2dpDrawLabelAt  = cf_3dpTail.screenPoint();
        }
        else    // this->bHorizCentered == TRUE; default 
        {
            // Use the PROJECTED MIDDLE of the line
            int iAvgX = ( iHeadX + iTailX ) / 2;
            int iAvgY = ( iHeadY + iTailY ) / 2;
                                
            cf_2dpDrawLabelAt  = cf_2DPoint( iAvgX, iAvgY );
        }

        //
        // Tack-on horizontal & vertical "text box
        // rotation tweaks":
        //
        cf_2dpDrawLabelAt.x() -= iTextBoxDeltaX;
        cf_2dpDrawLabelAt.y() += iTextBoxDeltaY;

        //
        // Barf the text out to the display, in
        // the *owning* object's font context!...
        //
        p_bf_dspOutputDisplay->dsp_text(   cf_2dpDrawLabelAt, 
                                            cf_strLineLabel );

    }   // end of screen for null-strings


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

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

    return;

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

    

BOOL
    cf_3DTextLine
        ::dispLabel()
            { return this->bDoWeDrawLabel; }

void
    cf_3DTextLine
        ::dispLabel( BOOL bNewState )
            { this->bDoWeDrawLabel = bNewState; }

BOOL
    cf_3DTextLine
        ::dispLine()
            { return this->bDoWeDrawLine; }

void
    cf_3DTextLine
        ::dispLine( BOOL bNewState )
            { this->bDoWeDrawLine = bNewState; }




//
// Reset a Marker Line's endpoints:
//
void    
    cf_3DTextLine
        ::endPoints(    cf_3DPoint cf_3dpPoint1, 
                    cf_3DPoint cf_3dpPoint2 ) 
{
    cf_3DPolyLine::reset();
    
    cf_3DPolyLine::addPoint( cf_3dpPoint1 );
    cf_3DPolyLine::addPoint( cf_3dpPoint2 );
}
    
void    
    cf_3DTextLine
        ::endPoints(    double  dPoint1X,
                        double  dPoint1Y,
                        double  dPoint1Z,
                        
                        double  dPoint2X,
                        double  dPoint2Y,
                        double  dPoint2Z  ) 
{
    cf_3DPolyLine::reset();

    cf_3DPoint  cf_3dpLineCtor;

    cf_3dpLineCtor.dataXYZ( dPoint1X, dPoint1Y, dPoint1Z );
    cf_3DPolyLine::addPoint( cf_3dpLineCtor );

    cf_3dpLineCtor.dataXYZ( dPoint2X, dPoint2Y, dPoint2Z );
    cf_3DPolyLine::addPoint( cf_3dpLineCtor );
}


BOOL
    cf_3DTextLine
        ::isActive()
            { return this->bIsActive; }

BOOL
    cf_3DTextLine
        ::isActive( BOOL bNewState )
            { return( this->bIsActive = bNewState ); }




cf_String* 
    cf_3DTextLine
        ::labelIs()
            { return &(this->cf_strLineLabel); }

void            
    cf_3DTextLine
        ::labelIs( cf_String *p_cf_strUseThisString )
{ 
    if ( p_cf_strUseThisString != NULL )
    {
        this->cf_strLineLabel = *p_cf_strUseThisString; 
        this->bDoWeDrawLabel = TRUE;
        // we'll say if they GAVE a label, they MUST want to draw it!
    }
}


void            
    cf_3DTextLine
        ::labelIs( const char *a_cStringConst )
{
    if ( a_cStringConst != NULL )
    {
        this->cf_strLineLabel = a_cStringConst; 
        this->bDoWeDrawLabel = TRUE;
    }   // we'll say if they GAVE a label, they MUST want to draw it!
}


BOOL            
    cf_3DTextLine
        ::labelSet()
            { return TRUE; }    // since we always have a value...
            // compare with a "3D Text-Marker" object, 
            // which new()s a pointer to a cf_String...
    

void            
    cf_3DTextLine
        ::labelPlacedVertAboveLine( BOOL bNewState )
    { 
        this->bVertShiftUp = bNewState; 
        this->bVertShiftDown = !bNewState; 
        this->bVertCentered = !bNewState; 
    }

BOOL            
    cf_3DTextLine
        ::labelPlacedVertAboveLine()
            { return this->bVertShiftUp; }
    
void            
    cf_3DTextLine
        ::labelPlacedVertBelowLine( BOOL bNewState )
    { 
        this->bVertShiftUp = !bNewState; 
        this->bVertShiftDown = bNewState; 
        this->bVertCentered = !bNewState; 
    }

BOOL            
    cf_3DTextLine
        ::labelPlacedVertBelowLine()
            { return this->bVertShiftDown; }

void            
    cf_3DTextLine
        ::labelPlacedVertCentOnLine( BOOL bNewState )
    { 
        this->bVertShiftUp = !bNewState; 
        this->bVertShiftDown = !bNewState; 
        this->bVertCentered = bNewState; 
    }

BOOL            
    cf_3DTextLine
        ::labelPlacedVertCentOnLine()
            { return this->bVertCentered; }

void            
    cf_3DTextLine
        ::labelPlacedHorizLeftOnLine( BOOL bNewState )
    { 
        this->bHorizShiftLeft = bNewState; 
        this->bHorizShiftRight = !bNewState; 
        this->bHorizCentered = !bNewState; 
    }

BOOL            
    cf_3DTextLine
        ::labelPlacedHorizLeftOnLine()
            { return this->bHorizShiftLeft; }

void            
    cf_3DTextLine
        ::labelPlacedHorizRightOnLine( BOOL bNewState )
    { 
        this->bHorizShiftLeft = !bNewState; 
        this->bHorizShiftRight = bNewState; 
        this->bHorizCentered = !bNewState; 
    }

BOOL            
    cf_3DTextLine
        ::labelPlacedHorizRightOnLine()
            { return this->bHorizShiftRight; }

void            
    cf_3DTextLine
        ::labelPlacedHorizCentOnLine( BOOL bNewState )
    { 
        this->bHorizShiftLeft = !bNewState; 
        this->bHorizShiftRight = !bNewState; 
        this->bHorizCentered = bNewState; 
    }

BOOL            
    cf_3DTextLine
        ::labelPlacedHorizCentOnLine()
            { return this->bHorizCentered; }



void
    cf_3DTextLine
        ::on()
            { this->bIsActive = TRUE; }

void
    cf_3DTextLine
        ::off()
            { this->bIsActive = FALSE; }
    

//
// End of class cf_3DTextLine Implementation
//

////////////////////////////////////////
// END of File: CO1_TLIN.CPP
////////////////////////////////////////
    
    







