I tried implementing the Cyrus Beck algorithm for convex polygons. The problem that I was encountering was to find the direction of normal vectors as they must always point inside. For solving this I found the coordinates of the centroid, which always lie inside a convex polygon. This method seems to work in the cases I tested. Is this fool proof ? Are there any better alternatives ?
CyrusBeck.cpp
#include<iostream>
#include<cmath>
#include"graphics.hpp"
#define P pair<double, double>
vector<P> V, N;
P C;
double dot(P A, P B){
return (A.first*B.first + A.second*B.second);
}
P operator - (const P &A, const P &B){
return make_pair(A.first-B.first, A.second-B.second);
}
P operator + (const P &A, const P &B){
return make_pair(A.first+B.first, A.second+B.second);
}
P operator * (const P &A, const double t){
return make_pair(t*A.first, t*A.second);
}
void computeNormal(int n = V.size()){
double m;
P prev = V[0];
double x=-1, y;
for(int i=1; i<n; ++i){
m = -(V[i].first-prev.first)/(V[i].second-prev.second);
P d = V[i]-prev;
int lr=1, tb=1;
if(V[i-1].first>C.first)
lr = -1;
if(V[i-1].second>C.second)
tb=-1;
N[i-1].first = lr*abs(cos(atan(m)));
N[i-1].second = tb*abs(sin(atan(m)));
prev = V[i];
}
m = -(V[0].first-prev.first)/(V[0].second-prev.second);
int lr=1, tb=1;
if(V[n-1].first>C.first)
lr = -1;
if(V[n-1].second>C.second)
tb=-1;
N[n-1].first = lr*abs(cos(atan(m)));
N[n-1].second = tb*abs(sin(atan(m)));
}
int check(P A, P B, int n){
P p = B - V[0];
double d1 = dot(p, N[0]);
P q = A - V[0];
double d2 = dot(q, N[0]);
if(d1<0&&d2<0)
return 0;
if(d1>=0&&d2>=0)
return 1;
return -1;
}
void Clip(P A, P B, double &tE, double &tL, int n = V.size()){
tE = 0; tL = 1;
for(int i=0; i<n; ++i){
double d = dot((B-A), N[i]);
if(d==0)
continue;
double t = dot((A-V[i]), N[i])/dot((A-B), N[i]);
if(d>0&&t>tE)
tE = t;
else if(d<0&&t<tL)
tL = t;
}
}
void display(){
cout<<"Enter the number of vertices\n";
int n; cin>>n;
V.resize(n);
N.resize(n);
cout<<"Enter the coordinates of the vertices in order\n";
for(int i=0; i<n; ++i){
cin>>V[i].first>>V[i].second;
C = C + V[i];
}
C.first/=n; C.second/=n;
drawPolygon(V, n, white);
glutSwapBuffers();
cout<<"Enter the co-ordinates of the line(4)\n";
P A, B;
cin>>A.first>>A.second>>B.first>>B.second;
drawLine(A.first, A.second, B.first, B.second, red);
glutSwapBuffers();
char c = '\0';
while(c!='Y'&&c!='y'){
cout<<"Clip? (Y/N)\n";
cin>>c;
}
computeNormal();
int chk = check(A, B, n);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
drawPolygon(V, n, white);
if(chk==-1){
double tE, tL;
Clip(A, B, tE, tL);
if(tE>tL)
chk = 0;
else{
P E = A + (B-A)*tE;
P L = A + (B-A)*tL;
drawLine(E.first, E.second, L.first, L.second, blue);
}
}
if(chk==1)
drawLine(A.first, A.second, B.first, B.second, blue);
glutSwapBuffers();
}
int main(int argc, char *argv[]){
init(&argc, argv);
}
graphics.hpp
#ifndef GRAPHICS_H
#define GRAPHICS_H
#include<GL/glut.h>
#include<vector>
using namespace std;
extern float red[3];
extern float green[3];
extern float blue[3];
extern float white[3];
int roundoff(double x);
void init(int* argc, char** argv);
void putpixel(float x, float y, float z, float a[3]);
void drawLine(double x1, double y1, double x2, double y2, float a[3]);
void drawRectangle(double x1, double y1, double x2, double y2, float a[3]);
void drawPolygon(vector<pair<double, double>> v, int n, float a[3]);
void MatrixMultiply(vector<vector<double>> &mat1, vector<vector<double>> &mat2, vector<vector<double>> &res,
int n, int m, int r);
void display();
#endif
graphics.cpp
#include<iostream>
#include"graphics.hpp"
float red[3] = { 1.0f, 0.0f, 0.0f };
float green[3] = { 0.0f, 1.0f, 0.0f };
float blue[3] = { 0.0f, 0.0f, 1.0f };
float white[3] = { 1.0f, 1.0f, 1.0f };
int roundoff(double x){
if (x < 0.0)
return (int)(x - 0.5);
else
return (int)(x + 0.5);
}
void init(int *argc, char** argv){
glutInit(argc, argv); // Initialize GLUT
glutInitWindowSize(800, 800); // Set the window's initial width & height
glutInitWindowPosition(0, 0); // Position the window's initial top-left corner
glutCreateWindow("Graphics"); // Create a window with the given title
gluOrtho2D(0, 800, 0, 800); // specifies the projection matrix
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set background color to black and opaque
glClear(GL_COLOR_BUFFER_BIT); // Clear the color buffer (background)
glutDisplayFunc(display); // Register display callback handler for window re-paint
glutMainLoop(); // Enter the event-processing loop
}
void putpixel(float x, float y, float z, float a[3]){
glPointSize(2);
glBegin(GL_POINTS); // HERE THE POINTS SHOULD BE CREATED
glColor3f(a[0], a[1], a[2]);
glVertex3f(x, y, z); // Specify points in 3d plane
std::cout<<x<<' '<<y<<' '<<z<<'\n';
glEnd();
}
void drawLine(double x1, double y1, double x2, double y2, float a[3]){
glLineWidth(2.5);
glColor3f(a[0], a[1], a[2]);
glBegin(GL_LINES);
glVertex2d(x1, y1);
glVertex2d(x2, y2);
glEnd();
}
void drawRectangle(double x1, double y1, double x2, double y2, float a[3]){
glColor3f(a[0], a[1], a[2]);
glRectd(x1, y1, x2, y2);
}
void drawPolygon(vector<pair<double, double>> v, int n, float a[3]){
glColor3f(a[0], a[1], a[2]);
glBegin(GL_POLYGON);
for(int i=0; i<n; ++i)
glVertex2d(v[i].first, v[i].second);
glEnd();
}
void MatrixMultiply(vector<vector<double>> &mat1, vector<vector<double>> &mat2, vector<vector<double>> &res,
int n, int m, int r){
int x, i, j;
for(i = 0; i < n; i++){
for (j = 0; j < r; j++){
res[i][j] = 0;
for (x = 0; x < m; x++){
res[i][j] += mat1[i][x] * mat2[x][j];
}
}
}
}
Related
This is my fist time studying Computer Graphics and i was given the code below from my professor. I think i have understood how the algorithm is implemented in general, but what i fail to understand is in what way the incx,incy,inc1,inc2 lines work. I obviously know they are there to increase something but since i haven't fully understood the algorithm i'm kinda baffled. This is the full code:
#include <gl/glut.h>
#include <stdio.h>
int xstart, ystart, xend, yend;
void myInit() {
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.0, 0.0, 0.0, 1.0);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0, 500, 0, 500);
}
void draw_pixel(int x, int y) {
glBegin(GL_POINTS);
glVertex2i(x, y);
glEnd();
}
void draw_line(int xstart, int xend, int ystart, int yend) {
int dx, dy, i, e;
int incx, incy, inc1, inc2;
int x,y;
dx = xend-xstart;
dy = yend-ystart;
if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
incx = 1;
if (xend < xstart) incx = -1;
incy = 1;
if (yend < ystart) incy = -1;
x = xstart;
y = ystart;
if (dx > dy) {
draw_pixel(x, y);
e = 2 * dy-dx;
inc1 = 2*(dy-dx);
inc2 = 2*dy;
for (i=0; i<dx; i++) {
if (e >= 0) {
y += incy;
e += inc1;
}
else
e += inc2;
x += incx;
draw_pixel(x, y);
}
} else {
draw_pixel(x, y);
e = 2*dx-dy;
inc1 = 2*(dx-dy);
inc2 = 2*dx;
for (i=0; i<dy; i++) {
if (e >= 0) {
x += incx;
e += inc1;
}
else
e += inc2;
y += incy;
draw_pixel(x, y);
}
}
}
void myDisplay() {
draw_line(xstart, xend, ystart, yend);
glFlush();
}
void main(int argc, char **argv) {
printf( "Enter (xstart, ystart, xend, yend)\n");
scanf("%d %d %d %d", &xstart, &ystart, &xend, ¥d);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(0, 0);
glutCreateWindow("Bresenham's Line Algorithm Visualization");
myInit();
glutDisplayFunc(myDisplay);
glutMainLoop();
}
I've done some research and there are many methods to doing this if the vertices and points are predetermined as seen here. However in my case, everything is specified by the user. The code I have put together (with the help of others), allows the user to create the polygon, and place points. I wrote functions to try and create vectors from the point to the vertices and then compute the angle. If it comes to 360 it should be inside and it should be colored green. Else it should be outside and red.
This is what I've been working on, but I cant seem to figure it out:
(Edit: Included my entire code)
GLint vert[100][2];
int width = 400, height = 600, n = 0, m = 0, type = GL_LINE_STRIP, v;
bool rubberbanding = false;
bool closed = false;
double testx, testy;
bool isitin;
double dotp(double x1, double y1, double x2, double y2) {
double a;
a = (x1 * x2) + (y1 * y2);
return a;
}
double mag(double x1, double y1, double x2, double y2) {
double a;
double x = (x2 - x1);
double y = (y2 - y1);
a = sqrt((x*x) + (y*y));
return a;
}
bool inpoly(int numv, GLint vx[][2], GLint vy[][2], double tx, double ty) {
double angle = 0.0;
int n = 0;
while (n != numv) {
//vector from point to vertex
double newv1x = vx[n][0] - tx;
double newv1y = vy[n][1] - ty;
double magv1 = mag(tx, ty, vx[n][0], vy[n][1]); //magnitude of vector
//vector from point to next vertex
double newv2x = vx[n + 1][0] - tx;
double newv2y = vy[n + 1][1] - ty;
double magv2 = mag(tx, ty, vx[n+1][0], vy[n+1][1]);//magnitude of vector
//dot product between the two vectors
double dp = dotp(newv1x, newv1y, newv2x, newv2y);
//angle between two vectors
double vang = acos(dp / (magv1*magv2));
angle += vang;
n++;
}
//vector from point to last vertex
double newv1x = vx[numv][0] - tx;
double newv1y = vy[numv][1] - ty;
double magv1 = mag(tx, ty, vx[numv][0], vy[numv][1]); //magnitude of vector
//vector from point to first vertex
double newv2x = vx[0][0] - tx;
double newv2y = vy[0][1] - ty;
double magv2 = mag(tx, ty, vx[0][0], vy[0][1]);//magnitude of vector
//dot product between the two vectors
double dp = dotp(newv1x, newv1y, newv2x, newv2y);
//angle between two vectors
double vang = acos(dp / (magv1*magv2));
angle += vang;
if (angle == 360.0) return true;
return false;
}
void display(){
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1, 1, 0);
glBegin(closed ? GL_LINE_LOOP : GL_LINE_STRIP);
for(int i = 0; i < m; i++){
glVertex2iv(vert[i]);
}
glEnd();
/*
glColor3f(0, 0, 1);
glBegin(GL_POINTS);
for (int i = m; i < n; i++) {
glVertex2iv(vert[i]);
}
*/
isitin = inpoly(m, vert, vert, testx, testy);
if (isitin == true) {
glColor3f(0, 1, 0);
glBegin(GL_POINTS);
for (int i = m; i < n; i++) {
glVertex2iv(vert[i]);
}
}
else {
glColor3f(1, 0, 0);
glBegin(GL_POINTS);
for (int i = m; i < n; i++) {
glVertex2iv(vert[i]);
}
}
glEnd();
glutSwapBuffers();
glutPostRedisplay();
}
void keyboard(unsigned char key, int x, int y){
switch(key){
case 'r': n = 0; m = 0; closed = false; break;
case 'c': closed = true; break;
}
glutPostRedisplay();
}
int findVertex(int x, int y){
int dx, dy;
for(int i = 0; i < n; i++){
dx = vert[i][0] - x;
dy = vert[i][1] - y;
if(dx*dx + dy*dy < 16) return i;
}
return - 1;
}
void mousemove(int x, int y)
{
testx = x;
testy = height - 1 - y;
}
void mouse(int button, int state, int x, int y){
switch(button){
case GLUT_LEFT_BUTTON:
if(state == GLUT_DOWN){
if (n < 100) {
v = n++;
vert[v][0] = x;
vert[v][1] = height - 1 - y;
// n++;
rubberbanding = true;
glutPostRedisplay();
if (!closed) m = n;
}
}
else{
rubberbanding = false;
}
break;
}
}
void motion(int x, int y){
if(rubberbanding){
vert[v][0] = x;
vert[v][1] = height - 1 - y;
glutPostRedisplay();
}
}
void main(int argc, char** argv){
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE);
glutInitWindowSize(width,height);
glutInitWindowPosition(50,100);
glutCreateWindow("Project 3");
glClearColor(0.0,0.0,0.0,0.0);
glColor3f( 1, 1, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, width, 0, height);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutMouseFunc(mouse);
glutPassiveMotionFunc(mousemove);
glutMotionFunc(motion);
glutMainLoop();
}
When I run the program in Visual Studio, I can draw the polygon, and I can specify
points, but for some reason all the points appear red. If anyone has any ideas on how to fix this, it would be greatly appreciated.
Probably your error is that acos returns in radians, and you're testing if the sum equals 360 degrees.
Also, you shouldn't compare doubles that way, since that calculation is probably adding rounding error in each sum. See here for more information.
I am working on animating a fractal (Triangle fractal) frame-by-frame. I know I need to use a call-back method to do this, but I am not sure how to implement it. I wish to get it working via a left-mouse click so I have this code:
void mouse(int button, int state, int x, int y){
if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN){
glClear(GL_COLOR_BUFFER_BIT);
divide_triangle(v[0], v[1], v[2], n);
}
//Closes the window on right button
if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN){
exit(0);
}
}
This is my mouse click call back, but this doesn't re-animate the triangle each time the triangle is drawn. How can show the process of the drawing each time I recurse through the triangle drawing?
void divide_triangle(point2 a, point2 b, point2 c, int m)
{
/* triangle subdivision using vertex coordinates */
point2 v0, v1, v2;
int j;
if(m>0){
for(j=0; j<2; j++) v0[j]=(a[j]+b[j])/2;
for(j=0; j<2; j++) v1[j]=(a[j]+c[j])/2;
for(j=0; j<2; j++) v2[j]=(b[j]+c[j])/2;
divide_triangle(a, v0, v1, m-1);
divide_triangle(c, v1, v2, m-1);
divide_triangle(b, v2, v0, m-1);
}
else(triangle(a,b,c));
glutPostRedisplay();
/* draw triangle at end of recursion */
}
I want to redisplay once I draw the new triangle here, and make it appear to be an animation, so I guess I would need a delay between the redisplays. How can I set that up? But I also want to make it where I can draw this without animating everytime, I.e. I click a specific mouse key: say 'F1' or some unreserved key and it would just display the final recursive triangle.
Here is my full code for your viewing:
#ifdef __APPLE__ //For use with OS X
#include <GLUT/glut.h>
#else //Linux
#include <GL/glut.h>
#endif
#include <stdlib.h>
#include <GL/glut.h>
typedef GLfloat point2[2];
/* initial triangle – global variables */
point2 v[]={{-2.0, -1.5}, {2.0, -1.5},
{0.0, 1.5}};
int n; /* number of recursive steps */
int windowX, windowY; //Window size parameters.
float red = .25;
float green = .25;
float blue = .70;
bool color_state = true;
void mouse(int button, int state, int x, int y);
void triangle( point2 a, point2 b, point2 c);
void divide_triangle(point2 a, point2 b, point2 c, int m);
void swap_colors();
void display(void){
glClear(GL_COLOR_BUFFER_BIT);
divide_triangle(v[0], v[1], v[2], n);
glFlush();
}
void init(){
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-2.0, 2.0, -2.0, 2.0);
glMatrixMode(GL_MODELVIEW);
glClearColor (0.10, 0.10, 0.10 ,1.0);
glColor3f(red, green, blue);
}
int main(int argc, char **argv){
if(argc <= 1){
windowX = 500;
windowY = 500;
n = 4;
}
else if(argc > 1){
windowX = atoi(argv[1]); //atoi converts char to int
windowY = atoi(argv[2]);
n = atoi(argv[3]);
}
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(windowX, windowY);
glutCreateWindow("N-Force");
glutDisplayFunc(display);
glutTimerFunc(30, recurse, -1)
glutMouseFunc(mouse);
init();
glutMainLoop();
}
void mouse(int button, int state, int x, int y){
if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN){ //Swap colors
glClear(GL_COLOR_BUFFER_BIT);
divide_triangle(v[0], v[1], v[2], n);
}
//Closes the window on right button
if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN){
exit(0);
}
}
void divide_triangle(point2 a, point2 b, point2 c, int m)
{
/* triangle subdivision using vertex coordinates */
point2 v0, v1, v2;
int j;
if(m>0){
for(j=0; j<2; j++) v0[j]=(a[j]+b[j])/2;
for(j=0; j<2; j++) v1[j]=(a[j]+c[j])/2;
for(j=0; j<2; j++) v2[j]=(b[j]+c[j])/2;
divide_triangle(a, v0, v1, m-1);
divide_triangle(c, v1, v2, m-1);
divide_triangle(b, v2, v0, m-1);
}
else(triangle(a,b,c));
glutPostRedisplay();
/* draw triangle at end of recursion */
}
void triangle( point2 a, point2 b, point2 c){
glBegin(GL_TRIANGLES);
glVertex2fv(a);
glVertex2fv(b);
glVertex2fv(c);
glEnd();
}
void swap_colors(){ //maybe add parameters x and y to change colors based on coordinates
if(color_state == true){
red = blue = green = .1;
color_state = false;
}
else{
red = 0.25;
green = .25;
blue = 0.70;
color_state = true;
}
}
/* TO DO:
1. add cmd line args, (width, depth, and recursive depth) (CHECK)
2. add color swap
3. add exit callback (check> right mouse)
4. Idle callback for animation
*/
Use a glutTimerFunc() callback with a Boolean flag to increment the recursion depth value and post redisplays:
bool animating = false;
unsigned int n = 4;
void timer( int value )
{
if( !animating )
return;
n++;
if( n > 6 )
n = 0;
glutTimerFunc( 200, timer, 0 );
glutPostRedisplay();
}
void mouse(int button, int state, int x, int y)
{
if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
{
animating = !animating;
glutTimerFunc( 0, timer, 0 );
}
}
All together:
#include <GL/glut.h>
bool animating = false;
unsigned int n = 4;
void timer( int value )
{
if( !animating )
return;
n++;
if( n > 6 )
n = 0;
glutTimerFunc( 200, timer, 0 );
glutPostRedisplay();
}
void mouse(int button, int state, int x, int y)
{
if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
{
animating = !animating;
glutTimerFunc( 0, timer, 0 );
}
}
typedef GLfloat point2[2];
void divide_triangle(point2 a, point2 b, point2 c, int m)
{
/* triangle subdivision using vertex coordinates */
if(m>0)
{
point2 v0, v1, v2;
for( int j=0; j<2; j++) v0[j]=(a[j]+b[j])/2;
for( int j=0; j<2; j++) v1[j]=(a[j]+c[j])/2;
for( int j=0; j<2; j++) v2[j]=(b[j]+c[j])/2;
divide_triangle(a, v0, v1, m-1);
divide_triangle(c, v1, v2, m-1);
divide_triangle(b, v2, v0, m-1);
}
else
{
glVertex2fv(a);
glVertex2fv(b);
glVertex2fv(c);
}
}
void display(void)
{
glClearColor (0.10, 0.10, 0.10 ,1.0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-2.0, 2.0, -2.0, 2.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
float red = .25;
float green = .25;
float blue = .70;
glColor3f(red, green, blue);
/* initial triangle – global variables */
point2 v[]={{-2.0, -1.5}, {2.0, -1.5}, {0.0, 1.5}};
glBegin(GL_TRIANGLES);
divide_triangle(v[0], v[1], v[2], n);
glEnd();
glFlush();
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(500, 500);
glutCreateWindow("N-Force");
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMainLoop();
}
I guess you want to have an idle() callback function, doing PostRedisplay only if your anim flag is on. (idle is called repetitively by glut).
In OpenGL, when I want to draw a filled circle, I'd do:
void DrawPoint(float X, float Y, float Z, float Radius) const
{
glRasterPos2f(X, Y);
glPointSize(Radius);
glBegin(GL_POINTS);
glVertex3f(X, Y, Z);
glEnd();
glPointSize(this->PointSize);
glFlush();
}
However, I could not find any equivalent for glPointSize in Direct-X. So I tried:
struct Vector3
{
double X, Y, Z;
};
#include <vector>
void DrawCircle1(float X, float Y, DWORD Color)
{
const int sides = 20;
std::vector<D3DXVECTOR3> points;
for(int i = 0; i < sides; ++i)
{
double angle = D3DX_PI * 2 / sides * i;
points.emplace_back(D3DXVECTOR3(sin(angle), cos(angle), 0));
}
device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, sides, &points[0], sizeof(D3DXVECTOR3));
}
void DrawCircle2(float CenterX, float CenterY, float Radius, int Rotations)
{
std::vector<D3DXVECTOR3> Points;
float Theta = 2 * 3.1415926535897932384626433832795 / float(Rotations);
float Cos = cosf(Theta);
float Sine = sinf(Theta);
float X = Radius, Y = 0, Temp = 0;
for(int I = 0; I < Rotations; ++I)
{
Points.push_back(D3DXVECTOR3(X + CenterX, Y + CenterY, 0));
Temp = X;
X = Cos * X - Sine * Y;
Y = Sine * Temp + Cos * Y;
}
device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, Points.size(), &Points[0], sizeof(D3DXVECTOR3));
}
But none of these work. I cannot figure out why nothing works. The first one draws a gigantic circle that is black and the second one draws a long triangle.
Any ideas how I can draw a filled in circle or a point of a certain size and colour in Direct-X?
static const int CIRCLE_RESOLUTION = 64;
struct VERTEX_2D_DIF { // transformed colorized
float x, y, z, rhw;
D3DCOLOR color;
static const DWORD FVF = D3DFVF_XYZRHW|D3DFVF_DIFFUSE;
};
void DrawCircleFilled(float mx, float my, float r, D3DCOLOR color)
{
VERTEX_2D_DIF verts[CIRCLE_RESOLUTION+1];
for (int i = 0; i < CIRCLE_RESOLUTION+1; i++)
{
verts[i].x = mx + r*cos(D3DX_PI*(i/(CIRCLE_RESOLUTION/2.0f)));
verts[i].y = my + r*sin(D3DX_PI*(i/(CIRCLE_RESOLUTION/2.0f)));
verts[i].z = 0;
verts[i].rhw = 1;
verts[i].color = color;
}
m_pDevice->SetFVF(VERTEX_2D_DIF::FVF);
m_pDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, CIRCLE_RESOLUTION-1, &verts, sizeof(VERTEX_2D_DIF));
}
I try in 3D but i am a beginner, so i try do with 2D first and value of z = 0. I have an array of points with values random in array points[] using std::vector. I have functions Distance(...) and CaculateF(...) to caculate new value for points[] and store in array pnew[]. I need draw points[] and move them to the value of pnew[], but i only know drawing random points in array points[] first, i can't move them exactly to values in pnew[]. Can anybody help me?!
#include<stdlib.h>
#include<glut.h>
#include<iostream>
#include<conio.h>
#include<math.h>
#include<omp.h>
#include<time.h>
#include<Windows.h>
#include<vector>
using namespace std;
struct Point
{
float x, y , z;
float vx, vy, vz;
unsigned long m;
unsigned char r, g, b, a;
};
vector< Point > points, pnew;
void animation_points( int value )
{
// move all points left each frame
for( size_t i = 0; i < points.size(); ++i )
{
points[i].x -= 1;
// wrap point around if it's moved off
// the edge of our 100x100 area
if( points[i].x < -50 )
{
points[i].x = 100 + points[i].x;
}
}
glutPostRedisplay();
glutTimerFunc(30, animation_points, 1);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-50, 50, -50, 50, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// draw
glColor3ub( 255, 255, 255 );
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );
glVertexPointer( 2, GL_FLOAT, sizeof(Point), &points[0].x );
glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof(Point), &points[0].r );
glPointSize( 3.0 );
glDrawArrays( GL_POINTS, 0, points.size() );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
glFlush();
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
}
//Distance between i and j
float Distance(float x1,float y1, float z1, float x2, float y2, float z2)
{
return (sqrt(pow(x1-x2,2) + pow(y1-y2,2) + pow(z1-z2,2)));
}
//Value of F on Ox, Oy, Oz
Point CalculateF(double d, Point a, Point b, int dt)
{
Point F;
float vnewx, vnewy, vnewz, xnew , ynew, znew;
float G = 6.6742*pow(10,-11);
float Fx = (G*a.m*b.m/pow(d,2)*(a.x-b.x)/d);
float Fy = (G*a.m*b.m/pow(d,2)*(a.y-b.y)/d);
float Fz = (G*a.m*b.m/pow(d,2)*(a.z-b.z)/d);
vnewx = a.vx + Fx*dt/a.m;
vnewy = a.vy + Fy*dt/a.m;
vnewz = a.vz + Fz*dt/a.m;
xnew = a.x + a.x*dt;
ynew = a.y + a.y*dt;
znew = a.z + a.z*dt;
F.x = xnew;
F.y = ynew;
F.z = znew;
F.vx = vnewx;
F.vy = vnewy;
F.vz = vnewz;
F.m = a.m;
return F;
}
int main(int argc, char **argv)
{
// begin
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
glutInitWindowSize(640,480);
glutCreateWindow("N - body");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
// animation points
//glutTimerFunc(30, animation_points, 1);
////
int n, t;
cout<<"\n Number of body: ";
cin>>n;
// move after time t
cout<<"\n\n Time: ";
cin>>t;
t *= 3600;
// random points
for( int i = 0; i < n; ++i )
{
Point pt;
pt.x = -50 + (rand() % 100);
pt.y = -50 + (rand() % 100);
pt.z = 0;
pt.r = rand() % 255;
pt.g = rand() % 255;
pt.b = rand() % 255;
pt.a = 255;
points.push_back(pt);
}
glutMainLoop();
float d;
//#pragma omp parallel default(shared) private(i,j)
for (int i = 0 ; i < n ; i++)
{
//#pragma omp for schedule(static)
for (int j = 0 ; j < n ; j++)
{
d = Distance(points[i].x, points[i].y,points[i].z, points[j].x, points[j].y, points[j].z);
if (d!=0)
points[i] = CalculateF(d,points[i], points[j], t);
}
pnew.push_back(points[i]);
}
return 0;
}
You need to store the initial and the target positions of your points in arrays, then interpolate between them in the rendering code. To do that, you determine how much time has passed, compute a double lambda in the range 0.0 to 1.0 from the time, then draw the points at the position p_start + lambda * (p_target - p_start).