#define _USE_MATH_DEFINES #include <math.h> #include <windows.h> #include <GL/glut.h> #include <stdio.h> #include "gvector.h" #include "gparticle.h" #include "gworld.h" extern int coloroffset; GParticle::GParticle( double x, double y ) : pos( GVector( x, y ) ), F( GVector( 0.0, 0.0 ) ), a( GVector( 0.0, 0.0 ) ), v( GVector( 0.0, 0.0 ) ), m( 1.0 ), r( 0.1 ), Q( 1.0 ), springs( 0 ), next( 0 ), name( 0 ), inworld( false ), init( true ) { } GParticle::~GParticle(void) { } void GParticle::AddSpring( GParticle* p ) { GSpring* s = new GSpring(); s->K = SPRING_K; s->part = p; s->next = springs; springs = s; } bool GParticle::HasSpring( GParticle* p ) { for ( GSpring* s = springs ; s ; s = s->next ) { if ( s->part == p ) return true; } return false; } void GParticle::HideSprings( GWorld* w ) { for ( GSpring* s = springs ; s ; s = s->next ) { s->part->HideSprings( w ); w->Remove( s->part ); } init = true; } void GParticle::Init( GWorld* w ) { for ( GSpring* s = springs ; s ; s = s->next ) { if ( !s->part->inworld ) { s->part->pos = NearBy(); w->Add( s->part ); } } init = false; return; init = false; int n = initn; if ( !n ) return; GParticle* p; double dx, dy, dt; double l = rand() % n + 1; for ( int i = 0 ; i < l ; i++ ) { dt = ( rand() % 628 ) / 100.0; dx = r * 2 * cos( dt + i * 2.0 * M_PI / l ) ; dy = r * 2 * sin( dt + i * 2.0 * M_PI / l ) ; p = new GParticle( pos.x + dx, pos.y + dy ); if ( n > 1 ) p->name = "some"; else p->name = "none"; w->Add( p ); AddSpring( p ); p->initn = n - 1; p->Q = Q * 0.9; } } GVector GParticle::NearBy() { double dx, dy; int i = rand() % 2048; dx = r * 2 * cos( i * 2.0 * M_PI / 2048 ) ; dy = r * 2 * sin( i * 2.0 * M_PI / 2048 ) ; return pos + GVector( dx, dy ); } void GParticle::ComputeForce( GWorld* w ) { if ( !inworld ) return; GParticle* p; GSpring* s; GVector dv( 0.0, 0.0 ); GVector fv( 0.0, 0.0 ); double dd; // Electrostatic forces for ( p = w->parts ; p ; p = p->next ) { if ( !p->inworld ) continue; if ( p->pos.x == pos.x && p->pos.y == pos.y ) continue; dv = pos - p->pos ; //vector pointing from p to this dd = ~dv + p->r + r + 0.001 ; //add radii, so dd is never zero dv = dv / ~dv ; //normalize dv into a unit vector //Coulomb's Law: fv = dv * ( CONST_k * Q * p->Q / ( dd * dd ) ); F = F + fv; } // Spring forces for ( s = springs ; s ; s = s->next ) { p = s->part; if ( !p->inworld ) continue; dv = pos - p->pos ; //vector pointing from p to this if ( ~dv < p->r + r * 2 ) continue; //ignore close springs dd = ~dv + p->r + r ; //add radii, so dd is dist between surfaces dv = dv / ~dv; dv = dv * dd; // Hooke's Law: fv = dv * ( -1 * s->K ); F = F + fv; p->F = p->F - fv; } //Gravitational force toward the center //fv = ( pos / dd ) * ( -1 * CONST_G * w->mass * m / ( dd * dd ) ); //Instead of using real gravity, we'll use a version that's //actually useful, which is more like a spring connecting everything //in the world to the center. dd = ~pos + r * 10.0; fv = ( pos / dd ) * ( -1 * CONST_G * w->mass * m * dd ); if ( w->heavyg ) fv = fv * 1000.0; F = F + fv; } extern GParticle* p; void GParticle::Step( GWorld* w ) { init = false; for ( GSpring* s = springs ; s ; s = s->next ) { if ( !s->part->inworld ) init = true; } if ( p == this ) return; double fric = ( init && initn ) ? CONST_f : CONST_f * 5.0; if ( w->greased ) fric = CONST_f; if ( w->nofric ) fric = 0.0; v = v * ( 1.0 - fric ); if ( ~v < STATIC_v ) { v = GVector( 0, 0 ); if ( ~F < STATIC_f ) F = GVector( 0, 0 ); else F = F - ( F / ~F ) * STATIC_f ; } a = F / m; v = v + a; pos = pos + v; } void GParticle::Render() { if ( !inworld ) return; //Inefficient circle drawing. Fix this later. GLint i; GLfloat cosine, sine; if ( init && springs ) SetColor( Pink ); else SetColor( Blue ); glBegin(GL_POLYGON); for(i=0;i<100;i++) { cosine = float( pos.x + r * cos(i*2*M_PI/100.0) ); sine = float( pos.y + r * sin(i*2*M_PI/100.0) ); glVertex2f( cosine, sine ); } glEnd(); //Draw springs. GSpring* s; GParticle* p; GVector sv( 0.0, 0.0 ); GVector ev( 0.0, 0.0 ); GVector dv( 0.0, 0.0 ); for ( s = springs ; s ; s = s->next ) { p = s->part; if ( !p->inworld ) continue; dv = p->pos - this->pos; sv = pos + ( dv / ~dv ) * r; ev = p->pos - ( dv / ~dv ) * p->r; glLineWidth( 2.0 ); glBegin( GL_LINE_STRIP ); SetColor( Green ); glVertex2f( sv.x, sv.y ); SetColor( Green, true ); glVertex2f( ev.x, ev.y ); glEnd(); } //Draw node name. SetColor( Yellow ); glBegin( GL_LINE_STRIP ); glVertex2f( 0, 0 ); glVertex2f( 0, 0 ); glEnd(); glRasterPos2f( pos.x, pos.y ); for ( char* c = name ; c && *c ; c++ ) glutBitmapCharacter( GLUT_BITMAP_8_BY_13, *c ); } void GParticle::SetColor( Color c, bool dark ) { if ( coloroffset >= Rotate ) coloroffset = 0; c = (Color)((int)c + coloroffset); if ( c >= Rotate ) c = (Color)((int)c - (int)Rotate); float r, g, b; switch( c ) { default: case Blue: r = 0.4; g = 0.4; b = 1.0; break; case Cyan: r = 0.2; g = 1.0; b = 1.0; break; case Green: r = 0.2; g = 1.0; b = 0.2; break; case Lavender: r = 1.0; g = 0.4; b = 1.0; break; case Orange: r = 1.0; g = 0.6; b = 0.2; break; case Pink: r = 1.0; g = 0.4; b = 0.4; break; case Yellow: r = 1.0; g = 1.0; b = 0.0; break; } if ( dark ) { if ( r < 0.5 ) r = 0; else r /= 5.0; if ( g < 0.5 ) g = 0; else g /= 5.0; if ( b < 0.5 ) b = 0; else b /= 5.0; } glColor3f( r, g, b ); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 4785 | Sam Stafford |
Add new command to cycle the palette. I do not recommend that you actually use this command if you value your retinas. User-visible change. |
||
#1 | 4763 | Sam Stafford |
Rename //guest/sam_stafford/jamgraph/... to //guest/sam_stafford/jamgraph/main/... to support mainline model in sample depot. |
||
//guest/sam_stafford/jamgraph/gparticle.cpp | |||||
#3 | 3051 | Sam Stafford |
A few bug fixes and a few new options. Run "jamgraph -h" for info. |
||
#2 | 3033 | Sam Stafford |
Jamgraph functional. Usage: jam -ndd | jamgraph Still twiddling with the interface, so it's undocumented. |
||
#1 | 3023 | Sam Stafford |
A toy. Soon to be (hopefully) a toy powered by Jam. |