C Algorithm into Code: Coordinates within a certain parameter - c

Here is some pseudocode. I understand how to do everything except Im unsure of what the condition should be to check if the randomly generated coordinate is within the circle.
For example with circle of radius 1,
(-1, 1) would not fall in the circle, (-1, 0.5) would though.
numDartsInCircle = 0
repeat 1000 times
throw a dart (generate (x,y), where -1 ≤ x ≤ 1, -1 ≤ y ≤ 1)
if dart is in circle
numDartsInCircle++
fractionOfDartsInCircle = numDartsInCircle / 1000
pi ≅ fractionOfDartsInCircle * 4

The formula for the distance from the origin (0,0) to a point (x,y) is sqrt(x*x + y*y). If the distance is less than the radius of the circle, which in this case is 1, then the point lies within the circle. If the distance is equal to or more than the radius then the point does not lie within the circle.
Best of luck.

What exactly was hard about this?
I took your pseudo-code and made C code almost line-for-line.
(you may notice that I don't actually have any if statements in the code)
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int numDartsInCircle = 0;
int throws = 1000;
int trial;
double pi;
for( trial=0; trial<throws; ++trial )
{
double x = 2*((double)rand() / RAND_MAX) - 1;
double y = 2*((double)rand() / RAND_MAX) - 1;
numDartsInCircle += ( x*x + y*y <= 1.0 );
}
pi = 4* (double)numDartsInCircle / throws;
return !printf("Pi is approximately %f\n", pi);
}

Related

(C programming) Writing the Leibniz method using a WHILE loop

The purpose of my assignment is to create a FOR loop that performs the circle method of getting pi and a WHILE loop that performs the Leibniz method for approximating Pi. I have no idea where to start for the Leibniz method because I don't understand what expression to put in the while loop to make it work. Please help me.
This method approximates pi by using a formula derived by Gottfried
Leibniz, also known as "the father of calculus." This method uses an
infinite series of additions and subtractions to approximate pi:
π/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 + . . .
Notice that this approximates pi / 4. After the summation of the
terms, you need to multiply the value by 4 to arrive at the final
approximation. Analogous to the circle method, the more terms in the
series, the closer the approximation of pi: (Example)
Iterations Leibniz Method
1 4.000000000000
10 3.041839618929
100 3.131592903559
1000 3.140592653840
10000 3.141492653590
100000 3.141582653590
I have already completed the circle method for loop, and it works on its own. It's the while loop that the focus should be on.
double circle_pi(int rectangles)
{
double radius = 2.0;
long i;
long double width = radius / (long double)rectangles;
long double rect_area = 0.0;
long double midpoint, height;
midpoint = width / 2.0;
for(i = 1; i <= rectangles; i++)
{
height = sqrt((radius * radius) - (midpoint * midpoint));
midpoint = midpoint + width;
rect_area = rect_area + width * height;
}
return rect_area;
}
double leibniz_pi(int iterations)
{
while()
{
/* code */
}
return
}
This is my driver.c code to go with it. I cannot make changes to it.
double circle_pi(int rectangles); /* Calculates PI using a quarter circle */
double leibniz_pi(int iterations); /* Calculates PI using a series */
int main(void)
{
int i; /* loop counter */
/* Print out table header */
printf("Approximations for pi\n");
printf("Iterations Circle Method Leibniz Method\n");
printf("----------------------------------------------\n");
/* Print out values for each set of numbers */
for (i = 1; i <= 1000000; i *= 10)
{
/* Calculate PI with both methods */
double pi_circle = circle_pi(i);
double pi_leibniz = leibniz_pi(i);
/* Print the results of the calculations */
printf("%10i%20.12f%16.12f\n", i, pi_circle, pi_leibniz);
}
return 0; /* Return success to the OS */
}```
The Leibniz method subtracts and adds fractions with odd denominators alternately.
Thus, our code will look something like the following:
int count = 0;
int iters = 10000;
double pi_4 = 0;
while (count < iters) {
if (count % 2 == 0) {
// On "even" counts (where our fraction is 1/1, 1/5, 1/9..., add)
pi_4 += 1.0 / (1.0 + 2 * count);
else {
// On "odd" counts (where our fraction is 1/3, 1/7, 1/11..., subtract)
pi_4 -= 1.0 / (1.0 + 2 * count);
}
count++;
}
return 4 * pi_4;

Estimating the value of Pi using the Monte Carlo Method

I am writing a C program that will be able to accept an input value that dictates the number of iterations that will be used to estimate Pi.
For example, the number of points to be created as the number of iterations increases and the value of Pi also.
Here is the code I have so far:
#include <stdio.h>
#include <stdlib.h>
main()
{
const double pp = (double)RAND_MAX * RAND_MAX;
int innerPoint = 0, i, count;
printf("Enter the number of points:");
scanf("%d", &innerPoint);
for (i = 0; i < count; ++i){
float x = rand();
float y = rand();
if (x * x + y * y <= 1){
++innerPoint;
}
int ratio = 4 *(innerPoint/ i);
printf("Pi value is:", ratio);
}
}
Help fix my code as I'm facing program errors.
rand() returns an integer [0...RAND_MAX].
So something like:
float x = rand()*scale; // Scale is about 1.0/RAND_MAX
The quality of the Monte Carlo method is dependent on a good random number generator. rand() may not be that good, but let us assume it is a fair random number generator for this purpose.
The range of [0...RAND_MAX] is RAND_MAX+1 different values that should be distributed evenly from [0.0...1.0].
((float) rand())/RAND_MAX biases the end points 0.0 and 1.0 giving them twice the weight of others.
Consider instead [0.5, 1.5, 2.5, ... RAND_MAX + 0.5]/(RAND_MAX + 1).
RAND_MAX may exceed the precision of float so converting rand() or RAND_MAX, both int, to float can incurring rounding and further disturb the Monte Carlo method. Consider double.
#define RAND_MAX_P1 ((double)RAND_MAX + 1.0)
// float x = rand();
double x = ((double) rand() + 0.5)/RAND_MAX_P1;
x * x + y * y can also incur excessive rounding. C has hypot(x,y) for a better precision sqrt(x*x + y*y). Yet here, with small count, it likely makes no observable difference.
// if (x * x + y * y <= 1)
if (hypot(x, y <= 1.0))
I am sure it is not the best solution, but it should do the job and is similar to your code. Use a sample size of at least 10000 to get a value near PI.
As mentioned in the commenter: You should look at the data types of the return values functions give you.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
// Initialize random number generation
srand(time(NULL));
int samples = 10000;
int points_inside =0;
// Read integer - sample size (use at least 10000 to get near PI)
printf("Enter the number of points:");
scanf("%d", &samples);
for (int i = 0; i < samples; ++i){
// Get two numbers between 0 and 1
float x = (float) rand() / (float)RAND_MAX;
float y = (float) rand() / (float)RAND_MAX;
// Check if point is inside
if (x * x + y * y <= 1){
points_inside++;
}
// Calculate current ratio
float current_ratio = 4 * ((float) points_inside / (float) i);
printf("Current value of pi value is: %f \n", current_ratio);
}
}

find the length of any arc on a circle

I have an interesting (to me anyway) problem. I am working on OpenServo.org for V4 and I am trying to determine the length of an arc of travel and its direction.
I have a magnetic encoder that returns the position of the shaft from 0 to 4095.
The servo has two logical end points, call them MAX and MIN which are set in software and can be changed at any time, and the shaft must rotate (i.e. travel) on one arc between the MAX and MIN positions. For example in the picture the blue arc is valid but the red is not for all travel between and including MIN and MAX.
I am trying to work out a simple algorithm using only integer math that can tell me the distance between any two points A and B that can be anywhere on the circumference, bounded by MIN and MAX and with either A as the current place and B is the target position, or B is the current place and A is the target (which is denoted by a negative distance from B to A). Note the side I allowed to travel is known, it is either "red" or "blue".
The issue is when the 4095/0 exists in the ARC, then the calculations get a bit interesting.
You need to adjust all your coordinates so they're on the same side of your limit points. Since it's a circular system you can add 4096 without affecting the absolute position.
lowest = min(MIN, MAX);
if (A < lowest)
A += 4096;
if (B < lowest)
B += 4096;
distance = B - A; /* or abs(B - A) */
In your example A would not be adjusted but B would be adjusted to 5156. The difference would be a positive 1116.
In your second example with A=3000 and B=2500, they're both above 2000 so neither would need adjustment. The difference is -500.
Here's a simple algorithm:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int rotate_diff(int a, int b, bool * clockwise);
int main(void) {
int degrees_rotated, a, b;
bool clockwise;
a = 4040;
b = 1060;
degrees_rotated = rotate_diff(a, b, &clockwise);
printf("A = %d, B = %d, rotation = %d degrees, direction = %s\n",
a, b, degrees_rotated,
(clockwise ? "clockwise" : "counter-clockwise"));
return EXIT_SUCCESS;
}
int rotate_diff(int a, int b, bool * clockwise) {
static const int min = 2000;
if ( a <= min ) {
a += 4096;
}
if ( b <= min ) {
b += 4096;
}
int degrees_rotated = b - a;
if ( degrees_rotated > 0 ) {
*clockwise = false;
} else {
degrees_rotated = -degrees_rotated;
*clockwise = true;
}
return degrees_rotated * 360 / 4096;
}
Note that this gives you the degrees traveled, but not the distance traveled, since you don't tell us what dimensions of the shaft are. To get the distance traveled, obviously multiply the circumference by the degrees traveled divided by 360. If your points 0 through 4095 are some kind of known units, then just skip the conversion to degrees in the above algorithm, and change the variable names accordingly.
Unless I missed something, this should give the result you need:
if MIN < A,B < MAX
distance = A - B
else
if A > MAX and B < MIN
distance = A - (B + 4096)
else if B > MAX and A < MIN
distance = (A + 4096) - B
else
distance = A - B
(get the absolute value of the distance if you don't need the direction)

Optimize C code preventing while loops [duplicate]

I'm looking for some nice C code that will accomplish effectively:
while (deltaPhase >= M_PI) deltaPhase -= M_TWOPI;
while (deltaPhase < -M_PI) deltaPhase += M_TWOPI;
What are my options?
Edit Apr 19, 2013:
Modulo function updated to handle boundary cases as noted by aka.nice and arr_sea:
static const double _PI= 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348;
static const double _TWO_PI= 6.2831853071795864769252867665590057683943387987502116419498891846156328125724179972560696;
// Floating-point modulo
// The result (the remainder) has same sign as the divisor.
// Similar to matlab's mod(); Not similar to fmod() - Mod(-3,4)= 1 fmod(-3,4)= -3
template<typename T>
T Mod(T x, T y)
{
static_assert(!std::numeric_limits<T>::is_exact , "Mod: floating-point type expected");
if (0. == y)
return x;
double m= x - y * floor(x/y);
// handle boundary cases resulted from floating-point cut off:
if (y > 0) // modulo range: [0..y)
{
if (m>=y) // Mod(-1e-16 , 360. ): m= 360.
return 0;
if (m<0 )
{
if (y+m == y)
return 0 ; // just in case...
else
return y+m; // Mod(106.81415022205296 , _TWO_PI ): m= -1.421e-14
}
}
else // modulo range: (y..0]
{
if (m<=y) // Mod(1e-16 , -360. ): m= -360.
return 0;
if (m>0 )
{
if (y+m == y)
return 0 ; // just in case...
else
return y+m; // Mod(-106.81415022205296, -_TWO_PI): m= 1.421e-14
}
}
return m;
}
// wrap [rad] angle to [-PI..PI)
inline double WrapPosNegPI(double fAng)
{
return Mod(fAng + _PI, _TWO_PI) - _PI;
}
// wrap [rad] angle to [0..TWO_PI)
inline double WrapTwoPI(double fAng)
{
return Mod(fAng, _TWO_PI);
}
// wrap [deg] angle to [-180..180)
inline double WrapPosNeg180(double fAng)
{
return Mod(fAng + 180., 360.) - 180.;
}
// wrap [deg] angle to [0..360)
inline double Wrap360(double fAng)
{
return Mod(fAng ,360.);
}
One-liner constant-time solution:
Okay, it's a two-liner if you count the second function for [min,max) form, but close enough — you could merge them together anyways.
/* change to `float/fmodf` or `long double/fmodl` or `int/%` as appropriate */
/* wrap x -> [0,max) */
double wrapMax(double x, double max)
{
/* integer math: `(max + x % max) % max` */
return fmod(max + fmod(x, max), max);
}
/* wrap x -> [min,max) */
double wrapMinMax(double x, double min, double max)
{
return min + wrapMax(x - min, max - min);
}
Then you can simply use deltaPhase = wrapMinMax(deltaPhase, -M_PI, +M_PI).
The solutions is constant-time, meaning that the time it takes does not depend on how far your value is from [-PI,+PI) — for better or for worse.
Verification:
Now, I don't expect you to take my word for it, so here are some examples, including boundary conditions. I'm using integers for clarity, but it works much the same with fmod() and floats:
Positive x:
wrapMax(3, 5) == 3: (5 + 3 % 5) % 5 == (5 + 3) % 5 == 8 % 5 == 3
wrapMax(6, 5) == 1: (5 + 6 % 5) % 5 == (5 + 1) % 5 == 6 % 5 == 1
Negative x:
Note: These assume that integer modulo copies left-hand sign; if not, you get the above ("Positive") case.
wrapMax(-3, 5) == 2: (5 + (-3) % 5) % 5 == (5 - 3) % 5 == 2 % 5 == 2
wrapMax(-6, 5) == 4: (5 + (-6) % 5) % 5 == (5 - 1) % 5 == 4 % 5 == 4
Boundaries:
wrapMax(0, 5) == 0: (5 + 0 % 5) % 5 == (5 + 0) % 5 == 5 % 5 == 0
wrapMax(5, 5) == 0: (5 + 5 % 5) % 5 == (5 + 0) % 5== 5 % 5 == 0
wrapMax(-5, 5) == 0: (5 + (-5) % 5) % 5 == (5 + 0) % 5 == 5 % 5 == 0
Note: Possibly -0 instead of +0 for floating-point.
The wrapMinMax function works much the same: wrapping x to [min,max) is the same as wrapping x - min to [0,max-min), and then (re-)adding min to the result.
I don't know what would happen with a negative max, but feel free to check that yourself!
If ever your input angle can reach arbitrarily high values, and if continuity matters, you can also try
atan2(sin(x),cos(x))
This will preserve continuity of sin(x) and cos(x) better than modulo for high values of x, especially in single precision (float).
Indeed, exact_value_of_pi - double_precision_approximation ~= 1.22e-16
On the other hand, most library/hardware use a high precision approximation of PI for applying the modulo when evaluating trigonometric functions (though x86 family is known to use a rather poor one).
Result might be in [-pi,pi], you'll have to check the exact bounds.
Personaly, I would prevent any angle to reach several revolutions by wrapping systematically and stick to a fmod solution like the one of boost.
There is also fmod function in math.h but the sign causes trouble so that a subsequent operation is needed to make the result fir in the proper range (like you already do with the while's). For big values of deltaPhase this is probably faster than substracting/adding `M_TWOPI' hundreds of times.
deltaPhase = fmod(deltaPhase, M_TWOPI);
EDIT:
I didn't try it intensively but I think you can use fmod this way by handling positive and negative values differently:
if (deltaPhase>0)
deltaPhase = fmod(deltaPhase+M_PI, 2.0*M_PI)-M_PI;
else
deltaPhase = fmod(deltaPhase-M_PI, 2.0*M_PI)+M_PI;
The computational time is constant (unlike the while solution which gets slower as the absolute value of deltaPhase increases)
I would do this:
double wrap(double x) {
return x-2*M_PI*floor(x/(2*M_PI)+0.5);
}
There will be significant numerical errors. The best solution to the numerical errors is to store your phase scaled by 1/PI or by 1/(2*PI) and depending on what you are doing store them as fixed point.
Instead of working in radians, use angles scaled by 1/(2π) and use modf, floor etc. Convert back to radians to use library functions.
This also has the effect that rotating ten thousand and a half revolutions is the same as rotating half then ten thousand revolutions, which is not guaranteed if your angles are in radians, as you have an exact representation in the floating point value rather than summing approximate representations:
#include <iostream>
#include <cmath>
float wrap_rads ( float r )
{
while ( r > M_PI ) {
r -= 2 * M_PI;
}
while ( r <= -M_PI ) {
r += 2 * M_PI;
}
return r;
}
float wrap_grads ( float r )
{
float i;
r = modff ( r, &i );
if ( r > 0.5 ) r -= 1;
if ( r <= -0.5 ) r += 1;
return r;
}
int main ()
{
for (int rotations = 1; rotations < 100000; rotations *= 10 ) {
{
float pi = ( float ) M_PI;
float two_pi = 2 * pi;
float a = pi;
a += rotations * two_pi;
std::cout << rotations << " and a half rotations in radians " << a << " => " << wrap_rads ( a ) / two_pi << '\n' ;
}
{
float pi = ( float ) 0.5;
float two_pi = 2 * pi;
float a = pi;
a += rotations * two_pi;
std::cout << rotations << " and a half rotations in grads " << a << " => " << wrap_grads ( a ) / two_pi << '\n' ;
}
std::cout << '\n';
}}
Here is a version for other people finding this question that can use C++ with Boost:
#include <boost/math/constants/constants.hpp>
#include <boost/math/special_functions/sign.hpp>
template<typename T>
inline T normalizeRadiansPiToMinusPi(T rad)
{
// copy the sign of the value in radians to the value of pi
T signedPI = boost::math::copysign(boost::math::constants::pi<T>(),rad);
// set the value of rad to the appropriate signed value between pi and -pi
rad = fmod(rad+signedPI,(2*boost::math::constants::pi<T>())) - signedPI;
return rad;
}
C++11 version, no Boost dependency:
#include <cmath>
// Bring the 'difference' between two angles into [-pi; pi].
template <typename T>
T normalizeRadiansPiToMinusPi(T rad) {
// Copy the sign of the value in radians to the value of pi.
T signed_pi = std::copysign(M_PI,rad);
// Set the value of difference to the appropriate signed value between pi and -pi.
rad = std::fmod(rad + signed_pi,(2 * M_PI)) - signed_pi;
return rad;
}
I encountered this question when searching for how to wrap a floating point value (or a double) between two arbitrary numbers. It didn't answer specifically for my case, so I worked out my own solution which can be seen here. This will take a given value and wrap it between lowerBound and upperBound where upperBound perfectly meets lowerBound such that they are equivalent (ie: 360 degrees == 0 degrees so 360 would wrap to 0)
Hopefully this answer is helpful to others stumbling across this question looking for a more generic bounding solution.
double boundBetween(double val, double lowerBound, double upperBound){
if(lowerBound > upperBound){std::swap(lowerBound, upperBound);}
val-=lowerBound; //adjust to 0
double rangeSize = upperBound - lowerBound;
if(rangeSize == 0){return upperBound;} //avoid dividing by 0
return val - (rangeSize * std::floor(val/rangeSize)) + lowerBound;
}
A related question for integers is available here:
Clean, efficient algorithm for wrapping integers in C++
A two-liner, non-iterative, tested solution for normalizing arbitrary angles to [-π, π):
double normalizeAngle(double angle)
{
double a = fmod(angle + M_PI, 2 * M_PI);
return a >= 0 ? (a - M_PI) : (a + M_PI);
}
Similarly, for [0, 2π):
double normalizeAngle(double angle)
{
double a = fmod(angle, 2 * M_PI);
return a >= 0 ? a : (a + 2 * M_PI);
}
In the case where fmod() is implemented through truncated division and has the same sign as the dividend, it can be taken advantage of to solve the general problem thusly:
For the case of (-PI, PI]:
if (x > 0) x = x - 2PI * ceil(x/2PI) #Shift to the negative regime
return fmod(x - PI, 2PI) + PI
And for the case of [-PI, PI):
if (x < 0) x = x - 2PI * floor(x/2PI) #Shift to the positive regime
return fmod(x + PI, 2PI) - PI
[Note that this is pseudocode; my original was written in Tcl, and I didn't want to torture everyone with that. I needed the first case, so had to figure this out.]
deltaPhase -= floor(deltaPhase/M_TWOPI)*M_TWOPI;
The way suggested you suggested is best. It is fastest for small deflections. If angles in your program are constantly being deflected into the proper range, then you should only run into big out of range values rarely. Therefore paying the cost of a complicated modular arithmetic code every round seems wasteful. Comparisons are cheap compared to modular arithmetic (http://embeddedgurus.com/stack-overflow/2011/02/efficient-c-tip-13-use-the-modulus-operator-with-caution/).
In C99:
float unwindRadians( float radians )
{
const bool radiansNeedUnwinding = radians < -M_PI || M_PI <= radians;
if ( radiansNeedUnwinding )
{
if ( signbit( radians ) )
{
radians = -fmodf( -radians + M_PI, 2.f * M_PI ) + M_PI;
}
else
{
radians = fmodf( radians + M_PI, 2.f * M_PI ) - M_PI;
}
}
return radians;
}
If linking against glibc's libm (including newlib's implementation) you can access
__ieee754_rem_pio2f() and __ieee754_rem_pio2() private functions:
extern __int32_t __ieee754_rem_pio2f (float,float*);
float wrapToPI(float xf){
const float p[4]={0,M_PI_2,M_PI,-M_PI_2};
float yf[2];
int q;
int qmod4;
q=__ieee754_rem_pio2f(xf,yf);
/* xf = q * M_PI_2 + yf[0] + yf[1] /
* yf[1] << y[0], not sure if it could be ignored */
qmod4= q % 4;
if (qmod4==2)
/* (yf[0] > 0) defines interval (-pi,pi]*/
return ( (yf[0] > 0) ? -p[2] : p[2] ) + yf[0] + yf[1];
else
return p[qmod4] + yf[0] + yf[1];
}
Edit: Just realised that you need to link to libm.a, I couldn't find the symbols declared in libm.so
I have used (in python):
def WrapAngle(Wrapped, UnWrapped ):
TWOPI = math.pi * 2
TWOPIINV = 1.0 / TWOPI
return UnWrapped + round((Wrapped - UnWrapped) * TWOPIINV) * TWOPI
c-code equivalent:
#define TWOPI 6.28318531
double WrapAngle(const double dWrapped, const double dUnWrapped )
{
const double TWOPIINV = 1.0/ TWOPI;
return dUnWrapped + round((dWrapped - dUnWrapped) * TWOPIINV) * TWOPI;
}
notice that this brings it in the wrapped domain +/- 2pi so for +/- pi domain you need to handle that afterward like:
if( angle > pi):
angle -= 2*math.pi

Draw a polygon in C

i need to draw a polygon of "n" sides given 2 points (the center and 1 of his vertex) just that i suck in math. I have been reading a lot and all this is what i have been able to figure it (i dont know if it is correct):
Ok, i take the distance between the 2 points (radius) with the theorem of Pythagoras:
sqrt(pow(abs(x - xc), 2) + pow(abs(y - yc), 2));
And the angle between this 2 points with atan2, like this:
atan2(abs(y - yc), abs(x - xc));
Where xc, yc is the center point and x, y is the only vertex know.
And with that data i do:
void polygon(int xc, int yc, int radius, double angle, int sides)
{
int i;
double ang = 360/sides; //Every vertex is about "ang" degrees from each other
radian = 180/M_PI;
int points_x[7]; //Here i store the calculated vertexs
int points_y[7]; //Here i store the calculated vertexs
/*Here i calculate the vertexs of the polygon*/
for(i=0; i<sides; i++)
{
points_x[i] = xc + ceil(radius * cos(angle/radian));
points_y[i] = yc + ceil(radius * sin(angle/radian));
angle = angle+ang;
}
/*Here i draw the polygon with the know vertexs just calculated*/
for(i=0; i<sides-1; i++)
line(points_x[i], points_y[i], points_x[i+1], points_y[i+1]);
line(points_y[i], points_x[i], points_x[0], points_y[0]);
}
The problem is that the program dont work correctly because it draw the lines not like a polygon.
Someone how know enough of math to give a hand? im working in this graphics primitives with C and turbo C.
Edit: i dont want to fill the polygon, just draw it.
Consider what 360/sides actually returns if sides is not a factor of 360 (this is integer division - see what 360/7 actually returns).
There is no need to use degrees at all - use 2*Math_PI/(double)nsides and work throughout in radians.
also you can omit the final line by using the modulus function (module nsides).
If you have more than 7 sides you will not be able to store all the points. You don't need to store all the points if you are simply drawing the polygon rather than storing it - just the last point and the current one.
You should be using radians in all your calculations. Here's a complete program that illustrates how best to do this:
#include <stdio.h>
#define PI 3.141592653589
static void line (int x1, int y1, int x2, int y2) {
printf ("Line from (%3d,%3d) - (%3d,%3d)\n", x1, y1, x2, y2);
}
static void polygon (int xc, int yc, int x, int y, int n) {
int lastx, lasty;
double r = sqrt ((x - xc) * (x - xc) + (y - yc) * (y - yc));
double a = atan2 (y - yc, x - xc);
int i;
for (i = 1; i <= n; i++) {
lastx = x; lasty = y;
a = a + PI * 2 / n;
x = round ((double)xc + (double)r * cos(a));
y = round ((double)yc + (double)r * sin(a));
line (lastx, lasty, x, y);
}
}
int main(int argc, char* argv[]) {
polygon (0,0,0,10,4); // A diamond.
polygon (0,0,10,10,4); // A square.
polygon (0,0,0,10,8); // An octagon.
return 0;
}
which outputs (no fancy graphics here, but you should get the idea):
===
Line from ( 0, 10) - (-10, 0)
Line from (-10, 0) - ( 0,-10)
Line from ( 0,-10) - ( 10, 0)
Line from ( 10, 0) - ( 0, 10)
===
Line from ( 10, 10) - (-10, 10)
Line from (-10, 10) - (-10,-10)
Line from (-10,-10) - ( 10,-10)
Line from ( 10,-10) - ( 10, 10)
===
Line from ( 0, 10) - ( -7, 7)
Line from ( -7, 7) - (-10, 0)
Line from (-10, 0) - ( -7, -7)
Line from ( -7, -7) - ( 0,-10)
Line from ( 0,-10) - ( 7, -7)
Line from ( 7, -7) - ( 10, 0)
Line from ( 10, 0) - ( 7, 7)
Line from ( 7, 7) - ( 0, 10)
I've written the polygon function as per your original specification, passing in just the two co-ordinates. As an aside, you don't want those abs calls in your calculations for radius and angle because:
they're useless for radius (since -n2 = n2 for all n).
they're bad for angle since that will force you into a specific quadrant (wrong starting point).
I'm not going to just give you the answer, but I have some advice. First, learn how line drawing works INSIDE AND OUT. When you have this down, try to write a filled triangle renderer.
Generally, filled polygons are drawn 1 horizontal scan line at a time, top to bottom. You're job is to determine the starting and stopping x coordinate for every scan line. Note that the edge of a polygon follows a straight line (hint, hint)... :)
You're trying to draw a filled poly I guess?
If you're going to try to draw the polys using a line primitive, you're going to have a lot of pain coming to you. dicroce actually gave you some very good advice on that front.
Your best bet is to find a primitive that fills for you and supply it a coordinates list. It's up to you to determine the coordinates to give it.
I think the main trouble is: atan2(abs(y - yc), abs(x - xc)); is giving you radians, not degrees, just convert it to degrees and try.
/* all angles in radians */
double ainc = PI*2 / sides;
int x1, y1;
for (i = 0; i <= sides; i++){
double a = angle + ainc * i;
int x = xc + radius * cos(a);
int y = yc + radius * sin(a);
if (i > 0) line(x1, y1, x, y);
x1 = x; y1 = y;
}
Or, you could save the points in an array and call the DrawPoly routine if you've got one.
If you want a filled polygon, call FillPoly if you've got one.

Resources