os/graphics/graphicsdeviceinterface/gdi/sgdi/LINE.CPP
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include <gdi.h>
    17 
    18 #ifdef __ARMCC__
    19 #pragma arm
    20 #pragma O3
    21 #pragma Otime
    22 #endif
    23 
    24 EXPORT_C TLinearDDA::TLinearDDA():
    25 	iCount(0),
    26 	iDifference(),
    27 	iFinish(),
    28 	iGradient(0),
    29 	iInc(),
    30 	iPos(),
    31 	iStart(),
    32 	iBoundingRect(),
    33 	iBoundingRectSet(EFalse),
    34 	iInsideX(EFalse),
    35 	iInsideY(EFalse),
    36 	iStatus(EComplete)
    37 /** Constructs the default linear DDA.
    38 
    39 No start or end point is defined for the line. */
    40 	{}
    41 
    42  
    43 EXPORT_C TLinearDDA::TLinearDDA(const TLinearDDA& aLine):
    44 	iCount(aLine.iCount),
    45 	iDifference(aLine.iDifference),
    46 	iFinish(aLine.iFinish),
    47 	iGradient(aLine.iGradient),
    48 	iInc(aLine.iInc),
    49 	iPos(aLine.iPos),
    50 	iStart(aLine.iStart),
    51 	iBoundingRect(aLine.iBoundingRect),
    52 	iBoundingRectSet(aLine.iBoundingRectSet),
    53 	iInsideX(aLine.iInsideX),
    54 	iInsideY(aLine.iInsideY),
    55 	iStatus(aLine.iStatus)
    56 /** Copy constructs a linear DDA from the specified linear DDA.
    57 
    58 @param aLine The linear DDA to be copied. */
    59 	{}
    60 
    61  
    62 EXPORT_C void TLinearDDA::Construct(const TPoint& aStart,const TPoint& aFinish,TLineMode aMode)
    63 /** Constructs a linear DDA, setting the start and end points of the line.
    64 
    65 @param aStart The start point of the line. 
    66 @param aFinish The end point of the line. 
    67 @param aMode The mode of the line; defaults to centred. */
    68 	{
    69 	iStart=aStart;
    70 	iFinish=aFinish;
    71 	iDifference=(iFinish-iStart).AsSize();
    72 	iDifference.iWidth=Abs(iDifference.iWidth);
    73 	iDifference.iHeight=Abs(iDifference.iHeight);
    74 	iInc.iX=(iStart.iX>iFinish.iX)?-1:1;
    75 	iInc.iY=(iStart.iY>iFinish.iY)?-1:1;
    76 	if(iDifference.iWidth)
    77 		iGradient=(iFinish.iY-iStart.iY)/(iFinish.iX-iStart.iX);
    78 	iPos=iStart;
    79 	if(!iGradient)
    80 		iCount=iDifference.iWidth;
    81 	else
    82 		iCount=iDifference.iHeight;
    83 	if(aMode==ECenter)
    84 		iCount>>=1;
    85 	else
    86 		if(iCount)
    87 			iCount--;
    88 	iStatus=EInitialised;
    89 	if(aStart==aFinish)
    90 		iStatus=EComplete;
    91 	iBoundingRectSet=EFalse;
    92 	iInsideX = EFalse;
    93 	iInsideY = EFalse;
    94 	}
    95 
    96  
    97 EXPORT_C TBool TLinearDDA::SingleStep(TPoint& aPosition)
    98 /** Gets the pixel co-ordinates of the next pixel on the pixel line.
    99 
   100 The function is called repeatedly until the whole line has been traversed or, 
   101 if JumpToRect() has been called, until the part of the line inside the rectangle 
   102 has been traversed. Note that, for performance reasons, JumpToRect() may fail 
   103 to detect the intersection of the line with the rectangle accurately and 
   104 SingleStep() may return more points than strictly necessary.
   105 
   106 @param aPosition On entry to the first call, this can be a reference to any 
   107 point. On return from the first call, this is the position of the first pixel 
   108 in the line, as specified during construction of this object. On return from 
   109 subsequent calls, this is the position of subsequent pixels in the line, as 
   110 calculated by the function. On return from the final call, this is the position 
   111 of the last pixel in the line, as specified during construction of this object.
   112 @return ETrue, when the position of the last pixel is returned; EFalse, 
   113 otherwise. */
   114     {
   115     switch (iStatus)
   116         {
   117         case EInitialised:
   118             aPosition = iStart;
   119             iStatus = ECurrent;
   120             return EFalse;
   121         case ECurrent:
   122             if (iDifference.iHeight == 0) // horizontal line
   123                 {
   124                 iPos.iX += iInc.iX;
   125                 if (iPos.iX == iFinish.iX)
   126                     {
   127                     iStatus = EComplete;
   128                     }
   129                 }
   130             else if (iDifference.iWidth == 0) // vertical line
   131                 {
   132                 iPos.iY += iInc.iY;
   133                 if (iPos.iY == iFinish.iY)
   134                     {
   135                     iStatus = EComplete;
   136                     }
   137                 }
   138             else // diagonal stripes
   139                 {
   140                 if (!iGradient)
   141                     {
   142                     iCount -= iDifference.iHeight;
   143                     iPos.iX += iInc.iX;
   144                     if (iCount < 0)
   145                         {
   146                         iCount += iDifference.iWidth;
   147                         iPos.iY += iInc.iY;
   148                         }
   149                     }
   150                 else
   151                     {
   152                     iCount -= iDifference.iWidth;
   153                     iPos.iY += iInc.iY;
   154                     if (iCount < 0)
   155                         {
   156                         iCount += iDifference.iHeight;
   157                         iPos.iX += iInc.iX;
   158                         }
   159                     }
   160                 if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY))
   161                     {
   162                     iStatus = EComplete;
   163                     }
   164                 }
   165             // common
   166             aPosition = iPos;
   167             if (iStatus == EComplete)
   168                 {
   169                 return ETrue;
   170                 }
   171             if(iBoundingRectSet)
   172                 {
   173                 if (iPos.iX >= iBoundingRect.iTl.iX && iPos.iX < iBoundingRect.iBr.iX)
   174                     iInsideX = ETrue;
   175                 else
   176                     if (iInsideX)
   177                         {
   178                         iStatus=EComplete;
   179                         return(ETrue);
   180                         }
   181                 if (iPos.iY >= iBoundingRect.iTl.iY && iPos.iY < iBoundingRect.iBr.iY)
   182                     iInsideY = ETrue;
   183                 else
   184                     if (iInsideY)
   185                         {
   186                         iStatus=EComplete;
   187                         return(ETrue);
   188                         }
   189                 }
   190             return EFalse;
   191         default:
   192             aPosition = iFinish;
   193             return ETrue;
   194         }
   195     }
   196  
   197 EXPORT_C TBool TLinearDDA::NextStep(TPoint& aPosition)
   198 /** Gets the pixel co-ordinates of the start of the next scan line.
   199 
   200 The best line that joins the start and end points is formed from all the scan 
   201 lines returned by this function.
   202 
   203 The function is called repeatedly until the start position of all scanlines 
   204 has been returned.
   205 
   206 The start and end points passed to the constructor of this object define the 
   207 boundaries of the line. Successive scan lines move from the start point to 
   208 the end point.
   209 
   210 @param aPosition On entry to the first call, this can be a reference to any 
   211 point. On return from the first call, this is the position of the pixel that 
   212 defines the leftmost position of the first scan line. On return from subsequent 
   213 calls, this is the position of the pixel that defines the leftmost position 
   214 of the next scan line. On return from the final call, this is the position 
   215 of the last pixel in the line, as specified during construction. 
   216 @return ETrue, when the position of the last pixel is returned; EFalse, 
   217 otherwise. */
   218     {
   219     if (!iDifference.iHeight) // horizontal line
   220         {
   221         iPos = iFinish;
   222         iStatus = EComplete;
   223         aPosition = iFinish;
   224         return ETrue;
   225         }
   226     if (!iDifference.iWidth || iGradient || (iStatus != ECurrent))
   227         {
   228         return SingleStep(aPosition);
   229         }
   230     // !iGradient && (iStatus != EInitialised)
   231     if(iBoundingRectSet)
   232         { // slower version
   233         while ((iCount - iDifference.iHeight) >= 0)
   234             {
   235             if (SingleStep(aPosition))
   236                 return ETrue;
   237             }
   238         return SingleStep(aPosition);
   239         }
   240     // faster version avoids function calls
   241     TBool lastLoop = EFalse;
   242     do {
   243         if ((iCount - iDifference.iHeight) < 0)
   244             {
   245             lastLoop = ETrue;
   246             }
   247         iCount -= iDifference.iHeight;
   248         iPos.iX += iInc.iX;
   249         if (iCount < 0)
   250             {
   251             iCount += iDifference.iWidth;
   252             iPos.iY += iInc.iY;
   253             }
   254 
   255         if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY))
   256             {
   257             aPosition = iFinish;
   258             iStatus = EComplete;
   259             return ETrue;
   260             }
   261         }
   262         while (!lastLoop);
   263     aPosition = iPos;
   264     return EFalse;
   265     }
   266  
   267 EXPORT_C TBool TLinearDDA::SingleScanline(TPoint& aStartPosition,TPoint& aEndPosition)
   268 /** Gets the start and end pixel co-ordinates that define the next scan line.
   269 
   270 The best line that joins the start and end points is formed from all the scan 
   271 lines returned by this function.
   272 
   273 The function is called repeatedly until the position of all scanlines has 
   274 been returned.
   275 
   276 The start and end points passed to the constructor of this object define the 
   277 boundaries of the line. Successive scan lines move from the start point to 
   278 the end point.
   279 
   280 @param aStartPosition On entry to the first call, this can be a reference 
   281 to any point. On return from the first call, this is the position of the pixel 
   282 that defines the leftmost position of the first scan line. On return from 
   283 subsequent calls, this is the position of the pixel that defines the leftmost 
   284 position of the next scan line. On return from the final call, either this 
   285 or aEndPosition is set to the end point, as specified during construction.
   286 @param aEndPosition On entry to the first call, this can be a reference to 
   287 any point. On return from the first call, this is the position of the pixel 
   288 that defines the rightmost position of the first scan line. On return from 
   289 subsequent calls, this is the position of the pixel that defines the rightmost 
   290 position of the next scan line. On return from the final call, either this 
   291 or aStartPosition is set to the end point, as specified during construction.
   292 @return ETrue, when the position of the last scan line includes the end point; 
   293 EFalse, otherwise. */
   294     {
   295     TBool done=EFalse;
   296     if(iDifference.iHeight==0)
   297         {
   298         aStartPosition=iStart;
   299         aEndPosition=iFinish;
   300         return(ETrue);
   301         }
   302     if(iDifference.iWidth==0 || iGradient)
   303         {
   304         done=SingleStep(aStartPosition);
   305         aEndPosition=aStartPosition;
   306         return(done);
   307         }
   308     // !iGradient
   309     done=SingleStep(aStartPosition);
   310     aEndPosition=aStartPosition;
   311     while(iCount-iDifference.iHeight>=0 && !done)
   312         {
   313         iCount -= iDifference.iHeight;
   314         iPos.iX += iInc.iX;
   315         if (iCount < 0)
   316             {
   317             iCount += iDifference.iWidth;
   318             iPos.iY += iInc.iY;
   319             }
   320 
   321         if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY))
   322             {
   323             iStatus = EComplete;
   324             done = ETrue;
   325             }
   326         }
   327     aEndPosition = iPos;
   328     return done;
   329     }
   330  
   331 EXPORT_C void TLinearDDA::JumpToRect(const TRect& aRect)
   332 /** Jumps to start of a clipping rectangle.
   333 
   334 This will accelerate the linear DDA to the vicinity of the specified rectangle. 
   335 It is NOT guaranteed to reach the rectangle, but will reduce co-ordinates 
   336 that are 1000's out to co-ordinates that are 10's out. Because of this, failure 
   337 to intersect the rectangle may not be detected. If it is, or the line has 
   338 not been constructed or has been run to completion, then a subsequent call 
   339 to the stepping functions returns ETrue.
   340 
   341 @param aRect The rectangle to be jumped to. */
   342 	{
   343 	if(aRect.IsEmpty() || iStatus!=EInitialised) return;
   344 	iBoundingRect=aRect;
   345 	iBoundingRectSet=ETrue;
   346 
   347 	TInt nearestx = 0;
   348 	if (iStart.iX < aRect.iTl.iX)
   349 		nearestx = aRect.iTl.iX;
   350 	else if (iStart.iX >= aRect.iBr.iX)
   351 		nearestx = aRect.iBr.iX;
   352 	else
   353 		iInsideX = ETrue;
   354 	TInt nearesty = 0;
   355 	if (iStart.iY < aRect.iTl.iY)
   356 		nearesty = aRect.iTl.iY;
   357 	else if (iStart.iY >= aRect.iBr.iY)
   358 		nearesty = aRect.iBr.iY;
   359 	else
   360 		iInsideY = ETrue;
   361 	if (iInsideX && iInsideY)
   362 		return;
   363 
   364 	TInt dummy;
   365 	if(!iGradient)
   366 		{
   367 		if (iInsideX)
   368 			return;
   369 		JumpToXCoord(nearestx,dummy);
   370 		}
   371 	else
   372 		{
   373 		if (iInsideY)
   374 			return;
   375 		JumpToYCoord(dummy,nearesty);
   376 		}
   377 	}
   378 
   379  
   380 EXPORT_C void TLinearDDA::JumpToXCoord(const TInt aXCoord,TInt& aYCoord)
   381 /** Jumps to x co-ordinate.
   382 
   383 The other co-ordinate of the intersection is returned through a reference 
   384 argument. After a jump call, the line is ready to continue through calls to 
   385 the stepping functions.
   386 
   387 This function accelerates the Linear DDA stepping functions (e.g. SingleStep()) 
   388 making them return EFalse when they reach the specified co-ordinate. If the 
   389 line does not cross the co-ordinate, has not been constructed, has been run 
   390 to completion or the intersection is the end point of the line then the stepping 
   391 functions will return ETrue.
   392 
   393 @param aXCoord x co-ordinate to jump to 
   394 @param aYCoord On return, this parameter holds the y co-ordinate which corresponds 
   395 to the specified x co-ordinate */
   396 	{
   397 	if(iStatus==EComplete) return; // not constructed
   398 	if((iStart.iX<aXCoord && iFinish.iX<aXCoord) || (iStart.iX>aXCoord && iFinish.iX>aXCoord))
   399 		return; // no intersection
   400 	aYCoord=iStart.iY;
   401 	if(iStart.iX==aXCoord) return; // trivial first intersection
   402 	iStatus=ECurrent;
   403 	if(iDifference.iHeight==0) // horizontal line
   404 		iPos.iX=aXCoord;
   405 	else
   406 		{
   407 		if(!iGradient)
   408 			{
   409 			TInt64 numsteps=Abs(aXCoord-iPos.iX);
   410 			TInt64 tempcount=TInt64(iCount)-(TInt64(iDifference.iHeight)*numsteps);
   411 			numsteps=Abs(tempcount/iDifference.iWidth);
   412 			tempcount+=numsteps*iDifference.iWidth;
   413 			while(tempcount<0)
   414 				{
   415 				tempcount+=iDifference.iWidth;
   416 				numsteps++;
   417 				}
   418 			iCount = I64INT(tempcount);
   419 			iPos.iY += (iInc.iY * I64INT(numsteps));
   420 			iPos.iX=aXCoord;
   421 			aYCoord=iPos.iY;
   422 			}
   423 		else
   424 			{
   425 			while(iPos.iX!=aXCoord)
   426 				{
   427 				iCount-=iDifference.iWidth;
   428 				if(iCount<0)
   429 					{
   430 					iCount+=iDifference.iHeight;
   431 					iPos.iX+=iInc.iX;
   432 					}
   433 				iPos.iY+=iInc.iY;
   434 				}
   435 			aYCoord=iPos.iY;
   436 			}
   437 		}
   438     if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY))
   439         {
   440         iStatus=EComplete;
   441         }
   442 	}
   443 
   444  
   445 EXPORT_C void TLinearDDA::JumpToYCoord(TInt& aXCoord,const TInt aYCoord)
   446 /** Jumps to a y co-ordinate.
   447 
   448 The other co-ordinate of the intersection is returned through a reference 
   449 argument. After a jump call, the line is ready to continue through calls to 
   450 the stepping functions.
   451 
   452 This function accelerates the Linear DDA stepping functions (e.g. SingleStep()) 
   453 making them return EFalse when they reach the specified co-ordinate. If the 
   454 line does not cross the co-ordinate, has not been constructed, has been run 
   455 to completion or the intersection is the end point of the line then they will 
   456 return ETrue. 
   457 
   458 @param aXCoord On return, this parameter holds the x co-ordinate which corresponds 
   459 to the specified y co-ordinate. 
   460 @param aYCoord y co-ordinate to jump to */
   461 	{
   462 	if(iStatus==EComplete) return; // not constructed
   463 	if((iStart.iY<aYCoord && iFinish.iY<aYCoord) || (iStart.iY>aYCoord && iFinish.iY>aYCoord))
   464 		return; // no intersection
   465 	aXCoord=iStart.iX;
   466 	if(iStart.iY==aYCoord) return; // trivial first intersection
   467 	iStatus=ECurrent;
   468 	if(iDifference.iWidth==0) // vertical line
   469 		iPos.iY=aYCoord;
   470 	else
   471 		{
   472 		if(!iGradient)
   473 			{
   474 			while(iPos.iY!=aYCoord)
   475 				{
   476 				iCount-=iDifference.iHeight;
   477 				if(iCount<0)
   478 					{
   479 					iCount+=iDifference.iWidth;
   480 					iPos.iY+=iInc.iY;
   481 					}
   482 				iPos.iX+=iInc.iX;
   483 				}
   484 			aXCoord=iPos.iX;
   485 			}
   486 		else
   487 			{
   488 			TInt64 numsteps=Abs(aYCoord-iPos.iY);
   489 			TInt64 tempcount=TInt64(iCount)-(TInt64(iDifference.iWidth)*numsteps);
   490 			numsteps=Abs(tempcount/iDifference.iHeight);
   491 			tempcount+=numsteps*iDifference.iHeight;
   492 			while (tempcount<0)
   493 				{
   494 				tempcount+=iDifference.iHeight;
   495 				numsteps++;
   496 				}
   497 			iCount = I64INT(tempcount);
   498 			iPos.iX += (iInc.iX * I64INT(numsteps));
   499 			iPos.iY=aYCoord;
   500 			aXCoord=iPos.iX;
   501 			}
   502 		}
   503     if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY))
   504         {
   505         iStatus=EComplete;
   506         }
   507 	}
   508 
   509 void TLinearDDA::UpdatePosition()
   510 	{
   511 	}
   512 
   513 EXPORT_C void TLinearDDA::JumpToXCoord2(TInt aXCoord,TInt& aYCoord)
   514 /**
   515 Jumps to x co-ordinate.
   516 
   517 This works in the same way as TLinearDDA::JumpToXCoord except that it make sure
   518 that using the NextStep function does not return the same value twice.
   519 
   520 @param aXCoord x co-ordinate to jump to
   521 @param aYCoord On return, this parameter holds the y co-ordinate which corresponds
   522 to the specified x co-ordinate
   523 @see TLinearDDA::JumpToXCoord(TInt, TInt&)
   524 */
   525 	{
   526 	JumpToXCoord(aXCoord,aYCoord);
   527 	iStatus=ECurrent;
   528 	}
   529 
   530 EXPORT_C void TLinearDDA::JumpToYCoord2(TInt& aXCoord,TInt aYCoord)
   531 /**
   532 Jumps to a y co-ordinate.
   533 
   534 This works in the same way as TLinearDDA::JumpToYCoord except that it make sure
   535 that using the NextStep function does not return the same value twice.
   536 
   537 @param aXCoord On return, this parameter holds the x co-ordinate which corresponds
   538 to the specified y co-ordinate.
   539 @param aYCoord y co-ordinate to jump to
   540 @see TLinearDDA::JumpToYCoord(TInt&, TInt)
   541 */ 
   542 	{
   543 	JumpToYCoord(aXCoord,aYCoord);
   544 	iStatus=ECurrent;
   545 	}