I am looking for an algorithm which can draw a nice looking 3D sphere on small resolution. I found Bresenham's circle algorithm but it's for 2D drawing. I just need spheres borders (I don't need it filled). I also googled for a solution of the problem but I didn't find anything. This article doesn't help (what is the brute force algorithm?). I can't use any OpenGL libraries, I need vanilla C/C++ solution. Thank you in advance.
if I get it right you want to render all surface Voxels of sphere
The brute force is O(R^3). If you just project rays from plane and compute the 3-th coordinate then you get O(R^2) but to make sure that no Voxels are missing you have to do this projection from all 3 planes which is still O(R^2)
It look like this:
on LED cube 16x16x16 simulation. Now the algorithm:
compute visible bounding box
no need to render whole rendering space just the sphere so center +/- radius...
take one plane (XY for example)
Cast rays from all x,y points inside bounding box which is just 2 for loops and compute the z coordinates where the ray hits via sphere equation:
(x-x0)^2 + (y-y0)^2 + (z-z0)^2 = R^2
so
z=z0 +/- sqrt(R^2 - (x-x0)^2 - (y-y0)^2)
and render the two voxels. The int sqrt(int x) for limited size (like LED Cube/Screen or Voxel space) can be done via LUT lookup table to speed things up.
do the step #2 for all planes (xy,yz,xz)
The code in C++ looks like this:
//---------------------------------------------------------------------------
//--- LED cube class ver: 1.00 ----------------------------------------------
//---------------------------------------------------------------------------
#ifndef _LED_cube_h
#define _LED_cube_h
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
const int _LED_cube_size=16;
//---------------------------------------------------------------------------
class LED_cube
{
public:
int n,map[_LED_cube_size][_LED_cube_size][_LED_cube_size];
LED_cube() { n=_LED_cube_size; }
LED_cube(LED_cube& a) { *this=a; }
~LED_cube() { }
LED_cube* operator = (const LED_cube *a) { *this=*a; return this; }
//LED_cube* operator = (const LED_cube &a) { /*...copy...*/ return this; }
void cls(int col); // clear cube with col 0x00BBGGRR
void sphere(int x0,int y0,int z0,int r,int col); // draws sphere surface with col 0x00BBGGRR
void glDraw(); // render cube by OpenGL as 1x1x1 cube at 0,0,0
};
//---------------------------------------------------------------------------
void LED_cube::cls(int col)
{
int x,y,z;
for (x=0;x<n;x++)
for (y=0;y<n;y++)
for (z=0;z<n;z++)
map[x][y][z]=col;
}
//---------------------------------------------------------------------------
void LED_cube::sphere(int x0,int y0,int z0,int r,int col)
{
int x,y,z,xa,ya,za,xb,yb,zb,xr,yr,zr,xx,yy,zz,rr=r*r;
// bounding box
xa=x0-r; if (xa<0) xa=0; xb=x0+r; if (xb>n) xb=n;
ya=y0-r; if (ya<0) ya=0; yb=y0+r; if (yb>n) yb=n;
za=z0-r; if (za<0) za=0; zb=z0+r; if (zb>n) zb=n;
// project xy plane
for (x=xa,xr=x-x0,xx=xr*xr;x<xb;x++,xr++,xx=xr*xr)
for (y=ya,yr=y-y0,yy=yr*yr;y<yb;y++,yr++,yy=yr*yr)
{
zz=rr-xx-yy; if (zz<0) continue; zr=sqrt(zz);
z=z0-zr; if ((z>0)&&(z<n)) map[x][y][z]=col;
z=z0+zr; if ((z>0)&&(z<n)) map[x][y][z]=col;
}
// project xz plane
for (x=xa,xr=x-x0,xx=xr*xr;x<xb;x++,xr++,xx=xr*xr)
for (z=za,zr=z-z0,zz=zr*zr;z<zb;z++,zr++,zz=zr*zr)
{
yy=rr-xx-zz; if (yy<0) continue; yr=sqrt(yy);
y=y0-yr; if ((y>0)&&(y<n)) map[x][y][z]=col;
y=y0+yr; if ((y>0)&&(y<n)) map[x][y][z]=col;
}
// project yz plane
for (y=ya,yr=y-y0,yy=yr*yr;y<yb;y++,yr++,yy=yr*yr)
for (z=za,zr=z-z0,zz=zr*zr;z<zb;z++,zr++,zz=zr*zr)
{
xx=rr-zz-yy; if (xx<0) continue; xr=sqrt(xx);
x=x0-xr; if ((x>0)&&(x<n)) map[x][y][z]=col;
x=x0+xr; if ((x>0)&&(x<n)) map[x][y][z]=col;
}
}
//---------------------------------------------------------------------------
void LED_cube::glDraw()
{
#ifdef __gl_h_
int x,y,z;
float p[3],dp=1.0/float(n-1);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE,GL_ONE);
glPointSize(2.0);
glBegin(GL_POINTS);
for (p[0]=-0.5,x=0;x<n;x++,p[0]+=dp)
for (p[1]=-0.5,y=0;y<n;y++,p[1]+=dp)
for (p[2]=-0.5,z=0;z<n;z++,p[2]+=dp)
{
glColor4ubv((BYTE*)(&map[x][y][z]));
glVertex3fv(p);
}
glEnd();
glDisable(GL_BLEND);
glPointSize(1.0);
#endif
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
class usage:
LED_cube cube;
cube.cls(0x00202020); // clear space to dark gray color
int a=cube.n>>1; // just place sphere to middle and size almost the whole space
int r=a-3;
cube.sphere(a,a,a,r,0x00FFFFFF);
cube.glDraw(); // just for mine visualization you have to rewrite it to your rendering system
If you want to use C only then decompose class to just global functions and variables and translate C++ operators x++,--,+=,-=,*=,... to C style x=x+1,...
Based on the link, it looks like you're more interested in voxel algorithms for spheres, rather than graphics per se; say something like this page helps with. You don't want a ball, but the surface only.
Midpoint circle algorithm can be used to draw 3D voxel spheres: consider the sphere as a stack of slices, and each slice contains a circle.
In practice, you use two nested midpoint circles, the outer defining the radius for the inner one. (Although a naive algorithm drawing circles on top of each other will likely leave holes in the voxels, the midpoint circle algorithm exploits symmetries, and if correctly implemented, no such holes should occur.)
You build six caps in tandem, like carving a cube into a sphere. Since the surface slopes on each cap are always less than 1, going outwards on a cap will at most change each coordinate by 1, so holes cannot occur.
The problem with this approach is the complexity: each point you calculate may affect up to 48 voxel cells. (At each cap, each point is calculated within an octant, and therefore affects eight cells. There are six caps, and 6*8=48.)
I suggest a different approach.
The equation for the surface of a r-radius sphere centered at x0, y0, z0, is
(x - x0)2 + (y - y0)2 + (z - z0)2 = r2
With integer coordinater, the grid points are rarely exactly on the sphere surface, allow a range of values:
RRMIN ≤ (x - x0)2 + (y - y0)2 + (z - z0)2 ≤ RRMAX
where RRMIN and RRMAX are constants; specifically, minimum and maximum distance squared to the sphere center.
I recommend using doubled coordinates for general cases. This allows you to select whether the center of the sphere is centered at a coordinate (implying odd diameter), or centered between two adjacent cordinates (implying even diameter).
If you have a SIZE×SIZE×SIZE grid of voxels (lights, building blocks, whatever), then
int sphere_surface(const char x, const char y, const char z,
const char size, const int rrmin, const int rrmax)
{
const int center = size - (size & 1); /* Size rounded down to even integer */
const int dx = center - x - x,
dy = center - y - y,
dz = center - z - z; /* Doubled coordinates */
const int rr = dx*dx + dy*dy + dz*dz; /* Distance squared */
return (rrmin <= rr) && (rr <= rrmax);
}
returns 1 if point (x,y,z) is within the surface region of the sphere centered in the cube. (Technically, it returns if the distance from that point to the center of the size-sized cube is within sqrt(rrmin)/2 and sqrt(rrmax)/2, inclusive.)
The "correct" values of rrmin and rrmax are highly context dependent. rrmax is typically somewhere near size*size (remember, the function uses doubled coordinates), with rrmin somewhat less.
For example, if you have a 3×3×3 grid, you only want the six center cells on each face to fulfill the condition; you can do that with size=3, rrmin=1, rrmax=4:
If you have a 4×4×4 grid, you want the four center cells on each face to fulfill the condition (so a total of 24 of the 64 cells are considered to be on the sphere surface); you can do that with size=4, rrmin=11, rrmax=11:
With a 5×5×5 grid, we get to the interesting side effects of the above algorithm.
size=5, rrmin=8, rrmax=16 yields a very "angular" sphere, almost a cube standing on a corner:
size=5, rrmin=12, rrmax=20 yields my favourite approximate sphere:
size=5, rrmin=16, rrmax=24 yields a rounded cube (each face a 3×3 flat):
Obviously, using rrmin=0 includes all inner cells, too, yielding a ball instead of just the surface of a sphere.
As the grid size increases, the more variants of each size sphere you can represent.
The above function is especially useful on microcontrollers, because you can simply loop through your lattice, updating the state at each point, as you wish. Furthermore, most microcontrollers are tight on memory, but have very fast (single-clock) addition, subtraction, and multiplication instructions. (Although a 16×16-bit multiplication with 32-bit result typically takes two or more instructions.)
A typical microcontroller does not have the ROM/flash capability to store enough interesting voxel patterns, and only a few have DMA capability from an SD card via SPI (so you could just load "frames" of voxel patterns from a microSD card), but functions like the above can produce interesting shapes with few inputs -- and particularly inputs you can interpolate.
The above function can also be adapted for approximated antialising (by comparing rr to rrmin and rrmax), in case your voxels are not just binary, but e.g. PWM-controlled LEDs.
Since visualizing the above is typically a bit difficult, here is the quick little hack that I used to generate the above images. It outputs an SVG image to standard output, and ASCII slices to standard error, when given size, rrmin, and rrmax as command-line parameters.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define BORDER 2
#define XC(x,y,z) ((x)*16 + (y)*12)
#define YC(x,y,z) ((x)*6 - (y)*8 - (z)*17)
static int xt = 0;
static int yt = 0;
static void fcube(FILE *out, const int x, const int y, const int z, const int fill)
{
const int xc = xt + XC(x,y,z);
const int yc = yt + YC(x,y,z);
fprintf(out, "<path d=\"M%d,%dl16,6,12,-8,0,-17,-16,-6,-12,8z\" fill=\"#%06x\" stroke=\"#000\" />\n", xc, yc, fill & 0xFFFFFF);
fprintf(out, "<path d=\"M%d,%dl16,6,12,-8m-12,8l0,17\" fill=\"none\" stroke=\"#000\" />\n", xc, yc-17);
}
static unsigned long rrmin = 0UL;
static unsigned long rrmax = 0UL;
static int center = 0;
static int surface(const int x, const int y, const int z)
{
/* Doubled coordinates: */
const long dx = 2*x - center,
dy = 2*y - center,
dz = 2*z - center;
const unsigned long rr = dx*dx + dy*dy + dz*dz;
return (rrmin <= rr) && (rr <= rrmax);
}
int main(int argc, char *argv[])
{
int width, height;
int size, x, y, z;
char dummy;
if (argc != 4 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s SIZE RRMIN RRMAX\n", argv[0]);
fprintf(stderr, "Where\n");
fprintf(stderr, " SIZE is the size of the voxel cube\n");
fprintf(stderr, " RRMIN is the minimum distance squared, and\n");
fprintf(stderr, " RRMAX is the maximum distance squared,\n");
fprintf(stderr, " using doubled coordinates.\n");
fprintf(stderr, "\n");
fprintf(stderr, "Examples:\n");
fprintf(stderr, " %s 3 1 4\n", argv[0]);
fprintf(stderr, " %s 4 11 11\n", argv[0]);
fprintf(stderr, " %s 5 8 16\n", argv[0]);
fprintf(stderr, " %s 5 12 20\n", argv[0]);
fprintf(stderr, " %s 5 16 24\n", argv[0]);
fprintf(stderr, "\n");
return EXIT_FAILURE;
}
if (sscanf(argv[1], " %d %c", &size, &dummy) != 1 || size < 3) {
fprintf(stderr, "%s: Invalid size.\n", argv[1]);
return EXIT_FAILURE;
}
if (sscanf(argv[2], " %lu %c", &rrmin, &dummy) != 1) {
fprintf(stderr, "%s: Invalid rrmin.\n", argv[2]);
return EXIT_FAILURE;
}
if (sscanf(argv[3], " %lu %c", &rrmax, &dummy) != 1 || rrmax < rrmin) {
fprintf(stderr, "%s: Invalid rrmax.\n", argv[3]);
return EXIT_FAILURE;
}
/* Calculate coordinate range. */
{ int xmin = XC(0,0,0);
int ymin = YC(0,0,0);
int xmax = XC(0,0,0);
int ymax = YC(0,0,0);
for (z = 0; z <= size; z++)
for (y = 0; y <= size; y++)
for (x = 0; x <= size; x++) {
const int xc = XC(x,y,z);
const int yc = YC(x,y,z);
if (xc < xmin) xmin = xc;
if (xc > xmax) xmax = xc;
if (yc < ymin) ymin = yc;
if (yc > ymax) ymax = yc;
}
xt = BORDER - xmin;
width = xmax - xmin + 2*BORDER;
yt = BORDER - ymin;
height = ymax - ymin + 2*BORDER;
}
center = size - 1;
/* SVG preamble. */
printf("<?xml version=\"1.0\"?>\n");
printf("<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 %d %d\">\n", width, height);
printf("<path d=\"M%d,%dL%d,%d,%d,%d,%d,%d,%d,%d,%d,%dz\" fill=\"#f7f7f7\" stroke=\"#666666\"/>\n",
xt+XC( 0, 0, 0), yt+YC( 0, 0, 0),
xt+XC(size, 0, 0), yt+YC(size, 0, 0),
xt+XC(size,size, 0), yt+YC(size,size, 0),
xt+XC(size,size,size), yt+YC(size,size,size),
xt+XC(0, size,size), yt+YC( 0,size,size),
xt+XC(0, 0,size), yt+YC( 0, 0,size));
printf("<path d=\"M%d,%dL%d,%d,%d,%dM%d,%dL%d,%d\" fill=\"none\" stroke=\"#666666\"/>\n",
xt+XC( 0, 0, 0), yt+YC( 0, 0, 0),
xt+XC( 0,size, 0), yt+YC( 0,size, 0),
xt+XC(size,size, 0), yt+YC(size,size, 0),
xt+XC( 0,size, 0), yt+YC( 0,size, 0),
xt+XC( 0,size,size), yt+YC( 0,size,size));
for (z = 0; z < size; z++)
for (y = size - 1; y >= 0; y--)
for (x = 0; x < size; x++)
if (surface(x,y,z))
fcube(stdout, x, y, z, 0x00CCFF);
printf("</svg>\n");
for (z=0; z < size; z++) {
for (y = 0; y < size; y++) {
for (x = 0; x < size; x++)
fputc(surface(x,y,z) ? 'X' : '.', stderr);
fputs(" ", stderr);
for (x = 0; x < size; x++)
fputc(surface(x,z,y) ? 'X' : '.', stderr);
fputs(" ", stderr);
for (x = 0; x < size; x++)
fputc(surface(y,z,x) ? 'X' : '.', stderr);
fputc('\n', stderr);
}
fputc('\n', stderr);
}
return EXIT_SUCCESS;
}
I didn't bother to finesse the output; you can quite easily e.g. choose different colors for each face, maybe add shadows to the background planes, et cetera.
The above images were created with this program, then converted to PNG using GIMP, but I recommend using your browser to view the generated files locally.
Questions?
the most common library used in this field is openGL
and this slide show you how to configure the library on your IDE download the files from here
http://www.xmission.com/~nate/glut.html
then put them in this paths
glut32.dll -> C:\Windows\System32
glut32.lib -> C:\Program Files\Microsoft Visual Studio .NET\Vc7\PlatformSDK\lib
glut.h -> C:\Program Files\Microsoft Visual Studio .NET\Vc7\PlatformSDK\Include\gl
opengl-superbible-4th this a text book amazing one start from scratch to the advanced level
I can't use any OpenGL libraries, I need vanilla C/C++ solution.
Does that mean no graphics libraries at all? In that case, the very simple answer is: you don't. Neither C nor C++ has native graphics-rendering abilites. you need to use an external library and driver just to get in touch with the OS' frame-buffer and/or graphics card.
However, as for my non-graphics related solution, it depends:
I found Bresenham's circle algorithm but it's for 2D drawing. I just need spheres borders.
Does this mean you literally just need the sphere's borders? Because in that case, you should just use the 2d drawing algorithm you already have, since it gives you the borders right then and there.
If it means you want the individual voxels of the sphere, it's a little more complicated and is going to need a little more math, and possibly to the extent where a software renderer is just going to get punched in the face in terms of performance, depending on how many voxels and individual vertices your sphere has.
What I think you're trying to get is what game and physics-engine developers call a "bounding-box" or "collision-box", sometimes referred to as just "hitbox". All that requires is drawing a cube (usually wireframe) that encloses the entirety of the sphere and nothing more (In other words, you just draw a cube with the same width, height, and depth as the sphere, assuming we're working with an X-Y-Z dimension).
Related
I'm making a 3D voxel game to learn OpenGL (think Minecraft). I know that rendering each face of each cube is slow, so I'm working on meshing. My meshing algorithm of choice is similar to greedy meshing, although it doesn't merge quads so that they all become one quad. Here's what some of my important code looks like:
void build_mesh(chunk *c) {
if (c->meshes != NULL) {
vector_free(c->meshes); // deleted old mesh list
}
c->meshes = vector_create(); // creates a new mesh list
for (int x = 0; x < CHUNK_SIZE; x++) {
for (int y = 0; y < CHUNK_HEIGHT; y++) {
for (int z = 0; z < CHUNK_SIZE; z++) {
if (c->data[x][y][z] == 1) {
mesh m;
m.pos.x = x;
m.pos.y = y;
m.pos.z = z;
if (x - 1 < 0 || c->data[x - 1][y][z] == 0) {
// if we're in here that means we have to render the quad
m.type = X_MIN;
vector_add(&c->meshes, m);
}
if (x + 1 >= CHUNK_SIZE || c->data[x + 1][y][z] == 0) {
m.type = X_POS;
vector_add(&c->meshes, m);
}
if (y - 1 < 0 || c->data[x][y - 1][z] == 0) {
m.type = Y_MIN;
vector_add(&c->meshes, m);
}
if (y + 1 >= CHUNK_HEIGHT || c->data[x][y + 1][z] == 0) {
m.type = Y_POS;
vector_add(&c->meshes, m);
}
if (z - 1 < 0 || c->data[x][y][z - 1] == 0) {
m.type = Z_MIN;
vector_add(&c->meshes, m);
}
if (z + 1 >= CHUNK_SIZE || c->data[x][y][z + 1] == 0) {
m.type = Z_POS;
vector_add(&c->meshes, m);
}
}
}
}
}
}
void render_chunk(chunk *c, vert *verts, unsigned int program, mat4 model, unsigned int modelLoc, bool greedy) {
// meshing code
if (greedy) {
for (int i = 0; i < vector_size(c->meshes); i++) {
glm_translate_make(model, (vec3){c->meshes[i].pos.x, c->meshes[i].pos.y, c->meshes[i].pos.z});
setMat4(modelLoc, model);
glBindVertexArray(verts[c->meshes[i].type].VAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
return;
}
for (int x = 0; x < CHUNK_SIZE; x++) {
for (int y = 0; y < CHUNK_HEIGHT; y++) {
for (int z = 0; z < CHUNK_SIZE; z++) {
for (int i = 0; i < 6; i++) {
if (c->data[x][y][z] == 1) {
glm_translate_make(model, (vec3){x, y, z});
setMat4(modelLoc, model);
glBindVertexArray(verts[i].VAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
}
}
}
}
}
build_mesh only gets called when the chunk gets updated and render_chunk gets called every frame. If greedy is true, greedy meshing is implemented. However, the problem is that greedy meshing is significantly slower than just rendering everything, which should not be happening. Does anyone have any ideas what's going on?
Edit: After timing the mesh rendering, it take ~30-40 ms per frame. However, it scales up really well and still take 30-40 ms regardless of how large the chunk is.
18432 calls to glDrawArrays is way too much as the call it self is a performance hit alone due the way how GL works.
You should group your meshes to much less VAO/VBOs ... for example 128 or less ... you can divide your voxel space into slices so if you got 128x32x32 cubes try to put 32x32 cubes into single VAO/VBOs and see if it makes any difference in speed ... also I would get rid of the translation of cubes and store the cube vertexes into VBO already translated.
My answer in the duplicate (sadly deleted) QA:
How to best write a voxel engine in C with performance in mind
did go one step further representing your voxel space in a 3D texture where each texel represents a voxel and ray tracing it in fragment shader using just single glDraw rendering single QUAD covering the screen. Using the same techniques as Wolfenstein like ray cast just ported to 3D.
The ray tracing (vertex shader casts the start rays) stuff was ported from this:
raytrace through 3D mesh
Here preview from the deleted QA:
IIRC it was 128x128x128 or 256x256x256 voxels rendered in 12.4ms (ignore the fps it was measuring something else). there where a lot of room to optimize more in the shaders as I wanted to keep them as simple and understandable as I could (so no more advanced optimizations)...
There are also other options like using point sprites, or geometry shader emitting the cubes etc ...
In case lowering the number of glDraws is not enough speed boost you might want to implement BVH structures to speed up rendering ... however for single 128x32x32 space I see no point in this as that should be handled with ease...
I am working on the following code in C. So far it has all been working and it is zoomed to the correct level, etc, however I am struggling with getting the colors to work as I want. Ideally I would like to end up with something like this regardless of color:
however my program as it is below currently produces something like this:
Therefore, I would appreciate any help I could get with making the colors turn out as I want them to.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define ITERMAX 100.0
#define DIVERGING 1.1
#define XMAX 500
#define YMAX 500
#define COLORINTENSITY 255
/* allow up to ITERMAX feedbacks searching for convergence
for the feedback
z0 = 0 + 0i
znew = z^2 + c
If we have not diverged to distance DIVERGING before ITERMAX feedbacks
we will assume the feedback is convergent at this value of c.
We will report divergence if |z|^2 > DIVERGING
*/
/* We will print color values for each pixel from (0, 0) to (XMAX, YMAX)
The color of pixel (cx, cy) will be set by convergent()
or by divergent()
depending on the convergence or divergence of the feedback
when c = cx + icy
*/
/* The max value of the red, green, or blue component of a color */
void convergent(); /* one color for convergence */
void divergent(); /* a different color for divergence */
void feedback(double *x, double *y, double cx, double cy);
void pixel(char red, char green, char blue);
FILE *fp;
int main()
{
fp = fopen("mandelbrot.ppm", "wb");
double x, y, cx, cy;
int iteration,squarex, squarey, pixelx, pixely;
double grow=1.0;
/* header for PPM output */
fprintf(fp, "P6\n# CREATOR: EK, BB, RPJ via the mandel program\n");
fprintf(fp, "%d %d\n%d\n",XMAX, YMAX, COLORINTENSITY);
for (pixely = 0; pixely < YMAX; pixely++) {
for (pixelx = 0; pixelx < XMAX; pixelx++) {
cx = (((float)pixelx)/((float)XMAX)-0.5)/grow*3.0-0.7;
cy = (((float)pixely)/((float)YMAX)-0.5)/grow*3.0;
x = 0.0; y = 0.0;
for (iteration=1;iteration<ITERMAX;iteration++) {
feedback(&x, &y, cx, cy);
if (x*x + y*y > 100.0) iteration = 1000;
}
if (iteration==ITERMAX) {
iteration = x*x + y*y;
pixel((char) 0, (char) 0, (char) 0);
}
else {
iteration = sqrt(x*x + y*y);
pixel((char) iteration, (char) 0, (char) iteration);
}
}
}
}
void feedback(double *x, double *y, double cx, double cy) {
/* Update x and y according to the feedback equation
xnew = x^2 - y^2 + cx
ynew = 2xy + cy
(these are the real and imaginary parts of the complex equation:
znew = z^2 + c)
*/
double xnew = (*x) * (*x) - (*y) * (*y) + cx;
double ynew = 2 * *x * *y + cy;
*x = xnew;
*y = ynew;
}
void pixel(char red, char green, char blue) {
/* put a r-g-b triple to the standard out */
fputc(red, fp);
fputc(green, fp);
fputc(blue, fp);
}
To fix the banding, you need to iterate over your tables to find your maximum value for the iteration count, then scale your other values to be relative to this max (ie. normalize the values). You may also wish to logarithmically rescale the values to adjust the slope of the color-change.
And you probably don't want to work directly in RGB space. If you define your colors in HSB space, you can set a constant hue and saturation, and vary the brightness proportionally to the normalized iteration counts.
I am searching online for an efficient method that can intersect a Cartesian rectangular 3D grid with a close irregular 3D surface which is triangulated.
This surface is represented is a set of vertices, V, and a set of faces, F. The Cartesian rectangular grid is stored as:
x_0, x_1, ..., x_(ni-1)
y_0, y_1, ..., y_(nj-1)
z_0, z_1, ..., z_(nk-1)
In the figure below, a single cell of the Cartesian grid is shown. In addition, two triangles of the surface is schematically shown. This intersection is shown by a dotted red lines with the solid red circles the intersection points with this particular cell. My goal is to find the points of intersection of the surface with the edges of the cells, which can be non-planar.
I will implement in either MATLAB, C, or C++.
Assuming we have a regular axis-aligned rectangular grid, with each grid cell matching the unit cube (and thus grid point (i,j,k) is at (i,j,k), with i,j,k integers), I would suggest trying a 3D variant of 2D triangle rasterization.
The basic idea is to draw the triangle perimeter, then every intersection between the triangle and each plane perpendicular to an axis and intersecting that axis at integer coordinates.
You end up with line segments on grid cell faces, wherever the triangle passes through a grid cell. The lines on the faces of each grid cell form a closed planar polygon. (However, you'll need to connect the line segments and orient the polygon yourself.)
For finding out only the grid cells the triangle passes through, a simplified approach can be used, and a bitmap (one bit per grid cell). This case is essentially just a 3D version of triangle rasterization.
The key observation is that if you have a line (X0,Y0,Z0)-(X1,Y1,Z1), you can split it into segments at integer coordinates xi along the x axis using
ti = (xi - X0) / (X1 - X0)
yi = (1 - ti) Y0 + ti Y1
zi = (1 - ti) Z0 + ti Z1
Similarly along the other axes, of course.
You'll need to do three passes, one along each axis. If you sort the vertices so that the coordinates are nondecreasing along that axis, i.e. p0 ≤ p1 ≤ p2, one endpoint is at integer coordinates intersecting line p0p2, and the other endpoint intersects line p0p1 at small coordinates, and line p1p2 at large coordinates.
The intersection line between those endpoints is perpendicular to one axis, but it still needs to be split into segments that do not cross integer coordinates along the other two dimensions. This is fortunately simple; just maintain tj and tk along those two dimensions just like ti above, and step to the next integer coordinate that has the smaller t value; start at 0, and end at 1.
The edges of the original triangle also need to be drawn, just split along all three dimensions. Again, this is straightforward, by maintaining the t for each axis, and stepping along the axis with the smallest value. I have example code in C99 for this, the most complicated case, below.
There are quite a few implementation details to consider.
Because each cell shares each face with another cell, and each edge with three other edges, let's define the following properties for each cell (i,j,k), where i,j,k are integers identifying the cell:
X face: The cell face at x=i, perpendicular to the x axis
Y face: The cell face at y=j, perpendicular to the y axis
Z face: The cell face at z=k, perpendicular to the z axis
X edge: The edge from (i,j,k) to (i+1,j,k)
Y edge: The edge from (i,j,k) to (i,j+1,k)
Z edge: The edge from (i,j,k) to (i,j,k+1)
The other three faces for cell (i,j,k) are
the X face at (i+1,j,k)
the Y face at (i,j+1,k)
the Z face at (i,j,k+1)
Similarly, each edge is an edge for three other cells. The X edge of cell (i,j,k) is also an edge for grid cells (i,j+1,k), (i,j,k+1), and (i,j+1,k+1). The Y edge of cell (i,j,k) is also an edge for grid cells (i+1,j,k), (i,j,k+1), and (i+1,j,k+1). The Z edge of cell (i,j,k) is also an edge for grid cells (i+1,j,k), (i,j+1,k), and (i+1,j+1,k).
Here is an image that might help.
(Ignore the fact that it's left-handed; I just thought it'd be easier to label this way.)
This means that if you have a line segment on a specific grid cell face, the line segment is shared between the two grid cells sharing that face. Similarly, if a line segment endpoint is on a grid cell edge, there are four different grid cell faces the other line segment endpoint could be on.
To clarify this, my example code below prints not only the coordinates, but the grid cell and the face/edge/vertex the line segment endpoint is on.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <math.h>
typedef struct {
double x;
double y;
double z;
} vector;
typedef struct {
long x;
long y;
long z;
} gridpos;
typedef enum {
INSIDE = 0, /* Point is inside the grid cell */
X_FACE = 1, /* Point is at integer X coordinate (on the YZ face) */
Y_FACE = 2, /* Point is at integer Y coordinate (on the XZ face) */
Z_EDGE = 3, /* Point is at integet X and Y coordinates (on the Z edge) */
Z_FACE = 4, /* Point is at integer Z coordinate (on the XY face) */
Y_EDGE = 5, /* Point is at integer X and Z coordinates (on the Y edge) */
X_EDGE = 6, /* Point is at integer Y and Z coordinates (on the X edge) */
VERTEX = 7, /* Point is at integer coordinates (at the grid point) */
} cellpos;
static inline cellpos cellpos_of(const vector v)
{
return (v.x == floor(v.x))
+ (v.y == floor(v.y)) * 2
+ (v.z == floor(v.z)) * 4;
}
static const char *const face_name[8] = {
"inside",
"x-face",
"y-face",
"z-edge",
"z-face",
"y-edge",
"x-edge",
"vertex",
};
static int line_segments(const vector p0, const vector p1,
int (*segment)(void *custom,
const gridpos src_cell, const cellpos src_face, const vector src_vec,
const gridpos dst_cell, const cellpos dst_face, const vector dst_vec),
void *const custom)
{
const vector range = { p1.x - p0.x, p1.y - p0.y, p1.z - p0.z };
const gridpos step = { (range.x < 0.0) ? -1L : (range.x > 0.0) ? +1L : 0L,
(range.y < 0.0) ? -1L : (range.y > 0.0) ? +1L : 0L,
(range.z < 0.0) ? -1L : (range.z > 0.0) ? +1L : 0L };
const gridpos end = { floor(p1.x), floor(p1.y), floor(p1.z) };
gridpos prev_cell, curr_cell = { floor(p0.x), floor(p0.y), floor(p0.z) };
vector prev_vec, curr_vec = p0;
vector curr_at = { 0.0, 0.0, 0.0 };
vector next_at = { (range.x != 0.0 && curr_cell.x != end.x) ? ((double)(curr_cell.x + step.x) - p0.x) / range.x : 1.0,
(range.y != 0.0 && curr_cell.y != end.y) ? ((double)(curr_cell.y + step.y) - p0.y) / range.y : 1.0,
(range.z != 0.0 && curr_cell.z != end.z) ? ((double)(curr_cell.z + step.z) - p0.z) / range.z : 1.0};
cellpos prev_face, curr_face;
double at;
int retval;
curr_face = cellpos_of(p0);
while (curr_at.x < 1.0 || curr_at.y < 1.0 || curr_at.z < 1.0) {
prev_cell = curr_cell;
prev_face = curr_face;
prev_vec = curr_vec;
if (next_at.x < 1.0 && next_at.x <= next_at.y && next_at.x <= next_at.z) {
/* YZ plane */
at = next_at.x;
curr_vec.x = round( (1.0 - at) * p0.x + at * p1.x );
curr_vec.y = (1.0 - at) * p0.y + at * p1.y;
curr_vec.z = (1.0 - at) * p0.z + at * p1.z;
} else
if (next_at.y < 1.0 && next_at.y < next_at.x && next_at.y <= next_at.z) {
/* XZ plane */
at = next_at.y;
curr_vec.x = (1.0 - at) * p0.x + at * p1.x;
curr_vec.y = round( (1.0 - at) * p0.y + at * p1.y );
curr_vec.z = (1.0 - at) * p0.z + at * p1.z;
} else
if (next_at.z < 1.0 && next_at.z < next_at.x && next_at.z < next_at.y) {
/* XY plane */
at = next_at.z;
curr_vec.x = (1.0 - at) * p0.x + at * p1.x;
curr_vec.y = (1.0 - at) * p0.y + at * p1.y;
curr_vec.z = round( (1.0 - at) * p0.z + at * p1.z );
} else {
at = 1.0;
curr_vec = p1;
}
curr_face = cellpos_of(curr_vec);
curr_cell.x = floor(curr_vec.x);
curr_cell.y = floor(curr_vec.y);
curr_cell.z = floor(curr_vec.z);
retval = segment(custom,
prev_cell, prev_face, prev_vec,
curr_cell, curr_face, curr_vec);
if (retval)
return retval;
if (at < 1.0) {
curr_at = next_at;
if (at >= next_at.x) {
/* recalc next_at.x */
if (curr_cell.x != end.x) {
next_at.x = ((double)(curr_cell.x + step.x) - p0.x) / range.x;
if (next_at.x > 1.0)
next_at.x = 1.0;
} else
next_at.x = 1.0;
}
if (at >= next_at.y) {
/* reclac next_at.y */
if (curr_cell.y != end.y) {
next_at.y = ((double)(curr_cell.y + step.y) - p0.y) / range.y;
if (next_at.y > 1.0)
next_at.y = 1.0;
} else
next_at.y = 1.0;
}
if (at >= next_at.z) {
/* recalc next_at.z */
if (curr_cell.z != end.z) {
next_at.z = ((double)(curr_cell.z + step.z) - p0.z) / range.z;
if (next_at.z > 1.0)
next_at.z = 1.0;
} else
next_at.z = 1.0;
}
} else {
curr_at.x = curr_at.y = curr_at.z = 1.0;
next_at.x = next_at.y = next_at.z = 1.0;
}
}
return 0;
}
int print_segment(void *outstream,
const gridpos src_cell, const cellpos src_face, const vector src_vec,
const gridpos dst_cell, const cellpos dst_face, const vector dst_vec)
{
FILE *const out = outstream ? outstream : stdout;
fprintf(out, "%.6f %.6f %.6f %.6f %.6f %.6f %s %ld %ld %ld %s %ld %ld %ld\n",
src_vec.x, src_vec.y, src_vec.z,
dst_vec.x, dst_vec.y, dst_vec.z,
face_name[src_face], src_cell.x, src_cell.y, src_cell.z,
face_name[dst_face], dst_cell.x, dst_cell.y, dst_cell.z);
fflush(out);
return 0;
}
static int parse_vector(const char *s, vector *const v)
{
double x, y, z;
char c;
if (!s)
return EINVAL;
if (sscanf(s, " %lf %*[,/:;] %lf %*[,/:;] %lf %c", &x, &y, &z, &c) == 3) {
if (v) {
v->x = x;
v->y = y;
v->z = z;
}
return 0;
}
return ENOENT;
}
int main(int argc, char *argv[])
{
vector start, end;
if (argc != 3 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s x0:y0:z0 x1:y1:z1\n", argv[0]);
fprintf(stderr, "\n");
return EXIT_FAILURE;
}
if (parse_vector(argv[1], &start)) {
fprintf(stderr, "%s: Invalid start point.\n", argv[1]);
return EXIT_FAILURE;
}
if (parse_vector(argv[2], &end)) {
fprintf(stderr, "%s: Invalid end point.\n", argv[2]);
return EXIT_FAILURE;
}
if (line_segments(start, end, print_segment, stdout))
return EXIT_FAILURE;
return EXIT_SUCCESS;
}
The program takes two command-line parameters, the 3D endpoints for the line to be segmented. If you compile the above to say example, then running
./example 0.5/0.25/3.50 3.5/4.0/0.50
outputs
0.500000 0.250000 3.500000 1.000000 0.875000 3.000000 inside 0 0 3 x-face 1 0 3
1.000000 0.875000 3.000000 1.100000 1.000000 2.900000 x-face 1 0 3 y-face 1 1 2
1.100000 1.000000 2.900000 1.900000 2.000000 2.100000 y-face 1 1 2 y-face 1 2 2
1.900000 2.000000 2.100000 2.000000 2.125000 2.000000 y-face 1 2 2 y-edge 2 2 2
2.000000 2.125000 2.000000 2.700000 3.000000 1.300000 y-edge 2 2 2 y-face 2 3 1
2.700000 3.000000 1.300000 3.000000 3.375000 1.000000 y-face 2 3 1 y-edge 3 3 1
3.000000 3.375000 1.000000 3.500000 4.000000 0.500000 y-edge 3 3 1 y-face 3 4 0
which shows that line (0.5, 0.25, 3.50) - (3.5, 4.0, 0.50) gets split into seven segments; this particular line passing through exactly seven grid cells.
For the rasterization case -- when you are only interested in which grid cells the surface triangles pass through --, you do not need to store the line segment points, only compute them all. When a point is at a vertex or inside a grid cell, mark the bit corresponding to that grid cell. When a point is at a face, set the bit for the two grid cells that share that face. When a line segment endpoint is at an edge, set the bit for the four grid cells that share that edge.
Questions?
Break the problem down into smaller steps.
Finding the intersection of a line segment with a triangle is easy.
Once you have that implemented, just perform a nested loop that checks for intersection between every combination of lines from the grid with triangles of the surface.
Use Line-Plane intersection as explained here on each surface triangle edge. You'll use six planes, one for each grid cell face.
This is my first post on here, so go easy on me!
I have a very strange problem. I've written a c code that converts particle data to grid data (the data comes from a cosmological simulation). In order to do this conversion, I am using the gsl Monte Carlo vegas integrator. When I run it in serial, it runs just fine and gives me the correct answer (albeit slowly). As an attempt at speeding it up, I tried openmp. The problem is that when I run it in parallel, the integration times out (I set a MAX_ITER variable in the integration loop to avoid an infinite loop due to lack of convergence). The random number generator is set and initialized before the parallel block of code. I checked and double checked, and all of the data about the particle that it fails at in parallel (x, y, and z position and integration bounds being passed to the integrator) are the same in both serial and parallel. I also tried increasing my MAX_ITER variable from 100 to 1000, but that did nothing; it just took longer to fail.
My question then, is if anyone has any idea why the code would run in serial, but time out in parallel when using the exact same particles?
Also, in case you want it, the numbers for the offending particle are: x = 0.630278, y = 24.952896, z = 3.256376, h = 3 (this is the smoothing length of the particle, which serves to "smear" out the particle's mass, as the goal of the simulation is to use particles to sample a fluid. This is the sph method), x integration bounds (lower, upper) = {0, 630278}, y bounds = {21.952896, 27.952896}, and z bounds = {0.256376, 6.256375}
The idea behind the conversion is that the particle's mass is contained within a "smoothing sphere" of radius h and centered at the particle itself. This mass is not distributed uniformly, but is done so according to the sph kernel (this is the function I'm integrating). Thus, depending on how the sphere is placed within its "home cell", only a part of the sphere may actually be inside this cell. The goal then is to get the appropriate bounds of integration and pass them to the integrator. The integrator (the code is below) has a check, whereby if the point given to it by the Monte Carlo integrator lies outside the sphere, it returns 0 (this is because getting the exact limits of integration for every possible case is a huge pain).
The code for my loop is here:
// Loop over every particle
#pragma omp parallel shared(M_P, m_header, NumPartTot, num_grid_elements, cxbounds,
cybounds, czbounds, master_cell) private(index, x, y, z, i, j, k, h, tid, cell,
corners)
{
tid = omp_get_thread_num();
// Set up cell struct. Allocate memory!
cell = set_up_cell();
#pragma omp for
for(index = 1; index <= NumPartTot; index++)
{
printf("\n\n\n************************************\n");
printf("Running particle: %d on thread: %d\n", index, tid);
printf("x = %f y = %f z = %f\n", M_P[index].Pos[0], M_P[index].Pos[1], M_P[index].Pos[2]);
printf("**************************************\n\n\n");
fflush(stdout);
// Set up convenience variables
x = M_P[index].Pos[0];
y = M_P[index].Pos[1];
z = M_P[index].Pos[2];
// Figure out which cell the particle is in
i = (int)((x / m_header.BoxSize) * num_grid_elements);
j = (int)((y / m_header.BoxSize) * num_grid_elements);
k = (int)((z / m_header.BoxSize) * num_grid_elements);
corners = get_corners(i, j, k);
// Check to see what type of particle we're dealing with
if(M_P[index].Type == 0)
{
h = M_P[index].hsml;
convert_gas(i, j, k, x, y, z, h, index, cell, corners);
}
else
{
update_cell_non_gas_properties(index, i, j, k, cell);
}
}
// Copy each thread's version of cell to cell_master
#ifdef _OPENMP
copy_to_master_cell(cell);
free_cell(cell);
#endif
} /*-- End of parallel region --*/
The problem occurs in the function convert_gas. The problematic section is here (in the home cell block):
// Case 6: Left face
if(((x + h) < cxbounds[i][j][k].hi) && ((x - h) < cxbounds[i][j][k].lo) &&
((y + h) < cybounds[i][j][k].hi) && ((y - h) >= cybounds[i][j][k].lo) &&
((z + h) < czbounds[i][j][k].hi) && ((z - h) >= czbounds[i][j][k].lo))
{
printf("Using case 6\n");
fflush(stdout);
// Home cell
ixbounds.lo = cxbounds[i][j][k].lo;
ixbounds.hi = x + h;
iybounds.lo = y - h;
iybounds.hi = y + h;
izbounds.lo = z - h;
izbounds.hi = z + h;
kernel = integrate(ixbounds, iybounds, izbounds, h, index, i, j, k);
update_cell_gas_properties(kernel, i, j, k, index, cell);
// Left cell
ixbounds.lo = x - h;
ixbounds.hi = cxbounds[i][j][k].lo;
iybounds.lo = y - h; // Not actual bounds. See note above.
iybounds.hi = y + h;
izbounds.lo = z - h;
izbounds.hi = z + h;
kernel = integrate(ixbounds, iybounds, izbounds, h, index, i - 1, j, k);
update_cell_gas_properties(kernel, i - 1, j, k, index, cell);
return;
}
The data that I'm currently using is test data, so I know exactly where the particles should be and what integration bounds they should have. When using gdb, I find that all of these numbers are correct. The integration loop in the function integrate is here (TOLERANCE is 0.2, WARM_CALLS is 10000, and N_CALLS is 100000):
gsl_monte_vegas_init(monte_state);
// Warm up
gsl_monte_vegas_integrate(&monte_function, lower_bounds, upper_bounds, 3,
WARM_CALLS, random_generator, monte_state, &result, &error);
// Actual integration
do
{
gsl_monte_vegas_integrate(&monte_function, lower_bounds, upper_bounds, 3,
N_CALLS, random_generator, monte_state, &result, &error);
iter++;
} while(fabs(gsl_monte_vegas_chisq(monte_state) - 1.0) > TOLERANCE && iter < MAX_ITER);
if(iter >= MAX_ITER)
{
fprintf(stdout, "ERROR!!! Max iterations %d exceeded!!!\n"
"See M_P[%d].id : %d (%f %f %f)\n"
"lower bnds : (%f %f %f) upper bnds : (%f %f %f)\n"
"trying to integrate in cell %d %d %d\n\n", MAX_ITER, pind, M_P[pind].id,
M_P[pind].Pos[0], M_P[pind].Pos[1], M_P[pind].Pos[2],
ixbounds.lo, iybounds.lo, izbounds.lo, ixbounds.hi, iybounds.hi, izbounds.hi, i, j, k);
fflush(stdout);
exit(1);
}
Again, this exact code (but without openmp, I pass that compile time option as an option in the makefile) with the exact same numbers runs in serial, but not in parallel. I'm sure it's something stupid that I've done and simply cannot see at the moment (at least, I hope!) Anyways, thanks for the help in advance!
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.