1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/graphics/graphicsdeviceinterface/gdi/sgdi/LINE.CPP Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,545 @@
1.4 +// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include <gdi.h>
1.20 +
1.21 +#ifdef __ARMCC__
1.22 +#pragma arm
1.23 +#pragma O3
1.24 +#pragma Otime
1.25 +#endif
1.26 +
1.27 +EXPORT_C TLinearDDA::TLinearDDA():
1.28 + iCount(0),
1.29 + iDifference(),
1.30 + iFinish(),
1.31 + iGradient(0),
1.32 + iInc(),
1.33 + iPos(),
1.34 + iStart(),
1.35 + iBoundingRect(),
1.36 + iBoundingRectSet(EFalse),
1.37 + iInsideX(EFalse),
1.38 + iInsideY(EFalse),
1.39 + iStatus(EComplete)
1.40 +/** Constructs the default linear DDA.
1.41 +
1.42 +No start or end point is defined for the line. */
1.43 + {}
1.44 +
1.45 +
1.46 +EXPORT_C TLinearDDA::TLinearDDA(const TLinearDDA& aLine):
1.47 + iCount(aLine.iCount),
1.48 + iDifference(aLine.iDifference),
1.49 + iFinish(aLine.iFinish),
1.50 + iGradient(aLine.iGradient),
1.51 + iInc(aLine.iInc),
1.52 + iPos(aLine.iPos),
1.53 + iStart(aLine.iStart),
1.54 + iBoundingRect(aLine.iBoundingRect),
1.55 + iBoundingRectSet(aLine.iBoundingRectSet),
1.56 + iInsideX(aLine.iInsideX),
1.57 + iInsideY(aLine.iInsideY),
1.58 + iStatus(aLine.iStatus)
1.59 +/** Copy constructs a linear DDA from the specified linear DDA.
1.60 +
1.61 +@param aLine The linear DDA to be copied. */
1.62 + {}
1.63 +
1.64 +
1.65 +EXPORT_C void TLinearDDA::Construct(const TPoint& aStart,const TPoint& aFinish,TLineMode aMode)
1.66 +/** Constructs a linear DDA, setting the start and end points of the line.
1.67 +
1.68 +@param aStart The start point of the line.
1.69 +@param aFinish The end point of the line.
1.70 +@param aMode The mode of the line; defaults to centred. */
1.71 + {
1.72 + iStart=aStart;
1.73 + iFinish=aFinish;
1.74 + iDifference=(iFinish-iStart).AsSize();
1.75 + iDifference.iWidth=Abs(iDifference.iWidth);
1.76 + iDifference.iHeight=Abs(iDifference.iHeight);
1.77 + iInc.iX=(iStart.iX>iFinish.iX)?-1:1;
1.78 + iInc.iY=(iStart.iY>iFinish.iY)?-1:1;
1.79 + if(iDifference.iWidth)
1.80 + iGradient=(iFinish.iY-iStart.iY)/(iFinish.iX-iStart.iX);
1.81 + iPos=iStart;
1.82 + if(!iGradient)
1.83 + iCount=iDifference.iWidth;
1.84 + else
1.85 + iCount=iDifference.iHeight;
1.86 + if(aMode==ECenter)
1.87 + iCount>>=1;
1.88 + else
1.89 + if(iCount)
1.90 + iCount--;
1.91 + iStatus=EInitialised;
1.92 + if(aStart==aFinish)
1.93 + iStatus=EComplete;
1.94 + iBoundingRectSet=EFalse;
1.95 + iInsideX = EFalse;
1.96 + iInsideY = EFalse;
1.97 + }
1.98 +
1.99 +
1.100 +EXPORT_C TBool TLinearDDA::SingleStep(TPoint& aPosition)
1.101 +/** Gets the pixel co-ordinates of the next pixel on the pixel line.
1.102 +
1.103 +The function is called repeatedly until the whole line has been traversed or,
1.104 +if JumpToRect() has been called, until the part of the line inside the rectangle
1.105 +has been traversed. Note that, for performance reasons, JumpToRect() may fail
1.106 +to detect the intersection of the line with the rectangle accurately and
1.107 +SingleStep() may return more points than strictly necessary.
1.108 +
1.109 +@param aPosition On entry to the first call, this can be a reference to any
1.110 +point. On return from the first call, this is the position of the first pixel
1.111 +in the line, as specified during construction of this object. On return from
1.112 +subsequent calls, this is the position of subsequent pixels in the line, as
1.113 +calculated by the function. On return from the final call, this is the position
1.114 +of the last pixel in the line, as specified during construction of this object.
1.115 +@return ETrue, when the position of the last pixel is returned; EFalse,
1.116 +otherwise. */
1.117 + {
1.118 + switch (iStatus)
1.119 + {
1.120 + case EInitialised:
1.121 + aPosition = iStart;
1.122 + iStatus = ECurrent;
1.123 + return EFalse;
1.124 + case ECurrent:
1.125 + if (iDifference.iHeight == 0) // horizontal line
1.126 + {
1.127 + iPos.iX += iInc.iX;
1.128 + if (iPos.iX == iFinish.iX)
1.129 + {
1.130 + iStatus = EComplete;
1.131 + }
1.132 + }
1.133 + else if (iDifference.iWidth == 0) // vertical line
1.134 + {
1.135 + iPos.iY += iInc.iY;
1.136 + if (iPos.iY == iFinish.iY)
1.137 + {
1.138 + iStatus = EComplete;
1.139 + }
1.140 + }
1.141 + else // diagonal stripes
1.142 + {
1.143 + if (!iGradient)
1.144 + {
1.145 + iCount -= iDifference.iHeight;
1.146 + iPos.iX += iInc.iX;
1.147 + if (iCount < 0)
1.148 + {
1.149 + iCount += iDifference.iWidth;
1.150 + iPos.iY += iInc.iY;
1.151 + }
1.152 + }
1.153 + else
1.154 + {
1.155 + iCount -= iDifference.iWidth;
1.156 + iPos.iY += iInc.iY;
1.157 + if (iCount < 0)
1.158 + {
1.159 + iCount += iDifference.iHeight;
1.160 + iPos.iX += iInc.iX;
1.161 + }
1.162 + }
1.163 + if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY))
1.164 + {
1.165 + iStatus = EComplete;
1.166 + }
1.167 + }
1.168 + // common
1.169 + aPosition = iPos;
1.170 + if (iStatus == EComplete)
1.171 + {
1.172 + return ETrue;
1.173 + }
1.174 + if(iBoundingRectSet)
1.175 + {
1.176 + if (iPos.iX >= iBoundingRect.iTl.iX && iPos.iX < iBoundingRect.iBr.iX)
1.177 + iInsideX = ETrue;
1.178 + else
1.179 + if (iInsideX)
1.180 + {
1.181 + iStatus=EComplete;
1.182 + return(ETrue);
1.183 + }
1.184 + if (iPos.iY >= iBoundingRect.iTl.iY && iPos.iY < iBoundingRect.iBr.iY)
1.185 + iInsideY = ETrue;
1.186 + else
1.187 + if (iInsideY)
1.188 + {
1.189 + iStatus=EComplete;
1.190 + return(ETrue);
1.191 + }
1.192 + }
1.193 + return EFalse;
1.194 + default:
1.195 + aPosition = iFinish;
1.196 + return ETrue;
1.197 + }
1.198 + }
1.199 +
1.200 +EXPORT_C TBool TLinearDDA::NextStep(TPoint& aPosition)
1.201 +/** Gets the pixel co-ordinates of the start of the next scan line.
1.202 +
1.203 +The best line that joins the start and end points is formed from all the scan
1.204 +lines returned by this function.
1.205 +
1.206 +The function is called repeatedly until the start position of all scanlines
1.207 +has been returned.
1.208 +
1.209 +The start and end points passed to the constructor of this object define the
1.210 +boundaries of the line. Successive scan lines move from the start point to
1.211 +the end point.
1.212 +
1.213 +@param aPosition On entry to the first call, this can be a reference to any
1.214 +point. On return from the first call, this is the position of the pixel that
1.215 +defines the leftmost position of the first scan line. On return from subsequent
1.216 +calls, this is the position of the pixel that defines the leftmost position
1.217 +of the next scan line. On return from the final call, this is the position
1.218 +of the last pixel in the line, as specified during construction.
1.219 +@return ETrue, when the position of the last pixel is returned; EFalse,
1.220 +otherwise. */
1.221 + {
1.222 + if (!iDifference.iHeight) // horizontal line
1.223 + {
1.224 + iPos = iFinish;
1.225 + iStatus = EComplete;
1.226 + aPosition = iFinish;
1.227 + return ETrue;
1.228 + }
1.229 + if (!iDifference.iWidth || iGradient || (iStatus != ECurrent))
1.230 + {
1.231 + return SingleStep(aPosition);
1.232 + }
1.233 + // !iGradient && (iStatus != EInitialised)
1.234 + if(iBoundingRectSet)
1.235 + { // slower version
1.236 + while ((iCount - iDifference.iHeight) >= 0)
1.237 + {
1.238 + if (SingleStep(aPosition))
1.239 + return ETrue;
1.240 + }
1.241 + return SingleStep(aPosition);
1.242 + }
1.243 + // faster version avoids function calls
1.244 + TBool lastLoop = EFalse;
1.245 + do {
1.246 + if ((iCount - iDifference.iHeight) < 0)
1.247 + {
1.248 + lastLoop = ETrue;
1.249 + }
1.250 + iCount -= iDifference.iHeight;
1.251 + iPos.iX += iInc.iX;
1.252 + if (iCount < 0)
1.253 + {
1.254 + iCount += iDifference.iWidth;
1.255 + iPos.iY += iInc.iY;
1.256 + }
1.257 +
1.258 + if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY))
1.259 + {
1.260 + aPosition = iFinish;
1.261 + iStatus = EComplete;
1.262 + return ETrue;
1.263 + }
1.264 + }
1.265 + while (!lastLoop);
1.266 + aPosition = iPos;
1.267 + return EFalse;
1.268 + }
1.269 +
1.270 +EXPORT_C TBool TLinearDDA::SingleScanline(TPoint& aStartPosition,TPoint& aEndPosition)
1.271 +/** Gets the start and end pixel co-ordinates that define the next scan line.
1.272 +
1.273 +The best line that joins the start and end points is formed from all the scan
1.274 +lines returned by this function.
1.275 +
1.276 +The function is called repeatedly until the position of all scanlines has
1.277 +been returned.
1.278 +
1.279 +The start and end points passed to the constructor of this object define the
1.280 +boundaries of the line. Successive scan lines move from the start point to
1.281 +the end point.
1.282 +
1.283 +@param aStartPosition On entry to the first call, this can be a reference
1.284 +to any point. On return from the first call, this is the position of the pixel
1.285 +that defines the leftmost position of the first scan line. On return from
1.286 +subsequent calls, this is the position of the pixel that defines the leftmost
1.287 +position of the next scan line. On return from the final call, either this
1.288 +or aEndPosition is set to the end point, as specified during construction.
1.289 +@param aEndPosition On entry to the first call, this can be a reference to
1.290 +any point. On return from the first call, this is the position of the pixel
1.291 +that defines the rightmost position of the first scan line. On return from
1.292 +subsequent calls, this is the position of the pixel that defines the rightmost
1.293 +position of the next scan line. On return from the final call, either this
1.294 +or aStartPosition is set to the end point, as specified during construction.
1.295 +@return ETrue, when the position of the last scan line includes the end point;
1.296 +EFalse, otherwise. */
1.297 + {
1.298 + TBool done=EFalse;
1.299 + if(iDifference.iHeight==0)
1.300 + {
1.301 + aStartPosition=iStart;
1.302 + aEndPosition=iFinish;
1.303 + return(ETrue);
1.304 + }
1.305 + if(iDifference.iWidth==0 || iGradient)
1.306 + {
1.307 + done=SingleStep(aStartPosition);
1.308 + aEndPosition=aStartPosition;
1.309 + return(done);
1.310 + }
1.311 + // !iGradient
1.312 + done=SingleStep(aStartPosition);
1.313 + aEndPosition=aStartPosition;
1.314 + while(iCount-iDifference.iHeight>=0 && !done)
1.315 + {
1.316 + iCount -= iDifference.iHeight;
1.317 + iPos.iX += iInc.iX;
1.318 + if (iCount < 0)
1.319 + {
1.320 + iCount += iDifference.iWidth;
1.321 + iPos.iY += iInc.iY;
1.322 + }
1.323 +
1.324 + if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY))
1.325 + {
1.326 + iStatus = EComplete;
1.327 + done = ETrue;
1.328 + }
1.329 + }
1.330 + aEndPosition = iPos;
1.331 + return done;
1.332 + }
1.333 +
1.334 +EXPORT_C void TLinearDDA::JumpToRect(const TRect& aRect)
1.335 +/** Jumps to start of a clipping rectangle.
1.336 +
1.337 +This will accelerate the linear DDA to the vicinity of the specified rectangle.
1.338 +It is NOT guaranteed to reach the rectangle, but will reduce co-ordinates
1.339 +that are 1000's out to co-ordinates that are 10's out. Because of this, failure
1.340 +to intersect the rectangle may not be detected. If it is, or the line has
1.341 +not been constructed or has been run to completion, then a subsequent call
1.342 +to the stepping functions returns ETrue.
1.343 +
1.344 +@param aRect The rectangle to be jumped to. */
1.345 + {
1.346 + if(aRect.IsEmpty() || iStatus!=EInitialised) return;
1.347 + iBoundingRect=aRect;
1.348 + iBoundingRectSet=ETrue;
1.349 +
1.350 + TInt nearestx = 0;
1.351 + if (iStart.iX < aRect.iTl.iX)
1.352 + nearestx = aRect.iTl.iX;
1.353 + else if (iStart.iX >= aRect.iBr.iX)
1.354 + nearestx = aRect.iBr.iX;
1.355 + else
1.356 + iInsideX = ETrue;
1.357 + TInt nearesty = 0;
1.358 + if (iStart.iY < aRect.iTl.iY)
1.359 + nearesty = aRect.iTl.iY;
1.360 + else if (iStart.iY >= aRect.iBr.iY)
1.361 + nearesty = aRect.iBr.iY;
1.362 + else
1.363 + iInsideY = ETrue;
1.364 + if (iInsideX && iInsideY)
1.365 + return;
1.366 +
1.367 + TInt dummy;
1.368 + if(!iGradient)
1.369 + {
1.370 + if (iInsideX)
1.371 + return;
1.372 + JumpToXCoord(nearestx,dummy);
1.373 + }
1.374 + else
1.375 + {
1.376 + if (iInsideY)
1.377 + return;
1.378 + JumpToYCoord(dummy,nearesty);
1.379 + }
1.380 + }
1.381 +
1.382 +
1.383 +EXPORT_C void TLinearDDA::JumpToXCoord(const TInt aXCoord,TInt& aYCoord)
1.384 +/** Jumps to x co-ordinate.
1.385 +
1.386 +The other co-ordinate of the intersection is returned through a reference
1.387 +argument. After a jump call, the line is ready to continue through calls to
1.388 +the stepping functions.
1.389 +
1.390 +This function accelerates the Linear DDA stepping functions (e.g. SingleStep())
1.391 +making them return EFalse when they reach the specified co-ordinate. If the
1.392 +line does not cross the co-ordinate, has not been constructed, has been run
1.393 +to completion or the intersection is the end point of the line then the stepping
1.394 +functions will return ETrue.
1.395 +
1.396 +@param aXCoord x co-ordinate to jump to
1.397 +@param aYCoord On return, this parameter holds the y co-ordinate which corresponds
1.398 +to the specified x co-ordinate */
1.399 + {
1.400 + if(iStatus==EComplete) return; // not constructed
1.401 + if((iStart.iX<aXCoord && iFinish.iX<aXCoord) || (iStart.iX>aXCoord && iFinish.iX>aXCoord))
1.402 + return; // no intersection
1.403 + aYCoord=iStart.iY;
1.404 + if(iStart.iX==aXCoord) return; // trivial first intersection
1.405 + iStatus=ECurrent;
1.406 + if(iDifference.iHeight==0) // horizontal line
1.407 + iPos.iX=aXCoord;
1.408 + else
1.409 + {
1.410 + if(!iGradient)
1.411 + {
1.412 + TInt64 numsteps=Abs(aXCoord-iPos.iX);
1.413 + TInt64 tempcount=TInt64(iCount)-(TInt64(iDifference.iHeight)*numsteps);
1.414 + numsteps=Abs(tempcount/iDifference.iWidth);
1.415 + tempcount+=numsteps*iDifference.iWidth;
1.416 + while(tempcount<0)
1.417 + {
1.418 + tempcount+=iDifference.iWidth;
1.419 + numsteps++;
1.420 + }
1.421 + iCount = I64INT(tempcount);
1.422 + iPos.iY += (iInc.iY * I64INT(numsteps));
1.423 + iPos.iX=aXCoord;
1.424 + aYCoord=iPos.iY;
1.425 + }
1.426 + else
1.427 + {
1.428 + while(iPos.iX!=aXCoord)
1.429 + {
1.430 + iCount-=iDifference.iWidth;
1.431 + if(iCount<0)
1.432 + {
1.433 + iCount+=iDifference.iHeight;
1.434 + iPos.iX+=iInc.iX;
1.435 + }
1.436 + iPos.iY+=iInc.iY;
1.437 + }
1.438 + aYCoord=iPos.iY;
1.439 + }
1.440 + }
1.441 + if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY))
1.442 + {
1.443 + iStatus=EComplete;
1.444 + }
1.445 + }
1.446 +
1.447 +
1.448 +EXPORT_C void TLinearDDA::JumpToYCoord(TInt& aXCoord,const TInt aYCoord)
1.449 +/** Jumps to a y co-ordinate.
1.450 +
1.451 +The other co-ordinate of the intersection is returned through a reference
1.452 +argument. After a jump call, the line is ready to continue through calls to
1.453 +the stepping functions.
1.454 +
1.455 +This function accelerates the Linear DDA stepping functions (e.g. SingleStep())
1.456 +making them return EFalse when they reach the specified co-ordinate. If the
1.457 +line does not cross the co-ordinate, has not been constructed, has been run
1.458 +to completion or the intersection is the end point of the line then they will
1.459 +return ETrue.
1.460 +
1.461 +@param aXCoord On return, this parameter holds the x co-ordinate which corresponds
1.462 +to the specified y co-ordinate.
1.463 +@param aYCoord y co-ordinate to jump to */
1.464 + {
1.465 + if(iStatus==EComplete) return; // not constructed
1.466 + if((iStart.iY<aYCoord && iFinish.iY<aYCoord) || (iStart.iY>aYCoord && iFinish.iY>aYCoord))
1.467 + return; // no intersection
1.468 + aXCoord=iStart.iX;
1.469 + if(iStart.iY==aYCoord) return; // trivial first intersection
1.470 + iStatus=ECurrent;
1.471 + if(iDifference.iWidth==0) // vertical line
1.472 + iPos.iY=aYCoord;
1.473 + else
1.474 + {
1.475 + if(!iGradient)
1.476 + {
1.477 + while(iPos.iY!=aYCoord)
1.478 + {
1.479 + iCount-=iDifference.iHeight;
1.480 + if(iCount<0)
1.481 + {
1.482 + iCount+=iDifference.iWidth;
1.483 + iPos.iY+=iInc.iY;
1.484 + }
1.485 + iPos.iX+=iInc.iX;
1.486 + }
1.487 + aXCoord=iPos.iX;
1.488 + }
1.489 + else
1.490 + {
1.491 + TInt64 numsteps=Abs(aYCoord-iPos.iY);
1.492 + TInt64 tempcount=TInt64(iCount)-(TInt64(iDifference.iWidth)*numsteps);
1.493 + numsteps=Abs(tempcount/iDifference.iHeight);
1.494 + tempcount+=numsteps*iDifference.iHeight;
1.495 + while (tempcount<0)
1.496 + {
1.497 + tempcount+=iDifference.iHeight;
1.498 + numsteps++;
1.499 + }
1.500 + iCount = I64INT(tempcount);
1.501 + iPos.iX += (iInc.iX * I64INT(numsteps));
1.502 + iPos.iY=aYCoord;
1.503 + aXCoord=iPos.iX;
1.504 + }
1.505 + }
1.506 + if ((iPos.iX == iFinish.iX) && (iPos.iY == iFinish.iY))
1.507 + {
1.508 + iStatus=EComplete;
1.509 + }
1.510 + }
1.511 +
1.512 +void TLinearDDA::UpdatePosition()
1.513 + {
1.514 + }
1.515 +
1.516 +EXPORT_C void TLinearDDA::JumpToXCoord2(TInt aXCoord,TInt& aYCoord)
1.517 +/**
1.518 +Jumps to x co-ordinate.
1.519 +
1.520 +This works in the same way as TLinearDDA::JumpToXCoord except that it make sure
1.521 +that using the NextStep function does not return the same value twice.
1.522 +
1.523 +@param aXCoord x co-ordinate to jump to
1.524 +@param aYCoord On return, this parameter holds the y co-ordinate which corresponds
1.525 +to the specified x co-ordinate
1.526 +@see TLinearDDA::JumpToXCoord(TInt, TInt&)
1.527 +*/
1.528 + {
1.529 + JumpToXCoord(aXCoord,aYCoord);
1.530 + iStatus=ECurrent;
1.531 + }
1.532 +
1.533 +EXPORT_C void TLinearDDA::JumpToYCoord2(TInt& aXCoord,TInt aYCoord)
1.534 +/**
1.535 +Jumps to a y co-ordinate.
1.536 +
1.537 +This works in the same way as TLinearDDA::JumpToYCoord except that it make sure
1.538 +that using the NextStep function does not return the same value twice.
1.539 +
1.540 +@param aXCoord On return, this parameter holds the x co-ordinate which corresponds
1.541 +to the specified y co-ordinate.
1.542 +@param aYCoord y co-ordinate to jump to
1.543 +@see TLinearDDA::JumpToYCoord(TInt&, TInt)
1.544 +*/
1.545 + {
1.546 + JumpToYCoord(aXCoord,aYCoord);
1.547 + iStatus=ECurrent;
1.548 + }