1 /*************************************************
\r
3 * EasyBMP Cross-Platform Windows Bitmap Library *
\r
5 * Author: Paul Macklin *
\r
6 * email: pmacklin@math.uci.edu *
\r
8 * file: EasyBMP_Geometry.h *
\r
10 * version: 1.05.00 *
\r
12 * License: BSD (revised) *
\r
13 * Copyright: 2005-2006 by the EasyBMP Project *
\r
15 * description: draw simple geometric objects *
\r
17 *************************************************/
\r
19 #include "../../../../include/freenet/captcha/easybmp/EasyBMP_Geometry.h"
\r
21 int ebmpRound( double input )
\r
23 double output = floor( input );
\r
24 if( output - input >= 0.50 )
\r
25 { return (int) ( output+1 ); }
\r
26 return (int) output;
\r
29 double InverseAngle( double Xdir, double Ydir )
\r
31 double pi = 3.14159265358979;
\r
32 double Norm = sqrt( Xdir*Xdir + Ydir*Ydir );
\r
38 double Xabs = fabs( Xdir );
\r
39 double Yabs = fabs( Ydir );
\r
40 double theta = 0.5*( acos( Xabs ) + asin( Yabs ) );
\r
42 if( Xdir >= 0.0 && Ydir >= 0.0 )
\r
44 if( Xdir < 0.0 && Ydir >= 0.0 )
\r
45 { return pi - theta; }
\r
46 if( Xdir < 0.0 && Ydir < 0.0 )
\r
47 { return pi + theta; }
\r
48 return 2*pi - theta;
\r
51 double LineFunction( double SlopeX , double SlopeY, int StartX, int StartY, double TestX, double TestY )
\r
53 return fabs( SlopeX*(TestY-StartY) - SlopeY*(TestX-StartX) );
\r
56 void DrawAALine( BMP &Image , int FromX, int FromY, int ToX, int ToY , RGBApixel Color )
\r
58 double SlopeX = ToX-FromX;
\r
59 double SlopeY = ToY-FromY;
\r
61 if( fabs( SlopeX ) <= 0.8 && fabs( SlopeY ) <= 0.8 ) // nothing to do; don't bother
\r
65 double Norm = sqrt( Square( SlopeX ) + Square( SlopeY ) );
\r
71 if( FromX >= Image.TellWidth() )
\r
72 { FromX = Image.TellWidth()-1; }
\r
75 if( ToX >= Image.TellWidth() )
\r
76 { ToX = Image.TellWidth()-1; }
\r
80 if( FromY >= Image.TellHeight() )
\r
81 { FromY = Image.TellHeight()-1; }
\r
84 if( ToY >= Image.TellHeight() )
\r
85 { ToY = Image.TellHeight()-1; }
\r
91 if( RightI < LeftI ){ int temp = LeftI; LeftI = RightI; RightI = temp; }
\r
94 if( RightJ < LeftJ ){ int temp = LeftJ; LeftJ = RightJ; RightJ = temp; }
\r
97 for( i=LeftI ; i <= RightI ; i++ )
\r
99 for( j=LeftJ ; j <= RightJ ; j++ )
\r
105 double x = i-1.5*dx;
\r
106 double y = j-1.5*dx;
\r
110 for( ii=-2; ii<=1 ; ii++)
\r
112 for( jj=-2 ; jj<=1 ; jj++)
\r
114 x = i+ii*dx+0.5*dx;
\r
115 y = j+jj*dy+0.5*dy;
\r
116 double Temp1 = LineFunction( SlopeX, SlopeY , FromX, FromY, x,y );
\r
117 if( Temp1 <= 0.5 ){ Temp1 = 1.0; }else{ Temp1 = 0.0; }
\r
123 double MinValue = 0.03125; // 1.0/32.0
\r
125 if( Temp > MinValue )
\r
127 Image(i,j)->Red = (ebmpBYTE) (unsigned int) ( (1.0-Temp)*( (double) Image(i,j)->Red )
\r
128 +Temp*( (double) Color.Red ) );
\r
129 Image(i,j)->Green = (ebmpBYTE) (unsigned int) ( (1.0-Temp)*( (double) Image(i,j)->Green )
\r
130 +Temp*( (double) Color.Green ) );
\r
131 Image(i,j)->Blue = (ebmpBYTE) (unsigned int) ( (1.0-Temp)*( (double) Image(i,j)->Blue )
\r
132 +Temp*( (double) Color.Blue ) );
\r
141 void DrawFastLine( BMP &Image , int FromX, int FromY, int ToX, int ToY , RGBApixel Color )
\r
145 if( FromX >= Image.TellWidth() )
\r
146 { FromX = Image.TellWidth()-1; }
\r
149 if( ToX >= Image.TellWidth() )
\r
150 { ToX = Image.TellWidth()-1; }
\r
154 if( FromY >= Image.TellHeight() )
\r
155 { FromY = Image.TellHeight()-1; }
\r
158 if( ToY >= Image.TellHeight() )
\r
159 { ToY = Image.TellHeight()-1; }
\r
163 // source: http://www.gamedev.net/reference/articles/article1275.asp
\r
165 int dX = ToX - FromX;
\r
166 int dY = ToY - FromY;
\r
168 if( dX == 0 && dY == 0 ) // nothing to do; don't bother
\r
175 { Xinc1 = -1; dX = -dX; }
\r
178 { Yinc1 = -1; dY = -dY; }
\r
180 int x = FromX; // Start x off at the first pixel
\r
181 int y = FromY; // Start y off at the first pixel
\r
186 double Denominator;
\r
189 int NumberOfPixels;
\r
191 if ( dX >= dY ) // There is at least one x-value for every y-value
\r
193 Xinc1 = 0; // Don't change the x when numerator >= denominator
\r
194 Yinc2 = 0; // Don't change the y for every iteration
\r
195 Denominator = dX+0.0;
\r
196 Numerator = 0.5*dX;
\r
198 NumberOfPixels = dX; // There are more x-values than y-values
\r
200 else // There is at least one y-value for every x-value
\r
202 Xinc2 = 0; // Don't change the x for every iteration
\r
203 Yinc1 = 0; // Don't change the y when numerator >= denominator
\r
204 Denominator = dY+0.0;
\r
205 Numerator = 0.5*dY;
\r
207 NumberOfPixels = dY; // There are more y-values than x-values
\r
212 for (CurrentPixel = 0; CurrentPixel <= NumberOfPixels; CurrentPixel++ )
\r
214 Image(x,y)->Red = Color.Red;
\r
215 Image(x,y)->Green = Color.Green;
\r
216 Image(x,y)->Blue = Color.Blue;
\r
218 Numerator += NumberToAdd; // Increase the numerator by the top of the fraction
\r
219 if( Numerator >= Denominator ) // Check if numerator >= denominator
\r
221 Numerator -= Denominator; // Calculate the new numerator value
\r
222 x += Xinc1; // Change the x as appropriate
\r
223 y += Yinc1; // Change the y as appropriate
\r
225 x += Xinc2; // Change the x as appropriate
\r
226 y += Yinc2; // Change the y as appropriate
\r
232 void DrawArc( BMP &Image , double CenterX, double CenterY , double Radius,
\r
233 double FromTheta, double ToTheta , RGBApixel Color )
\r
235 double pi = 3.14159265358979;
\r
237 while( ToTheta < FromTheta )
\r
238 { ToTheta += 2*pi; }
\r
240 double Arclength = (ToTheta-FromTheta)*Radius;
\r
241 if( fabs( Arclength ) <= 1e-5 ) // if it's short, don't bother
\r
244 // set up the final circle first
\r
247 int FinalWidth = (int) floor( 2.0*Radius + 1.0); // was ceil ,also tried Round
\r
250 Radius = 0.5*(FinalWidth-1.0);
\r
251 // end new for testing
\r
253 int FinalHeight = FinalWidth;
\r
254 Downsampled.SetSize( FinalWidth , FinalHeight );
\r
256 // make a temporary circle of double resolution
\r
259 double TempRadius = 2.0*Radius;
\r
261 Temp.SetSize( 2*FinalWidth, 2*FinalHeight );
\r
262 double dTheta = 1.0/TempRadius;
\r
264 double CenterXtemp = FinalWidth - 0.5; // was TempRadius + .5
\r
265 double CenterYtemp = FinalHeight - 0.5; // was TempRadius + 0.5;
\r
269 double OuterRadiusSquared = TempRadius+1.0;
\r
270 OuterRadiusSquared *= OuterRadiusSquared;
\r
271 double InnerRadiusSquared = TempRadius-1.0;
\r
272 InnerRadiusSquared *= InnerRadiusSquared;
\r
274 for( x=0 ; x < Temp.TellWidth() ;x++)
\r
276 for( y=0 ; y < Temp.TellHeight() ; y++)
\r
278 double X = x-CenterXtemp;
\r
279 double Y = y-CenterYtemp;
\r
280 double TempRadiusSquared = X*X + Y*Y;
\r
282 if( InnerRadiusSquared <= TempRadiusSquared &&
\r
283 TempRadiusSquared <= OuterRadiusSquared )
\r
285 double Angle = InverseAngle( X, Y );
\r
286 bool PlotIt = false;
\r
287 if( FromTheta <= Angle && Angle <= ToTheta )
\r
290 if( FromTheta <= Angle && Angle <= ToTheta )
\r
293 if( FromTheta <= Angle && Angle <= ToTheta )
\r
297 { Temp(x,y)->Red = 0; }
\r
302 // downsample to anti-alias
\r
305 for( i=0 ; i < Downsampled.TellWidth() ; i++ )
\r
307 for( j=0 ; j < Downsampled.TellHeight() ; j++ )
\r
309 double TempRed = 0.0;
\r
312 for( k=0 ; k <= 1 ; k++ )
\r
314 for( ell=0 ; ell <= 1 ; ell++ )
\r
318 TempRed += (double) Temp(I,J)->Red;
\r
323 Downsampled(i,j)->Red = (ebmpBYTE) TempRed;
\r
327 // paste with alpha blending
\r
329 int DestinationTopLeft = ebmpRound( CenterX - Radius );
\r
330 int DestinationTopRight = ebmpRound( CenterY - Radius );
\r
332 for( i=0 ; i < Downsampled.TellWidth() ; i++)
\r
334 for( j=0 ; j < Downsampled.TellHeight() ; j++)
\r
336 int DestinationI = DestinationTopLeft+i;
\r
337 int DestinationJ = DestinationTopRight+j;
\r
338 if( DestinationI >= 0 && DestinationI < Image.TellWidth() &&
\r
339 DestinationJ >= 0 && DestinationJ < Image.TellHeight() )
\r
341 double alpha = (255.0 - Downsampled(i,j)->Red )/255.0;
\r
342 Image(DestinationI,DestinationJ)->Red = (ebmpBYTE) (
\r
343 (1.0-alpha)*Image(DestinationI,DestinationJ)->Red
\r
344 + (alpha)*Color.Red );
\r
345 Image(DestinationI,DestinationJ)->Green = (ebmpBYTE) (
\r
346 (1.0-alpha)*Image(DestinationI,DestinationJ)->Green
\r
347 + (alpha)*Color.Green );
\r
348 Image(DestinationI,DestinationJ)->Blue = (ebmpBYTE) (
\r
349 (1.0-alpha)*Image(DestinationI,DestinationJ)->Blue
\r
350 + (alpha)*Color.Blue );
\r
359 void DrawLine( BMP &Image , int FromX , int FromY, int ToX, int ToY, RGBApixel Color )
\r
361 if( FromX != ToX && FromY != ToY )
\r
363 DrawAALine( Image, FromX, FromY, ToX, ToY, Color);
\r
365 DrawFastLine( Image, FromX, FromY, ToX, ToY, Color);
\r