void ocpnDC::DrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, bool b_hiqual ) { if( dc ) dc->DrawLines( n, points, xoffset, yoffset ); else if( ConfigurePen() ) { glPushAttrib( GL_COLOR_BUFFER_BIT | GL_LINE_BIT | GL_HINT_BIT ); //Save state SetGLAttrs( b_hiqual ); bool b_draw_thick = false; SetGLStipple(); // Enable anti-aliased lines, at best quality if( b_hiqual ) { if( m_pen.GetWidth() > 1 ) { GLint parms[2]; glGetIntegerv( GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0] ); if( m_pen.GetWidth() > parms[1] ) b_draw_thick = true; else glLineWidth( wxMax(g_GLMinLineWidth, m_pen.GetWidth()) ); } else glLineWidth( wxMax(g_GLMinLineWidth, 1) ); } else { if( m_pen.GetWidth() > 1 ) { GLint parms[2]; glGetIntegerv( GL_ALIASED_LINE_WIDTH_RANGE, &parms[0] ); if( m_pen.GetWidth() > parms[1] ) b_draw_thick = true; else glLineWidth( wxMax(g_GLMinLineWidth, m_pen.GetWidth()) ); } else glLineWidth( wxMax(g_GLMinLineWidth, 1) ); } if( b_draw_thick/*m_pen.GetWidth() > 1*/) { wxPoint p0 = points[0]; for( int i = 1; i < n; i++ ) { DrawThickLine( p0.x + xoffset, p0.y + yoffset, points[i].x + xoffset, points[i].y + yoffset, m_pen, b_hiqual ); p0 = points[i]; } } else { glBegin( GL_LINE_STRIP ); for( int i = 0; i < n; i++ ) glVertex2i( points[i].x + xoffset, points[i].y + yoffset ); glEnd(); } glPopAttrib(); // restore state } }
void ocpnDC::DrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, bool b_hiqual ) { if( dc ) dc->DrawLine( x1, y1, x2, y2 ); else { glPushAttrib( GL_COLOR_BUFFER_BIT | GL_LINE_BIT | GL_ENABLE_BIT | GL_HINT_BIT ); //Save state if( ConfigurePen() ) { glDisable( GL_MULTISAMPLE ); bool b_draw_thick = false; float pen_width = wxMax(g_GLMinLineWidth, m_pen.GetWidth()); // Enable anti-aliased lines, at best quality if( b_hiqual ) { SetGLStipple(); glEnable( GL_LINE_SMOOTH ); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glHint( GL_LINE_SMOOTH_HINT, GL_NICEST ); if( pen_width > 1.0 ) { GLint parms[2]; glGetIntegerv( GL_SMOOTH_LINE_WIDTH_RANGE, &parms[0] ); if( pen_width > parms[1] ) b_draw_thick = true; else glLineWidth( pen_width ); } else glLineWidth( pen_width ); } else { glDisable( GL_LINE_SMOOTH ); glDisable( GL_BLEND ); if( pen_width > 1 ) { GLint parms[2]; glGetIntegerv( GL_ALIASED_LINE_WIDTH_RANGE, &parms[0] ); if( pen_width > parms[1] ) b_draw_thick = true; else glLineWidth( pen_width ); } else glLineWidth( pen_width ); } if( b_draw_thick ) DrawThickLine( x1, y1, x2, y2, m_pen, b_hiqual ); else { wxDash *dashes; int n_dashes = m_pen.GetDashes( &dashes ); if( n_dashes ) { double angle = atan2( (double) ( y2 - y1 ), (double) ( x2 - x1 ) ); double cosa = cos( angle ); double sina = sin( angle ); double t1 = m_pen.GetWidth(); double lpix = sqrt( (double) ( x1 - x2 ) * ( x1 - x2 ) + (double) ( y1 - y2 ) * ( y1 - y2 ) ); double lrun = 0.; double xa = x1; double ya = y1; double ldraw = t1 * dashes[0]; double lspace = t1 * dashes[1]; while( lrun < lpix ) { // Dash double xb = xa + ldraw * cosa; double yb = ya + ldraw * sina; if( ( lrun + ldraw ) >= lpix ) // last segment is partial draw { xb = x2; yb = y2; } glBegin( GL_LINES ); glVertex2f( xa, ya ); glVertex2f( xb, yb ); glEnd(); xa = xa + ( lspace + ldraw ) * cosa; ya = ya + ( lspace + ldraw ) * sina; lrun += lspace + ldraw; } } else // not dashed { glBegin( GL_LINES ); glVertex2i( x1, y1 ); glVertex2i( x2, y2 ); glEnd(); } } } glPopAttrib(); } }
// Draw a string in the specified font void BaseEngine::DrawString(int iX, int iY, const char* pText, unsigned int uiColour, Font* pFont, SDL_Surface* pTarget ) { if ( pTarget == NULL ) pTarget = m_pActualScreen; if ( pFont == NULL ) pFont = g_pMainFont; if ( m_bInsideDraw ) if (SDL_MUSTLOCK(m_pActualScreen)) SDL_UnlockSurface(m_pActualScreen); SDL_Color color = { (uiColour&0xff0000)>>16, (uiColour&0xff00)>>8, (uiColour&0xff), 0 }; if ( ( pFont != NULL ) && ( pFont->GetFont() != NULL ) ) { SDL_Surface *sText = TTF_RenderText_Solid( pFont->GetFont(), pText, color ); SDL_Rect rcDest = {iX,iY,0,0}; SDL_BlitSurface( sText, NULL, pTarget, &rcDest ); SDL_FreeSurface( sText ); } if ( m_bInsideDraw ) if (SDL_MUSTLOCK(m_pActualScreen)) SDL_LockSurface(m_pActualScreen); } // Draw a triangle, as two vertical sided regions. void BaseEngine::DrawTriangle( double fX1, double fY1, double fX2, double fY2, double fX3, double fY3, unsigned int uiColour, SDL_Surface* pTarget ) { if ( pTarget == NULL ) pTarget = m_pActualScreen; // Ensure order is 1 2 3 from left to right if ( fX1 > fX2 ) { Swap( fX1,fX2 ); Swap( fY1,fY2 ); } // Bigger of 1 and 2 is in position 2 if ( fX2 > fX3 ) { Swap( fX2,fX3 ); Swap( fY2,fY3 ); } // Bigger of new 2 and 3 is in position 3 if ( fX1 > fX2 ) { Swap( fX1,fX2 ); Swap( fY1,fY2 ); } // Bigger of 1 and new 2 is in position 2 if ( fX1 == fX2 ) DrawVerticalSidedRegion( fX1, fX3, fY1, fY3, fY2, fY3, uiColour, pTarget ); else if ( fX2 == fX3 ) DrawVerticalSidedRegion( fX1, fX3, fY1, fY2, fY1, fY3, uiColour, pTarget ); else { // Split into two triangles. Find position on line 1-3 to split at double dSplitPointY = (double)fY1 + ( ( (double)((fX2-fX1)*(fY3-fY1)) ) / (double)(fX3-fX1) ); DrawVerticalSidedRegion( fX1, fX2, fY1, fY2, fY1, dSplitPointY, uiColour, pTarget ); DrawVerticalSidedRegion( fX2, fX3, fY2, fY3, dSplitPointY, fY3, uiColour, pTarget ); } } // Draw a vertical sided region. // If two points are the same then it is a triangle. // To do an arbitrary triangle, just draw two next to each other, one for left and one for right. void BaseEngine::DrawVerticalSidedRegion( double fX1, double fX2,// X positions double fY1a, double fY2a, // Start y positions for x1 and x2 double fY1b, double fY2b, // End y positions for x1 and x2 unsigned int uiColour, SDL_Surface* pTarget) { if ( pTarget == NULL ) pTarget = m_pActualScreen; // Ensure X1< X2, otherwise steps will go wrong! // Switch the points if x and y are wrong way round if ( fX2< fX1 ) { Swap(fX1,fX2); Swap(fY1a,fY2a); Swap(fY1b,fY2b); } int iXStart = (int)(fX1+0.5); int iXEnd = (int)(fX2+0.5); // If integer x positions are the same then avoid floating point inaccuracy problems by a special case if ( iXStart == iXEnd ) { int iYStart = (int)(fY1a+0.5); int iYEnd = (int)(fY2a+0.5); for ( int iY = iYStart ; iY<= iYEnd ; iY++ ) SafeSetPixel( iXStart, iY, uiColour, pTarget ); } else { // Draw left hand side int iYStart = (int)(fY1a+0.5); int iYEnd = (int)(fY1b+0.5); if ( iYStart> iYEnd ) Swap( iYStart, iYEnd ); //printf( "Firstline %d to %d (%f to %f)\n", iYStart, iYEnd, fY1a, fY1b ); for ( int iY = iYStart ; iY<= iYEnd ; iY++ ) SafeSetPixel( iXStart, iY, uiColour, pTarget ); // Draw the middle for ( int iX = iXStart+1 ; iX< iXEnd ; iX++ ) { double fYStart = fY1a + ( (((double)iX)-fX1)*(fY2a-fY1a)) /(fX2-fX1); double fYEnd = fY1b + ((((double)iX)-fX1)*(fY2b-fY1b))/(fX2-fX1); if ( fYEnd< fYStart ) Swap( fYStart, fYEnd ); int iYStart = (int)(fYStart+0.5); int iYEnd = (int)(fYEnd+0.5); //printf( "Line from %d to %d (%f to %f)\n", iYStart, iYEnd, fYStart, fYEnd ); for ( int iY = iYStart ; iY<= iYEnd ; iY++ ) SafeSetPixel( iX, iY, uiColour, pTarget ); } // Draw right hand side iYStart = (int)(fY2a+0.5); iYEnd = (int)(fY2b+0.5); if ( iYStart> iYEnd ) Swap( iYStart, iYEnd ); //printf( "Last line %d to %d (%f to %f)\n", iYStart, iYEnd, fY2a, fY2b ); for ( int iY = iYStart ; iY<= iYEnd ; iY++ ) SafeSetPixel( iXEnd, iY, uiColour, pTarget ); } } // Draw a rectangle on the specified surface void BaseEngine::DrawRectangle(int iX1, int iY1, int iX2, int iY2, unsigned int uiColour, SDL_Surface* pTarget) { if ( pTarget == NULL ) pTarget = m_pActualScreen; if ( iX2 < iX1 ) { int t = iX1; iX1 = iX2; iX2 = t; } if ( iY2 < iY1 ) { int t = iY1; iY1 = iY2; iY2 = t; } for ( int iX = iX1 ; iX <= iX2 ; iX++ ) for ( int iY = iY1 ; iY <= iY2 ; iY++ ) SafeSetPixel( iX, iY, uiColour, pTarget ); } // Draw an oval on the specified surface void BaseEngine::DrawOval(int iX1, int iY1, int iX2, int iY2, unsigned int uiColour, SDL_Surface* pTarget) { if ( pTarget == NULL ) pTarget = m_pActualScreen; if ( iX2 < iX1 ) { int t = iX1; iX1 = iX2; iX2 = t; } if ( iY2 < iY1 ) { int t = iY1; iY1 = iY2; iY2 = t; } double fCentreX = ((double)(iX2+iX1))/2.0; double fCentreY = ((double)(iY2+iY1))/2.0; double fXFactor = (double)((iX2-iX1) * (iX2-iX1))/4.0; double fYFactor = (double)((iY2-iY1) * (iY2-iY1))/4.0; double fDist; for ( int iX = iX1 ; iX <= iX2 ; iX++ ) for ( int iY = iY1 ; iY <= iY2 ; iY++ ) { fDist = ((double)iX - fCentreX) * ((double)iX - fCentreX)/fXFactor + ((double)iY - fCentreY) * ((double)iY - fCentreY)/fYFactor; if ( fDist <= 1.0 ) SafeSetPixel( iX, iY, uiColour, pTarget ); } } // Draw an oval on the specified surface void BaseEngine::DrawHollowOval( int iX1, int iY1, int iX2, int iY2, int iX3, int iY3, int iX4, int iY4, unsigned int uiColour, SDL_Surface* pTarget) { if ( pTarget == NULL ) pTarget = m_pActualScreen; if ( iX2 < iX1 ) Swap( iX1, iX2 ); if ( iY2 < iY1 ) Swap( iY1, iY2 ); if ( iX4 < iX3 ) Swap( iX3, iX4 ); if ( iY4 < iY3 ) Swap( iY3, iY4 ); double fCentreX1 = ((double)(iX2+iX1))/2.0; double fCentreY1 = ((double)(iY2+iY1))/2.0; double fXFactor1 = (double)((iX2-iX1) * (iX2-iX1))/4.0; double fYFactor1 = (double)((iY2-iY1) * (iY2-iY1))/4.0; double fCentreX2 = ((double)(iX4+iX3))/2.0; double fCentreY2 = ((double)(iY4+iY3))/2.0; double fXFactor2 = (double)((iX4-iX3) * (iX4-iX3))/4.0; double fYFactor2 = (double)((iY4-iY3) * (iY4-iY3))/4.0; double fDist1, fDist2; for ( int iX = iX1 ; iX <= iX2 ; iX++ ) for ( int iY = iY1 ; iY <= iY2 ; iY++ ) { fDist1 = ((double)iX - fCentreX1) * ((double)iX - fCentreX1)/fXFactor1 + ((double)iY - fCentreY1) * ((double)iY - fCentreY1)/fYFactor1; fDist2 = ((double)iX - fCentreX2) * ((double)iX - fCentreX2)/fXFactor2 + ((double)iY - fCentreY2) * ((double)iY - fCentreY2)/fYFactor2; if ( ( fDist1 <= 1.0 ) && ( fDist2 >= 1.0 ) ) SafeSetPixel( iX, iY, uiColour, pTarget ); } } // Draw a line on the specified surface void BaseEngine::DrawLine(double fX1, double fY1, double fX2, double fY2, unsigned int uiColour, SDL_Surface* pTarget) { if ( pTarget == NULL ) pTarget = m_pActualScreen; int iX1 = (int)(fX1+0.5); int iX2 = (int)(fX2+0.5); int iY1 = (int)(fY1+0.5); int iY2 = (int)(fY2+0.5); int iSteps = (iX2-iX1); if ( iSteps < 0 ) iSteps = -iSteps; if ( iY2 > iY1 ) iSteps += (iY2-iY1); else iSteps += (iY1-iY2); iSteps+=2; double fXStep = ((double)(fX2-fX1))/iSteps; double fYStep = ((double)(fY2-fY1))/iSteps; for ( int i = 0 ; i <= iSteps ; i++ ) { SafeSetPixel( (int)(0.5 + fX1 + fXStep*i), (int)(0.5 + fY1 + fYStep*i), uiColour, pTarget ); } } // Draw a thick line on the specified surface void BaseEngine::DrawThickLine( double fX1, double fY1, double fX2, double fY2, unsigned int uiColour, int iThickness, SDL_Surface* pTarget) { if ( pTarget == NULL ) pTarget = m_pActualScreen; if ( iThickness < 2 ) { // Go to the quicker draw function DrawLine(fX1, fY1, fX2, fY2, uiColour, pTarget); return; } double fAngle1 = GetAngle( fX1, fY1, fX2, fY2 ); double fAngle1a = fAngle1 - ((5 * M_PI) / 4.0); double fAngle1b = fAngle1 + ((5 * M_PI) / 4.0); double fRectX1 = fX1 + iThickness * cos(fAngle1a) * 0.5; double fRectY1 = fY1 + iThickness * sin(fAngle1a) * 0.5; double fRectX2 = fX1 + iThickness * cos(fAngle1b) * 0.5; double fRectY2 = fY1 + iThickness * sin(fAngle1b) * 0.5; double fAngle2 = fAngle1 + M_PI; double fAngle2a = fAngle2 - ((5 * M_PI) / 4.0); double fAngle2b = fAngle2 + ((5 * M_PI) / 4.0); double fRectX3 = fX2 + iThickness * cos(fAngle2a) * 0.5; double fRectY3 = fY2 + iThickness * sin(fAngle2a) * 0.5; double fRectX4 = fX2 + iThickness * cos(fAngle2b) * 0.5; double fRectY4 = fY2 + iThickness * sin(fAngle2b) * 0.5; DrawTriangle( fRectX1, fRectY1, fRectX2, fRectY2, fRectX3, fRectY3, uiColour, pTarget ); DrawTriangle( fRectX3, fRectY3, fRectX4, fRectY4, fRectX1, fRectY1, uiColour, pTarget ); } // Draw a polygon on the specified surface void BaseEngine::DrawPolygon( int iPoints, double* pXArray, double* pYArray, unsigned int uiColour, SDL_Surface* pTarget) { if ( pTarget == NULL ) pTarget = m_pActualScreen; if ( iPoints == 1 ) { SafeSetPixel( pXArray[0], pYArray[0], uiColour, pTarget ); return; } if ( iPoints == 2 ) { DrawLine( pXArray[0], pYArray[0], pXArray[1], pYArray[1], uiColour, pTarget ); return; } /* if ( iPoints == 3 ) { printf( "Draw triangle for points 0, 1, 2 of %d available\n", iPoints ); DrawTriangle( pXArray[0], pYArray[0], pXArray[1], pYArray[1], pXArray[2], pYArray[2], uiColour, pTarget ); return; } */ // Otherwise attempt to eliminate a point by filling the polygon, then call this again double fXCentre, fYCentre; //fX1, fX2, fX3, fY1, fY2, fY3; int i2, i3; double fAngle1, fAngle2, fAngle3; for ( int i1 = 0 ; i1 < iPoints ; i1++ ) { i2 = i1 + 1; if ( i2 >= iPoints ) i2 -= iPoints; i3 = i1 + 2; if ( i3 >= iPoints ) i3 -= iPoints; fXCentre = (pXArray[i1] + pXArray[i2] + pXArray[i3]) / 3.0; fYCentre = (pYArray[i1] + pYArray[i2] + pYArray[i3]) / 3.0; fAngle1 = GetAngle( fXCentre, fYCentre, pXArray[i1], pYArray[i1] ); fAngle2 = GetAngle( fXCentre, fYCentre, pXArray[i2], pYArray[i2] ); fAngle3 = GetAngle( fXCentre, fYCentre, pXArray[i3], pYArray[i3] ); // Now work out the relative angle positions and make sure all are positive fAngle2 -= fAngle1; if ( fAngle2 < 0 ) fAngle2 += 2*M_PI; fAngle3 -= fAngle1; if ( fAngle3 < 0 ) fAngle3 += 2*M_PI; if ( fAngle2 < fAngle3 ) { // Then points are in clockwise order so central one can be eliminated as long as we don't // fill an area that we shouldn't bool bPointIsWithinTriangle = false; if ( iPoints > 3 ) { // Need to check that there isn't a point within the area - for convex shapes double fLineAngle12 = GetAngle( pXArray[i1], pYArray[i1], pXArray[i2], pYArray[i2] ); if ( fLineAngle12 < 0 ) fLineAngle12 += M_PI * 2.0; double fLineAngle23 = GetAngle( pXArray[i2], pYArray[i2], pXArray[i3], pYArray[i3] ); if ( fLineAngle23 < 0 ) fLineAngle23 += M_PI * 2.0; double fLineAngle31 = GetAngle( pXArray[i3], pYArray[i3], pXArray[i1], pYArray[i1] ); if ( fLineAngle31 < 0 ) fLineAngle31 += M_PI * 2.0; for ( int i = i3+1 ; i != i1 ; i++ ) { if ( i >= iPoints ) { i = 0; if ( i1 == 0 ) break; // From the for loop - finished } // Otherwise we need to work out whether point i is to right of line i3 to i1 double fPointAngle1 = GetAngle( pXArray[i1], pYArray[i1], pXArray[i], pYArray[i] ); if ( fPointAngle1 < 0 ) fPointAngle1 += M_PI * 2.0; fPointAngle1 -= fLineAngle12; if ( fPointAngle1 < 0 ) fPointAngle1 += M_PI * 2.0; double fPointAngle2 = GetAngle( pXArray[i2], pYArray[i2], pXArray[i], pYArray[i] ); if ( fPointAngle2 < 0 ) fPointAngle2 += M_PI * 2.0; fPointAngle2 -= fLineAngle23; if ( fPointAngle2 < 0 ) fPointAngle2 += M_PI * 2.0; double fPointAngle3 = GetAngle( pXArray[i3], pYArray[i3], pXArray[i], pYArray[i] ); if ( fPointAngle3 < 0 ) fPointAngle3 += M_PI * 2.0; fPointAngle3 -= fLineAngle31; if ( fPointAngle3 < 0 ) fPointAngle3 += M_PI * 2.0; if ( ( fPointAngle1 < M_PI ) && ( fPointAngle2 < M_PI ) && ( fPointAngle3 < M_PI ) ) bPointIsWithinTriangle = true; } } if ( !bPointIsWithinTriangle ) {// If not then try the next position printf( "Draw for points %d, %d, %d of %d available\n", i1, i2, i3, iPoints ); DrawTriangle( pXArray[i1], pYArray[i1], pXArray[i2], pYArray[i2], pXArray[i3], pYArray[i3], /*GetColour(iPoints)*/uiColour, pTarget ); // Remove the point i2 and then recurse for ( int i = i2 ; i < (iPoints-1) ; i++ ) { printf( "\tCopy point %d to %d\n", i+1, i ); pXArray[i] = pXArray[i+1]; pYArray[i] = pYArray[i+1]; } if ( iPoints > 3 ) DrawPolygon( iPoints - 1, pXArray, pYArray, uiColour, pTarget ); return; // Done } } } } /* Added in 2014 since it was used in the GroundMovement playback program so may be useful elsewhere too, but students can ignore this */ void BaseEngine::DrawShortenedArrow( int iX1,int iY1,int iX2,int iY2, int iShortenedStart,int iShortenedEnd, unsigned int uiColour,int iThickness, int iHeadSize,SDL_Surface* pTarget ) { if ( pTarget == NULL ) pTarget = m_pActualScreen; //iShortenedStart += 10; // Test //iShortenedEnd += 10; // Test double dAngle1 = GetAngle( iX1,iY1,iX2,iY2 ); double dAngle2 = dAngle1 + M_PI; double dX1 = iX1 + iShortenedStart * cos( dAngle1 ); double dY1 = iY1 + iShortenedStart * sin( dAngle1 ); double dX2 = iX2 + iShortenedEnd * cos( dAngle2 ); double dY2 = iY2 + iShortenedEnd * sin( dAngle2 ); // First draw the line if ( iThickness < 2 ) { // Go to the quicker draw function DrawLine( dX1,dY1,dX2,dY2,uiColour,pTarget ); } else { double dX1l = iX1 + iShortenedStart * cos( dAngle1 ); double dY1l = iY1 + iShortenedStart * sin( dAngle1 ); double dX2l = iX2 + (iShortenedEnd + iThickness*1.5) * cos( dAngle2 ); double dY2l = iY2 + (iShortenedEnd + iThickness*1.5) * sin( dAngle2 ); DrawThickLine( dX1l,dY1l,dX2l,dY2l,uiColour,iThickness,pTarget ); } // Now draw the arrow head. // Need three points - one is end of line and others are at 60 degrees from it. DrawTriangle( dX2,dY2, dX2 + iHeadSize * cos( dAngle2 + M_PI / 6.0 ),dY2 + iHeadSize * sin( dAngle2 + M_PI / 6.0 ), dX2 + iHeadSize * cos( dAngle2 - M_PI / 6.0 ),dY2 + iHeadSize * sin( dAngle2 - M_PI / 6.0 ), uiColour,pTarget ); } /* Added in 2014 since it was used in the GroundMovement playback program so may be useful elsewhere too, but students can ignore this */ void BaseEngine::DrawShortenedLine( int iX1,int iY1,int iX2,int iY2, int iShortenedStart,int iShortenedEnd, unsigned int uiColour,int iThickness,SDL_Surface* pTarget ) { if ( pTarget == NULL ) pTarget = m_pActualScreen; double dAngle1 = GetAngle( iX1,iY1,iX2,iY2 ); double dAngle2 = dAngle1 + M_PI; // First draw the line if ( iThickness < 2 ) { // Go to the quicker draw function double dX1 = iX1 + iShortenedStart * cos( dAngle1 ); double dY1 = iY1 + iShortenedStart * sin( dAngle1 ); double dX2 = iX2 + iShortenedEnd * cos( dAngle2 ); double dY2 = iY2 + iShortenedEnd * sin( dAngle2 ); DrawLine( dX1,dY1,dX2,dY2,uiColour,pTarget ); } else { double dX1l = iX1 + iShortenedStart * cos( dAngle1 ); double dY1l = iY1 + iShortenedStart * sin( dAngle1 ); double dX2l = iX2 + iShortenedEnd * cos( dAngle2 ); double dY2l = iY2 + iShortenedEnd * sin( dAngle2 ); if ( iX1 == iX2 ) printf( "Draw shortened line %d,%d to %d,%d shortened by %d,%d is %f,%f %f,%f\n", iX1,iY1,iX2,iY2,iShortenedStart,iShortenedEnd, dX1l,dY1l,dX2l,dY2l ); DrawThickLine( dX1l,dY1l,dX2l,dY2l,uiColour,iThickness,pTarget ); } } void BaseEngine::NotifyAllObjects( int iSignalNumber ) { if (displayableObjects != NULL) { for (int i = 0; (*displayableObjects)[i] != NULL; i++) { (*displayableObjects)[i]->Notify(iSignalNumber); } } } /* Send a specified notification value to all displayable objects and count the number which give a non-zero response. */ int BaseEngine::NotifyAllObjectsGetCountNonZero( int iSignalNumber ) { int iReturn = 0; if (displayableObjects != NULL) { for (int i = 0; (*displayableObjects)[i] != NULL; i++) { if ((*displayableObjects)[i]->Notify(iSignalNumber) != 0) iReturn++; } } return iReturn; }