[PD-cvs] externals/boids/boids2d boids2d.c,1.2,1.3

/*j j45ch at users.sourceforge.net
Mon Apr 2 18:00:10 CEST 2007


Update of /cvsroot/pure-data/externals/boids/boids2d
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20209

Modified Files:
	boids2d.c 
Log Message:
 	boids2d-help.pd boids2d.c makefile


Index: boids2d.c
===================================================================
RCS file: /cvsroot/pure-data/externals/boids/boids2d/boids2d.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** boids2d.c	31 Mar 2007 17:18:34 -0000	1.2
--- boids2d.c	2 Apr 2007 16:00:08 -0000	1.3
***************
*** 1 ****
! /*

	boids2d 08/2005 a.sier / jasch adapted from boids by eric singer © 1995-2003 eric l. singer
	free for non-commercial use
*/

#include 	"m_pd.h"
#include	<stdlib.h>
#include	<math.h>

// constants
#define			kAssistInlet	1
#define			kAssistOutlet	2
#define			kMaxLong		0xFFFFFFFF
#define			kMaxNeighbors	4

// util
#define MAX(a,b) ((a)>(b)?(a):(b))
#define CLIP(x,a,b) (x)=(x)<(a)?(a):(x)>(b)?(b):(x)

// initial flight parameters
const short			kNumBoids		= 12;	// number of boids
const short			kNumNeighbors	= 2;	// must be <= kMaxNeighbors
const double 		kMinSpeed		= 0.15;	// boids' minimum speed
const double		kMaxSpeed		= 0.25;	// boids' maximum speed
const double		kCenterWeight	= 0.25;	// flock centering
const double		kAttractWeight	= 0.300;// attraction point seeking
const double		kMatchWeight	= 0.100;// neighbors velocity matching
const double		kAvoidWeight	= 0.10;	// neighbors avoidance
const double		kWallsWeight	= 0.500;// wall avoidance [210]
const double		kEdgeDist		= 0.5;	// vision distance to avoid wall edges [5]
const double		kSpeedupFactor	= 0.100;// alter animation speed
const double		kInertiaFactor	= 0.20;	// willingness to change speed & direction
const double		kAccelFactor	= 0.100;// neighbor avoidance accelerate or decelerate rate
const double		kPrefDist		= 0.25;	// preferred distance from neighbors
const double		kFlyRectTop		= 1.0;	// fly rect boundaries
const double		kFlyRectLeft	= -1.0;	
const double		kFlyRectBottom	= -1.0;	
const double		kFlyRectRight	= 1.0;	
// const double		kFlyRectFront	= 1.0;	
// const double		kFlyRectBack	= -1.0;	


// typedefs
typedef struct Velocity {
	double		x;
	double		y;
//	double		z;
} Velocity;

typedef struct Point2d {
	double		x;
	double		y;
//	double		z;
} Point2d;

typedef struct Box3D {
	double		left, right;
	double		top, bottom;
//	double		front, back;
} Box3D;

typedef struct _Boid {
	Point2d		oldPos;
	Point2d		newPos;
	Velocity	oldDir;
	Velocity	newDir;
	double		speed;
	short		neighbor[kMaxNeighbors];
	double		neighborDistSqr[kMaxNeighbors];
} t_one_boid, *BoidPtr;

typedef struct _FlockObject {
	t_object	ob;
	void		*out1, *out2;
	short		mode;
	long		numBoids;
	long		numNeighbors;
	Box3D		flyRect;
	double 		minSpeed;
	double		maxSpeed;
	double		centerWeight;
	double		attractWeight;
	double		matchWeight;
	double		avoidWeight;
	double		wallsWeight;
	double		edgeDist;
	double		speedupFactor;
	double		inertiaFactor;
	double		accelFactor;
	double		prefDist;
	double		prefDistSqr;
	Point2d		centerPt;
	Point2d		attractPt;
	BoidPtr		boid;
	double 		d2r, r2d;
} t_boids, *FlockPtr;

// variables
// void 		*flock;
t_symbol 	*ps_nothing;

// prototypes
void *boids2d_class;
void *Flock_new(t_symbol *s, long argc, t_atom *argv);
void Flock_free(t_boids *x);
void Flock_bang(t_boids *x);
void Flock_dump(t_boids *x);
void Flock_mode(t_boids *x, t_float arg);
void Flock_numNeighbors(t_boids *x, t_float arg);
void Flock_numBoids(t_boids *x, t_float arg);
void Flock_minSpeed(t_boids *x, t_float arg);
void Flock_maxSpeed(t_boids *x, t_float arg);
void Flock_centerWeight(t_boids *x, t_float arg);
void Flock_attractWeight(t_boids *x, t_float arg);
void Flock_matchWeight(t_boids *x, t_float arg);
void Flock_avoidWeight(t_boids *x, t_float arg);
void Flock_wallsWeight(t_boids *x, t_float arg);
void Flock_edgeDist(t_boids *x, t_float arg);
void Flock_speedupFactor(t_boids *x, t_float arg);
void Flock_inertiaFactor(t_boids *x, t_float arg);
void Flock_accelFactor(t_boids *x, t_float arg);
void Flock_prefDist(t_boids *x, t_float arg);
void Flock_flyRect(t_boids *x, t_symbol *msg, short argc, t_atom *argv);
void Flock_attractPt(t_boids *x, t_symbol *msg, short argc, t_atom *argv);
void Flock_reset(t_boids *x);
void Flock_resetBoids(t_boids *x);
void InitFlock(t_boids *x);
void FlightStep(t_boids *x);
Point2d FindFlockCenter(t_boids *x);
float MatchAndAvoidNeighbors(t_boids *x, short theBoid, Velocity *matchNeighborVel, Velocity *avoidNeighborVel);
Velocity SeekPoint(t_boids *x, short theBoid, Point2d seekPt);
Velocity AvoidWalls(t_boids *x, short theBoid);
int InFront(BoidPtr theBoid, BoidPtr neighbor);
void NormalizeVelocity(Velocity *direction);
double RandomInt(double minRange, double maxRange);
double DistSqrToPt(Point2d firstPoint, Point2d secondPoint);

void boids2d_setup(void)
{
	boids2d_class = class_new(gensym("boids2d"), (t_newmethod)Flock_new, 
			(t_method)Flock_free, sizeof(t_boids), 0, A_GIMME, 0);
	/*	setup((t_messlist **) &flock, (method)Flock_new, (method)Flock_free, (short) sizeof(FlockObject), 0L, A_LONG, A_DEFLONG, 0); */
	class_addfloat(boids2d_class,  (t_method) Flock_numBoids);
	class_addbang(boids2d_class,   (t_method) Flock_bang);
	class_addmethod(boids2d_class, (t_method) Flock_numNeighbors,		gensym("neighbors"), 	A_FLOAT, 0);
	class_addmethod(boids2d_class, (t_method) Flock_numBoids,			gensym("number"), 		A_FLOAT, 0);
	class_addmethod(boids2d_class, (t_method) Flock_mode,				gensym("mode"), 		A_FLOAT, 0);
	class_addmethod(boids2d_class, (t_method) Flock_minSpeed,			gensym("minspeed"), 	A_FLOAT, 0);
	class_addmethod(boids2d_class, (t_method) Flock_maxSpeed,			gensym("maxspeed"), 	A_FLOAT, 0);
	class_addmethod(boids2d_class, (t_method) Flock_centerWeight,		gensym("center"), 		A_FLOAT, 0);
	class_addmethod(boids2d_class, (t_method) Flock_attractWeight,		gensym("attract"), 		A_FLOAT, 0);
	class_addmethod(boids2d_class, (t_method) Flock_matchWeight,		gensym("match"), 		A_FLOAT, 0);
	class_addmethod(boids2d_class, (t_method) Flock_avoidWeight,		gensym("avoid"), 		A_FLOAT, 0);
	class_addmethod(boids2d_class, (t_method) Flock_wallsWeight,		gensym("repel"), 		A_FLOAT, 0);
	class_addmethod(boids2d_class, (t_method) Flock_edgeDist,			gensym("edgedist"), 	A_FLOAT, 0);
	class_addmethod(boids2d_class, (t_method) Flock_speedupFactor,		gensym("speed"), 		A_FLOAT, 0);
	class_addmethod(boids2d_class, (t_method) Flock_inertiaFactor,		gensym("inertia"),	 	A_FLOAT, 0);
	class_addmethod(boids2d_class, (t_method) Flock_accelFactor,		gensym("accel"), 		A_FLOAT, 0);
	class_addmethod(boids2d_class, (t_method) Flock_prefDist,			gensym("prefdist"), 	A_FLOAT, 0);
	class_addmethod(boids2d_class, (t_method) Flock_flyRect,			gensym("flyrect"), 		A_GIMME, 0);
	class_addmethod(boids2d_class, (t_method) Flock_attractPt, 			gensym("attractpt"), 	A_GIMME, 0);
	class_addmethod(boids2d_class, (t_method) Flock_resetBoids, 		gensym("reset"), 		0);
	class_addmethod(boids2d_class, (t_method) Flock_reset, 				gensym("init"), 		0);
	class_addmethod(boids2d_class, (t_method) Flock_dump, 				gensym("dump"), 		0);
	
	post("boids2d 2005-2006 a.sier / jasch   © 1995-2003 eric l. singer   "__DATE__" "__TIME__);	
	ps_nothing = gensym("");
}


void *Flock_new(t_symbol *s, long argc, t_atom *argv)
{	
	t_boids *x = (t_boids *)pd_new(boids2d_class);
	x->out1 = outlet_new(&x->ob, NULL);
	x->out2 = outlet_new(&x->ob, NULL);
	
	x->numBoids = 16;
	if((argc >= 1) && (argv[0].a_type == A_FLOAT)){
		x->numBoids = argv[0].a_w.w_float;
	}
	x->boid = (t_one_boid *)malloc(sizeof(t_one_boid) * x->numBoids);
	
	InitFlock(x);
	
	x->mode = 0;
	if((argc >= 2) && (argv[1].a_type == A_FLOAT)){
		x->mode = (short)(CLIP(argv[1].a_w.w_float, 0, 2));
	}
	
	x->d2r = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068/180.0;
	x->r2d = 180.0/3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068;
	
	return(x);
}


void Flock_free(t_boids *x)
{
	free(x->boid);
}

void Flock_bang(t_boids *x)
{
	short	i;
	t_atom 	outlist[10];
	t_atom 	*out;
	
	double 	tempNew_x, tempNew_y; 
	double 	tempOld_x, tempOld_y;
	double	delta_x, delta_y; 
	double 	azi, speed;
	// double tempspeed;
	
	out = outlist;
		
	FlightStep(x);


	switch(x->mode) { // newpos
		case 0:
		for (i = 0; i < x->numBoids; i++){
			SETFLOAT(out+0, i);
			SETFLOAT(out+1, x->boid[i].newPos.x);
			SETFLOAT(out+2, x->boid[i].newPos.y);
		//	SETFLOAT(out+3, x->boid[i].newPos.z);
			outlet_list(x->out1, 0L, 3, out);
		}
		break;
		case 1: //newpos + oldpos
		for (i = 0; i < x->numBoids; i++){
			SETFLOAT(out+0, i);
			SETFLOAT(out+1, x->boid[i].newPos.x);
			SETFLOAT(out+2, x->boid[i].newPos.y);
			// SETFLOAT(out+3, x->boid[i].newPos.z);
			SETFLOAT(out+3, x->boid[i].oldPos.x);
			SETFLOAT(out+4, x->boid[i].oldPos.y);
			// SETFLOAT(out+6, x->boid[i].oldPos.z);
			outlet_list(x->out1, 0L, 5, out);
		}
		break;
		case 2:
		for (i = 0; i < x->numBoids; i++){						
			tempNew_x = x->boid[i].newPos.x;
			tempNew_y = x->boid[i].newPos.y;
			// tempNew_z = x->boid[i].newPos.z;
			tempOld_x = x->boid[i].oldPos.x;
			tempOld_y = x->boid[i].oldPos.y;
			// tempOld_z = x->boid[i].oldPos.z;
			delta_x = tempNew_x - tempOld_x;
			delta_y = tempNew_y - tempOld_y;
			// delta_z = tempNew_z - tempOld_z;
			azi = atan2(delta_y, delta_x) * x->r2d;
			// ele = atan2(delta_y, delta_x) * x->r2d;
			speed = sqrt(delta_x * delta_x + delta_y * delta_y);//  + delta_z * delta_z);
			SETFLOAT(out+0, i);
			SETFLOAT(out+1, tempNew_x);
			SETFLOAT(out+2, tempNew_y);
			// SETFLOAT(out+3, tempNew_z);
			SETFLOAT(out+3, tempOld_x);
			SETFLOAT(out+4, tempOld_y);
			// SETFLOAT(out+6, tempOld_z);
			SETFLOAT(out+5, speed);
			SETFLOAT(out+6, azi);
			// SETFLOAT(out+9, ele);
			outlet_list(x->out1, 0L, 7, out);
		}
		break;	
	}
}

void Flock_dump(t_boids *x)
{
	t_atom	outList[6];
	
	outList[0].a_type = A_FLOAT;
	outList[0].a_w.w_float =  x->numNeighbors;
	outlet_anything(x->out2, gensym("neighbors"), 1, outList);

	outList[0].a_type = A_FLOAT;
	outList[0].a_w.w_float =  x->minSpeed;
	outlet_anything(x->out2, gensym("minspeed"), 1, outList);

	outList[0].a_type = A_FLOAT;
	outList[0].a_w.w_float =  x->maxSpeed;
	outlet_anything(x->out2, gensym("maxspeed"), 1, outList);

	outList[0].a_type = A_FLOAT;
	outList[0].a_w.w_float =  x->centerWeight;
	outlet_anything(x->out2, gensym("center"), 1, outList);

	outList[0].a_type = A_FLOAT;
	outList[0].a_w.w_float =  x->attractWeight;
	outlet_anything(x->out2, gensym("attract"), 1, outList);

	outList[0].a_type = A_FLOAT;
	outList[0].a_w.w_float =  x->matchWeight;
	outlet_anything(x->out2, gensym("match"), 1, outList);

	outList[0].a_type = A_FLOAT;
	outList[0].a_w.w_float =  x->avoidWeight;
	outlet_anything(x->out2, gensym("avoid"), 1, outList);

	outList[0].a_type = A_FLOAT;
	outList[0].a_w.w_float =  x->wallsWeight;
	outlet_anything(x->out2, gensym("repel"), 1, outList);

	outList[0].a_type = A_FLOAT;
	outList[0].a_w.w_float =  x->edgeDist;
	outlet_anything(x->out2, gensym("edgedist"), 1, outList);

	outList[0].a_type = A_FLOAT;
	outList[0].a_w.w_float =  x->speedupFactor;
	outlet_anything(x->out2, gensym("speed"), 1, outList);

	outList[0].a_type = A_FLOAT;
	outList[0].a_w.w_float =  x->inertiaFactor;
	outlet_anything(x->out2, gensym("inertia"), 1, outList);

	outList[0].a_type = A_FLOAT;
	outList[0].a_w.w_float =  x->accelFactor;
	outlet_anything(x->out2, gensym("accel"), 1, outList);

	outList[0].a_type = A_FLOAT;
	outList[0].a_w.w_float = x->prefDist;
	outlet_anything(x->out2, gensym("prefdist"), 1, outList);

	outList[0].a_type = A_FLOAT;
	outList[0].a_w.w_float =  x->flyRect.left;
	outList[1].a_type = A_FLOAT;
	outList[1].a_w.w_float =  x->flyRect.top;
	outList[2].a_type = A_FLOAT;
	outList[2].a_w.w_float =  x->flyRect.right;
	outList[3].a_type = A_FLOAT;
	outList[3].a_w.w_float =  x->flyRect.bottom;
	/*outList[4].a_type = A_FLOAT;
	outList[4].a_w.w_float =  x->flyRect.front;
	outList[5].a_type = A_FLOAT;
	outList[5].a_w.w_float =  x->flyRect.back;*/
	outlet_anything(x->out2, gensym("flyrect"), 4, outList);

	outList[0].a_type = A_FLOAT;
	outList[0].a_w.w_float =  x->attractPt.x;
	outList[1].a_type = A_FLOAT;
	outList[1].a_w.w_float =  x->attractPt.y;
	/*outList[2].a_type = A_FLOAT;
	outList[2].a_w.w_float =  x->attractPt.z;*/
	outlet_anything(x->out2, gensym("attractpt"), 2, outList);
	
	outList[0].a_type = A_FLOAT;
	outList[0].a_w.w_float =  x->mode;
	outlet_anything(x->out2, gensym("mode"), 1, outList);
	
	outList[0].a_type = A_FLOAT;
	outList[0].a_w.w_float =  x->numBoids;
	outlet_anything(x->out2, gensym("number"), 1, outList);
}


void Flock_mode(t_boids *x, t_float arg)
{
	long m = (long)arg;
	x->mode = CLIP(m, 0, 2);
}

void Flock_numNeighbors(t_boids *x, t_float arg)
{
	x->numNeighbors = (long)arg;
}

void Flock_numBoids(t_boids *x, t_float arg)
{
	x->boid = (t_one_boid *)realloc(x->boid, sizeof(t_one_boid) * (long)arg);
	x->numBoids = (long)arg;
	Flock_resetBoids(x);
}

void Flock_minSpeed(t_boids *x, t_float arg)
{
	x->minSpeed = MAX(arg, 0.000001);
}

void Flock_maxSpeed(t_boids *x, t_float arg)
{
	x->maxSpeed = arg;
}

void Flock_centerWeight(t_boids *x, t_float arg)
{
	x->centerWeight = arg;
}

void Flock_attractWeight(t_boids *x, t_float arg)
{
	x->attractWeight = arg;
}

void Flock_matchWeight(t_boids *x, t_float arg)
{
	x->matchWeight = arg;
}

void Flock_avoidWeight(t_boids *x, t_float arg)
{
	x->avoidWeight = arg;
}

void Flock_wallsWeight(t_boids *x, t_float arg)
{
	x->wallsWeight = arg;
}

void Flock_edgeDist(t_boids *x, t_float arg)
{
	x->edgeDist = arg;
}

void Flock_speedupFactor(t_boids *x, t_float arg)
{
	x->speedupFactor = arg;
}

void Flock_inertiaFactor(t_boids *x, t_float arg)
{
	if(arg == 0){
		x->inertiaFactor = 0.000001;
	}else{
		x->inertiaFactor = arg;
	}
}

void Flock_accelFactor(t_boids *x, t_float arg)
{
	x->accelFactor = arg;
}

void Flock_prefDist(t_boids *x, t_float arg)
{
	x->prefDist = arg;
}

void Flock_flyRect(t_boids *x, t_symbol *msg, short argc, t_atom *argv)
{
	double temp[4];
	short i;
	if(argc == 4){
		for(i=0;i<4;i++) {
			if(argv[i].a_type == A_FLOAT) {
				temp[i] = (double)argv[i].a_w.w_float;	
			}
		}
		x->flyRect.left 		= temp[0];
		x->flyRect.top 		= temp[1];
		x->flyRect.right 	= temp[2];
		x->flyRect.bottom 	= temp[3];
		// x->flyRect.front 	= temp[4];
		// x->flyRect.back 		= temp[5];
	}else{
		error("boids2d: flyrect needs four values");
	}
}

void Flock_attractPt(t_boids *x, t_symbol *msg, short argc, t_atom *argv)
{
	double temp[2];
	short i;
	if(argc == 2){
	for(i=0;i<2;i++) {
		if(argv[i].a_type == A_FLOAT) {
			temp[i] = (double)argv[i].a_w.w_float;	
		}
	}
	x->attractPt.x = temp[0];
	x->attractPt.y = temp[1];
	// x->attractPt.z = temp[2];
	}else{
		error("boids2d: attractPt needs two values");
	}
}

void Flock_reset(t_boids *x)
{
	InitFlock(x);
}

void Flock_resetBoids(t_boids *x)
{
	long i, j;
	double rndAngle;
	
	for (i = 0; i <  x->numBoids; i++) { // init everything to 0.0
		x->boid[i].oldPos.x = 0.0;
		x->boid[i].oldPos.y = 0.0;
		// x->boid[i].oldPos.z = 0.0;

		x->boid[i].newPos.x = 0.0;
		x->boid[i].newPos.y = 0.0;
		// x->boid[i].newPos.z = 0.0;
		
		x->boid[i].oldDir.x = 0.0;
		x->boid[i].oldDir.y = 0.0;
		// x->boid[i].oldDir.z = 0.0;
		
		x->boid[i].newDir.x = 0.0;
		x->boid[i].newDir.y = 0.0;
		// x->boid[i].newDir.z = 0.0;
		
		x->boid[i].speed = 0.0;
		
		for(j=0; j<kMaxNeighbors;j++){
			x->boid[i].neighbor[j] = 0;
			x->boid[i].neighborDistSqr[j] = 0.0;
		}
	}
	for (i = 0; i <  x->numBoids; i++) {				// set the initial locations and velocities of the boids
		x->boid[i].newPos.x = x->boid[i].oldPos.x = RandomInt(x->flyRect.right,x->flyRect.left);		// set random location within flyRect
		x->boid[i].newPos.y = x->boid[i].oldPos.y = RandomInt(x->flyRect.bottom, x->flyRect.top);
		// x->boid[i].newPos.z = x->boid[i].oldPos.z = RandomInt(x->flyRect.back, x->flyRect.front);
		rndAngle = RandomInt(0, 360) * x->d2r;		// set velocity from random angle
		x->boid[i].newDir.x = sin(rndAngle);
		x->boid[i].newDir.y = cos(rndAngle);
		// x->boid[i].newDir.z = (cos(rndAngle) + sin(rndAngle)) * 0.5;
		x->boid[i].speed = (kMaxSpeed + kMinSpeed) * 0.5;
	}
}

void InitFlock(t_boids *x)
{
	x->numNeighbors		= kNumNeighbors;
	x->minSpeed			= kMinSpeed;
	x->maxSpeed			= kMaxSpeed;
	x->centerWeight		= kCenterWeight;
	x->attractWeight		= kAttractWeight;
	x->matchWeight		= kMatchWeight;
	x->avoidWeight		= kAvoidWeight;
	x->wallsWeight		= kWallsWeight;
	x->edgeDist			= kEdgeDist;
	x->speedupFactor		= kSpeedupFactor;
	x->inertiaFactor		= kInertiaFactor;
	x->accelFactor		= kAccelFactor;
	x->prefDist			= kPrefDist;
	x->prefDistSqr		= kPrefDist * kPrefDist;
	x->flyRect.top		= kFlyRectTop;
	x->flyRect.left		= kFlyRectLeft;
	x->flyRect.bottom	= kFlyRectBottom;
	x->flyRect.right		= kFlyRectRight;
	// x->flyRect.front		= kFlyRectFront;
	// x->flyRect.back		= kFlyRectBack;
	x->attractPt.x		= (kFlyRectLeft + kFlyRectRight) * 0.5;
	x->attractPt.y		= (kFlyRectTop + kFlyRectBottom) * 0.5;
	// x->attractPt.z		= (kFlyRectFront + kFlyRectBack) * 0.5;
	Flock_resetBoids(x);
}

void FlightStep(t_boids *x)
{
	Velocity		goCenterVel;
	Velocity		goAttractVel;
	Velocity		matchNeighborVel;
	Velocity		avoidWallsVel;
	Velocity		avoidNeighborVel;
	float			avoidNeighborSpeed;
	const Velocity	zeroVel	= {0.0, 0.0};//, 0.0};
	short			i;

	x->centerPt = FindFlockCenter(x);
	for (i = 0; i <  x->numBoids; i++) {						// save position and velocity
		x->boid[i].oldPos.x = x->boid[i].newPos.x;
		x->boid[i].oldPos.y = x->boid[i].newPos.y;
		// x->boid[i].oldPos.z = x->boid[i].newPos.z;
		
		x->boid[i].oldDir.x = x->boid[i].newDir.x;
		x->boid[i].oldDir.y = x->boid[i].newDir.y;
		// x->boid[i].oldDir.z = x->boid[i].newDir.z;
	}
	for (i = 0; i < x->numBoids; i++) {
		if (x->numNeighbors > 0) {							// get all velocity components
			avoidNeighborSpeed = MatchAndAvoidNeighbors(x, i,&matchNeighborVel, &avoidNeighborVel);
		} else {
			matchNeighborVel = zeroVel;
			avoidNeighborVel = zeroVel;
			avoidNeighborSpeed = 0;
		}
		goCenterVel = SeekPoint(x, i, x->centerPt);			
		goAttractVel = SeekPoint(x, i, x->attractPt);
		avoidWallsVel = AvoidWalls(x, i);
	
		// compute resultant velocity using weights and inertia
		x->boid[i].newDir.x = x->inertiaFactor * (x->boid[i].oldDir.x) +
							(x->centerWeight * goCenterVel.x +
							 x->attractWeight * goAttractVel.x +
							 x->matchWeight * matchNeighborVel.x +
							 x->avoidWeight * avoidNeighborVel.x +
							 x->wallsWeight * avoidWallsVel.x) / x->inertiaFactor;
		x->boid[i].newDir.y = x->inertiaFactor * (x->boid[i].oldDir.y) +
							(x->centerWeight * goCenterVel.y +
							 x->attractWeight * goAttractVel.y +
							 x->matchWeight * matchNeighborVel.y +
							 x->avoidWeight * avoidNeighborVel.y +
							 x->wallsWeight * avoidWallsVel.y) / x->inertiaFactor;
		/*x->boid[i].newDir.z = x->inertiaFactor * (x->boid[i].oldDir.z) +
							(x->centerWeight * goCenterVel.z +
							 x->attractWeight * goAttractVel.z +
							 x->matchWeight * matchNeighborVel.z +
							 x->avoidWeight * avoidNeighborVel.z +
							 x->wallsWeight * avoidWallsVel.z) / x->inertiaFactor;*/
		NormalizeVelocity(&(x->boid[i].newDir));	// normalize velocity so its length is unity

		// set to avoidNeighborSpeed bounded by minSpeed and maxSpeed
		if ((avoidNeighborSpeed >= x->minSpeed) &&
				(avoidNeighborSpeed <= x->maxSpeed))
			x->boid[i].speed = avoidNeighborSpeed;
		else if (avoidNeighborSpeed > x->maxSpeed)
			x->boid[i].speed = x->maxSpeed;
		else
			x->boid[i].speed = x->minSpeed;

		// calculate new position, applying speedupFactor
		x->boid[i].newPos.x += x->boid[i].newDir.x * x->boid[i].speed * (x->speedupFactor / 100.0);
		x->boid[i].newPos.y += x->boid[i].newDir.y * x->boid[i].speed * (x->speedupFactor / 100.0);
		// x->boid[i].newPos.z += x->boid[i].newDir.z * x->boid[i].speed * (x->speedupFactor / 100.0);

	}
}

Point2d FindFlockCenter(t_boids *x)
{
	double			totalH = 0, totalV = 0, totalD = 0;
	Point2d			centerPoint;
	short			i;

	for (i = 0 ; i <  x->numBoids; i++)
	{
		totalH += x->boid[i].oldPos.x;
		totalV += x->boid[i].oldPos.y;
		// totalD += x->boid[i].oldPos.z;
	}
	centerPoint.x = (double)(totalH / x->numBoids);
	centerPoint.y = (double)(totalV / x->numBoids);
	// centerPoint.z = (double)	(totalD / x->numBoids);
		
	return(centerPoint);
}

float MatchAndAvoidNeighbors(t_boids *x, short theBoid, Velocity *matchNeighborVel, Velocity *avoidNeighborVel)
{
	short			i, j, neighbor;
	double			distSqr;
	double			dist, distH, distV,distD;
	double			tempSpeed;
	short			numClose = 0;
	Velocity		totalVel = {0.0,0.0};//,0.0};

	/**********************/
	/* Find the neighbors */	
	/**********************/

	/* special case of one neighbor */
	if (x->numNeighbors == 1) {
		x->boid[theBoid].neighborDistSqr[0] = kMaxLong;
	
		for (i = 0; i < x->numBoids; i++) {
			if (i != theBoid) {
				distSqr = DistSqrToPt(x->boid[theBoid].oldPos, x->boid[i].oldPos);
				
				/* if this one is closer than the closest so far, then remember it */
				if (x->boid[theBoid].neighborDistSqr[0] > distSqr) {
					x->boid[theBoid].neighborDistSqr[0] = distSqr;
					x->boid[theBoid].neighbor[0] = i;
				}
			}
		}
	}
	/* more than one neighbor */
	else {
		for (j = 0; j < x->numNeighbors; j++)
			x->boid[theBoid].neighborDistSqr[j] = kMaxLong;
		
		for (i = 0 ; i < x->numBoids; i++) {
			/* if this one is not me... */
			if (i != theBoid) {
				distSqr = DistSqrToPt(x->boid[theBoid].oldPos, x->boid[i].oldPos);
	
				/* if distSqr is less than the distance at the bottom of the array, sort into array */
				if (distSqr < x->boid[theBoid].neighborDistSqr[x->numNeighbors-1]) {
					j = x->numNeighbors - 1;
				
					/* sort distSqr in to keep array in size order, smallest first */
					while ((distSqr < x->boid[theBoid].neighborDistSqr[j-1]) && (j > 0)) {
						x->boid[theBoid].neighborDistSqr[j] = x->boid[theBoid].neighborDistSqr[j - 1];
						x->boid[theBoid].neighbor[j] = x->boid[theBoid].neighbor[j - 1];
						j--;
					}
					x->boid[theBoid].neighborDistSqr[j] = distSqr;
					x->boid[theBoid].neighbor[j] = i;					
				}
			}
		}
	}

	/*********************************/
	/* Match and avoid the neighbors */	
	/*********************************/

	matchNeighborVel->x = 0;
	matchNeighborVel->y = 0;
	// matchNeighborVel->z = 0;
	
	// set tempSpeed to old speed
	tempSpeed = x->boid[theBoid].speed;
	
	for (i = 0; i < x->numNeighbors; i++) {
		neighbor = x->boid[theBoid].neighbor[i];
		
		// calculate matchNeighborVel by averaging the neighbor velocities
		matchNeighborVel->x += x->boid[neighbor].oldDir.x;
		matchNeighborVel->y += x->boid[neighbor].oldDir.y;
		// matchNeighborVel->z += x->boid[neighbor].oldDir.z;
			
		// if distance is less than preferred distance, then neighbor influences boid
		distSqr = x->boid[theBoid].neighborDistSqr[i];
		if (distSqr < x->prefDistSqr) {
			dist = sqrt(distSqr);

			distH = x->boid[neighbor].oldPos.x - x->boid[theBoid].oldPos.x;
			distV = x->boid[neighbor].oldPos.y - x->boid[theBoid].oldPos.y;
			// distD = x->boid[neighbor].oldPos.z - x->boid[theBoid].oldPos.z;
			
			if(dist == 0.0) dist = 0.0000001;
			totalVel.x = totalVel.x - distH - (distH * ((float) x->prefDist / (dist)));
			totalVel.y = totalVel.y - distV - (distV * ((float) x->prefDist / (dist)));
			// totalVel.z = totalVel.z - distD - (distV * ((float) x->prefDist / (dist)));
		
			numClose++;
		}
		if (InFront(&(x->boid[theBoid]), &(x->boid[neighbor]))) {	// adjust speed
			if (distSqr < x->prefDistSqr) 
				tempSpeed /= (x->accelFactor / 100.0);
			else
				tempSpeed *= (x->accelFactor / 100.0);
		}
		else {
			if (distSqr < x->prefDistSqr)
				tempSpeed *= (x->accelFactor / 100.0);
			else
				tempSpeed /= (x->accelFactor / 100.0);
		}
	}
	if (numClose) {
		avoidNeighborVel->x = totalVel.x / numClose;
		avoidNeighborVel->y = totalVel.y / numClose;
		// avoidNeighborVel->z = totalVel.z / numClose;
		NormalizeVelocity(matchNeighborVel);
	}
	else {
		avoidNeighborVel->x = 0;
		avoidNeighborVel->y = 0;
		// avoidNeighborVel->z = 0;
	}
	return(tempSpeed);
}


Velocity SeekPoint(t_boids *x, short theBoid, Point2d seekPt)
{
	Velocity	tempDir;
	tempDir.x = seekPt.x - x->boid[theBoid].oldPos.x;	
	tempDir.y = seekPt.y - x->boid[theBoid].oldPos.y;
	// tempDir.z = seekPt.z - x->boid[theBoid].oldPos.z;
	NormalizeVelocity(&tempDir);
	return(tempDir);
}


Velocity AvoidWalls(t_boids *x, short theBoid)
{
	Point2d		testPoint;
	Velocity	tempVel = {0.0, 0.0};//, 0.0};
		
	/* calculate test point in front of the nose of the boid */
	/* distance depends on the boid's speed and the avoid edge constant */
	testPoint.x = x->boid[theBoid].oldPos.x + x->boid[theBoid].oldDir.x * x->boid[theBoid].speed * x->edgeDist;
	testPoint.y = x->boid[theBoid].oldPos.y + x->boid[theBoid].oldDir.y * x->boid[theBoid].speed * x->edgeDist;
	// testPoint.z = x->boid[theBoid].oldPos.z + x->boid[theBoid].oldDir.z * x->boid[theBoid].speed * x->edgeDist;

	/* if test point is out of the left (right) side of x->flyRect, */
	/* return a positive (negative) horizontal velocity component */
	if (testPoint.x < x->flyRect.left)
		tempVel.x = fabs(x->boid[theBoid].oldDir.x);
	else if (testPoint.x > x->flyRect.right)
		tempVel.x = - fabs(x->boid[theBoid].oldDir.x);

	/* same with top and bottom */
	if (testPoint.y < x->flyRect.top)
		tempVel.y = fabs(x->boid[theBoid].oldDir.y);
	else if (testPoint.y > x->flyRect.bottom)
		tempVel.y = - fabs(x->boid[theBoid].oldDir.y);

	/* same with front and back
	if (testPoint.z < x->flyRect.front)
		tempVel.z = fabs(x->boid[theBoid].oldDir.z);
	else if (testPoint.z > x->flyRect.back)
		tempVel.z = - fabs(x->boid[theBoid].oldDir.z);
	*/
	
	return(tempVel);
}


int InFront(BoidPtr theBoid, BoidPtr neighbor)
{
	float	grad, intercept;
	int result;
	
/* 

Find the gradient and y-intercept of a line passing through theBoid's oldPos
perpendicular to its direction of motion.  Another boid is in front of theBoid
if it is to the right or left of this linedepending on whether theBoid is moving
right or left.  However, if theBoid is travelling vertically then just compare
their vertical coordinates.	

*/
	// xy plane
	
	// if theBoid is not travelling vertically...
	if (theBoid->oldDir.x != 0) {
		// calculate gradient of a line _perpendicular_ to its direction (hence the minus)
		grad = -theBoid->oldDir.y / theBoid->oldDir.x;
		
		// calculate where this line hits the y axis (from y = mx + c)
		intercept = theBoid->oldPos.y - (grad * theBoid->oldPos.x);

		/* compare the horizontal position of the neighbor boid with */
		/* the point on the line that has its vertical coordinate */
		if (neighbor->oldPos.x >= ((neighbor->oldPos.y - intercept) / grad)) {
			/* return true if the first boid's horizontal movement is +ve */
			result = (theBoid->oldDir.x > 0);

			if (result==0) return 0;
			else goto next;
			
		} else {
			/* return true if the first boid's horizontal movement is +ve */
			result = (theBoid->oldDir.x < 0);
			if (result==0) return 0;
			else goto next;
		}
	}
	/* else theBoid is travelling vertically, so just compare vertical coordinates */
	else if (theBoid->oldDir.y > 0) {
		result = (neighbor->oldPos.y > theBoid->oldPos.y);
		if (result==0){ 
			return 0;
		}else{
			goto next;
		}
	}else{
		result = (neighbor->oldPos.y < theBoid->oldPos.y);
		if (result==0){
			return 0;
		} else {
			goto next;
		}
	}
next:
/*
	// yz plane
	
	// if theBoid is not travelling vertically... 
	if (theBoid->oldDir.y != 0) {
		// calculate gradient of a line _perpendicular_ to its direction (hence the minus) 
		grad = -theBoid->oldDir.z / theBoid->oldDir.y;
		
		// calculate where this line hits the y axis (from y = mx + c) 
		intercept = theBoid->oldPos.z - (grad * theBoid->oldPos.y);

		// compare the horizontal position of the neighbor boid with 
		// the point on the line that has its vertical coordinate 
		if (neighbor->oldPos.y >= ((neighbor->oldPos.z - intercept) / grad)) {
			// return true if the first boid's horizontal movement is +ve 
			result = (theBoid->oldDir.y > 0);
			if (result==0){ 
				return 0;
			}else{
				goto next2;
			}
		} else {
			// return true if the first boid's horizontal movement is +ve 
			result = (theBoid->oldDir.y < 0);
			if (result==0){
				return 0;
			}else{
				goto next2;
			}
		}
	}
	// else theBoid is travelling vertically, so just compare vertical coordinates 
	else if (theBoid->oldDir.z > 0) {
		result = (neighbor->oldPos.z > theBoid->oldPos.z);
		if (result==0){ 
			return 0;
		}else{
			goto next2;
		}
	}else{
		result = (neighbor->oldPos.z < theBoid->oldPos.z);
		if (result==0){
			return 0;
		}else{
			goto next2;
		}
	}
next2: */
	return 1;
}

void NormalizeVelocity(Velocity *direction)
{
	float	my_hypot;
	
	my_hypot = sqrt(direction->x * direction->x + direction->y * direction->y);// + direction->z * direction->z );

	if (my_hypot != 0.0) {
		direction->x = direction->x / my_hypot;
		direction->y = direction->y / my_hypot;
		// direction->z = direction->z / my_hypot;
	}
}

double RandomInt(double minRange, double maxRange)
{
	unsigned short	qdRdm;
	double			t, result;
	
	qdRdm = rand();
	t = (double)qdRdm / 65536.0; 	// now 0 <= t <= 1
	result = (t * (maxRange - minRange)) + minRange;
	return(result);
}

double DistSqrToPt(Point2d firstPoint, Point2d secondPoint)
{
	double	a, b,c;
	a = firstPoint.x - secondPoint.x;
	b = firstPoint.y - secondPoint.y;	
	//c = firstPoint.z - secondPoint.z;	
	return(a * a + b * b); // + c * c);
}
\ No newline at end of file
--- 1,962 ----
! /*
! 
!     boids2d 08/2005 a.sier / jasch adapted from boids by eric singer  1995-2003 eric l. singer
!     
! 	This program is free software; you can redistribute it and/or modify
! 	it under the terms of the GNU General Public License as published by
! 	the Free Software Foundation; either version 2 of the License, or
! 	(at your option) any later version.
! 
! 	This program is distributed in the hope that it will be useful,
! 	but WITHOUT ANY WARRANTY; without even the implied warranty of
! 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
! 	GNU General Public License for more details.
! 
! 	You should have received a copy of the GNU General Public License
! 	along with this program; if not, write to the Free Software
! 	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
! */
! 
! #include     "m_pd.h"
! #include    <stdlib.h>
! #include    <math.h>
! 
! // constants
! #define            kAssistInlet    1
! #define            kAssistOutlet    2
! #define            kMaxLong        0xFFFFFFFF
! #define            kMaxNeighbors    4
! 
! // util
! #define MAX(a,b) ((a)>(b)?(a):(b))
! #define CLIP(x,a,b) (x)=(x)<(a)?(a):(x)>(b)?(b):(x)
! 
! // initial flight parameters
! const short			kNumBoids        = 12;	// number of boids
! const short			kNumNeighbors    = 2;    // must be <= kMaxNeighbors
! const double		kMinSpeed        = 0.15;	// boids' minimum speed
! const double        kMaxSpeed        = 0.25;    // boids' maximum speed
! const double        kCenterWeight    = 0.25;    // flock centering
! const double        kAttractWeight    = 0.300;// attraction point seeking
! const double        kMatchWeight    = 0.100;// neighbors velocity matching
! const double        kAvoidWeight    = 0.10;    // neighbors avoidance
! const double        kWallsWeight    = 0.500;// wall avoidance [210]
! const double        kEdgeDist        = 0.5;    // vision distance to avoid wall edges [5]
! const double        kSpeedupFactor    = 0.100;// alter animation speed
! const double        kInertiaFactor    = 0.20;    // willingness to change speed & direction
! const double        kAccelFactor    = 0.100;// neighbor avoidance accelerate or decelerate rate
! const double        kPrefDist        = 0.25;    // preferred distance from neighbors
! const double        kFlyRectTop        = 1.0;    // fly rect boundaries
! const double		kFlyRectLeft    = -1.0;    
! const double		kFlyRectBottom    = -1.0;    
! const double		kFlyRectRight    = 1.0;    
! // const double        kFlyRectFront    = 1.0;    
! // const double        kFlyRectBack    = -1.0;    
! 
! 
! // typedefs
! typedef struct Velocity {
!     double        x;
!     double        y;
! //    double        z;
! } Velocity;
! 
! typedef struct Point2d {
!     double        x;
!     double        y;
! //    double        z;
! } Point2d;
! 
! typedef struct Box3D {
!     double        left, right;
!     double        top, bottom;
! //    double        front, back;
! } Box3D;
! 
! typedef struct _Boid {
!     Point2d        oldPos;
!     Point2d        newPos;
!     Velocity    oldDir;
!     Velocity    newDir;
!     double        speed;
!     short        neighbor[kMaxNeighbors];
!     double        neighborDistSqr[kMaxNeighbors];
! } t_one_boid, *BoidPtr;
! 
! typedef struct _FlockObject {
! 	t_object	ob;
!     void		*out1, *out2;
!     short		mode;
!     long		numBoids;
!     long		numNeighbors;
!     Box3D		flyRect;
!     double		minSpeed;
!     double		maxSpeed;
!     double		centerWeight;
!     double        attractWeight;
!     double        matchWeight;
!     double        avoidWeight;
!     double        wallsWeight;
!     double        edgeDist;
!     double        speedupFactor;
!     double        inertiaFactor;
!     double        accelFactor;
!     double        prefDist;
!     double        prefDistSqr;
!     Point2d        centerPt;
!     Point2d        attractPt;
!     BoidPtr        boid;
!     double         d2r, r2d;
! } t_boids, *FlockPtr;
! 
! // variables
! // void         *flock;
! t_symbol     *ps_nothing;
! 
! // prototypes
! void *boids2d_class;
! void *Flock_new(t_symbol *s, long argc, t_atom *argv);
! void Flock_free(t_boids *x);
! void Flock_bang(t_boids *x);
! void Flock_dump(t_boids *x);
! void Flock_mode(t_boids *x, t_float arg);
! void Flock_numNeighbors(t_boids *x, t_float arg);
! void Flock_numBoids(t_boids *x, t_float arg);
! void Flock_minSpeed(t_boids *x, t_float arg);
! void Flock_maxSpeed(t_boids *x, t_float arg);
! void Flock_centerWeight(t_boids *x, t_float arg);
! void Flock_attractWeight(t_boids *x, t_float arg);
! void Flock_matchWeight(t_boids *x, t_float arg);
! void Flock_avoidWeight(t_boids *x, t_float arg);
! void Flock_wallsWeight(t_boids *x, t_float arg);
! void Flock_edgeDist(t_boids *x, t_float arg);
! void Flock_speedupFactor(t_boids *x, t_float arg);
! void Flock_inertiaFactor(t_boids *x, t_float arg);
! void Flock_accelFactor(t_boids *x, t_float arg);
! void Flock_prefDist(t_boids *x, t_float arg);
! void Flock_flyRect(t_boids *x, t_symbol *msg, short argc, t_atom *argv);
! void Flock_attractPt(t_boids *x, t_symbol *msg, short argc, t_atom *argv);
! void Flock_reset(t_boids *x);
! void Flock_resetBoids(t_boids *x);
! void InitFlock(t_boids *x);
! void FlightStep(t_boids *x);
! Point2d FindFlockCenter(t_boids *x);
! float MatchAndAvoidNeighbors(t_boids *x, short theBoid, Velocity *matchNeighborVel, Velocity *avoidNeighborVel);
! Velocity SeekPoint(t_boids *x, short theBoid, Point2d seekPt);
! Velocity AvoidWalls(t_boids *x, short theBoid);
! int InFront(BoidPtr theBoid, BoidPtr neighbor);
! void NormalizeVelocity(Velocity *direction);
! double RandomInt(double minRange, double maxRange);
! double DistSqrToPt(Point2d firstPoint, Point2d secondPoint);
! 
! void boids2d_setup(void)
! {
!     boids2d_class = class_new(gensym("boids2d"), (t_newmethod)Flock_new, 
!             (t_method)Flock_free, sizeof(t_boids), 0, A_GIMME, 0);
!     /*    setup((t_messlist **) &flock, (method)Flock_new, (method)Flock_free, (short) sizeof(FlockObject), 0L, A_LONG, A_DEFLONG, 0); */
!     class_addfloat(boids2d_class,  (t_method) Flock_numBoids);
!     class_addbang(boids2d_class,   (t_method) Flock_bang);
!     class_addmethod(boids2d_class, (t_method) Flock_numNeighbors,        gensym("neighbors"),     A_FLOAT, 0);
!     class_addmethod(boids2d_class, (t_method) Flock_numBoids,            gensym("number"),         A_FLOAT, 0);
!     class_addmethod(boids2d_class, (t_method) Flock_mode,                gensym("mode"),         A_FLOAT, 0);
!     class_addmethod(boids2d_class, (t_method) Flock_minSpeed,            gensym("minspeed"),     A_FLOAT, 0);
!     class_addmethod(boids2d_class, (t_method) Flock_maxSpeed,            gensym("maxspeed"),     A_FLOAT, 0);
!     class_addmethod(boids2d_class, (t_method) Flock_centerWeight,        gensym("center"),         A_FLOAT, 0);
!     class_addmethod(boids2d_class, (t_method) Flock_attractWeight,        gensym("attract"),         A_FLOAT, 0);
!     class_addmethod(boids2d_class, (t_method) Flock_matchWeight,        gensym("match"),         A_FLOAT, 0);
!     class_addmethod(boids2d_class, (t_method) Flock_avoidWeight,        gensym("avoid"),         A_FLOAT, 0);
!     class_addmethod(boids2d_class, (t_method) Flock_wallsWeight,        gensym("repel"),         A_FLOAT, 0);
!     class_addmethod(boids2d_class, (t_method) Flock_edgeDist,            gensym("edgedist"),     A_FLOAT, 0);
!     class_addmethod(boids2d_class, (t_method) Flock_speedupFactor,        gensym("speed"),         A_FLOAT, 0);
!     class_addmethod(boids2d_class, (t_method) Flock_inertiaFactor,        gensym("inertia"),         A_FLOAT, 0);
!     class_addmethod(boids2d_class, (t_method) Flock_accelFactor,        gensym("accel"),         A_FLOAT, 0);
!     class_addmethod(boids2d_class, (t_method) Flock_prefDist,            gensym("prefdist"),     A_FLOAT, 0);
!     class_addmethod(boids2d_class, (t_method) Flock_flyRect,            gensym("flyrect"),         A_GIMME, 0);
!     class_addmethod(boids2d_class, (t_method) Flock_attractPt,             gensym("attractpt"),     A_GIMME, 0);
!     class_addmethod(boids2d_class, (t_method) Flock_resetBoids,         gensym("reset"),         0);
!     class_addmethod(boids2d_class, (t_method) Flock_reset,                 gensym("init"),         0);
!     class_addmethod(boids2d_class, (t_method) Flock_dump,                 gensym("dump"),         0);
!     
!     post("boids2d 2005-2006 a.sier / jasch    1995-2003 eric l. singer   "__DATE__" "__TIME__);    
!     ps_nothing = gensym("");
! }
! 
! 
! void *Flock_new(t_symbol *s, long argc, t_atom *argv)
! {    
!     t_boids *x = (t_boids *)pd_new(boids2d_class);
!     x->out1 = outlet_new(&x->ob, NULL);
!     x->out2 = outlet_new(&x->ob, NULL);
!     
!     x->numBoids = 16;
!     if((argc >= 1) && (argv[0].a_type == A_FLOAT)){
!         x->numBoids = argv[0].a_w.w_float;
!     }
!     x->boid = (t_one_boid *)malloc(sizeof(t_one_boid) * x->numBoids);
!     
!     InitFlock(x);
!     
!     x->mode = 0;
!     if((argc >= 2) && (argv[1].a_type == A_FLOAT)){
!         x->mode = (short)(CLIP(argv[1].a_w.w_float, 0, 2));
!     }
!     
!     x->d2r = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068/180.0;
!     x->r2d = 180.0/3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068;
!     
!     return(x);
! }
! 
! 
! void Flock_free(t_boids *x)
! {
!     free(x->boid);
! }
! 
! void Flock_bang(t_boids *x)
! {
!     short    i;
!     t_atom     outlist[10];
!     t_atom     *out;
!     
!     double     tempNew_x, tempNew_y; 
!     double     tempOld_x, tempOld_y;
!     double    delta_x, delta_y; 
!     double     azi, speed;
!     // double tempspeed;
!     
!     out = outlist;
!         
!     FlightStep(x);
! 
! 
!     switch(x->mode) { // newpos
!         case 0:
!         for (i = 0; i < x->numBoids; i++){
!             SETFLOAT(out+0, i);
!             SETFLOAT(out+1, x->boid[i].newPos.x);
!             SETFLOAT(out+2, x->boid[i].newPos.y);
!         //    SETFLOAT(out+3, x->boid[i].newPos.z);
!             outlet_list(x->out1, 0L, 3, out);
!         }
!         break;
!         case 1: //newpos + oldpos
!         for (i = 0; i < x->numBoids; i++){
!             SETFLOAT(out+0, i);
!             SETFLOAT(out+1, x->boid[i].newPos.x);
!             SETFLOAT(out+2, x->boid[i].newPos.y);
!             // SETFLOAT(out+3, x->boid[i].newPos.z);
!             SETFLOAT(out+3, x->boid[i].oldPos.x);
!             SETFLOAT(out+4, x->boid[i].oldPos.y);
!             // SETFLOAT(out+6, x->boid[i].oldPos.z);
!             outlet_list(x->out1, 0L, 5, out);
!         }
!         break;
!         case 2:
!         for (i = 0; i < x->numBoids; i++){                        
!             tempNew_x = x->boid[i].newPos.x;
!             tempNew_y = x->boid[i].newPos.y;
!             // tempNew_z = x->boid[i].newPos.z;
!             tempOld_x = x->boid[i].oldPos.x;
!             tempOld_y = x->boid[i].oldPos.y;
!             // tempOld_z = x->boid[i].oldPos.z;
!             delta_x = tempNew_x - tempOld_x;
!             delta_y = tempNew_y - tempOld_y;
!             // delta_z = tempNew_z - tempOld_z;
!             azi = atan2(delta_y, delta_x) * x->r2d;
!             // ele = atan2(delta_y, delta_x) * x->r2d;
!             speed = sqrt(delta_x * delta_x + delta_y * delta_y);//  + delta_z * delta_z);
!             SETFLOAT(out+0, i);
!             SETFLOAT(out+1, tempNew_x);
!             SETFLOAT(out+2, tempNew_y);
!             // SETFLOAT(out+3, tempNew_z);
!             SETFLOAT(out+3, tempOld_x);
!             SETFLOAT(out+4, tempOld_y);
!             // SETFLOAT(out+6, tempOld_z);
!             SETFLOAT(out+5, speed);
!             SETFLOAT(out+6, azi);
!             // SETFLOAT(out+9, ele);
!             outlet_list(x->out1, 0L, 7, out);
!         }
!         break;    
!     }
! }
! 
! void Flock_dump(t_boids *x)
! {
!     t_atom    outList[6];
!     
!     outList[0].a_type = A_FLOAT;
!     outList[0].a_w.w_float =  x->numNeighbors;
!     outlet_anything(x->out2, gensym("neighbors"), 1, outList);
! 
!     outList[0].a_type = A_FLOAT;
!     outList[0].a_w.w_float =  x->minSpeed;
!     outlet_anything(x->out2, gensym("minspeed"), 1, outList);
! 
!     outList[0].a_type = A_FLOAT;
!     outList[0].a_w.w_float =  x->maxSpeed;
!     outlet_anything(x->out2, gensym("maxspeed"), 1, outList);
! 
!     outList[0].a_type = A_FLOAT;
!     outList[0].a_w.w_float =  x->centerWeight;
!     outlet_anything(x->out2, gensym("center"), 1, outList);
! 
!     outList[0].a_type = A_FLOAT;
!     outList[0].a_w.w_float =  x->attractWeight;
!     outlet_anything(x->out2, gensym("attract"), 1, outList);
! 
!     outList[0].a_type = A_FLOAT;
!     outList[0].a_w.w_float =  x->matchWeight;
!     outlet_anything(x->out2, gensym("match"), 1, outList);
! 
!     outList[0].a_type = A_FLOAT;
!     outList[0].a_w.w_float =  x->avoidWeight;
!     outlet_anything(x->out2, gensym("avoid"), 1, outList);
! 
!     outList[0].a_type = A_FLOAT;
!     outList[0].a_w.w_float =  x->wallsWeight;
!     outlet_anything(x->out2, gensym("repel"), 1, outList);
! 
!     outList[0].a_type = A_FLOAT;
!     outList[0].a_w.w_float =  x->edgeDist;
!     outlet_anything(x->out2, gensym("edgedist"), 1, outList);
! 
!     outList[0].a_type = A_FLOAT;
!     outList[0].a_w.w_float =  x->speedupFactor;
!     outlet_anything(x->out2, gensym("speed"), 1, outList);
! 
!     outList[0].a_type = A_FLOAT;
!     outList[0].a_w.w_float =  x->inertiaFactor;
!     outlet_anything(x->out2, gensym("inertia"), 1, outList);
! 
!     outList[0].a_type = A_FLOAT;
!     outList[0].a_w.w_float =  x->accelFactor;
!     outlet_anything(x->out2, gensym("accel"), 1, outList);
! 
!     outList[0].a_type = A_FLOAT;
!     outList[0].a_w.w_float = x->prefDist;
!     outlet_anything(x->out2, gensym("prefdist"), 1, outList);
! 
!     outList[0].a_type = A_FLOAT;
!     outList[0].a_w.w_float =  x->flyRect.left;
!     outList[1].a_type = A_FLOAT;
!     outList[1].a_w.w_float =  x->flyRect.top;
!     outList[2].a_type = A_FLOAT;
!     outList[2].a_w.w_float =  x->flyRect.right;
!     outList[3].a_type = A_FLOAT;
!     outList[3].a_w.w_float =  x->flyRect.bottom;
!     /*outList[4].a_type = A_FLOAT;
!     outList[4].a_w.w_float =  x->flyRect.front;
!     outList[5].a_type = A_FLOAT;
!     outList[5].a_w.w_float =  x->flyRect.back;*/
!     outlet_anything(x->out2, gensym("flyrect"), 4, outList);
! 
!     outList[0].a_type = A_FLOAT;
!     outList[0].a_w.w_float =  x->attractPt.x;
!     outList[1].a_type = A_FLOAT;
!     outList[1].a_w.w_float =  x->attractPt.y;
!     /*outList[2].a_type = A_FLOAT;
!     outList[2].a_w.w_float =  x->attractPt.z;*/
!     outlet_anything(x->out2, gensym("attractpt"), 2, outList);
!     
!     outList[0].a_type = A_FLOAT;
!     outList[0].a_w.w_float =  x->mode;
!     outlet_anything(x->out2, gensym("mode"), 1, outList);
!     
!     outList[0].a_type = A_FLOAT;
!     outList[0].a_w.w_float =  x->numBoids;
!     outlet_anything(x->out2, gensym("number"), 1, outList);
! }
! 
! 
! void Flock_mode(t_boids *x, t_float arg)
! {
!     long m = (long)arg;
!     x->mode = CLIP(m, 0, 2);
! }
! 
! void Flock_numNeighbors(t_boids *x, t_float arg)
! {
!     x->numNeighbors = (long)arg;
! }
! 
! void Flock_numBoids(t_boids *x, t_float arg)
! {
!     x->boid = (t_one_boid *)realloc(x->boid, sizeof(t_one_boid) * (long)arg);
!     x->numBoids = (long)arg;
!     Flock_resetBoids(x);
! }
! 
! void Flock_minSpeed(t_boids *x, t_float arg)
! {
!     x->minSpeed = MAX(arg, 0.000001);
! }
! 
! void Flock_maxSpeed(t_boids *x, t_float arg)
! {
!     x->maxSpeed = (double)arg;
! }
! 
! void Flock_centerWeight(t_boids *x, t_float arg)
! {
!     x->centerWeight = (double)arg;
! }
! 
! void Flock_attractWeight(t_boids *x, t_float arg)
! {
!     x->attractWeight = (double)arg;
! }
! 
! void Flock_matchWeight(t_boids *x, t_float arg)
! {
!     x->matchWeight = (double)arg;
! }
! 
! void Flock_avoidWeight(t_boids *x, t_float arg)
! {
!     x->avoidWeight = (double)arg;
! }
! 
! void Flock_wallsWeight(t_boids *x, t_float arg)
! {
!     x->wallsWeight = (double)arg;
! }
! 
! void Flock_edgeDist(t_boids *x, t_float arg)
! {
!     x->edgeDist = (double)arg;
! }
! 
! void Flock_speedupFactor(t_boids *x, t_float arg)
! {
!     x->speedupFactor = (double)arg;
! }
! 
! void Flock_inertiaFactor(t_boids *x, t_float arg)
! {
!     if(arg == 0){
!         x->inertiaFactor = 0.000001;
!     }else{
!         x->inertiaFactor = (double)arg;
!     }
! }
! 
! void Flock_accelFactor(t_boids *x, t_float arg)
! {
!     x->accelFactor = (double)arg;
! }
! 
! void Flock_prefDist(t_boids *x, t_float arg)
! {
!     x->prefDist = (double)arg;
! }
! 
! void Flock_flyRect(t_boids *x, t_symbol *msg, short argc, t_atom *argv)
! {
!     double temp[4];
!     short i;
!     if(argc == 4){
!         for(i=0;i<4;i++) {
!             if(argv[i].a_type == A_FLOAT) {
!                 temp[i] = (double)argv[i].a_w.w_float;    
!             }
!         }
!         x->flyRect.left         = temp[0];
!         x->flyRect.top         = temp[1];
!         x->flyRect.right     = temp[2];
!         x->flyRect.bottom     = temp[3];
!         // x->flyRect.front     = temp[4];
!         // x->flyRect.back         = temp[5];
!     }else{
!         error("boids2d: flyrect needs four values");
!     }
! }
! 
! void Flock_attractPt(t_boids *x, t_symbol *msg, short argc, t_atom *argv)
! {
!     double temp[2];
!     short i;
!     if(argc == 2){
!     for(i=0;i<2;i++) {
!         if(argv[i].a_type == A_FLOAT) {
!             temp[i] = (double)argv[i].a_w.w_float;    
!         }
!     }
!     x->attractPt.x = temp[0];
!     x->attractPt.y = temp[1];
!     // x->attractPt.z = temp[2];
!     }else{
!         error("boids2d: attractPt needs two values");
!     }
! }
! 
! void Flock_reset(t_boids *x)
! {
!     InitFlock(x);
! }
! 
! void Flock_resetBoids(t_boids *x)
! {
!     long i, j;
!     double rndAngle;
!     
!     for (i = 0; i <  x->numBoids; i++) { // init everything to 0.0
!         x->boid[i].oldPos.x = 0.0;
!         x->boid[i].oldPos.y = 0.0;
!         // x->boid[i].oldPos.z = 0.0;
! 
!         x->boid[i].newPos.x = 0.0;
!         x->boid[i].newPos.y = 0.0;
!         // x->boid[i].newPos.z = 0.0;
!         
!         x->boid[i].oldDir.x = 0.0;
!         x->boid[i].oldDir.y = 0.0;
!         // x->boid[i].oldDir.z = 0.0;
!         
!         x->boid[i].newDir.x = 0.0;
!         x->boid[i].newDir.y = 0.0;
!         // x->boid[i].newDir.z = 0.0;
!         
!         x->boid[i].speed = 0.0;
!         
!         for(j=0; j<kMaxNeighbors;j++){
!             x->boid[i].neighbor[j] = 0;
!             x->boid[i].neighborDistSqr[j] = 0.0;
!         }
!     }
!     for (i = 0; i <  x->numBoids; i++) {                // set the initial locations and velocities of the boids
!         x->boid[i].newPos.x = x->boid[i].oldPos.x = RandomInt(x->flyRect.right,x->flyRect.left);        // set random location within flyRect
!         x->boid[i].newPos.y = x->boid[i].oldPos.y = RandomInt(x->flyRect.bottom, x->flyRect.top);
!         // x->boid[i].newPos.z = x->boid[i].oldPos.z = RandomInt(x->flyRect.back, x->flyRect.front);
!         rndAngle = RandomInt(0, 360) * x->d2r;        // set velocity from random angle
!         x->boid[i].newDir.x = sin(rndAngle);
!         x->boid[i].newDir.y = cos(rndAngle);
!         // x->boid[i].newDir.z = (cos(rndAngle) + sin(rndAngle)) * 0.5;
!         x->boid[i].speed = (kMaxSpeed + kMinSpeed) * 0.5;
!     }
! }
! 
! void InitFlock(t_boids *x)
! {
!     x->numNeighbors        = kNumNeighbors;
!     x->minSpeed            = kMinSpeed;
!     x->maxSpeed            = kMaxSpeed;
!     x->centerWeight        = kCenterWeight;
!     x->attractWeight        = kAttractWeight;
!     x->matchWeight        = kMatchWeight;
!     x->avoidWeight        = kAvoidWeight;
!     x->wallsWeight        = kWallsWeight;
!     x->edgeDist            = kEdgeDist;
!     x->speedupFactor        = kSpeedupFactor;
!     x->inertiaFactor        = kInertiaFactor;
!     x->accelFactor        = kAccelFactor;
!     x->prefDist            = kPrefDist;
!     x->prefDistSqr        = kPrefDist * kPrefDist;
!     x->flyRect.top        = kFlyRectTop;
!     x->flyRect.left        = kFlyRectLeft;
!     x->flyRect.bottom    = kFlyRectBottom;
!     x->flyRect.right        = kFlyRectRight;
!     // x->flyRect.front        = kFlyRectFront;
!     // x->flyRect.back        = kFlyRectBack;
!     x->attractPt.x        = (kFlyRectLeft + kFlyRectRight) * 0.5;
!     x->attractPt.y        = (kFlyRectTop + kFlyRectBottom) * 0.5;
!     // x->attractPt.z        = (kFlyRectFront + kFlyRectBack) * 0.5;
!     Flock_resetBoids(x);
! }
! 
! void FlightStep(t_boids *x)
! {
!     Velocity        goCenterVel;
!     Velocity        goAttractVel;
!     Velocity        matchNeighborVel;
!     Velocity        avoidWallsVel;
!     Velocity        avoidNeighborVel;
!     float            avoidNeighborSpeed;
!     const Velocity    zeroVel    = {0.0, 0.0};//, 0.0};
!     short            i;
! 
!     x->centerPt = FindFlockCenter(x);
!     for (i = 0; i <  x->numBoids; i++) {                        // save position and velocity
!         x->boid[i].oldPos.x = x->boid[i].newPos.x;
!         x->boid[i].oldPos.y = x->boid[i].newPos.y;
!         // x->boid[i].oldPos.z = x->boid[i].newPos.z;
!         
!         x->boid[i].oldDir.x = x->boid[i].newDir.x;
!         x->boid[i].oldDir.y = x->boid[i].newDir.y;
!         // x->boid[i].oldDir.z = x->boid[i].newDir.z;
!     }
!     for (i = 0; i < x->numBoids; i++) {
!         if (x->numNeighbors > 0) {                            // get all velocity components
!             avoidNeighborSpeed = MatchAndAvoidNeighbors(x, i,&matchNeighborVel, &avoidNeighborVel);
!         } else {
!             matchNeighborVel = zeroVel;
!             avoidNeighborVel = zeroVel;
!             avoidNeighborSpeed = 0;
!         }
!         goCenterVel = SeekPoint(x, i, x->centerPt);            
!         goAttractVel = SeekPoint(x, i, x->attractPt);
!         avoidWallsVel = AvoidWalls(x, i);
!     
!         // compute resultant velocity using weights and inertia
!         x->boid[i].newDir.x = x->inertiaFactor * (x->boid[i].oldDir.x) +
!                             (x->centerWeight * goCenterVel.x +
!                              x->attractWeight * goAttractVel.x +
!                              x->matchWeight * matchNeighborVel.x +
!                              x->avoidWeight * avoidNeighborVel.x +
!                              x->wallsWeight * avoidWallsVel.x) / x->inertiaFactor;
!         x->boid[i].newDir.y = x->inertiaFactor * (x->boid[i].oldDir.y) +
!                             (x->centerWeight * goCenterVel.y +
!                              x->attractWeight * goAttractVel.y +
!                              x->matchWeight * matchNeighborVel.y +
!                              x->avoidWeight * avoidNeighborVel.y +
!                              x->wallsWeight * avoidWallsVel.y) / x->inertiaFactor;
!         /*x->boid[i].newDir.z = x->inertiaFactor * (x->boid[i].oldDir.z) +
!                             (x->centerWeight * goCenterVel.z +
!                              x->attractWeight * goAttractVel.z +
!                              x->matchWeight * matchNeighborVel.z +
!                              x->avoidWeight * avoidNeighborVel.z +
!                              x->wallsWeight * avoidWallsVel.z) / x->inertiaFactor;*/
!         NormalizeVelocity(&(x->boid[i].newDir));    // normalize velocity so its length is unity
! 
!         // set to avoidNeighborSpeed bounded by minSpeed and maxSpeed
!         if ((avoidNeighborSpeed >= x->minSpeed) &&
!                 (avoidNeighborSpeed <= x->maxSpeed))
!             x->boid[i].speed = avoidNeighborSpeed;
!         else if (avoidNeighborSpeed > x->maxSpeed)
!             x->boid[i].speed = x->maxSpeed;
!         else
!             x->boid[i].speed = x->minSpeed;
! 
!         // calculate new position, applying speedupFactor
!         x->boid[i].newPos.x += x->boid[i].newDir.x * x->boid[i].speed * (x->speedupFactor / 100.0);
!         x->boid[i].newPos.y += x->boid[i].newDir.y * x->boid[i].speed * (x->speedupFactor / 100.0);
!         // x->boid[i].newPos.z += x->boid[i].newDir.z * x->boid[i].speed * (x->speedupFactor / 100.0);
! 
!     }
! }
! 
! Point2d FindFlockCenter(t_boids *x)
! {
!     double            totalH = 0, totalV = 0, totalD = 0;
!     Point2d            centerPoint;
!     short            i;
! 
!     for (i = 0 ; i <  x->numBoids; i++)
!     {
!         totalH += x->boid[i].oldPos.x;
!         totalV += x->boid[i].oldPos.y;
!         // totalD += x->boid[i].oldPos.z;
!     }
!     centerPoint.x = (double)(totalH / x->numBoids);
!     centerPoint.y = (double)(totalV / x->numBoids);
!     // centerPoint.z = (double)    (totalD / x->numBoids);
!         
!     return(centerPoint);
! }
! 
! float MatchAndAvoidNeighbors(t_boids *x, short theBoid, Velocity *matchNeighborVel, Velocity *avoidNeighborVel)
! {
!     short            i, j, neighbor;
!     double            distSqr;
!     double            dist, distH, distV,distD;
!     double            tempSpeed;
!     short            numClose = 0;
!     Velocity        totalVel = {0.0,0.0};//,0.0};
! 
!     /**********************/
!     /* Find the neighbors */    
!     /**********************/
! 
!     /* special case of one neighbor */
!     if (x->numNeighbors == 1) {
!         x->boid[theBoid].neighborDistSqr[0] = kMaxLong;
!     
!         for (i = 0; i < x->numBoids; i++) {
!             if (i != theBoid) {
!                 distSqr = DistSqrToPt(x->boid[theBoid].oldPos, x->boid[i].oldPos);
!                 
!                 /* if this one is closer than the closest so far, then remember it */
!                 if (x->boid[theBoid].neighborDistSqr[0] > distSqr) {
!                     x->boid[theBoid].neighborDistSqr[0] = distSqr;
!                     x->boid[theBoid].neighbor[0] = i;
!                 }
!             }
!         }
!     }
!     /* more than one neighbor */
!     else {
!         for (j = 0; j < x->numNeighbors; j++)
!             x->boid[theBoid].neighborDistSqr[j] = kMaxLong;
!         
!         for (i = 0 ; i < x->numBoids; i++) {
!             /* if this one is not me... */
!             if (i != theBoid) {
!                 distSqr = DistSqrToPt(x->boid[theBoid].oldPos, x->boid[i].oldPos);
!     
!                 /* if distSqr is less than the distance at the bottom of the array, sort into array */
!                 if (distSqr < x->boid[theBoid].neighborDistSqr[x->numNeighbors-1]) {
!                     j = x->numNeighbors - 1;
!                 
!                     /* sort distSqr in to keep array in size order, smallest first */
!                     while ((distSqr < x->boid[theBoid].neighborDistSqr[j-1]) && (j > 0)) {
!                         x->boid[theBoid].neighborDistSqr[j] = x->boid[theBoid].neighborDistSqr[j - 1];
!                         x->boid[theBoid].neighbor[j] = x->boid[theBoid].neighbor[j - 1];
!                         j--;
!                     }
!                     x->boid[theBoid].neighborDistSqr[j] = distSqr;
!                     x->boid[theBoid].neighbor[j] = i;                    
!                 }
!             }
!         }
!     }
! 
!     /*********************************/
!     /* Match and avoid the neighbors */    
!     /*********************************/
! 
!     matchNeighborVel->x = 0;
!     matchNeighborVel->y = 0;
!     // matchNeighborVel->z = 0;
!     
!     // set tempSpeed to old speed
!     tempSpeed = x->boid[theBoid].speed;
!     
!     for (i = 0; i < x->numNeighbors; i++) {
!         neighbor = x->boid[theBoid].neighbor[i];
!         
!         // calculate matchNeighborVel by averaging the neighbor velocities
!         matchNeighborVel->x += x->boid[neighbor].oldDir.x;
!         matchNeighborVel->y += x->boid[neighbor].oldDir.y;
!         // matchNeighborVel->z += x->boid[neighbor].oldDir.z;
!             
!         // if distance is less than preferred distance, then neighbor influences boid
!         distSqr = x->boid[theBoid].neighborDistSqr[i];
!         if (distSqr < x->prefDistSqr) {
!             dist = sqrt(distSqr);
! 
!             distH = x->boid[neighbor].oldPos.x - x->boid[theBoid].oldPos.x;
!             distV = x->boid[neighbor].oldPos.y - x->boid[theBoid].oldPos.y;
!             // distD = x->boid[neighbor].oldPos.z - x->boid[theBoid].oldPos.z;
!             
!             if(dist == 0.0) dist = 0.0000001;
!             totalVel.x = totalVel.x - distH - (distH * ((float) x->prefDist / (dist)));
!             totalVel.y = totalVel.y - distV - (distV * ((float) x->prefDist / (dist)));
!             // totalVel.z = totalVel.z - distD - (distV * ((float) x->prefDist / (dist)));
!         
!             numClose++;
!         }
!         if (InFront(&(x->boid[theBoid]), &(x->boid[neighbor]))) {    // adjust speed
!             if (distSqr < x->prefDistSqr) 
!                 tempSpeed /= (x->accelFactor / 100.0);
!             else
!                 tempSpeed *= (x->accelFactor / 100.0);
!         }
!         else {
!             if (distSqr < x->prefDistSqr)
!                 tempSpeed *= (x->accelFactor / 100.0);
!             else
!                 tempSpeed /= (x->accelFactor / 100.0);
!         }
!     }
!     if (numClose) {
!         avoidNeighborVel->x = totalVel.x / numClose;
!         avoidNeighborVel->y = totalVel.y / numClose;
!         // avoidNeighborVel->z = totalVel.z / numClose;
!         NormalizeVelocity(matchNeighborVel);
!     }
!     else {
!         avoidNeighborVel->x = 0;
!         avoidNeighborVel->y = 0;
!         // avoidNeighborVel->z = 0;
!     }
!     return(tempSpeed);
! }
! 
! 
! Velocity SeekPoint(t_boids *x, short theBoid, Point2d seekPt)
! {
!     Velocity    tempDir;
!     tempDir.x = seekPt.x - x->boid[theBoid].oldPos.x;    
!     tempDir.y = seekPt.y - x->boid[theBoid].oldPos.y;
!     // tempDir.z = seekPt.z - x->boid[theBoid].oldPos.z;
!     NormalizeVelocity(&tempDir);
!     return(tempDir);
! }
! 
! 
! Velocity AvoidWalls(t_boids *x, short theBoid)
! {
!     Point2d        testPoint;
!     Velocity    tempVel = {0.0, 0.0};//, 0.0};
!         
!     /* calculate test point in front of the nose of the boid */
!     /* distance depends on the boid's speed and the avoid edge constant */
!     testPoint.x = x->boid[theBoid].oldPos.x + x->boid[theBoid].oldDir.x * x->boid[theBoid].speed * x->edgeDist;
!     testPoint.y = x->boid[theBoid].oldPos.y + x->boid[theBoid].oldDir.y * x->boid[theBoid].speed * x->edgeDist;
!     // testPoint.z = x->boid[theBoid].oldPos.z + x->boid[theBoid].oldDir.z * x->boid[theBoid].speed * x->edgeDist;
! 
!     /* if test point is out of the left (right) side of x->flyRect, */
!     /* return a positive (negative) horizontal velocity component */
!     if (testPoint.x < x->flyRect.left)
!         tempVel.x = fabs(x->boid[theBoid].oldDir.x);
!     else if (testPoint.x > x->flyRect.right)
!         tempVel.x = - fabs(x->boid[theBoid].oldDir.x);
! 
!     /* same with top and bottom */
!     if (testPoint.y < x->flyRect.top)
!         tempVel.y = fabs(x->boid[theBoid].oldDir.y);
!     else if (testPoint.y > x->flyRect.bottom)
!         tempVel.y = - fabs(x->boid[theBoid].oldDir.y);
! 
!     /* same with front and back
!     if (testPoint.z < x->flyRect.front)
!         tempVel.z = fabs(x->boid[theBoid].oldDir.z);
!     else if (testPoint.z > x->flyRect.back)
!         tempVel.z = - fabs(x->boid[theBoid].oldDir.z);
!     */
!     
!     return(tempVel);
! }
! 
! 
! int InFront(BoidPtr theBoid, BoidPtr neighbor)
! {
!     float    grad, intercept;
!     int result;
!     
! /* 
! 
! Find the gradient and y-intercept of a line passing through theBoid's oldPos
! perpendicular to its direction of motion.  Another boid is in front of theBoid
! if it is to the right or left of this linedepending on whether theBoid is moving
! right or left.  However, if theBoid is travelling vertically then just compare
! their vertical coordinates.    
! 
! */
!     // xy plane
!     
!     // if theBoid is not travelling vertically...
!     if (theBoid->oldDir.x != 0) {
!         // calculate gradient of a line _perpendicular_ to its direction (hence the minus)
!         grad = -theBoid->oldDir.y / theBoid->oldDir.x;
!         
!         // calculate where this line hits the y axis (from y = mx + c)
!         intercept = theBoid->oldPos.y - (grad * theBoid->oldPos.x);
! 
!         /* compare the horizontal position of the neighbor boid with */
!         /* the point on the line that has its vertical coordinate */
!         if (neighbor->oldPos.x >= ((neighbor->oldPos.y - intercept) / grad)) {
!             /* return true if the first boid's horizontal movement is +ve */
!             result = (theBoid->oldDir.x > 0);
! 
!             if (result==0) return 0;
!             else goto next;
!             
!         } else {
!             /* return true if the first boid's horizontal movement is +ve */
!             result = (theBoid->oldDir.x < 0);
!             if (result==0) return 0;
!             else goto next;
!         }
!     }
!     /* else theBoid is travelling vertically, so just compare vertical coordinates */
!     else if (theBoid->oldDir.y > 0) {
!         result = (neighbor->oldPos.y > theBoid->oldPos.y);
!         if (result==0){ 
!             return 0;
!         }else{
!             goto next;
!         }
!     }else{
!         result = (neighbor->oldPos.y < theBoid->oldPos.y);
!         if (result==0){
!             return 0;
!         } else {
!             goto next;
!         }
!     }
! next:
! /*
!     // yz plane
!     
!     // if theBoid is not travelling vertically... 
!     if (theBoid->oldDir.y != 0) {
!         // calculate gradient of a line _perpendicular_ to its direction (hence the minus) 
!         grad = -theBoid->oldDir.z / theBoid->oldDir.y;
!         
!         // calculate where this line hits the y axis (from y = mx + c) 
!         intercept = theBoid->oldPos.z - (grad * theBoid->oldPos.y);
! 
!         // compare the horizontal position of the neighbor boid with 
!         // the point on the line that has its vertical coordinate 
!         if (neighbor->oldPos.y >= ((neighbor->oldPos.z - intercept) / grad)) {
!             // return true if the first boid's horizontal movement is +ve 
!             result = (theBoid->oldDir.y > 0);
!             if (result==0){ 
!                 return 0;
!             }else{
!                 goto next2;
!             }
!         } else {
!             // return true if the first boid's horizontal movement is +ve 
!             result = (theBoid->oldDir.y < 0);
!             if (result==0){
!                 return 0;
!             }else{
!                 goto next2;
!             }
!         }
!     }
!     // else theBoid is travelling vertically, so just compare vertical coordinates 
!     else if (theBoid->oldDir.z > 0) {
!         result = (neighbor->oldPos.z > theBoid->oldPos.z);
!         if (result==0){ 
!             return 0;
!         }else{
!             goto next2;
!         }
!     }else{
!         result = (neighbor->oldPos.z < theBoid->oldPos.z);
!         if (result==0){
!             return 0;
!         }else{
!             goto next2;
!         }
!     }
! next2: */
!     return 1;
! }
! 
! void NormalizeVelocity(Velocity *direction)
! {
!     float    my_hypot;
!     
!     my_hypot = sqrt(direction->x * direction->x + direction->y * direction->y);// + direction->z * direction->z );
! 
!     if (my_hypot != 0.0) {
!         direction->x = direction->x / my_hypot;
!         direction->y = direction->y / my_hypot;
!         // direction->z = direction->z / my_hypot;
!     }
! }
! 
! double RandomInt(double minRange, double maxRange)
! {
!     unsigned short    qdRdm;
!     double            t, result;
!     
!     qdRdm = rand();
!     t = (double)qdRdm / 65536.0;     // now 0 <= t <= 1
!     result = (t * (maxRange - minRange)) + minRange;
!     return(result);
! }
! 
! double DistSqrToPt(Point2d firstPoint, Point2d secondPoint)
! {
!     double    a, b,c;
!     a = firstPoint.x - secondPoint.x;
!     b = firstPoint.y - secondPoint.y;    
!     //c = firstPoint.z - secondPoint.z;    
!     return(a * a + b * b); // + c * c);
! }
\ No newline at end of file





More information about the Pd-cvs mailing list