diff -r 000000000000 -r 5d03bc08d59c graphicsdeviceinterface/gdi/sgdi/LINE.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graphicsdeviceinterface/gdi/sgdi/LINE.CPP Tue Feb 02 01:47:50 2010 +0200 @@ -0,0 +1,545 @@ +// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include + +#ifdef __ARMCC__ +#pragma arm +#pragma O3 +#pragma Otime +#endif + +EXPORT_C TLinearDDA::TLinearDDA(): + iCount(0), + iDifference(), + iFinish(), + iGradient(0), + iInc(), + iPos(), + iStart(), + iBoundingRect(), + iBoundingRectSet(EFalse), + iInsideX(EFalse), + iInsideY(EFalse), + iStatus(EComplete) +/** Constructs the default linear DDA. + +No start or end point is defined for the line. */ + {} + + +EXPORT_C TLinearDDA::TLinearDDA(const TLinearDDA& aLine): + iCount(aLine.iCount), + iDifference(aLine.iDifference), + iFinish(aLine.iFinish), + iGradient(aLine.iGradient), + iInc(aLine.iInc), + iPos(aLine.iPos), + iStart(aLine.iStart), + iBoundingRect(aLine.iBoundingRect), + iBoundingRectSet(aLine.iBoundingRectSet), + iInsideX(aLine.iInsideX), + iInsideY(aLine.iInsideY), + iStatus(aLine.iStatus) +/** Copy constructs a linear DDA from the specified linear DDA. + +@param aLine The linear DDA to be copied. */ + {} + + +EXPORT_C void TLinearDDA::Construct(const TPoint& aStart,const TPoint& aFinish,TLineMode aMode) +/** Constructs a linear DDA, setting the start and end points of the line. + +@param aStart The start point of the line. +@param aFinish The end point of the line. +@param aMode The mode of the line; defaults to centred. */ + { + iStart=aStart; + iFinish=aFinish; + iDifference=(iFinish-iStart).AsSize(); + iDifference.iWidth=Abs(iDifference.iWidth); + iDifference.iHeight=Abs(iDifference.iHeight); + iInc.iX=(iStart.iX>iFinish.iX)?-1:1; + iInc.iY=(iStart.iY>iFinish.iY)?-1:1; + if(iDifference.iWidth) + iGradient=(iFinish.iY-iStart.iY)/(iFinish.iX-iStart.iX); + iPos=iStart; + if(!iGradient) + iCount=iDifference.iWidth; + else + iCount=iDifference.iHeight; + if(aMode==ECenter) + iCount>>=1; + else + if(iCount) + iCount--; + iStatus=EInitialised; + if(aStart==aFinish) + iStatus=EComplete; + iBoundingRectSet=EFalse; + iInsideX = EFalse; + iInsideY = EFalse; + } + + +EXPORT_C TBool TLinearDDA::SingleStep(TPoint& aPosition) +/** Gets the pixel co-ordinates of the next pixel on the pixel line. + +The function is called repeatedly until the whole line has been traversed or, +if JumpToRect() has been called, until the part of the line inside the rectangle +has been traversed. Note that, for performance reasons, JumpToRect() may fail +to detect the intersection of the line with the rectangle accurately and +SingleStep() may return more points than strictly necessary. + +@param aPosition On entry to the first call, this can be a reference to any +point. On return from the first call, this is the position of the first pixel +in the line, as specified during construction of this object. On return from +subsequent calls, this is the position of subsequent pixels in the line, as +calculated by the function. On return from the final call, this is the position +of the last pixel in the line, as specified during construction of this object. +@return ETrue, when the position of the last pixel is returned; EFalse, +otherwise. */ + { + switch (iStatus) + { + case EInitialised: + aPosition = iStart; + iStatus = ECurrent; + return EFalse; + case ECurrent: + if (iDifference.iHeight == 0) // horizontal line + { + iPos.iX += iInc.iX; + if (iPos.iX == iFinish.iX) + { + iStatus = EComplete; + } + } + else if (iDifference.iWidth == 0) // vertical line + { + iPos.iY += iInc.iY; + if (iPos.iY == iFinish.iY) + { + iStatus = EComplete; + } + } + else // diagonal stripes + { + if (!iGradient) + { + iCount -= iDifference.iHeight; + iPos.iX += iInc.iX; + if (iCount < 0) + { + iCount += iDifference.iWidth; + iPos.iY += iInc.iY; + } + } + else + { + iCount -= iDifference.iWidth; + iPos.iY += iInc.iY; + if (iCount < 0) + { + iCount += iDifference.iHeight; + iPos.iX += iInc.iX; + } + } + if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY)) + { + iStatus = EComplete; + } + } + // common + aPosition = iPos; + if (iStatus == EComplete) + { + return ETrue; + } + if(iBoundingRectSet) + { + if (iPos.iX >= iBoundingRect.iTl.iX && iPos.iX < iBoundingRect.iBr.iX) + iInsideX = ETrue; + else + if (iInsideX) + { + iStatus=EComplete; + return(ETrue); + } + if (iPos.iY >= iBoundingRect.iTl.iY && iPos.iY < iBoundingRect.iBr.iY) + iInsideY = ETrue; + else + if (iInsideY) + { + iStatus=EComplete; + return(ETrue); + } + } + return EFalse; + default: + aPosition = iFinish; + return ETrue; + } + } + +EXPORT_C TBool TLinearDDA::NextStep(TPoint& aPosition) +/** Gets the pixel co-ordinates of the start of the next scan line. + +The best line that joins the start and end points is formed from all the scan +lines returned by this function. + +The function is called repeatedly until the start position of all scanlines +has been returned. + +The start and end points passed to the constructor of this object define the +boundaries of the line. Successive scan lines move from the start point to +the end point. + +@param aPosition On entry to the first call, this can be a reference to any +point. On return from the first call, this is the position of the pixel that +defines the leftmost position of the first scan line. On return from subsequent +calls, this is the position of the pixel that defines the leftmost position +of the next scan line. On return from the final call, this is the position +of the last pixel in the line, as specified during construction. +@return ETrue, when the position of the last pixel is returned; EFalse, +otherwise. */ + { + if (!iDifference.iHeight) // horizontal line + { + iPos = iFinish; + iStatus = EComplete; + aPosition = iFinish; + return ETrue; + } + if (!iDifference.iWidth || iGradient || (iStatus != ECurrent)) + { + return SingleStep(aPosition); + } + // !iGradient && (iStatus != EInitialised) + if(iBoundingRectSet) + { // slower version + while ((iCount - iDifference.iHeight) >= 0) + { + if (SingleStep(aPosition)) + return ETrue; + } + return SingleStep(aPosition); + } + // faster version avoids function calls + TBool lastLoop = EFalse; + do { + if ((iCount - iDifference.iHeight) < 0) + { + lastLoop = ETrue; + } + iCount -= iDifference.iHeight; + iPos.iX += iInc.iX; + if (iCount < 0) + { + iCount += iDifference.iWidth; + iPos.iY += iInc.iY; + } + + if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY)) + { + aPosition = iFinish; + iStatus = EComplete; + return ETrue; + } + } + while (!lastLoop); + aPosition = iPos; + return EFalse; + } + +EXPORT_C TBool TLinearDDA::SingleScanline(TPoint& aStartPosition,TPoint& aEndPosition) +/** Gets the start and end pixel co-ordinates that define the next scan line. + +The best line that joins the start and end points is formed from all the scan +lines returned by this function. + +The function is called repeatedly until the position of all scanlines has +been returned. + +The start and end points passed to the constructor of this object define the +boundaries of the line. Successive scan lines move from the start point to +the end point. + +@param aStartPosition On entry to the first call, this can be a reference +to any point. On return from the first call, this is the position of the pixel +that defines the leftmost position of the first scan line. On return from +subsequent calls, this is the position of the pixel that defines the leftmost +position of the next scan line. On return from the final call, either this +or aEndPosition is set to the end point, as specified during construction. +@param aEndPosition On entry to the first call, this can be a reference to +any point. On return from the first call, this is the position of the pixel +that defines the rightmost position of the first scan line. On return from +subsequent calls, this is the position of the pixel that defines the rightmost +position of the next scan line. On return from the final call, either this +or aStartPosition is set to the end point, as specified during construction. +@return ETrue, when the position of the last scan line includes the end point; +EFalse, otherwise. */ + { + TBool done=EFalse; + if(iDifference.iHeight==0) + { + aStartPosition=iStart; + aEndPosition=iFinish; + return(ETrue); + } + if(iDifference.iWidth==0 || iGradient) + { + done=SingleStep(aStartPosition); + aEndPosition=aStartPosition; + return(done); + } + // !iGradient + done=SingleStep(aStartPosition); + aEndPosition=aStartPosition; + while(iCount-iDifference.iHeight>=0 && !done) + { + iCount -= iDifference.iHeight; + iPos.iX += iInc.iX; + if (iCount < 0) + { + iCount += iDifference.iWidth; + iPos.iY += iInc.iY; + } + + if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY)) + { + iStatus = EComplete; + done = ETrue; + } + } + aEndPosition = iPos; + return done; + } + +EXPORT_C void TLinearDDA::JumpToRect(const TRect& aRect) +/** Jumps to start of a clipping rectangle. + +This will accelerate the linear DDA to the vicinity of the specified rectangle. +It is NOT guaranteed to reach the rectangle, but will reduce co-ordinates +that are 1000's out to co-ordinates that are 10's out. Because of this, failure +to intersect the rectangle may not be detected. If it is, or the line has +not been constructed or has been run to completion, then a subsequent call +to the stepping functions returns ETrue. + +@param aRect The rectangle to be jumped to. */ + { + if(aRect.IsEmpty() || iStatus!=EInitialised) return; + iBoundingRect=aRect; + iBoundingRectSet=ETrue; + + TInt nearestx = 0; + if (iStart.iX < aRect.iTl.iX) + nearestx = aRect.iTl.iX; + else if (iStart.iX >= aRect.iBr.iX) + nearestx = aRect.iBr.iX; + else + iInsideX = ETrue; + TInt nearesty = 0; + if (iStart.iY < aRect.iTl.iY) + nearesty = aRect.iTl.iY; + else if (iStart.iY >= aRect.iBr.iY) + nearesty = aRect.iBr.iY; + else + iInsideY = ETrue; + if (iInsideX && iInsideY) + return; + + TInt dummy; + if(!iGradient) + { + if (iInsideX) + return; + JumpToXCoord(nearestx,dummy); + } + else + { + if (iInsideY) + return; + JumpToYCoord(dummy,nearesty); + } + } + + +EXPORT_C void TLinearDDA::JumpToXCoord(const TInt aXCoord,TInt& aYCoord) +/** Jumps to x co-ordinate. + +The other co-ordinate of the intersection is returned through a reference +argument. After a jump call, the line is ready to continue through calls to +the stepping functions. + +This function accelerates the Linear DDA stepping functions (e.g. SingleStep()) +making them return EFalse when they reach the specified co-ordinate. If the +line does not cross the co-ordinate, has not been constructed, has been run +to completion or the intersection is the end point of the line then the stepping +functions will return ETrue. + +@param aXCoord x co-ordinate to jump to +@param aYCoord On return, this parameter holds the y co-ordinate which corresponds +to the specified x co-ordinate */ + { + if(iStatus==EComplete) return; // not constructed + if((iStart.iXaXCoord && iFinish.iX>aXCoord)) + return; // no intersection + aYCoord=iStart.iY; + if(iStart.iX==aXCoord) return; // trivial first intersection + iStatus=ECurrent; + if(iDifference.iHeight==0) // horizontal line + iPos.iX=aXCoord; + else + { + if(!iGradient) + { + TInt64 numsteps=Abs(aXCoord-iPos.iX); + TInt64 tempcount=TInt64(iCount)-(TInt64(iDifference.iHeight)*numsteps); + numsteps=Abs(tempcount/iDifference.iWidth); + tempcount+=numsteps*iDifference.iWidth; + while(tempcount<0) + { + tempcount+=iDifference.iWidth; + numsteps++; + } + iCount = I64INT(tempcount); + iPos.iY += (iInc.iY * I64INT(numsteps)); + iPos.iX=aXCoord; + aYCoord=iPos.iY; + } + else + { + while(iPos.iX!=aXCoord) + { + iCount-=iDifference.iWidth; + if(iCount<0) + { + iCount+=iDifference.iHeight; + iPos.iX+=iInc.iX; + } + iPos.iY+=iInc.iY; + } + aYCoord=iPos.iY; + } + } + if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY)) + { + iStatus=EComplete; + } + } + + +EXPORT_C void TLinearDDA::JumpToYCoord(TInt& aXCoord,const TInt aYCoord) +/** Jumps to a y co-ordinate. + +The other co-ordinate of the intersection is returned through a reference +argument. After a jump call, the line is ready to continue through calls to +the stepping functions. + +This function accelerates the Linear DDA stepping functions (e.g. SingleStep()) +making them return EFalse when they reach the specified co-ordinate. If the +line does not cross the co-ordinate, has not been constructed, has been run +to completion or the intersection is the end point of the line then they will +return ETrue. + +@param aXCoord On return, this parameter holds the x co-ordinate which corresponds +to the specified y co-ordinate. +@param aYCoord y co-ordinate to jump to */ + { + if(iStatus==EComplete) return; // not constructed + if((iStart.iYaYCoord && iFinish.iY>aYCoord)) + return; // no intersection + aXCoord=iStart.iX; + if(iStart.iY==aYCoord) return; // trivial first intersection + iStatus=ECurrent; + if(iDifference.iWidth==0) // vertical line + iPos.iY=aYCoord; + else + { + if(!iGradient) + { + while(iPos.iY!=aYCoord) + { + iCount-=iDifference.iHeight; + if(iCount<0) + { + iCount+=iDifference.iWidth; + iPos.iY+=iInc.iY; + } + iPos.iX+=iInc.iX; + } + aXCoord=iPos.iX; + } + else + { + TInt64 numsteps=Abs(aYCoord-iPos.iY); + TInt64 tempcount=TInt64(iCount)-(TInt64(iDifference.iWidth)*numsteps); + numsteps=Abs(tempcount/iDifference.iHeight); + tempcount+=numsteps*iDifference.iHeight; + while (tempcount<0) + { + tempcount+=iDifference.iHeight; + numsteps++; + } + iCount = I64INT(tempcount); + iPos.iX += (iInc.iX * I64INT(numsteps)); + iPos.iY=aYCoord; + aXCoord=iPos.iX; + } + } + if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY)) + { + iStatus=EComplete; + } + } + +void TLinearDDA::UpdatePosition() + { + } + +EXPORT_C void TLinearDDA::JumpToXCoord2(TInt aXCoord,TInt& aYCoord) +/** +Jumps to x co-ordinate. + +This works in the same way as TLinearDDA::JumpToXCoord except that it make sure +that using the NextStep function does not return the same value twice. + +@param aXCoord x co-ordinate to jump to +@param aYCoord On return, this parameter holds the y co-ordinate which corresponds +to the specified x co-ordinate +@see TLinearDDA::JumpToXCoord(TInt, TInt&) +*/ + { + JumpToXCoord(aXCoord,aYCoord); + iStatus=ECurrent; + } + +EXPORT_C void TLinearDDA::JumpToYCoord2(TInt& aXCoord,TInt aYCoord) +/** +Jumps to a y co-ordinate. + +This works in the same way as TLinearDDA::JumpToYCoord except that it make sure +that using the NextStep function does not return the same value twice. + +@param aXCoord On return, this parameter holds the x co-ordinate which corresponds +to the specified y co-ordinate. +@param aYCoord y co-ordinate to jump to +@see TLinearDDA::JumpToYCoord(TInt&, TInt) +*/ + { + JumpToYCoord(aXCoord,aYCoord); + iStatus=ECurrent; + }