Making (& filling) a circle
Posted: Sun Jul 18, 2004 12:44 pm
Here's some code to draw a rough circle out from a specified point that I needed to make the other day if anyone happens to be interested. It's broken into two funcs, one that draws a line between two points and one that handles the actual circle making. I'll probably fix it up a bit, if I do, I'll edit the post. But at the moment it works pretty well as it is.
Should note that what it actually modifies is a two-dimensional vector (the C++ version of a two-dimensional array). But the points are still there, since the vector is 640x480. Should be pretty easy to change to whatever you need.
Edit: Added a few comments.
Edit: Made the angle things const static
Edit: Optimized the line drawing a little.
Edit: And circle a bit.
Edit: See post below for filling it.
:)
Should note that what it actually modifies is a two-dimensional vector (the C++ version of a two-dimensional array). But the points are still there, since the vector is 640x480. Should be pretty easy to change to whatever you need.
Edit: Added a few comments.
Edit: Made the angle things const static
Edit: Optimized the line drawing a little.
Edit: And circle a bit.
Edit: See post below for filling it.
Code: Select all
#include <cmath>
#include <vector>
//.....
/***********************************
* Changes terrain between points *
* (xone, yone) and (xtwo, ytwo) to *
* be type. *
***********************************/
//http://ironbark.bendigo.latrobe.edu.au/courses/gdc/bitgrp/srgpdem/line2.c++
void World::changeTerrainLine(int xone, int yone, int xtwo, int ytwo, int type) {
int rise = (yone-ytwo);
int run = (xone-xtwo);
int steps; //How many steps to this line?
double xInc, yInc, x, y; //How much to increment, and current coordinates.
if (rise == 0 && run == 0) { //It must be a single point.
landRes.at(yone).at(xone) = type;
return;
}
//Use whichever is greater for the number of steps in this line.
if (abs(run) > abs(rise))
steps = abs(run);
else
steps = abs(rise);
xInc = (double)run/(double)steps;
yInc = (double)rise/(double)steps;
x = xtwo; //Gotta start somewhere.
y = ytwo;
int ix, iy; //Integer x, integer y. Because my vector can only take integers as coordinates.
//If you can use float for your coordinates, do so.
//Define the bounds
const unsigned int maxY = landRes.size();
const unsigned int maxX = landRes.at(0).size();
for (unsigned int i = 0;i < steps;i++) {
x += xInc;
y += yInc;
ix = (int)(x + 0.5); //Round
iy = (int)(y + 0.5); //Round
if (iy >= maxY)
iy = maxY-1;
else if (iy < 0)
iy = 0;
if (ix >= maxX)
ix = maxX-1;
else if (ix < 0)
ix = 0;
//I do the error checking so I don't need .at().
landRes[iy][ix] = type;
}
}
/*****************************************
* At the moment, just changes terrain in *
* an unfilled circle radius pixels from *
* center (x, y) to be type. *
*****************************************/
//divisions is unused as of yet.
void World::changeTerrainCircle(int x, int y, int radius, int type, int divisions) {
//(x-x1)^2 + (y-y1)^2 = r^2
//we know that x1,y1+radius and x1+radius,y1 are on the circle
//Define max bounds
const unsigned int maxX = landRes.at(0).size();
const unsigned int maxY = landRes.size();
if (x >= maxX)
x = maxX-1;
if (y >= maxY)
y = maxY-1;
//Eightfold circular symmetry
//http://ironbark.bendigo.latrobe.edu.au/courses/gdc/bitgrp/lect/lect03/lect03.html
int xOneEighty = x-radius; //180 degrees (left from center)
int yTwoSeventy = y-radius; //270 degrees (down from center)
int xZero = x+radius; //0 degrees (right from center)
int yNinety = y+radius; //90 degrees (up from center)
const static int xThirty = radius*cos(30*PI/180); //"Out" distance for thirty degrees.
const static int yThirty = radius*sin(30*PI/180); //"Up" distance for thirty degrees.
const static int xFortyFive = radius*cos(45*PI/180); //"Out" distance for forty-five degrees.
const static int yFortyFive = radius*sin(45*PI/180); //"Up" distance for forty-five degrees.
const static int xSixty = radius*cos(60*PI/180); //"Out" distance for sixty degrees.
const static int ySixty = radius*sin(60*PI/180); //"Up" distance for sixty degrees.
//Make sure it isn't outside the range of my screen vector.
if (xOneEighty < 0)
xOneEighty = 0;
if (yTwoSeventy < 0)
yTwoSeventy = 0;
if (xZero >= maxX)
xZero = maxX-1;
if (yNinety >= maxY)
yNinety = maxY-1;
//use logic, determine if you want to go left or right of the origin
//remember sixty goes very little x but lots of y and
//thirty goes lots of x but very little y.
/*
those of you on forum who don't know trigonometry or what im talking about here: draw a circle on a coordinate plane (graph paper :P) draw a line straight up and down through the middle of circle and one left and right through middle of circle (or use lines already there if youre on graph paper). then get a protractor and draw a line from the center to sixty degrees. make a point where the line goes through the rim of the circle. draw a line straight down to the x-axis. you'll note that you don't go over very far, but you do go pretty high up. thirty degrees is the opposite, whereas forty-five degrees is a line with a 1/1 slope.
*/
//MARFIX: Generalize this?
changeTerrainLine(xZero, y, x+xThirty, y+yThirty, type);
changeTerrainLine(x+xThirty, y+yThirty, x+xFortyFive, y+yFortyFive, type);
changeTerrainLine(x+xFortyFive, y+yFortyFive, x+xSixty, y+ySixty, type);
changeTerrainLine(x+xSixty, y+ySixty, x, yNinety, type);
changeTerrainLine(x, yNinety, x-xSixty, y+ySixty, type);
changeTerrainLine(x-xSixty, y+ySixty, x-xFortyFive, y+yFortyFive, type);
changeTerrainLine(x-xFortyFive, y+yFortyFive, x-xThirty, y+yThirty, type);
changeTerrainLine(x-xThirty, y+yThirty, xOneEighty, y, type);
changeTerrainLine(xOneEighty, y, x-xThirty, y-yThirty, type);
changeTerrainLine(x-xThirty, y-yThirty, x-xFortyFive, y-yFortyFive, type);
changeTerrainLine(x-xFortyFive, y-yFortyFive, x-xSixty, y-ySixty, type);
changeTerrainLine(x-xSixty, y-ySixty, x, yTwoSeventy, type);
changeTerrainLine(x, yTwoSeventy, x+xSixty, y-ySixty, type);
changeTerrainLine(x+xSixty, y-ySixty, x+xFortyFive, y-yFortyFive, type);
changeTerrainLine(x+xFortyFive, y-yFortyFive, x+xThirty, y-yThirty, type);
changeTerrainLine(x+xThirty, y-yThirty, xZero, y, type);
//Copy points within the square BL(xOneEighty, yTwoSeventy), TR(xZero, yNinety)
//to the 2d array that OpenGL needs to draw stuff with.
//Yes, my function is written a little weird.
generateTerrain(xOneEighty, xZero, yTwoSeventy, yNinety);
}