os/graphics/graphicsdeviceinterface/bitgdi/sbit/ELLIPSE.CPP
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 1997-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 <bitstd.h>
    17 #include <bitdev.h>
    18 #include "BITPANIC.H"
    19 #include <bitdraw.h>
    20 #include <graphics/fbsrasterizer.h>
    21 
    22 /*
    23  * TEllipse
    24  */
    25  
    26  /**
    27  Initialises the values of the ellipse so that it conforms to a rectangle entered as a parameter.
    28  @param aRect the rectangle within which the ellipse is drawn
    29  */
    30 EXPORT_C void TEllipse::Construct(const TRect& aRect)
    31 	{
    32 	TInt width=aRect.Width();
    33 	TInt height=aRect.Height();
    34 	iA=(width-1)>>1;
    35 	iB=(height-1)>>1;
    36 	iXAdj=(width+1)&1;
    37 	iYAdj=(height+1)&1;
    38 	iOffset=aRect.iTl;
    39 	iX=0;
    40 	iY=iB;
    41 	iASquared=iA*iA;
    42 	iBSquared=iB*iB;
    43 	iASquBSqu=iASquared*iBSquared;
    44 	iD1=iBSquared-iASquared*iB+(iASquared>>1);
    45 	if(width<=0 || height<=0)
    46 		iStatus=EComplete;
    47 	else if(width<=2 || height<=2)
    48 		iStatus=ELine;
    49 	else if(iA+iXAdj==0 || iB+iYAdj==0)
    50 		iStatus=EComplete;
    51 	else
    52 		iStatus=EInitialised;
    53 	}
    54 
    55 /**
    56 Does the next stage in producing an ellipse by taking four points (the corners of 
    57 the rectangle the ellipse should fill) as parameters. Updates TEllipse status 
    58 accordingly and calls <code>Output(aTopLeft,aTopRight,aBottomLeft,aBottomRight)</code>.
    59 @param aTopLeft Top left corner of rectangle 
    60 @param aTopRight Top right corner of rectangle
    61 @param aBottomLeft Bottom left corner of rectangle
    62 @param aBottomRight Bottom right corner of rectangle
    63 @return TBool ETrue if step completed successfully.
    64 */
    65 EXPORT_C TBool TEllipse::SingleStep(TPoint& aTopLeft,TPoint& aTopRight,
    66 									TPoint& aBottomLeft,TPoint& aBottomRight)
    67 	{
    68 	TBool ret=EFalse;
    69 	if(iStatus==EFirstSector)
    70 		{
    71 		if(iD1<0)
    72 			iD1+=iBSquared*((iX<<1)+3);
    73 		else if(iY>0)
    74 			{
    75 			iD1+=iBSquared*((iX<<1)+3)+iASquared*(2-(iY<<1));
    76 			iY--;
    77 			}
    78 		iX++;
    79 		ret=Output(aTopLeft,aTopRight,aBottomLeft,aBottomRight);
    80 		if(iStatus==EComplete && iX<iA)
    81 			{
    82 			iStatus=EFirstSector;
    83 			return(EFalse);
    84 			}
    85 		if(iASquared*iY<=iBSquared*(iX+1) && ret==EFalse)
    86 			{
    87 			iStatus=ESecondSector;
    88 			iD2=-iASquBSqu+iBSquared*iX*iX+iASquared*(iY-1)*(iY-1);
    89 			}
    90 		return(ret);
    91 		}
    92 	if(iStatus==ESecondSector)
    93 		{
    94 		if(iD2<0)
    95 			{
    96 			iD2+=iBSquared*((iX<<1)+2)+iASquared*(3-(iY<<1));
    97 			iX++;
    98 			}
    99 		else
   100 			iD2+=iASquared*(3-(iY<<1));
   101 		iY--;
   102 		return(Output(aTopLeft,aTopRight,aBottomLeft,aBottomRight));
   103 		}
   104 	if(iStatus==ELine)
   105 		{
   106 		ret=Output(aTopLeft,aTopRight,aBottomLeft,aBottomRight);
   107 		if(iA==0)
   108 			iY--;
   109 		else
   110 			{
   111 			iX++;
   112 			if(iX>iA+iXAdj) ret=ETrue;
   113 			else
   114 				{
   115 				iStatus=ELine;
   116 				ret=EFalse;
   117 				}
   118 			}
   119 		return(ret);
   120 		}
   121 	if(iStatus==EInitialised)
   122 		{
   123 		iStatus=EFirstSector;
   124 		return(Output(aTopLeft,aTopRight,aBottomLeft,aBottomRight));
   125 		}
   126 	Output(aTopLeft,aTopRight,aBottomLeft,aBottomRight);
   127 	return(ETrue);
   128 	}
   129 
   130 /**
   131 Sets the absolute points that define the ellipse as calculated using its iOffset 
   132 from the origin and using the half width and half height of the rectangle iA and iB.
   133 @param aTopLeft The absolute (x,y) position for the top left point.
   134 @param aTopRight The absolute (x,y) position for the top right point.
   135 @param aBottomLeft The absolute (x,y) position for the bottom left point.
   136 @param aBottomRight The absolute (x,y) position for the bottom right point.
   137 @return TBool ETrue if a valid rectangle is produced, else EFalse. Also sets
   138 iStatus to EComplete.
   139 */
   140 EXPORT_C TBool TEllipse::Output(TPoint& aTopLeft,TPoint& aTopRight,
   141 								TPoint& aBottomLeft,TPoint& aBottomRight)
   142 	{
   143 	TInt lx=iA-iX+iOffset.iX;
   144 	TInt ty=iB-iY+iOffset.iY;
   145 	TInt rx=iA+iX+iXAdj+iOffset.iX;
   146 	TInt by=iB+iY+iYAdj+iOffset.iY;
   147 	aTopLeft.SetXY(lx,ty);
   148 	aTopRight.SetXY(rx,ty);
   149 	aBottomLeft.SetXY(lx,by);
   150 	aBottomRight.SetXY(rx,by);
   151 	if(iY<=0)
   152 		{
   153 		iStatus=EComplete;
   154 		if(iYAdj==0 || ty>by)
   155 			return(ETrue);
   156 		}
   157 	return(EFalse);
   158 	}
   159 
   160 /**
   161 By analysing the current state of the ellipse the process is taken to the next appropriate step.
   162 If iStatus = EInitialised only one step will be taken, if the ellipse is already semi constructed then 
   163 it will be taken to completion. Takes in four point parameters that defines the rectangle in order to pass to 
   164 SingleStep(aTopLeft,aTopRight,aBottomLeft,aBottomRight).
   165 @param aTopLeft Top left corner of rectangle 
   166 @param aTopRight Top right corner of rectangle
   167 @param aBottomLeft Bottom left corner of rectangle
   168 @param aBottomRight Bottom right corner of rectangle
   169 @return TBool ETrue if a valid rectangle is produced, else EFalse.
   170 */
   171 EXPORT_C TBool TEllipse::NextStep(TPoint& aTopLeft,TPoint& aTopRight,
   172 								  TPoint& aBottomLeft,TPoint& aBottomRight)
   173 	{
   174 	if(iStatus==EInitialised)
   175 		return(SingleStep(aTopLeft,aTopRight,aBottomLeft,aBottomRight));
   176 	TInt prevlev=iY;
   177 	TBool ret;
   178 	do
   179 		ret=SingleStep(aTopLeft,aTopRight,aBottomLeft,aBottomRight);
   180 	while(prevlev==iY && ret==EFalse);
   181 	return(ret);
   182 	}
   183 
   184 /**
   185 Constructs an ellipse from the rectangle which it is given and assesses the 
   186 points position with regard to the ellipse and where they intersect. 
   187 @param aRect The rectangle within which the ellipse is drawn.
   188 @param aPoint A point to compare with the ellipse to determine if intersection occurs. 
   189 @return TPoint The point is set to the corner which the intersection is nearest to.
   190 */
   191 EXPORT_C TPoint TEllipse::Intersection(const TRect& aRect,const TPoint& aPoint)
   192 	{
   193 	Construct(aRect);					//constructs the rect (an elipse object)
   194 	TPoint centre=aRect.Center();		//centre of ellipse
   195 	TPoint ptcpy(aPoint);				
   196 	ptcpy-=iOffset;						//ptcpy = aPoint - iOffset - TPoint(iA,iB)	//radius from centre of ellipse		
   197 	ptcpy-=TPoint(iA,iB);				
   198 	TPoint pt[4],opt[4];			
   199 	TInt mpt[4],ompt[4];
   200 	TInt count=0;
   201 	for(;count<4;count++)
   202 		ompt[count]=KMaxTInt;			//fills ompt 1->4 with KMaxTInt
   203 	while(SingleStep(pt[0],pt[1],pt[2],pt[3])==EFalse) 	//creates a complete ellipse with pts as rect
   204 		for(count=0;count<4;count++)
   205 			{
   206 			mpt[count]=Abs((pt[count].iY-iOffset.iY-iB)*(ptcpy.iX)-(ptcpy.iY)*(pt[count].iX-iOffset.iX-iA));
   207 			if(mpt[count]<ompt[count]) //use the larger number set.
   208 				{
   209 				ompt[count]=mpt[count];
   210 				opt[count]=pt[count];
   211 				}						
   212 			}
   213 	if(pt[0].iY==pt[2].iY)	//if it is horizontal
   214 		for(count=0;count<4;count++)
   215 			{
   216 			mpt[count]=Abs((pt[count].iY-iOffset.iY-iB)*(ptcpy.iX)-(ptcpy.iY)*(pt[count].iX-iOffset.iX-iA));
   217 			if(mpt[count]<ompt[count]) //use the larger number set.
   218 				{
   219 				ompt[count]=mpt[count];
   220 				opt[count]=pt[count];
   221 				}
   222 			}
   223 	if(ptcpy.iX<0 && ptcpy.iY<0)	//if point is further left and higher than centre of rect
   224 		return(opt[0]);
   225 	if(ptcpy.iY<0)			//if point is higher than centre of rect
   226 		return(opt[1]);
   227 	if(ptcpy.iX<0)			//if point is further left than centre of rect
   228 		return(opt[2]);
   229 	if(aPoint.iX<centre.iX && aPoint.iY<centre.iY)	//if point is further left and higher than centre of rect
   230 		return(opt[0]);
   231 	if(aPoint.iY<centre.iY)	//if point is higher than centre of rect
   232 		return(opt[1]);
   233 	if(aPoint.iX<centre.iX)	//if point is further left than centre of rect
   234 		return(opt[2]);
   235 	return(opt[3]);			//else 
   236 	}
   237 
   238 //
   239 // Ellipse drawing
   240 //
   241 
   242 /**
   243 Draws and fills an ellipse.
   244 
   245 The function provides a concrete implementation of the pure virtual
   246 function <code>CGraphicsContext::DrawEllipse()</code>. The function
   247 behaviour is the same as documented in that class.
   248 */
   249 EXPORT_C void CFbsBitGc::DrawEllipse(const TRect& aRect)
   250 	{
   251 	if(CheckDevice(aRect)) return;
   252 	TRect rcpy(aRect);
   253 	rcpy.Move(iOrigin);
   254 	iDevice->TruncateRect(rcpy);
   255 	TRect clippedRect(rcpy);
   256 	clippedRect.Grow((iPenSize.iWidth>>1)+1,(iPenSize.iHeight>>1)+1);
   257 	if(UserClipRect(clippedRect)) return;
   258 	SetupDevice();
   259 	iDevice->DrawingBegin(&iBrushBitmap);
   260 	CFbsRasterizer* brushRasterizer = PrepareRasterizerForExtendedBitmap(iBrushBitmap);
   261 	if(iBrushStyle!=ENullBrush)
   262 		EllipseFill(rcpy);
   263 	if(iPenStyle!=ENullPen)
   264 		{
   265 		if(iPenSize.iWidth>1 && iPenSize.iHeight>1)
   266 			EllipseOutlineWide(rcpy);
   267 		else
   268 			if(iPenSize.iWidth==1 || iPenSize.iHeight==1)
   269 				EllipseOutline(rcpy);
   270 		}
   271 	if (brushRasterizer)
   272 		{
   273 		brushRasterizer->EndBitmap(iBrushBitmap.SerialNumber());
   274 		}
   275 	iDevice->DrawingEnd(&iBrushBitmap);
   276 	}
   277 
   278 void CFbsBitGc::EllipseOutline(const TRect& aRect)
   279 	{
   280 	CFbsDrawDevice* drawDevice = iDevice->iDrawDevice;
   281 	TPoint tl,tr,bl,br;
   282 	AddRect(aRect);
   283 #if defined(_DEBUG)
   284 	TRect deviceDestRect;
   285 	drawDevice->GetDrawRect(deviceDestRect);
   286 #endif
   287 	for(TInt count=0;count<iDefaultRegionPtr->Count();count++)
   288 		{
   289 		iClipRect=(*iDefaultRegionPtr)[count];
   290 		if(!iClipRect.Intersects(aRect))
   291 			continue;
   292 		iClipRect.Intersection(aRect);
   293 		if(UserClipRect(iClipRect)) continue;
   294 		BG_ASSERT_DEBUG(iClipRect.iTl.iX >= deviceDestRect.iTl.iX, EBitgdiPanicOutOfBounds);
   295 		BG_ASSERT_DEBUG(iClipRect.iTl.iY >= deviceDestRect.iTl.iY, EBitgdiPanicOutOfBounds);
   296 		BG_ASSERT_DEBUG(iClipRect.iBr.iX <= deviceDestRect.iBr.iX, EBitgdiPanicOutOfBounds);
   297 		BG_ASSERT_DEBUG(iClipRect.iBr.iY <= deviceDestRect.iBr.iY, EBitgdiPanicOutOfBounds);
   298 		TEllipse ellipse;
   299 		ellipse.Construct(aRect);
   300 		TInt pattern=0;
   301 		while(!ellipse.SingleStep(tl,tr,bl,br))
   302 			{
   303 			if(iPenStyle==CGraphicsContext::ESolidPen || (iDotMask&(1<<(pattern%iDotLength))))
   304 				{
   305 				if(tl.iY>=iClipRect.iTl.iY && tl.iY<iClipRect.iBr.iY)
   306 					{
   307 					if(tl.iX>=iClipRect.iTl.iX && tl.iX<iClipRect.iBr.iX)
   308 						drawDevice->WriteRgb(tl.iX,tl.iY,iPenColor,iDrawMode);
   309 					if(tr.iX>=iClipRect.iTl.iX && tr.iX<iClipRect.iBr.iX && tl.iX!=tr.iX)
   310 						drawDevice->WriteRgb(tr.iX,tr.iY,iPenColor,iDrawMode);
   311 					}
   312 				if(bl.iY>=iClipRect.iTl.iY && bl.iY<iClipRect.iBr.iY)
   313 					{
   314 					if(bl.iX>=iClipRect.iTl.iX && bl.iX<iClipRect.iBr.iX)
   315 						drawDevice->WriteRgb(bl.iX,bl.iY,iPenColor,iDrawMode);
   316 					if(br.iX>=iClipRect.iTl.iX && br.iX<iClipRect.iBr.iX && bl.iX!=br.iX)
   317 						drawDevice->WriteRgb(br.iX,br.iY,iPenColor,iDrawMode);
   318 					}
   319 				}
   320 			pattern++;
   321 			}
   322 		if(tl.iY==bl.iY && tl.iY>=iClipRect.iTl.iY && tl.iY<iClipRect.iBr.iY)
   323 			{
   324 			if(tl.iX>=iClipRect.iTl.iX && tl.iX<iClipRect.iBr.iX)
   325 				drawDevice->WriteRgb(tl.iX,tl.iY,iPenColor,iDrawMode);
   326 			if(tr.iX>=iClipRect.iTl.iX && tr.iX<iClipRect.iBr.iX && tl.iX!=tr.iX)
   327 				drawDevice->WriteRgb(tr.iX,tr.iY,iPenColor,iDrawMode);
   328 			}
   329 		drawDevice->UpdateRegion(iClipRect);
   330 		}
   331 	}
   332 
   333 void CFbsBitGc::EllipseOutlineWide(const TRect& aRect)
   334 	{
   335 	TRect rcpy(aRect);
   336 	TPoint tl,tr,bl,br;
   337 	TInt halfpenwidth=(iPenSize.iWidth+1)>>1;
   338 	TInt halfpenheight=(iPenSize.iHeight+1)>>1;
   339 	rcpy.Grow(halfpenwidth,halfpenheight);
   340 	AddRect(rcpy);
   341 	TInt dp=iDotParam;
   342 	for(TInt count=0;count<iDefaultRegionPtr->Count();count++)
   343 		{
   344 		iClipRect=(*iDefaultRegionPtr)[count];
   345 		if(!iClipRect.Intersects(rcpy))
   346 			continue;
   347 		iClipRect.Intersection(rcpy);
   348 		if(UserClipRect(iClipRect)) continue;
   349 		TEllipse ellipse;
   350 		ellipse.Construct(aRect);
   351 		iDotParam=Max(iPenSize.iWidth>>1,iPenSize.iHeight>>1);
   352 		while(!ellipse.SingleStep(tl,tr,bl,br))
   353 			{
   354 			PenDrawClipped(tl);
   355 			PenDrawClipped(tr);
   356 			PenDrawClipped(bl);
   357 			PenDrawClipped(br);
   358 			iDotParam+=iDotDirection;
   359 			}
   360 		if(tl.iY==bl.iY)
   361 			{
   362 			PenDrawClipped(tl);
   363 			PenDrawClipped(tr);
   364 			}
   365 		iDevice->iDrawDevice->UpdateRegion(iClipRect);
   366 		}
   367 	iDotParam=dp;
   368 	}
   369 
   370 // if iBrushBitmap is an extended bitmap, PrepareRasterizerForExtendedBitmap() must have been called before this method
   371 void CFbsBitGc::EllipseFill(const TRect& aRect)
   372 	{
   373 	TRect rcpy(aRect);
   374 	if(iPenSize.iWidth==0 || iPenSize.iHeight==0)
   375 		rcpy.Grow(1,1);
   376 	AddRect(aRect);
   377 	TPoint tl,tr,bl,br;
   378 	for(TInt count=0;count<iDefaultRegionPtr->Count();count++)
   379 		{
   380 		iClipRect=(*iDefaultRegionPtr)[count];
   381 		if(!iClipRect.Intersects(rcpy))
   382 			continue;
   383 		iClipRect.Intersection(rcpy);
   384 		if(UserClipRect(iClipRect)) continue;
   385 		TEllipse ellipse;
   386 		ellipse.Construct(rcpy);
   387 		while(!ellipse.NextStep(tl,tr,bl,br))
   388 			{
   389 			tl.iX++;
   390 			tr.iX--;
   391 			bl.iX++;
   392 			br.iX--;
   393 			ClipFillLine(tl,tr);
   394 			ClipFillLine(bl,br);
   395 			}
   396 		if(tl.iY==bl.iY)
   397 			{
   398 			tl.iX++;
   399 			tr.iX--;
   400 			ClipFillLine(tl,tr);
   401 			}
   402 		iDevice->iDrawDevice->UpdateRegion(iClipRect);
   403 		}
   404 	}
   405