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