From 6eee574901d8e2b054dcd79530fa3102991e81bc Mon Sep 17 00:00:00 2001 From: fdch Date: Sat, 11 Apr 2026 12:49:28 +0200 Subject: [PATCH 01/19] rearrange code structure --- .editorconfig | 38 +++++++++++++++++++++++++ .gitignore | 4 +++ Makefile | 8 +++--- boids2d-help.pd => help/boids2d-help.pd | 0 boids3d-help.pd => help/boids3d-help.pd | 0 boids2d.c => src/boids2d.c | 0 boids3d.c => src/boids3d.c | 0 7 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 .editorconfig create mode 100644 .gitignore rename boids2d-help.pd => help/boids2d-help.pd (100%) rename boids3d-help.pd => help/boids3d-help.pd (100%) rename boids2d.c => src/boids2d.c (100%) rename boids3d.c => src/boids3d.c (100%) diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5dc9d59 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,38 @@ +root = true + +[*] +# please only ever use utf-8 +charset = utf-8 + +; C and friends +[**.{c,cpp,h,hh,m,mm}] +# indent 4 spaces, BSD-style +indent_style = space +indent_size = 4 +indent_brace_style = BSD + +## let git handle proper EOL +#end_of_line = lf + +trim_trailing_whitespace = true +insert_final_newline = true + +max_line_length = 80 + +#continuation_indent_size = 4 +spaces_around_operators = true + +; applies only to Makefiles +[makefile] +indent_style = tab +tab_width = 4 +[**.am] +indent_style = tab +tab_width = 4 + +[**.tcl] +indent_style = space +indent_size = 4 +#continuation_indent_size = 8 +#curly_bracket_next_line = false + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..689190c --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.pd_linux +*.o +boids/ +compile_commands.json diff --git a/Makefile b/Makefile index 78a7435..cd4f469 100644 --- a/Makefile +++ b/Makefile @@ -7,15 +7,15 @@ lib.name = boids # input source file (class name == source file basename) class.sources = \ - boids2d.c \ - boids3d.c \ + src/boids2d.c \ + src/boids3d.c \ $(empty) # all extra files to be included in binary distribution of the library datafiles = \ boids-meta.pd \ - boids2d-help.pd \ - boids3d-help.pd \ + help/boids2d-help.pd \ + help/boids3d-help.pd \ README.txt LICENSE.txt datadirs = \ diff --git a/boids2d-help.pd b/help/boids2d-help.pd similarity index 100% rename from boids2d-help.pd rename to help/boids2d-help.pd diff --git a/boids3d-help.pd b/help/boids3d-help.pd similarity index 100% rename from boids3d-help.pd rename to help/boids3d-help.pd diff --git a/boids2d.c b/src/boids2d.c similarity index 100% rename from boids2d.c rename to src/boids2d.c diff --git a/boids3d.c b/src/boids3d.c similarity index 100% rename from boids3d.c rename to src/boids3d.c From d97c66489290889cd60d25469368cfd5a29135a7 Mon Sep 17 00:00:00 2001 From: fdch Date: Sat, 11 Apr 2026 15:11:10 +0200 Subject: [PATCH 02/19] format code and add clang-format --- .clang-format | 4 + .gitignore | 1 + src/boids2d.c | 979 ++++++++++++++++------------- src/boids3d.c | 1674 +++++++++++++++++++++++++++---------------------- 4 files changed, 1464 insertions(+), 1194 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..5734a4e --- /dev/null +++ b/.clang-format @@ -0,0 +1,4 @@ +BasedOnStyle: LLVM +IndentWidth: 4 +BreakBeforeBraces: Allman +AllowShortFunctionsOnASingleLine: None diff --git a/.gitignore b/.gitignore index 689190c..c167498 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.o boids/ compile_commands.json +.cache/ diff --git a/src/boids2d.c b/src/boids2d.c index a05e522..ea2106f 100644 --- a/src/boids2d.c +++ b/src/boids2d.c @@ -1,117 +1,123 @@ /* - 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 + 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 -#include +#include "m_pd.h" +#include +#include // constants -#define kAssistInlet 1 -#define kAssistOutlet 2 -#define kMaxLong 0xFFFFFFFF -#define kMaxNeighbors 4 +#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) +#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; - +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; +typedef struct Velocity +{ + double x; + double y; + // double z; } Velocity; -typedef struct Point2d { - double x; - double y; -// double z; +typedef struct Point2d +{ + double x; + double y; + // double z; } Point2d; -typedef struct Box3D { - double left, right; - double top, bottom; -// double front, back; +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]; +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; +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; +t_symbol *ps_nothing; // prototypes void *boids2d_class; @@ -141,7 +147,9 @@ 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); +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); @@ -151,62 +159,88 @@ 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); - - logpost(NULL, 4, "boids2d 2005-2006 a.sier / jasch 1995-2003 eric l. singer "__DATE__" "__TIME__); + 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); + + logpost(NULL, 4, + "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)){ + 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)){ + 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); -} + x->d2r = + 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068 / + 180.0; + x->r2d = + 180.0 / + 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068; + + return (x); +} void Flock_free(t_boids *x) { @@ -215,45 +249,48 @@ void Flock_free(t_boids *x) 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; + 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); + 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); + 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); + 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 + 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++){ + 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; @@ -265,73 +302,74 @@ void Flock_bang(t_boids *x) // 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); + 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 + 3, tempOld_x); + SETFLOAT(out + 4, tempOld_y); // SETFLOAT(out+6, tempOld_z); - SETFLOAT(out+5, speed); - SETFLOAT(out+6, azi); + SETFLOAT(out + 5, speed); + SETFLOAT(out + 6, azi); // SETFLOAT(out+9, ele); outlet_list(x->out1, 0L, 7, out); } - break; + break; } } void Flock_dump(t_boids *x) { - t_atom outList[6]; - + t_atom outList[6]; + outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->numNeighbors; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + outList[0].a_w.w_float = x->accelFactor; outlet_anything(x->out2, gensym("accel"), 1, outList); outList[0].a_type = A_FLOAT; @@ -339,13 +377,13 @@ void Flock_dump(t_boids *x) outlet_anything(x->out2, gensym("prefdist"), 1, outList); outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->flyRect.left; + 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[1].a_w.w_float = x->flyRect.top; outList[2].a_type = A_FLOAT; - outList[2].a_w.w_float = x->flyRect.right; + 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[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; @@ -353,23 +391,22 @@ void Flock_dump(t_boids *x) outlet_anything(x->out2, gensym("flyrect"), 4, outList); outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->attractPt.x; + 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[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; + 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; + 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; @@ -435,9 +472,12 @@ void Flock_speedupFactor(t_boids *x, t_float arg) void Flock_inertiaFactor(t_boids *x, t_float arg) { - if(arg == 0){ + if (arg == 0) + { x->inertiaFactor = 0.000001; - }else{ + } + else + { x->inertiaFactor = (double)arg; } } @@ -456,19 +496,24 @@ 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; + 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.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{ + } + else + { pd_error(x, "boids2d: flyrect needs four values"); } } @@ -477,16 +522,21 @@ 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; + 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]; } - x->attractPt.x = temp[0]; - x->attractPt.y = temp[1]; - // x->attractPt.z = temp[2]; - }else{ + else + { pd_error(x, "boids2d: attractPt needs two values"); } } @@ -500,8 +550,9 @@ void Flock_resetBoids(t_boids *x) { long i, j; double rndAngle; - - for (i = 0; i < x->numBoids; i++) { // init everything to 0.0 + + 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; @@ -509,27 +560,33 @@ void Flock_resetBoids(t_boids *x) 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; jboid[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 + 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; @@ -539,89 +596,99 @@ void Flock_resetBoids(t_boids *x) 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->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.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; + 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 + 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 { + 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); + 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->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->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 + 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)) + (avoidNeighborSpeed <= x->maxSpeed)) x->boid[i].speed = avoidNeighborSpeed; else if (avoidNeighborSpeed > x->maxSpeed) x->boid[i].speed = x->maxSpeed; @@ -629,20 +696,22 @@ void FlightStep(t_boids *x) 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); - + 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; + double totalH = 0, totalV = 0, totalD = 0; + Point2d centerPoint; + short i; - for (i = 0 ; i < x->numBoids; i++) + for (i = 0; i < x->numBoids; i++) { totalH += x->boid[i].oldPos.x; totalV += x->boid[i].oldPos.y; @@ -651,33 +720,41 @@ Point2d FindFlockCenter(t_boids *x) centerPoint.x = (double)(totalH / x->numBoids); centerPoint.y = (double)(totalV / x->numBoids); // centerPoint.z = (double) (totalD / x->numBoids); - - return(centerPoint); + + return (centerPoint); } -float MatchAndAvoidNeighbors(t_boids *x, short theBoid, Velocity *matchNeighborVel, Velocity *avoidNeighborVel) +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}; + 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 */ + /* Find the neighbors */ /**********************/ /* special case of one neighbor */ - if (x->numNeighbors == 1) { + 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) { + + 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; } @@ -685,129 +762,156 @@ float MatchAndAvoidNeighbors(t_boids *x, short theBoid, Velocity *matchNeighborV } } /* more than one neighbor */ - else { + else + { for (j = 0; j < x->numNeighbors; j++) x->boid[theBoid].neighborDistSqr[j] = kMaxLong; - - for (i = 0 ; i < x->numBoids; i++) { + + 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]) { + 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]; + + /* 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; + x->boid[theBoid].neighbor[j] = i; } } } } /*********************************/ - /* Match and avoid the neighbors */ + /* 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++) { + + 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 + + // if distance is less than preferred distance, then neighbor influences + // boid distSqr = x->boid[theBoid].neighborDistSqr[i]; - if (distSqr < x->prefDistSqr) { + 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))); - + + 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) + 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 { + else + { if (distSqr < x->prefDistSqr) tempSpeed *= (x->accelFactor / 100.0); else tempSpeed /= (x->accelFactor / 100.0); } } - if (numClose) { + if (numClose) + { avoidNeighborVel->x = totalVel.x / numClose; avoidNeighborVel->y = totalVel.y / numClose; // avoidNeighborVel->z = totalVel.z / numClose; NormalizeVelocity(matchNeighborVel); } - else { + else + { avoidNeighborVel->x = 0; avoidNeighborVel->y = 0; // avoidNeighborVel->z = 0; } - return(tempSpeed); + return (tempSpeed); } - Velocity SeekPoint(t_boids *x, short theBoid, Point2d seekPt) { - Velocity tempDir; - tempDir.x = seekPt.x - x->boid[theBoid].oldPos.x; + 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); + return (tempDir); } - Velocity AvoidWalls(t_boids *x, short theBoid) { - Point2d testPoint; - Velocity tempVel = {0.0, 0.0};//, 0.0}; - + 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; + 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); + 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); + tempVel.y = -fabs(x->boid[theBoid].oldDir.y); /* same with front and back if (testPoint.z < x->flyRect.front) @@ -815,126 +919,143 @@ Velocity AvoidWalls(t_boids *x, short theBoid) else if (testPoint.z > x->flyRect.back) tempVel.z = - fabs(x->boid[theBoid].oldDir.z); */ - - return(tempVel); -} + return (tempVel); +} int InFront(BoidPtr theBoid, BoidPtr neighbor) { - float grad, intercept; + 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. + /* -*/ + 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) + 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)) { + 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 { + 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; + if (result == 0) + return 0; + else + goto next; } } - /* else theBoid is travelling vertically, so just compare vertical coordinates */ - else if (theBoid->oldDir.y > 0) { + /* 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){ + if (result == 0) + { return 0; - }else{ + } + else + { goto next; } - }else{ + } + else + { result = (neighbor->oldPos.y < theBoid->oldPos.y); - if (result==0){ + if (result == 0) + { return 0; - } else { + } + 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; + /* + // 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 { - // return true if the first boid's horizontal movement is +ve - result = (theBoid->oldDir.y < 0); + } + // 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; } } - } - // 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: */ + 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 ); + float my_hypot; - if (my_hypot != 0.0) { + 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; @@ -943,20 +1064,20 @@ void NormalizeVelocity(Velocity *direction) double RandomInt(double minRange, double maxRange) { - unsigned short qdRdm; - double t, result; - + unsigned short qdRdm; + double t, result; + qdRdm = rand(); - t = (double)qdRdm / 65536.0; // now 0 <= t <= 1 + t = (double)qdRdm / 65536.0; // now 0 <= t <= 1 result = (t * (maxRange - minRange)) + minRange; - return(result); + return (result); } double DistSqrToPt(Point2d firstPoint, Point2d secondPoint) { - double a, b,c; + 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); + b = firstPoint.y - secondPoint.y; + // c = firstPoint.z - secondPoint.z; + return (a * a + b * b); // + c * c); } diff --git a/src/boids3d.c b/src/boids3d.c index 9e57be3..6e4f2ed 100644 --- a/src/boids3d.c +++ b/src/boids3d.c @@ -1,117 +1,121 @@ /* - boids3d 2005 - 2006 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 + boids3d 2005 - 2006 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 -#include +#include "m_pd.h" +#include +#include // constants -#define kAssistInlet 1 -#define kAssistOutlet 2 -#define kMaxLong 0xFFFFFFFF -#define kMaxNeighbors 4 +#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) +#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; - +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; +typedef struct Velocity +{ + double x; + double y; + double z; } Velocity; -typedef struct Point3d { - double x; - double y; - double z; +typedef struct Point3d +{ + double x; + double y; + double z; } Point3d; -typedef struct Box3D { - double left, right; - double top, bottom; - double front, back; +typedef struct Box3D +{ + double left, right; + double top, bottom; + double front, back; } Box3D; -typedef struct _Boid { - Point3d oldPos; - Point3d newPos; - Velocity oldDir; - Velocity newDir; - double speed; - short neighbor[kMaxNeighbors]; - double neighborDistSqr[kMaxNeighbors]; +typedef struct _Boid +{ + Point3d oldPos; + Point3d 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; - Point3d centerPt; - Point3d attractPt; - BoidPtr boid; - double d2r, r2d; +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; + Point3d centerPt; + Point3d attractPt; + BoidPtr boid; + double d2r, r2d; } t_boids, *FlockPtr; - -t_symbol *ps_nothing; +t_symbol *ps_nothing; void *boids3d_class; void *Flock_new(t_symbol *s, long argc, t_atom *argv); @@ -140,7 +144,9 @@ void Flock_resetBoids(t_boids *x); void InitFlock(t_boids *x); void FlightStep(t_boids *x); Point3d FindFlockCenter(t_boids *x); -float MatchAndAvoidNeighbors(t_boids *x, short theBoid, Velocity *matchNeighborVel, Velocity *avoidNeighborVel); +float MatchAndAvoidNeighbors(t_boids *x, short theBoid, + Velocity *matchNeighborVel, + Velocity *avoidNeighborVel); Velocity SeekPoint(t_boids *x, short theBoid, Point3d seekPt); Velocity AvoidWalls(t_boids *x, short theBoid); int InFront(BoidPtr theBoid, BoidPtr neighbor); @@ -150,807 +156,945 @@ double DistSqrToPt(Point3d firstPoint, Point3d secondPoint); void boids3d_setup(void) { - boids3d_class = class_new(gensym("boids3d"), (t_newmethod)Flock_new, - (t_method)Flock_free, sizeof(t_boids), 0, A_GIMME, 0); - class_addfloat(boids3d_class, (t_method) Flock_numBoids); - class_addbang(boids3d_class, (t_method) Flock_bang); - class_addmethod(boids3d_class, (t_method) Flock_numNeighbors, gensym("neighbors"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_numBoids, gensym("number"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_mode, gensym("mode"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_minSpeed, gensym("minspeed"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_maxSpeed, gensym("maxspeed"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_centerWeight, gensym("center"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_attractWeight, gensym("attract"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_matchWeight, gensym("match"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_avoidWeight, gensym("avoid"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_wallsWeight, gensym("repel"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_edgeDist, gensym("edgedist"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_speedupFactor, gensym("speed"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_inertiaFactor, gensym("inertia"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_accelFactor, gensym("accel"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_prefDist, gensym("prefdist"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_flyRect, gensym("flyrect"), A_GIMME, 0); - class_addmethod(boids3d_class, (t_method) Flock_attractPt, gensym("attractpt"), A_GIMME, 0); - class_addmethod(boids3d_class, (t_method) Flock_resetBoids, gensym("reset"), 0); - class_addmethod(boids3d_class, (t_method) Flock_reset, gensym("init"), 0); - class_addmethod(boids3d_class, (t_method) Flock_dump, gensym("dump"), 0); - - logpost(NULL, 4, "boids3d 2005-2006 a.sier / jasch © 1995-2003 eric l. singer "__DATE__" "__TIME__); - ps_nothing = gensym(""); + boids3d_class = + class_new(gensym("boids3d"), (t_newmethod)Flock_new, + (t_method)Flock_free, sizeof(t_boids), 0, A_GIMME, 0); + class_addfloat(boids3d_class, (t_method)Flock_numBoids); + class_addbang(boids3d_class, (t_method)Flock_bang); + class_addmethod(boids3d_class, (t_method)Flock_numNeighbors, + gensym("neighbors"), A_FLOAT, 0); + class_addmethod(boids3d_class, (t_method)Flock_numBoids, gensym("number"), + A_FLOAT, 0); + class_addmethod(boids3d_class, (t_method)Flock_mode, gensym("mode"), + A_FLOAT, 0); + class_addmethod(boids3d_class, (t_method)Flock_minSpeed, gensym("minspeed"), + A_FLOAT, 0); + class_addmethod(boids3d_class, (t_method)Flock_maxSpeed, gensym("maxspeed"), + A_FLOAT, 0); + class_addmethod(boids3d_class, (t_method)Flock_centerWeight, + gensym("center"), A_FLOAT, 0); + class_addmethod(boids3d_class, (t_method)Flock_attractWeight, + gensym("attract"), A_FLOAT, 0); + class_addmethod(boids3d_class, (t_method)Flock_matchWeight, gensym("match"), + A_FLOAT, 0); + class_addmethod(boids3d_class, (t_method)Flock_avoidWeight, gensym("avoid"), + A_FLOAT, 0); + class_addmethod(boids3d_class, (t_method)Flock_wallsWeight, gensym("repel"), + A_FLOAT, 0); + class_addmethod(boids3d_class, (t_method)Flock_edgeDist, gensym("edgedist"), + A_FLOAT, 0); + class_addmethod(boids3d_class, (t_method)Flock_speedupFactor, + gensym("speed"), A_FLOAT, 0); + class_addmethod(boids3d_class, (t_method)Flock_inertiaFactor, + gensym("inertia"), A_FLOAT, 0); + class_addmethod(boids3d_class, (t_method)Flock_accelFactor, gensym("accel"), + A_FLOAT, 0); + class_addmethod(boids3d_class, (t_method)Flock_prefDist, gensym("prefdist"), + A_FLOAT, 0); + class_addmethod(boids3d_class, (t_method)Flock_flyRect, gensym("flyrect"), + A_GIMME, 0); + class_addmethod(boids3d_class, (t_method)Flock_attractPt, + gensym("attractpt"), A_GIMME, 0); + class_addmethod(boids3d_class, (t_method)Flock_resetBoids, gensym("reset"), + 0); + class_addmethod(boids3d_class, (t_method)Flock_reset, gensym("init"), 0); + class_addmethod(boids3d_class, (t_method)Flock_dump, gensym("dump"), 0); + + logpost(NULL, 4, + "boids3d 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(boids3d_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); +{ + t_boids *x = (t_boids *)pd_new(boids3d_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); + free(x->boid); } void Flock_bang(t_boids *x) { - short i; - t_atom outlist[10]; - t_atom *out; - - double tempNew_x, tempNew_y, tempNew_z; - double tempOld_x, tempOld_y, tempOld_z; - double delta_x, delta_y, delta_z; - double azi, ele, speed; - - 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, 4, 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+4, x->boid[i].oldPos.x); - SETFLOAT(out+5, x->boid[i].oldPos.y); - SETFLOAT(out+6, x->boid[i].oldPos.z); - outlet_list(x->out1, 0L, 7, 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+4, tempOld_x); - SETFLOAT(out+5, tempOld_y); - SETFLOAT(out+6, tempOld_z); - SETFLOAT(out+7, speed); - SETFLOAT(out+8, azi); - SETFLOAT(out+9, ele); - outlet_list(x->out1, 0L, 10, out); - } - break; - } + short i; + t_atom outlist[10]; + t_atom *out; + + double tempNew_x, tempNew_y, tempNew_z; + double tempOld_x, tempOld_y, tempOld_z; + double delta_x, delta_y, delta_z; + double azi, ele, speed; + + 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, 4, 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 + 4, x->boid[i].oldPos.x); + SETFLOAT(out + 5, x->boid[i].oldPos.y); + SETFLOAT(out + 6, x->boid[i].oldPos.z); + outlet_list(x->out1, 0L, 7, 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 + 4, tempOld_x); + SETFLOAT(out + 5, tempOld_y); + SETFLOAT(out + 6, tempOld_z); + SETFLOAT(out + 7, speed); + SETFLOAT(out + 8, azi); + SETFLOAT(out + 9, ele); + outlet_list(x->out1, 0L, 10, 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"), 6, 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"), 3, 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); + 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"), 6, 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"), 3, 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); + long m = (long)arg; + x->mode = CLIP(m, 0, 2); } void Flock_numNeighbors(t_boids *x, t_float arg) { - x->numNeighbors = (long)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); + 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); + x->minSpeed = MAX(arg, 0.000001); } void Flock_maxSpeed(t_boids *x, t_float arg) { - x->maxSpeed = (double)arg; + x->maxSpeed = (double)arg; } void Flock_centerWeight(t_boids *x, t_float arg) { - x->centerWeight = (double)arg; + x->centerWeight = (double)arg; } void Flock_attractWeight(t_boids *x, t_float arg) { - x->attractWeight = (double)arg; + x->attractWeight = (double)arg; } void Flock_matchWeight(t_boids *x, t_float arg) { - x->matchWeight = (double)arg; + x->matchWeight = (double)arg; } void Flock_avoidWeight(t_boids *x, t_float arg) { - x->avoidWeight = (double)arg; + x->avoidWeight = (double)arg; } void Flock_wallsWeight(t_boids *x, t_float arg) { - x->wallsWeight = (double)arg; + x->wallsWeight = (double)arg; } void Flock_edgeDist(t_boids *x, t_float arg) { - x->edgeDist = (double)arg; + x->edgeDist = (double)arg; } void Flock_speedupFactor(t_boids *x, t_float arg) { - x->speedupFactor = (double)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; - } + 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; + x->accelFactor = (double)arg; } void Flock_prefDist(t_boids *x, t_float arg) { - x->prefDist = (double)arg; + x->prefDist = (double)arg; } void Flock_flyRect(t_boids *x, t_symbol *msg, short argc, t_atom *argv) { - double temp[6]; - short i; - if(argc == 6){ - for(i = 0; i < 6; 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{ - pd_error(x, "boids3d: flyrect needs 6 values"); - } + double temp[6]; + short i; + if (argc == 6) + { + for (i = 0; i < 6; 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 + { + pd_error(x, "boids3d: flyrect needs 6 values"); + } } void Flock_attractPt(t_boids *x, t_symbol *msg, short argc, t_atom *argv) { - double temp[3]; - short i; - if(argc == 3){ - for(i = 0; i < 3 ; 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{ - pd_error(x, "boids3d: attractPt needs 3 values"); - } + double temp[3]; + short i; + if (argc == 3) + { + for (i = 0; i < 3; 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 + { + pd_error(x, "boids3d: attractPt needs 3 values"); + } } void Flock_reset(t_boids *x) { - InitFlock(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; jboid[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; - } + 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); + 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); - - } + 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); + } } Point3d FindFlockCenter(t_boids *x) { - double totalH = 0, totalV = 0, totalD = 0; - Point3d centerPoint; - register 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); + double totalH = 0, totalV = 0, totalD = 0; + Point3d centerPoint; + register 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, Point3d 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 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) { - Point3d 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); + Point3d 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; - } - } + 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; - } - } + // 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; + return 1; } void NormalizeVelocity(Velocity *direction) { - float my_hypot; - - my_hypot = sqrt(direction->x * direction->x + direction->y * direction->y + direction->z * direction->z ); + float my_hypot; - if (my_hypot != 0.0) { - direction->x = direction->x / my_hypot; - direction->y = direction->y / my_hypot; - direction->z = direction->z / 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); + 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(Point3d firstPoint, Point3d 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); + 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); } From fd90b8ab84bc90db42775e2bd1c7f6ea07df2da9 Mon Sep 17 00:00:00 2001 From: fdch Date: Sat, 11 Apr 2026 17:34:01 +0200 Subject: [PATCH 03/19] rename variables following pd standard practice --- src/boids3d.c | 446 +++++++++++++++++++++++++------------------------- 1 file changed, 220 insertions(+), 226 deletions(-) diff --git a/src/boids3d.c b/src/boids3d.c index 6e4f2ed..ebdf59b 100644 --- a/src/boids3d.c +++ b/src/boids3d.c @@ -23,8 +23,6 @@ #include // constants -#define kAssistInlet 1 -#define kAssistOutlet 2 #define kMaxLong 0xFFFFFFFF #define kMaxNeighbors 4 @@ -56,46 +54,46 @@ const double kFlyRectFront = 1.0; const double kFlyRectBack = -1.0; // typedefs -typedef struct Velocity +typedef struct _velocity { double x; double y; double z; -} Velocity; +} t_velocity; -typedef struct Point3d +typedef struct _point { double x; double y; double z; -} Point3d; +} t_point; -typedef struct Box3D +typedef struct _box { double left, right; double top, bottom; double front, back; -} Box3D; +} t_box; -typedef struct _Boid +typedef struct _boid { - Point3d oldPos; - Point3d newPos; - Velocity oldDir; - Velocity newDir; + t_point oldPos; + t_point newPos; + t_velocity oldDir; + t_velocity newDir; double speed; short neighbor[kMaxNeighbors]; double neighborDistSqr[kMaxNeighbors]; -} t_one_boid, *BoidPtr; +} t_boid; -typedef struct _FlockObject +typedef struct _boids { t_object ob; void *out1, *out2; short mode; long numBoids; long numNeighbors; - Box3D flyRect; + t_box flyRect; double minSpeed; double maxSpeed; double centerWeight; @@ -109,117 +107,116 @@ typedef struct _FlockObject double accelFactor; double prefDist; double prefDistSqr; - Point3d centerPt; - Point3d attractPt; - BoidPtr boid; + t_point centerPt; + t_point attractPt; + t_boid *boid; double d2r, r2d; -} t_boids, *FlockPtr; - -t_symbol *ps_nothing; +} t_boids; void *boids3d_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); -Point3d FindFlockCenter(t_boids *x); -float MatchAndAvoidNeighbors(t_boids *x, short theBoid, - Velocity *matchNeighborVel, - Velocity *avoidNeighborVel); -Velocity SeekPoint(t_boids *x, short theBoid, Point3d 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(Point3d firstPoint, Point3d secondPoint); +void *boids_new(t_symbol *s, long argc, t_atom *argv); +void boids_free(t_boids *x); +void boids_bang(t_boids *x); +void boids_dump(t_boids *x); +void boids_mode(t_boids *x, t_float arg); +void boids_numNeighbors(t_boids *x, t_float arg); +void boids_numBoids(t_boids *x, t_float arg); +void boids_minSpeed(t_boids *x, t_float arg); +void boids_maxSpeed(t_boids *x, t_float arg); +void boids_centerWeight(t_boids *x, t_float arg); +void boids_attractWeight(t_boids *x, t_float arg); +void boids_matchWeight(t_boids *x, t_float arg); +void boids_avoidWeight(t_boids *x, t_float arg); +void boids_wallsWeight(t_boids *x, t_float arg); +void boids_edgeDist(t_boids *x, t_float arg); +void boids_speedupFactor(t_boids *x, t_float arg); +void boids_inertiaFactor(t_boids *x, t_float arg); +void boids_accelFactor(t_boids *x, t_float arg); +void boids_prefDist(t_boids *x, t_float arg); +void boids_flyRect(t_boids *x, t_symbol *msg, short argc, t_atom *argv); +void boids_attractPt(t_boids *x, t_symbol *msg, short argc, t_atom *argv); +void boids_reset(t_boids *x); +void boids_resetBoids(t_boids *x); +void boids_init(t_boids *x); +void boids_flightStep(t_boids *x); + +t_point boids_findFlockCenter(t_boids *x); +t_float boids_matchAndAvoidNeighbors(t_boids *x, short boid, + t_velocity *matchNeighborVel, + t_velocity *avoidNeighborVel); +t_velocity boids_seekPoint(t_boids *x, short boid, t_point seekPt); +t_velocity boids_avoidWalls(t_boids *x, short boid); +t_int boids_inFront(t_boid *boid, t_boid *neighbor); + +static void velocity_normalize(t_velocity *direction); +static double random_integer(double minRange, double maxRange); +static double point_squareDistance(t_point firstPoint, t_point secondPoint); void boids3d_setup(void) { boids3d_class = - class_new(gensym("boids3d"), (t_newmethod)Flock_new, - (t_method)Flock_free, sizeof(t_boids), 0, A_GIMME, 0); - class_addfloat(boids3d_class, (t_method)Flock_numBoids); - class_addbang(boids3d_class, (t_method)Flock_bang); - class_addmethod(boids3d_class, (t_method)Flock_numNeighbors, + class_new(gensym("boids3d"), (t_newmethod)boids_new, + (t_method)boids_free, sizeof(t_boids), 0, A_GIMME, 0); + class_addfloat(boids3d_class, (t_method)boids_numBoids); + class_addbang(boids3d_class, (t_method)boids_bang); + class_addmethod(boids3d_class, (t_method)boids_numNeighbors, gensym("neighbors"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)Flock_numBoids, gensym("number"), + class_addmethod(boids3d_class, (t_method)boids_numBoids, gensym("number"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)Flock_mode, gensym("mode"), + class_addmethod(boids3d_class, (t_method)boids_mode, gensym("mode"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)Flock_minSpeed, gensym("minspeed"), + class_addmethod(boids3d_class, (t_method)boids_minSpeed, gensym("minspeed"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)Flock_maxSpeed, gensym("maxspeed"), + class_addmethod(boids3d_class, (t_method)boids_maxSpeed, gensym("maxspeed"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)Flock_centerWeight, + class_addmethod(boids3d_class, (t_method)boids_centerWeight, gensym("center"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)Flock_attractWeight, + class_addmethod(boids3d_class, (t_method)boids_attractWeight, gensym("attract"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)Flock_matchWeight, gensym("match"), + class_addmethod(boids3d_class, (t_method)boids_matchWeight, gensym("match"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)Flock_avoidWeight, gensym("avoid"), + class_addmethod(boids3d_class, (t_method)boids_avoidWeight, gensym("avoid"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)Flock_wallsWeight, gensym("repel"), + class_addmethod(boids3d_class, (t_method)boids_wallsWeight, gensym("repel"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)Flock_edgeDist, gensym("edgedist"), + class_addmethod(boids3d_class, (t_method)boids_edgeDist, gensym("edgedist"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)Flock_speedupFactor, + class_addmethod(boids3d_class, (t_method)boids_speedupFactor, gensym("speed"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)Flock_inertiaFactor, + class_addmethod(boids3d_class, (t_method)boids_inertiaFactor, gensym("inertia"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)Flock_accelFactor, gensym("accel"), + class_addmethod(boids3d_class, (t_method)boids_accelFactor, gensym("accel"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)Flock_prefDist, gensym("prefdist"), + class_addmethod(boids3d_class, (t_method)boids_prefDist, gensym("prefdist"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)Flock_flyRect, gensym("flyrect"), + class_addmethod(boids3d_class, (t_method)boids_flyRect, gensym("flyrect"), A_GIMME, 0); - class_addmethod(boids3d_class, (t_method)Flock_attractPt, + class_addmethod(boids3d_class, (t_method)boids_attractPt, gensym("attractpt"), A_GIMME, 0); - class_addmethod(boids3d_class, (t_method)Flock_resetBoids, gensym("reset"), + class_addmethod(boids3d_class, (t_method)boids_resetBoids, gensym("reset"), 0); - class_addmethod(boids3d_class, (t_method)Flock_reset, gensym("init"), 0); - class_addmethod(boids3d_class, (t_method)Flock_dump, gensym("dump"), 0); + class_addmethod(boids3d_class, (t_method)boids_reset, gensym("init"), 0); + class_addmethod(boids3d_class, (t_method)boids_dump, gensym("dump"), 0); logpost(NULL, 4, "boids3d 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) +void *boids_new(t_symbol *s, long argc, t_atom *argv) { t_boids *x = (t_boids *)pd_new(boids3d_class); x->out1 = outlet_new(&x->ob, NULL); x->out2 = outlet_new(&x->ob, NULL); - x->numBoids = 16; + x->numBoids = kNumBoids; 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); + x->boid = (t_boid *)malloc(sizeof(t_boid) * x->numBoids); - InitFlock(x); + boids_init(x); x->mode = 0; if ((argc >= 2) && (argv[1].a_type == A_FLOAT)) @@ -237,12 +234,12 @@ void *Flock_new(t_symbol *s, long argc, t_atom *argv) return (x); } -void Flock_free(t_boids *x) +void boids_free(t_boids *x) { free(x->boid); } -void Flock_bang(t_boids *x) +void boids_bang(t_boids *x) { short i; t_atom outlist[10]; @@ -255,7 +252,7 @@ void Flock_bang(t_boids *x) out = outlist; - FlightStep(x); + boids_flightStep(x); switch (x->mode) { // newpos @@ -314,7 +311,7 @@ void Flock_bang(t_boids *x) } } -void Flock_dump(t_boids *x) +void boids_dump(t_boids *x) { t_atom outList[6]; @@ -401,70 +398,70 @@ void Flock_dump(t_boids *x) outlet_anything(x->out2, gensym("number"), 1, outList); } -void Flock_mode(t_boids *x, t_float arg) +void boids_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) +void boids_numNeighbors(t_boids *x, t_float arg) { x->numNeighbors = (long)arg; } -void Flock_numBoids(t_boids *x, t_float arg) +void boids_numBoids(t_boids *x, t_float arg) { - x->boid = (t_one_boid *)realloc(x->boid, sizeof(t_one_boid) * (long)arg); + x->boid = (t_boid *)realloc(x->boid, sizeof(t_boid) * (long)arg); x->numBoids = (long)arg; - Flock_resetBoids(x); + boids_resetBoids(x); } -void Flock_minSpeed(t_boids *x, t_float arg) +void boids_minSpeed(t_boids *x, t_float arg) { x->minSpeed = MAX(arg, 0.000001); } -void Flock_maxSpeed(t_boids *x, t_float arg) +void boids_maxSpeed(t_boids *x, t_float arg) { x->maxSpeed = (double)arg; } -void Flock_centerWeight(t_boids *x, t_float arg) +void boids_centerWeight(t_boids *x, t_float arg) { x->centerWeight = (double)arg; } -void Flock_attractWeight(t_boids *x, t_float arg) +void boids_attractWeight(t_boids *x, t_float arg) { x->attractWeight = (double)arg; } -void Flock_matchWeight(t_boids *x, t_float arg) +void boids_matchWeight(t_boids *x, t_float arg) { x->matchWeight = (double)arg; } -void Flock_avoidWeight(t_boids *x, t_float arg) +void boids_avoidWeight(t_boids *x, t_float arg) { x->avoidWeight = (double)arg; } -void Flock_wallsWeight(t_boids *x, t_float arg) +void boids_wallsWeight(t_boids *x, t_float arg) { x->wallsWeight = (double)arg; } -void Flock_edgeDist(t_boids *x, t_float arg) +void boids_edgeDist(t_boids *x, t_float arg) { x->edgeDist = (double)arg; } -void Flock_speedupFactor(t_boids *x, t_float arg) +void boids_speedupFactor(t_boids *x, t_float arg) { x->speedupFactor = (double)arg; } -void Flock_inertiaFactor(t_boids *x, t_float arg) +void boids_inertiaFactor(t_boids *x, t_float arg) { if (arg == 0) { @@ -476,17 +473,17 @@ void Flock_inertiaFactor(t_boids *x, t_float arg) } } -void Flock_accelFactor(t_boids *x, t_float arg) +void boids_accelFactor(t_boids *x, t_float arg) { x->accelFactor = (double)arg; } -void Flock_prefDist(t_boids *x, t_float arg) +void boids_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) +void boids_flyRect(t_boids *x, t_symbol *msg, short argc, t_atom *argv) { double temp[6]; short i; @@ -512,7 +509,7 @@ 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 boids_attractPt(t_boids *x, t_symbol *msg, short argc, t_atom *argv) { double temp[3]; short i; @@ -535,12 +532,12 @@ void Flock_attractPt(t_boids *x, t_symbol *msg, short argc, t_atom *argv) } } -void Flock_reset(t_boids *x) +void boids_reset(t_boids *x) { - InitFlock(x); + boids_init(x); } -void Flock_resetBoids(t_boids *x) +void boids_resetBoids(t_boids *x) { long i, j; double rndAngle; @@ -573,14 +570,15 @@ void Flock_resetBoids(t_boids *x) } 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.x = x->boid[i].oldPos.x = random_integer( + 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); + random_integer(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 + random_integer(x->flyRect.back, x->flyRect.front); + rndAngle = + random_integer(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; @@ -588,7 +586,7 @@ void Flock_resetBoids(t_boids *x) } } -void InitFlock(t_boids *x) +void boids_init(t_boids *x) { x->numNeighbors = kNumNeighbors; x->minSpeed = kMinSpeed; @@ -613,21 +611,21 @@ void InitFlock(t_boids *x) x->attractPt.x = (kFlyRectLeft + kFlyRectRight) * 0.5; x->attractPt.y = (kFlyRectTop + kFlyRectBottom) * 0.5; x->attractPt.z = (kFlyRectFront + kFlyRectBack) * 0.5; - Flock_resetBoids(x); + boids_resetBoids(x); } -void FlightStep(t_boids *x) +void boids_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}; + t_velocity goCenterVel; + t_velocity goAttractVel; + t_velocity matchNeighborVel; + t_velocity avoidWallsVel; + t_velocity avoidNeighborVel; + t_float avoidNeighborSpeed; + const t_velocity zeroVel = {0.0, 0.0, 0.0}; short i; - x->centerPt = FindFlockCenter(x); + x->centerPt = boids_findFlockCenter(x); for (i = 0; i < x->numBoids; i++) { // save position and velocity x->boid[i].oldPos.x = x->boid[i].newPos.x; @@ -642,8 +640,8 @@ void FlightStep(t_boids *x) { if (x->numNeighbors > 0) { // get all velocity components - avoidNeighborSpeed = MatchAndAvoidNeighbors(x, i, &matchNeighborVel, - &avoidNeighborVel); + avoidNeighborSpeed = boids_matchAndAvoidNeighbors( + x, i, &matchNeighborVel, &avoidNeighborVel); } else { @@ -651,9 +649,9 @@ void FlightStep(t_boids *x) avoidNeighborVel = zeroVel; avoidNeighborSpeed = 0; } - goCenterVel = SeekPoint(x, i, x->centerPt); - goAttractVel = SeekPoint(x, i, x->attractPt); - avoidWallsVel = AvoidWalls(x, i); + goCenterVel = boids_seekPoint(x, i, x->centerPt); + goAttractVel = boids_seekPoint(x, i, x->attractPt); + avoidWallsVel = boids_avoidWalls(x, i); // compute resultant velocity using weights and inertia x->boid[i].newDir.x = x->inertiaFactor * (x->boid[i].oldDir.x) + @@ -677,7 +675,7 @@ void FlightStep(t_boids *x) x->avoidWeight * avoidNeighborVel.z + x->wallsWeight * avoidWallsVel.z) / x->inertiaFactor; - NormalizeVelocity( + velocity_normalize( &(x->boid[i].newDir)); // normalize velocity so its length is unity // set to avoidNeighborSpeed bounded by minSpeed and maxSpeed @@ -699,10 +697,10 @@ void FlightStep(t_boids *x) } } -Point3d FindFlockCenter(t_boids *x) +t_point boids_findFlockCenter(t_boids *x) { double totalH = 0, totalV = 0, totalD = 0; - Point3d centerPoint; + t_point centerPoint; register short i; for (i = 0; i < x->numBoids; i++) @@ -718,16 +716,16 @@ Point3d FindFlockCenter(t_boids *x) return (centerPoint); } -float MatchAndAvoidNeighbors(t_boids *x, short theBoid, - Velocity *matchNeighborVel, - Velocity *avoidNeighborVel) +t_float boids_matchAndAvoidNeighbors(t_boids *x, short boid, + t_velocity *matchNeighborVel, + t_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}; + t_velocity totalVel = {0.0, 0.0, 0.0}; /**********************/ /* Find the neighbors */ @@ -736,21 +734,21 @@ float MatchAndAvoidNeighbors(t_boids *x, short theBoid, /* special case of one neighbor */ if (x->numNeighbors == 1) { - x->boid[theBoid].neighborDistSqr[0] = kMaxLong; + x->boid[boid].neighborDistSqr[0] = kMaxLong; for (i = 0; i < x->numBoids; i++) { - if (i != theBoid) + if (i != boid) { - distSqr = - DistSqrToPt(x->boid[theBoid].oldPos, x->boid[i].oldPos); + distSqr = point_squareDistance(x->boid[boid].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) + if (x->boid[boid].neighborDistSqr[0] > distSqr) { - x->boid[theBoid].neighborDistSqr[0] = distSqr; - x->boid[theBoid].neighbor[0] = i; + x->boid[boid].neighborDistSqr[0] = distSqr; + x->boid[boid].neighbor[0] = i; } } } @@ -759,37 +757,36 @@ float MatchAndAvoidNeighbors(t_boids *x, short theBoid, else { for (j = 0; j < x->numNeighbors; j++) - x->boid[theBoid].neighborDistSqr[j] = kMaxLong; + x->boid[boid].neighborDistSqr[j] = kMaxLong; for (i = 0; i < x->numBoids; i++) { /* if this one is not me... */ - if (i != theBoid) + if (i != boid) { - distSqr = - DistSqrToPt(x->boid[theBoid].oldPos, x->boid[i].oldPos); + distSqr = point_squareDistance(x->boid[boid].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]) + x->boid[boid].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)) + while ((distSqr < x->boid[boid].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]; + x->boid[boid].neighborDistSqr[j] = + x->boid[boid].neighborDistSqr[j - 1]; + x->boid[boid].neighbor[j] = + x->boid[boid].neighbor[j - 1]; j--; } - x->boid[theBoid].neighborDistSqr[j] = distSqr; - x->boid[theBoid].neighbor[j] = i; + x->boid[boid].neighborDistSqr[j] = distSqr; + x->boid[boid].neighbor[j] = i; } } } @@ -804,11 +801,11 @@ float MatchAndAvoidNeighbors(t_boids *x, short theBoid, matchNeighborVel->z = 0; // set tempSpeed to old speed - tempSpeed = x->boid[theBoid].speed; + tempSpeed = x->boid[boid].speed; for (i = 0; i < x->numNeighbors; i++) { - neighbor = x->boid[theBoid].neighbor[i]; + neighbor = x->boid[boid].neighbor[i]; // calculate matchNeighborVel by averaging the neighbor velocities matchNeighborVel->x += x->boid[neighbor].oldDir.x; @@ -817,27 +814,27 @@ float MatchAndAvoidNeighbors(t_boids *x, short theBoid, // if distance is less than preferred distance, then neighbor influences // boid - distSqr = x->boid[theBoid].neighborDistSqr[i]; + distSqr = x->boid[boid].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; + distH = x->boid[neighbor].oldPos.x - x->boid[boid].oldPos.x; + distV = x->boid[neighbor].oldPos.y - x->boid[boid].oldPos.y; + distD = x->boid[neighbor].oldPos.z - x->boid[boid].oldPos.z; if (dist == 0.0) dist = 0.0000001; totalVel.x = - totalVel.x - distH - (distH * ((float)x->prefDist / (dist))); + totalVel.x - distH - (distH * ((t_float)x->prefDist / (dist))); totalVel.y = - totalVel.y - distV - (distV * ((float)x->prefDist / (dist))); + totalVel.y - distV - (distV * ((t_float)x->prefDist / (dist))); totalVel.z = - totalVel.z - distD - (distV * ((float)x->prefDist / (dist))); + totalVel.z - distD - (distV * ((t_float)x->prefDist / (dist))); numClose++; } - if (InFront(&(x->boid[theBoid]), &(x->boid[neighbor]))) + if (boids_inFront(&(x->boid[boid]), &(x->boid[neighbor]))) { // adjust speed if (distSqr < x->prefDistSqr) tempSpeed /= (x->accelFactor / 100.0); @@ -857,7 +854,7 @@ float MatchAndAvoidNeighbors(t_boids *x, short theBoid, avoidNeighborVel->x = totalVel.x / numClose; avoidNeighborVel->y = totalVel.y / numClose; avoidNeighborVel->z = totalVel.z / numClose; - NormalizeVelocity(matchNeighborVel); + velocity_normalize(matchNeighborVel); } else { @@ -868,87 +865,84 @@ float MatchAndAvoidNeighbors(t_boids *x, short theBoid, return (tempSpeed); } -Velocity SeekPoint(t_boids *x, short theBoid, Point3d seekPt) +t_velocity boids_seekPoint(t_boids *x, short boid, t_point 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); + t_velocity tempDir; + tempDir.x = seekPt.x - x->boid[boid].oldPos.x; + tempDir.y = seekPt.y - x->boid[boid].oldPos.y; + tempDir.z = seekPt.z - x->boid[boid].oldPos.z; + velocity_normalize(&tempDir); return (tempDir); } -Velocity AvoidWalls(t_boids *x, short theBoid) +t_velocity boids_avoidWalls(t_boids *x, short boid) { - Point3d testPoint; - Velocity tempVel = {0.0, 0.0, 0.0}; + t_point testPoint; + t_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; + testPoint.x = x->boid[boid].oldPos.x + + x->boid[boid].oldDir.x * x->boid[boid].speed * x->edgeDist; + testPoint.y = x->boid[boid].oldPos.y + + x->boid[boid].oldDir.y * x->boid[boid].speed * x->edgeDist; + testPoint.z = x->boid[boid].oldPos.z + + x->boid[boid].oldDir.z * x->boid[boid].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); + tempVel.x = fabs(x->boid[boid].oldDir.x); else if (testPoint.x > x->flyRect.right) - tempVel.x = -fabs(x->boid[theBoid].oldDir.x); + tempVel.x = -fabs(x->boid[boid].oldDir.x); /* same with top and bottom */ if (testPoint.y < x->flyRect.top) - tempVel.y = fabs(x->boid[theBoid].oldDir.y); + tempVel.y = fabs(x->boid[boid].oldDir.y); else if (testPoint.y > x->flyRect.bottom) - tempVel.y = -fabs(x->boid[theBoid].oldDir.y); + tempVel.y = -fabs(x->boid[boid].oldDir.y); /* same with front and back */ if (testPoint.z < x->flyRect.front) - tempVel.z = fabs(x->boid[theBoid].oldDir.z); + tempVel.z = fabs(x->boid[boid].oldDir.z); else if (testPoint.z > x->flyRect.back) - tempVel.z = -fabs(x->boid[theBoid].oldDir.z); + tempVel.z = -fabs(x->boid[boid].oldDir.z); return (tempVel); } -int InFront(BoidPtr theBoid, BoidPtr neighbor) +t_int boids_inFront(t_boid *boid, t_boid *neighbor) { - float grad, intercept; + t_float grad, intercept; int result; /* - Find the gradient and y-intercept of a line passing through theBoid's oldPos + Find the gradient and y-intercept of a line passing through boid'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 + boid if it is to the right or left of this linedepending on whether + boid is moving right or left. However, if boid is travelling vertically then just compare their vertical coordinates. */ // xy plane - // if theBoid is not travelling vertically... - if (theBoid->oldDir.x != 0) + // if boid is not travelling vertically... + if (boid->oldDir.x != 0) { // calculate gradient of a line _perpendicular_ to its direction (hence // the minus) - grad = -theBoid->oldDir.y / theBoid->oldDir.x; + grad = -boid->oldDir.y / boid->oldDir.x; // calculate where this line hits the y axis (from y = mx + c) - intercept = theBoid->oldPos.y - (grad * theBoid->oldPos.x); + intercept = boid->oldPos.y - (grad * boid->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); + result = (boid->oldDir.x > 0); if (result == 0) return 0; @@ -958,19 +952,19 @@ int InFront(BoidPtr theBoid, BoidPtr neighbor) else { /* return true if the first boid's horizontal movement is +ve */ - result = (theBoid->oldDir.x < 0); + result = (boid->oldDir.x < 0); if (result == 0) return 0; else goto next; } } - /* else theBoid is travelling vertically, so just compare vertical + /* else boid is travelling vertically, so just compare vertical * coordinates */ - else if (theBoid->oldDir.y > 0) + else if (boid->oldDir.y > 0) { - result = (neighbor->oldPos.y > theBoid->oldPos.y); + result = (neighbor->oldPos.y > boid->oldPos.y); if (result == 0) { return 0; @@ -982,7 +976,7 @@ int InFront(BoidPtr theBoid, BoidPtr neighbor) } else { - result = (neighbor->oldPos.y < theBoid->oldPos.y); + result = (neighbor->oldPos.y < boid->oldPos.y); if (result == 0) { return 0; @@ -995,22 +989,22 @@ int InFront(BoidPtr theBoid, BoidPtr neighbor) next: // yz plane - // if theBoid is not travelling vertically... - if (theBoid->oldDir.y != 0) + // if boid is not travelling vertically... + if (boid->oldDir.y != 0) { // calculate gradient of a line _perpendicular_ to its direction (hence // the minus) - grad = -theBoid->oldDir.z / theBoid->oldDir.y; + grad = -boid->oldDir.z / boid->oldDir.y; // calculate where this line hits the y axis (from y = mx + c) - intercept = theBoid->oldPos.z - (grad * theBoid->oldPos.y); + intercept = boid->oldPos.z - (grad * boid->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); + result = (boid->oldDir.y > 0); if (result == 0) { return 0; @@ -1023,7 +1017,7 @@ int InFront(BoidPtr theBoid, BoidPtr neighbor) else { // return true if the first boid's horizontal movement is +ve - result = (theBoid->oldDir.y < 0); + result = (boid->oldDir.y < 0); if (result == 0) { return 0; @@ -1034,11 +1028,11 @@ int InFront(BoidPtr theBoid, BoidPtr neighbor) } } } - // else theBoid is travelling vertically, so just compare vertical + // else boid is travelling vertically, so just compare vertical // coordinates - else if (theBoid->oldDir.z > 0) + else if (boid->oldDir.z > 0) { - result = (neighbor->oldPos.z > theBoid->oldPos.z); + result = (neighbor->oldPos.z > boid->oldPos.z); if (result == 0) { return 0; @@ -1050,7 +1044,7 @@ int InFront(BoidPtr theBoid, BoidPtr neighbor) } else { - result = (neighbor->oldPos.z < theBoid->oldPos.z); + result = (neighbor->oldPos.z < boid->oldPos.z); if (result == 0) { return 0; @@ -1064,9 +1058,9 @@ int InFront(BoidPtr theBoid, BoidPtr neighbor) return 1; } -void NormalizeVelocity(Velocity *direction) +static void velocity_normalize(t_velocity *direction) { - float my_hypot; + t_float my_hypot; my_hypot = sqrt(direction->x * direction->x + direction->y * direction->y + direction->z * direction->z); @@ -1079,7 +1073,7 @@ void NormalizeVelocity(Velocity *direction) } } -double RandomInt(double minRange, double maxRange) +static double random_integer(double minRange, double maxRange) { unsigned short qdRdm; double t, result; @@ -1090,7 +1084,7 @@ double RandomInt(double minRange, double maxRange) return (result); } -double DistSqrToPt(Point3d firstPoint, Point3d secondPoint) +static double point_squareDistance(t_point firstPoint, t_point secondPoint) { double a, b, c; a = firstPoint.x - secondPoint.x; From b0053de9aef98ee3d57fa8cd74d13393c7602b11 Mon Sep 17 00:00:00 2001 From: fdch Date: Mon, 13 Apr 2026 14:56:23 +0200 Subject: [PATCH 04/19] begin class restructuring --- Makefile | 3 +- src/boids.c | 1074 +++++++++++++++++++++++++++++++++++++++++++ src/boids.h | 119 +++++ src/boids2d.c | 1083 ------------------------------------------- src/boids3d.c | 1094 -------------------------------------------- tests/load-test.pd | 19 + 6 files changed, 1213 insertions(+), 2179 deletions(-) create mode 100644 src/boids.c create mode 100644 src/boids.h delete mode 100644 src/boids2d.c delete mode 100644 src/boids3d.c create mode 100644 tests/load-test.pd diff --git a/Makefile b/Makefile index cd4f469..44c8359 100644 --- a/Makefile +++ b/Makefile @@ -7,8 +7,7 @@ lib.name = boids # input source file (class name == source file basename) class.sources = \ - src/boids2d.c \ - src/boids3d.c \ + src/boids.c \ $(empty) # all extra files to be included in binary distribution of the library diff --git a/src/boids.c b/src/boids.c new file mode 100644 index 0000000..b94f02e --- /dev/null +++ b/src/boids.c @@ -0,0 +1,1074 @@ +/* + + boids3d 2005 - 2006 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 "boids.h" +#include "m_pd.h" +#include +#include + +static void *boids3d_class, *boids2d_class; + +/* forward declarations */ +static void boids_free(t_boids *x); +static void boids_alloc(t_boids *x, size_t numBoids); +static void boids_bang(t_boids *x); +static void boids_dump(t_boids *x); +static void boids_mode(t_boids *x, t_floatarg f); +static void boids_numNeighbors(t_boids *x, t_floatarg f); +static void boids_float(t_boids *x, t_floatarg arg); +static void boids_minSpeed(t_boids *x, t_floatarg f); +static void boids_maxSpeed(t_boids *x, t_floatarg f); +static void boids_centerWeight(t_boids *x, t_floatarg f); +static void boids_attractWeight(t_boids *x, t_floatarg f); +static void boids_matchWeight(t_boids *x, t_floatarg f); +static void boids_avoidWeight(t_boids *x, t_floatarg f); +static void boids_wallsWeight(t_boids *x, t_floatarg f); +static void boids_edgeDist(t_boids *x, t_floatarg f); +static void boids_speedupFactor(t_boids *x, t_floatarg f); +static void boids_inertiaFactor(t_boids *x, t_floatarg f); +static void boids_accelFactor(t_boids *x, t_floatarg f); +static void boids_prefDist(t_boids *x, t_floatarg f); +static void boids_flyRect(t_boids *x, t_symbol *s, int argc, t_atom *argv); +static void boids_attractPt(t_boids *x, t_symbol *s, int argc, t_atom *argv); +static void boids_reset(t_boids *x); +static void boids_resetBoids(t_boids *x); +static void boids_init(t_boids *x); +static void boids_step(t_boids *x); +static t_point boids_findFlockCenter(t_boids *x); +static t_float boids_matchAndAvoidNeighbors(t_boids *x, size_t boid, + t_velocity *matchNeighborVel, + t_velocity *avoidNeighborVel); +static t_velocity boids_seekPoint(t_boids *x, size_t boid, t_point seekPt); +static t_velocity boids_avoidWalls(t_boids *x, size_t boid); + +static t_int boids_inFront(t_boid *boid, t_boid *neighbor); + +static void velocity_normalize(t_velocity *direction); +static void boid_alloc(t_boid *x); +static void boid_free(t_boid *x); +static t_float random_integer(t_float minRange, t_float maxRange); +static t_float point_squareDistance(t_point firstPoint, t_point secondPoint); + +/* --------------------------- boids methods ------------------------------ */ + +static void boids_bang(t_boids *x) +{ + t_atom outlist[10]; + t_atom *out; + + t_float tempNew_x, tempNew_y, tempNew_z; + t_float tempOld_x, tempOld_y, tempOld_z; + t_float delta_x, delta_y, delta_z; + t_float azi, ele, speed; + + out = outlist; + + boids_step(x); + + switch (x->mode) + { // newpos + case BOID_NEWPOS: + for (size_t i = 0; i < x->x_numBoids; i++) + { + SETFLOAT(out + 0, i); + SETFLOAT(out + 1, x->x_boid[i].newPos.x); + SETFLOAT(out + 2, x->x_boid[i].newPos.y); + if (!x->x_z) + outlet_list(x->x_out1, gensym("list"), 3, out); + else + { + SETFLOAT(out + 3, x->x_boid[i].newPos.z); + outlet_list(x->x_out1, gensym("list"), 4, out); + } + } + break; + case BOID_NEWOLD: // newpos + oldpos + for (size_t i = 0; i < x->x_numBoids; i++) + { + SETFLOAT(out + 0, i); + if (!x->x_z) + { + SETFLOAT(out + 1, x->x_boid[i].newPos.x); + SETFLOAT(out + 2, x->x_boid[i].newPos.y); + SETFLOAT(out + 3, x->x_boid[i].oldPos.x); + SETFLOAT(out + 4, x->x_boid[i].oldPos.y); + outlet_list(x->x_out1, gensym("list"), 5, out); + } + else + { + SETFLOAT(out + 1, x->x_boid[i].newPos.x); + SETFLOAT(out + 2, x->x_boid[i].newPos.y); + SETFLOAT(out + 3, x->x_boid[i].newPos.z); + SETFLOAT(out + 4, x->x_boid[i].oldPos.x); + SETFLOAT(out + 5, x->x_boid[i].oldPos.y); + SETFLOAT(out + 6, x->x_boid[i].oldPos.z); + outlet_list(x->x_out1, gensym("list"), 7, out); + } + } + break; + case BOID_ALL: + for (size_t i = 0; i < x->x_numBoids; i++) + { + tempNew_x = x->x_boid[i].newPos.x; + tempNew_y = x->x_boid[i].newPos.y; + tempOld_x = x->x_boid[i].oldPos.x; + tempOld_y = x->x_boid[i].oldPos.y; + delta_x = tempNew_x - tempOld_x; + delta_y = tempNew_y - tempOld_y; + + if (!x->x_z) + delta_z = 0.0; + else + { + tempNew_z = x->x_boid[i].newPos.z; + tempOld_z = x->x_boid[i].oldPos.z; + delta_z = tempNew_z - tempOld_z; + } + + azi = atan2(delta_y, delta_x) * R2D; + ele = atan2(delta_y, delta_x) * R2D; + speed = + sqrt(delta_x * delta_x + delta_y * delta_y + delta_z * delta_z); + SETFLOAT(out + 0, i); + if (!x->x_z) + { + SETFLOAT(out + 1, tempNew_x); + SETFLOAT(out + 2, tempNew_y); + SETFLOAT(out + 3, tempOld_x); + SETFLOAT(out + 4, tempOld_y); + SETFLOAT(out + 5, speed); + SETFLOAT(out + 6, azi); + SETFLOAT(out + 7, ele); + outlet_list(x->x_out1, gensym("list"), 8, out); + } + else + { + SETFLOAT(out + 1, tempNew_x); + SETFLOAT(out + 2, tempNew_y); + SETFLOAT(out + 3, tempNew_z); + SETFLOAT(out + 4, tempOld_x); + SETFLOAT(out + 5, tempOld_y); + SETFLOAT(out + 6, tempOld_z); + SETFLOAT(out + 7, speed); + SETFLOAT(out + 8, azi); + SETFLOAT(out + 9, ele); + outlet_list(x->x_out1, gensym("list"), 10, out); + } + } + break; + } +} + +static void boids_dump(t_boids *x) +{ + t_atom outList[6]; + + SETFLOAT(outList, x->x_numNeighbors); + outlet_anything(x->x_out2, gensym("neighbors"), 1, outList); + + SETFLOAT(outList, x->minSpeed); + outlet_anything(x->x_out2, gensym("minspeed"), 1, outList); + + SETFLOAT(outList, x->maxSpeed); + outlet_anything(x->x_out2, gensym("maxspeed"), 1, outList); + + SETFLOAT(outList, x->centerWeight); + outlet_anything(x->x_out2, gensym("center"), 1, outList); + + SETFLOAT(outList, x->attractWeight); + outlet_anything(x->x_out2, gensym("attract"), 1, outList); + + SETFLOAT(outList, x->matchWeight); + outlet_anything(x->x_out2, gensym("match"), 1, outList); + + SETFLOAT(outList, x->avoidWeight); + outlet_anything(x->x_out2, gensym("avoid"), 1, outList); + + SETFLOAT(outList, x->wallsWeight); + outlet_anything(x->x_out2, gensym("repel"), 1, outList); + + SETFLOAT(outList, x->edgeDist); + outlet_anything(x->x_out2, gensym("edgedist"), 1, outList); + + SETFLOAT(outList, x->speedupFactor); + outlet_anything(x->x_out2, gensym("speed"), 1, outList); + + SETFLOAT(outList, x->inertiaFactor); + outlet_anything(x->x_out2, gensym("inertia"), 1, outList); + + SETFLOAT(outList, x->accelFactor); + outlet_anything(x->x_out2, gensym("accel"), 1, outList); + + SETFLOAT(outList, x->prefDist); + outlet_anything(x->x_out2, gensym("prefdist"), 1, outList); + + SETFLOAT(outList + 0, x->flyRect.left); + SETFLOAT(outList + 1, x->flyRect.top); + SETFLOAT(outList + 2, x->flyRect.right); + SETFLOAT(outList + 3, x->flyRect.bottom); + if (!x->x_z) + outlet_anything(x->x_out2, gensym("flyrect"), 4, outList); + else + { + SETFLOAT(outList + 4, x->flyRect.front); + SETFLOAT(outList + 5, x->flyRect.back); + outlet_anything(x->x_out2, gensym("flyrect"), 6, outList); + } + + SETFLOAT(outList + 0, x->attractPt.x); + SETFLOAT(outList + 1, x->attractPt.y); + if (!x->x_z) + outlet_anything(x->x_out2, gensym("attractpt"), 2, outList); + else + { + SETFLOAT(outList + 2, x->attractPt.z); + outlet_anything(x->x_out2, gensym("attractpt"), 3, outList); + } + + SETFLOAT(outList, x->mode); + outlet_anything(x->x_out2, gensym("mode"), 1, outList); + + SETFLOAT(outList, x->x_numBoids); + outlet_anything(x->x_out2, gensym("number"), 1, outList); +} + +static void boids_mode(t_boids *x, t_floatarg f) +{ + const int m = (int)f; + x->mode = m < BOID_NEWPOS ? BOID_NEWPOS : BOID_ALL < m ? BOID_ALL : m; +} + +static void boids_numNeighbors(t_boids *x, t_floatarg f) +{ + x->x_numNeighbors = kMaxNeighbors < (size_t)f ? kMaxNeighbors : (size_t)f; + for (size_t i = 0; i < x->x_numNeighbors; i++) + { + x->x_boid[i].numNeighbors = x->x_numNeighbors; + boid_alloc(&x->x_boid[i]); + } +} + +static void boid_free(t_boid *x) +{ + if (x->neighbor) + { + freebytes(x->neighbor, sizeof(*x->neighbor) * x->numNeighbors); + x->neighbor = NULL; + } + + if (x->neighborDistSqr) + { + freebytes(x->neighborDistSqr, + sizeof(*x->neighborDistSqr) * x->numNeighbors); + x->neighborDistSqr = NULL; + } +} + +static void boid_alloc(t_boid *x) +{ + boid_free(x); + + x->neighbor = (size_t *)getbytes(sizeof(*x->neighbor) * x->numNeighbors); + x->neighborDistSqr = (t_float *)getbytes(sizeof(t_float) * x->numNeighbors); + + if (x->neighbor) + memset(x->neighbor, 0, sizeof(*x->neighbor) * x->numNeighbors); + + if (x->neighborDistSqr) + memset(x->neighborDistSqr, 0, + sizeof(*x->neighborDistSqr) * x->numNeighbors); +} + +static void boids_free(t_boids *x) +{ + if (!x->x_boid) + { + x->x_numBoids = 0; + return; + } + + for (size_t i = 0; i < x->x_numBoids; i++) + boid_free(&x->x_boid[i]); + + freebytes(x->x_boid, sizeof(t_boid) * x->x_numBoids); + x->x_boid = NULL; + x->x_numBoids = 0; +} + +static void boids_alloc(t_boids *x, size_t numBoids) +{ + boids_free(x); + + if (numBoids == 0) + return; + + x->x_boid = (t_boid *)getbytes(sizeof(*x->x_boid) * numBoids); + x->x_numBoids = numBoids; + + boids_resetBoids(x); +} + +static void boids_float(t_boids *x, t_floatarg fnumBoids) +{ + size_t numBoids = fnumBoids < 0.0 ? 0 : (size_t)fnumBoids; + if (x->x_numBoids == numBoids) + return; + boids_alloc(x, numBoids); +} + +static void boids_minSpeed(t_boids *x, t_floatarg f) +{ + x->minSpeed = f < 0.0 ? 0.000001 : f; +} + +static void boids_maxSpeed(t_boids *x, t_floatarg f) +{ + x->maxSpeed = f; +} + +static void boids_centerWeight(t_boids *x, t_floatarg f) +{ + x->centerWeight = f; +} + +static void boids_attractWeight(t_boids *x, t_floatarg f) +{ + x->attractWeight = f; +} + +static void boids_matchWeight(t_boids *x, t_floatarg f) +{ + x->matchWeight = f; +} + +static void boids_avoidWeight(t_boids *x, t_floatarg f) +{ + x->avoidWeight = f; +} + +static void boids_wallsWeight(t_boids *x, t_floatarg f) +{ + x->wallsWeight = f; +} + +static void boids_edgeDist(t_boids *x, t_floatarg f) +{ + x->edgeDist = f; +} + +static void boids_speedupFactor(t_boids *x, t_floatarg f) +{ + x->speedupFactor = f; +} + +static void boids_inertiaFactor(t_boids *x, t_floatarg f) +{ + x->inertiaFactor = f == 0.0 ? 0.000001 : f; +} + +static void boids_accelFactor(t_boids *x, t_floatarg f) +{ + x->accelFactor = f; +} + +static void boids_prefDist(t_boids *x, t_floatarg f) +{ + x->prefDist = f; +} + +static void boids_flyRect(t_boids *x, t_symbol *s, int argc, t_atom *argv) +{ + (void)s; + if (argc < 4) + return; + + if (argc == 4) + { + x->flyRect.left = atom_getfloat(argv + 0); + x->flyRect.top = atom_getfloat(argv + 1); + x->flyRect.right = atom_getfloat(argv + 2); + x->flyRect.bottom = atom_getfloat(argv + 3); + } + + if (argc == 6) + { + x->flyRect.front = atom_getfloat(argv + 5); + x->flyRect.back = atom_getfloat(argv + 6); + } +} + +static void boids_attractPt(t_boids *x, t_symbol *s, int argc, t_atom *argv) +{ + (void)s; + if (!argc || argc < 2) + return; + + x->attractPt.x = atom_getfloat(argv + 0); + x->attractPt.y = atom_getfloat(argv + 1); + if (argc == 3) + x->attractPt.z = atom_getfloat(argv + 2); +} + +static void boids_reset(t_boids *x) +{ + boids_init(x); +} + +static void boids_resetBoids(t_boids *x) +{ + t_float rndAngle; + + for (size_t i = 0; i < x->x_numBoids; i++) + { // init everything to 0.0 + x->x_boid[i].oldPos.x = 0.0; + x->x_boid[i].oldPos.y = 0.0; + x->x_boid[i].oldPos.z = 0.0; + + x->x_boid[i].newPos.x = 0.0; + x->x_boid[i].newPos.y = 0.0; + x->x_boid[i].newPos.z = 0.0; + + x->x_boid[i].oldDir.x = 0.0; + x->x_boid[i].oldDir.y = 0.0; + x->x_boid[i].oldDir.z = 0.0; + + x->x_boid[i].newDir.x = 0.0; + x->x_boid[i].newDir.y = 0.0; + x->x_boid[i].newDir.z = 0.0; + + x->x_boid[i].speed = 0.0; + + x->x_boid[i].numNeighbors = x->x_numNeighbors; + x->x_boid[i].x_z = x->x_z; + boid_alloc(&x->x_boid[i]); + } + for (size_t i = 0; i < x->x_numBoids; i++) + { // set the initial locations and velocities of the boids + x->x_boid[i].newPos.x = x->x_boid[i].oldPos.x = random_integer( + x->flyRect.right, + x->flyRect.left); // set random location within flyRect + x->x_boid[i].newPos.y = x->x_boid[i].oldPos.y = + random_integer(x->flyRect.bottom, x->flyRect.top); + x->x_boid[i].newPos.z = x->x_boid[i].oldPos.z = + random_integer(x->flyRect.back, x->flyRect.front); + rndAngle = + random_integer(0, 360) * D2R; // set velocity from random angle + x->x_boid[i].newDir.x = sin(rndAngle); + x->x_boid[i].newDir.y = cos(rndAngle); + x->x_boid[i].newDir.z = x->x_z * (cos(rndAngle) + sin(rndAngle)) * 0.5; + x->x_boid[i].speed = (kMaxSpeed + kMinSpeed) * 0.5; + } +} + +static void boids_init(t_boids *x) +{ + 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; + boids_resetBoids(x); +} + +static void boids_step(t_boids *x) +{ + t_velocity goCenterVel; + t_velocity goAttractVel; + t_velocity matchNeighborVel; + t_velocity avoidWallsVel; + t_velocity avoidNeighborVel; + t_float avoidNeighborSpeed; + const t_velocity zeroVel = {0.0, 0.0, 0.0}; + + x->centerPt = boids_findFlockCenter(x); + for (size_t i = 0; i < x->x_numBoids; i++) + { // save position and velocity + x->x_boid[i].oldPos.x = x->x_boid[i].newPos.x; + x->x_boid[i].oldPos.y = x->x_boid[i].newPos.y; + x->x_boid[i].oldPos.z = x->x_boid[i].newPos.z; + + x->x_boid[i].oldDir.x = x->x_boid[i].newDir.x; + x->x_boid[i].oldDir.y = x->x_boid[i].newDir.y; + x->x_boid[i].oldDir.z = x->x_boid[i].newDir.z; + } + + for (size_t i = 0; i < x->x_numBoids; i++) + { + if (x->x_numNeighbors > 0) + { // get all velocity components + avoidNeighborSpeed = boids_matchAndAvoidNeighbors( + x, i, &matchNeighborVel, &avoidNeighborVel); + } + else + { + matchNeighborVel = zeroVel; + avoidNeighborVel = zeroVel; + avoidNeighborSpeed = 0; + } + goCenterVel = boids_seekPoint(x, i, x->centerPt); + goAttractVel = boids_seekPoint(x, i, x->attractPt); + avoidWallsVel = boids_avoidWalls(x, i); + + // compute resultant velocity using weights and inertia + x->x_boid[i].newDir.x = x->inertiaFactor * (x->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->x_boid[i].newDir.y = x->inertiaFactor * (x->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->x_boid[i].newDir.z = x->inertiaFactor * (x->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; + // normalize velocity so its length is unity + velocity_normalize(&(x->x_boid[i].newDir)); + + // set to avoidNeighborSpeed bounded by minSpeed and maxSpeed + if ((avoidNeighborSpeed >= x->minSpeed) && + (avoidNeighborSpeed <= x->maxSpeed)) + x->x_boid[i].speed = avoidNeighborSpeed; + else if (avoidNeighborSpeed > x->maxSpeed) + x->x_boid[i].speed = x->maxSpeed; + else + x->x_boid[i].speed = x->minSpeed; + + // calculate new position, applying speedupFactor + x->x_boid[i].newPos.x += x->x_boid[i].newDir.x * x->x_boid[i].speed * + (x->speedupFactor / 100.0); + x->x_boid[i].newPos.y += x->x_boid[i].newDir.y * x->x_boid[i].speed * + (x->speedupFactor / 100.0); + x->x_boid[i].newPos.z += x->x_boid[i].newDir.z * x->x_boid[i].speed * + (x->speedupFactor / 100.0); + } +} + +static t_point boids_findFlockCenter(t_boids *x) +{ + t_float totalH = 0, totalV = 0, totalD = 0; + t_point centerPoint; + + for (size_t i = 0; i < x->x_numBoids; i++) + { + totalH += x->x_boid[i].oldPos.x; + totalV += x->x_boid[i].oldPos.y; + totalD += x->x_boid[i].oldPos.z; + } + centerPoint.x = (t_float)(totalH / x->x_numBoids); + centerPoint.y = (t_float)(totalV / x->x_numBoids); + centerPoint.z = (t_float)(totalD / x->x_numBoids); + + return centerPoint; +} + +static t_float boids_matchAndAvoidNeighbors(t_boids *x, size_t boid, + t_velocity *matchNeighborVel, + t_velocity *avoidNeighborVel) +{ + size_t neighbor; + t_float distSqr; + t_float dist, distH, distV, distD; + t_float tempSpeed; + size_t numClose = 0; + t_velocity totalVel = {0.0, 0.0, 0.0}; + + /**********************/ + /* Find the neighbors */ + /**********************/ + + /* special case of one neighbor */ + if (x->x_numNeighbors == 1) + { + x->x_boid[boid].neighborDistSqr[0] = (t_float)kMaxLong; + + for (size_t i = 0; i < x->x_numBoids; i++) + { + if (i != boid) + { + distSqr = point_squareDistance(x->x_boid[boid].oldPos, + x->x_boid[i].oldPos); + + /* if this one is closer than the closest so far, then remember + * it */ + if (x->x_boid[boid].neighborDistSqr[0] > distSqr) + { + x->x_boid[boid].neighborDistSqr[0] = distSqr; + x->x_boid[boid].neighbor[0] = i; + } + } + } + } + /* more than one neighbor */ + else + { + size_t j = 0; + for (; j < x->x_numNeighbors; j++) + x->x_boid[boid].neighborDistSqr[j] = (t_float)kMaxLong; + + for (size_t i = 0; i < x->x_numBoids; i++) + { + /* if this one is not me... */ + if (i != boid) + { + distSqr = point_squareDistance(x->x_boid[boid].oldPos, + x->x_boid[i].oldPos); + + /* if distSqr is less than the distance at the bottom of the + * array, sort into array */ + if (distSqr < + x->x_boid[boid].neighborDistSqr[x->x_numNeighbors - 1]) + { + j = x->x_numNeighbors - 1; + + /* sort distSqr in to keep array in size order, smallest + * first */ + while ((distSqr < x->x_boid[boid].neighborDistSqr[j - 1]) && + (j > 0)) + { + x->x_boid[boid].neighborDistSqr[j] = + x->x_boid[boid].neighborDistSqr[j - 1]; + x->x_boid[boid].neighbor[j] = + x->x_boid[boid].neighbor[j - 1]; + j--; + } + x->x_boid[boid].neighborDistSqr[j] = distSqr; + x->x_boid[boid].neighbor[j] = i; + } + } + } + } + + /*********************************/ + /* Match and avoid the neighbors */ + /*********************************/ + + matchNeighborVel->x = 0; + matchNeighborVel->y = 0; + matchNeighborVel->z = 0; + + // set tempSpeed to old speed + tempSpeed = x->x_boid[boid].speed; + + for (size_t i = 0; i < x->x_numNeighbors; i++) + { + neighbor = x->x_boid[boid].neighbor[i]; + + // calculate matchNeighborVel by averaging the neighbor velocities + matchNeighborVel->x += x->x_boid[neighbor].oldDir.x; + matchNeighborVel->y += x->x_boid[neighbor].oldDir.y; + matchNeighborVel->z += x->x_boid[neighbor].oldDir.z; + + // if distance is less than preferred distance, then neighbor influences + // boid + distSqr = x->x_boid[boid].neighborDistSqr[i]; + if (distSqr < x->prefDistSqr) + { + dist = sqrt(distSqr); + + distH = x->x_boid[neighbor].oldPos.x - x->x_boid[boid].oldPos.x; + distV = x->x_boid[neighbor].oldPos.y - x->x_boid[boid].oldPos.y; + distD = x->x_boid[neighbor].oldPos.z - x->x_boid[boid].oldPos.z; + + if (dist == 0.0) + dist = 0.0000001; + totalVel.x = + totalVel.x - distH - (distH * ((t_float)x->prefDist / (dist))); + totalVel.y = + totalVel.y - distV - (distV * ((t_float)x->prefDist / (dist))); + totalVel.z = + totalVel.z - distD - (distV * ((t_float)x->prefDist / (dist))); + + numClose++; + } + if (boids_inFront(&(x->x_boid[boid]), &(x->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; + velocity_normalize(matchNeighborVel); + } + else + { + avoidNeighborVel->x = 0; + avoidNeighborVel->y = 0; + avoidNeighborVel->z = 0; + } + return tempSpeed; +} + +static t_velocity boids_seekPoint(t_boids *x, size_t boid, t_point seekPt) +{ + t_velocity tempDir; + tempDir.x = seekPt.x - x->x_boid[boid].oldPos.x; + tempDir.y = seekPt.y - x->x_boid[boid].oldPos.y; + tempDir.z = seekPt.z - x->x_boid[boid].oldPos.z; + velocity_normalize(&tempDir); + return (tempDir); +} + +static t_velocity boids_avoidWalls(t_boids *x, size_t boid) +{ + t_point testPoint; + t_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->x_boid[boid].oldPos.x + x->x_boid[boid].oldDir.x * + x->x_boid[boid].speed * + x->edgeDist; + testPoint.y = x->x_boid[boid].oldPos.y + x->x_boid[boid].oldDir.y * + x->x_boid[boid].speed * + x->edgeDist; + testPoint.z = x->x_boid[boid].oldPos.z + x->x_boid[boid].oldDir.z * + x->x_boid[boid].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->x_boid[boid].oldDir.x); + else if (testPoint.x > x->flyRect.right) + tempVel.x = -fabs(x->x_boid[boid].oldDir.x); + + /* same with top and bottom */ + if (testPoint.y < x->flyRect.top) + tempVel.y = fabs(x->x_boid[boid].oldDir.y); + else if (testPoint.y > x->flyRect.bottom) + tempVel.y = -fabs(x->x_boid[boid].oldDir.y); + + /* same with front and back */ + if (testPoint.z < x->flyRect.front) + tempVel.z = fabs(x->x_boid[boid].oldDir.z); + else if (testPoint.z > x->flyRect.back) + tempVel.z = -fabs(x->x_boid[boid].oldDir.z); + + return (tempVel); +} + +static t_int boids_inFront(t_boid *boid, t_boid *neighbor) +{ + t_float grad, intercept; + int result; + + /* + + Find the gradient and y-intercept of a line passing through boid's oldPos + perpendicular to its direction of motion. Another boid is in front of + boid if it is to the right or left of this linedepending on whether + boid is moving right or left. However, if boid is travelling + vertically then just compare their vertical coordinates. + + */ + // xy plane + + // if boid is not travelling vertically... + if (boid->oldDir.x != 0) + { + // calculate gradient of a line _perpendicular_ to its direction (hence + // the minus) + grad = -boid->oldDir.y / boid->oldDir.x; + + // calculate where this line hits the y axis (from y = mx + c) + intercept = boid->oldPos.y - (grad * boid->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 = (boid->oldDir.x > 0); + + if (result == 0) + return 0; + else + goto next; + } + else + { + /* return true if the first boid's horizontal movement is +ve */ + result = (boid->oldDir.x < 0); + if (result == 0) + return 0; + else + goto next; + } + } + /* else boid is travelling vertically, so just compare vertical + * coordinates + */ + else if (boid->oldDir.y > 0) + { + result = (neighbor->oldPos.y > boid->oldPos.y); + if (result == 0) + { + return 0; + } + else + { + goto next; + } + } + else + { + result = (neighbor->oldPos.y < boid->oldPos.y); + if (result == 0) + { + return 0; + } + else + { + goto next; + } + } +next: + // yz plane + if (!boid->x_z) + return 1; + + // if boid is not travelling vertically... + if (boid->oldDir.y != 0) + { + // calculate gradient of a line _perpendicular_ to its direction (hence + // the minus) + grad = -boid->oldDir.z / boid->oldDir.y; + + // calculate where this line hits the y axis (from y = mx + c) + intercept = boid->oldPos.z - (grad * boid->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 = (boid->oldDir.y > 0); + if (result == 0) + { + return 0; + } + else + { + goto next2; + } + } + else + { + // return true if the first boid's horizontal movement is +ve + result = (boid->oldDir.y < 0); + if (result == 0) + { + return 0; + } + else + { + goto next2; + } + } + } + // else boid is travelling vertically, so just compare vertical + // coordinates + else if (boid->oldDir.z > 0) + { + result = (neighbor->oldPos.z > boid->oldPos.z); + if (result == 0) + { + return 0; + } + else + { + goto next2; + } + } + else + { + result = (neighbor->oldPos.z < boid->oldPos.z); + if (result == 0) + { + return 0; + } + else + { + goto next2; + } + } +next2: + return 1; +} + +static void velocity_normalize(t_velocity *direction) +{ + t_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; + } +} + +static t_float random_integer(t_float minRange, t_float maxRange) +{ + size_t qdRdm; + t_float t, result; + + qdRdm = rand(); + t = (t_float)qdRdm / 65536.0; // now 0 <= t <= 1 + result = (t * (maxRange - minRange)) + minRange; + return (result); +} + +static t_float point_squareDistance(t_point firstPoint, t_point secondPoint) +{ + t_float 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); +} + +static void *boids_new(t_boids *x, t_floatarg f, t_floatarg g) +{ + x->x_out1 = outlet_new(&x->x_obj, gensym("list")); + x->x_out2 = outlet_new(&x->x_obj, gensym("list")); + boids_float(x, f ? f : (t_floatarg)kNumBoids); + boids_mode(x, g ? g : 0.0); + return x; +} + +static void *boids2d_new(t_floatarg f, t_floatarg g) +{ + t_boids *x = (t_boids *)pd_new(boids2d_class); + x->x_z = 0.0; + return boids_new(x, f, g); +} + +static void *boids3d_new(t_floatarg f, t_floatarg g) +{ + t_boids *x = (t_boids *)pd_new(boids3d_class); + x->x_z = 1.0; + return boids_new(x, f, g); +} + +void boids_setup(void) +{ + const char *boids_names[2] = {"boids2d", "boids3d"}; + t_newmethod *boids_newfun[2] = {(t_newmethod)boids2d_new, + (t_newmethod)boids3d_new}; + t_class **boids_class[2] = {&boids2d_class, &boids3d_class}; + + for (int i = 0; i < 2; i++) + { + t_class *c = + class_new(gensym(boids_names[i]), (t_newmethod)boids_newfun[i], + (t_method)boids_free, sizeof(t_boids), 0, A_DEFFLOAT, + A_DEFFLOAT, A_NULL); + + *boids_class[i] = c; + class_sethelpsymbol(c, gensym(boids_names[i])); + class_addfloat(c, (t_method)boids_float); + class_addbang(c, (t_method)boids_bang); + class_addmethod(c, (t_method)boids_numNeighbors, gensym("neighbors"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_float, gensym("number"), A_FLOAT, + A_NULL); + class_addmethod(c, (t_method)boids_mode, gensym("mode"), A_FLOAT, + A_NULL); + class_addmethod(c, (t_method)boids_minSpeed, gensym("minspeed"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_maxSpeed, gensym("maxspeed"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_centerWeight, gensym("center"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_attractWeight, gensym("attract"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_matchWeight, gensym("match"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_avoidWeight, gensym("avoid"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_wallsWeight, gensym("repel"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_edgeDist, gensym("edgedist"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_speedupFactor, gensym("speed"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_inertiaFactor, gensym("inertia"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_accelFactor, gensym("accel"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_prefDist, gensym("prefdist"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_flyRect, gensym("flyrect"), A_GIMME, + A_NULL); + class_addmethod(c, (t_method)boids_attractPt, gensym("attractpt"), + A_GIMME, A_NULL); + class_addmethod(c, (t_method)boids_resetBoids, gensym("reset"), A_NULL); + class_addmethod(c, (t_method)boids_reset, gensym("init"), A_NULL); + class_addmethod(c, (t_method)boids_dump, gensym("dump"), A_NULL); + } + + logpost(NULL, 4, + "boids3d 2005-2006 a.sier / jasch © 1995-2003 eric l. singer " + " " __DATE__ " " __TIME__); +} diff --git a/src/boids.h b/src/boids.h new file mode 100644 index 0000000..d5a3417 --- /dev/null +++ b/src/boids.h @@ -0,0 +1,119 @@ +/* + + boids3d 2005 - 2006 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 + +// constants +#define kMaxLong 0xFFFFFFFF +#define kMaxNeighbors 16 +#define BOIDS_PI \ + 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068 +#define D2R (BOIDS_PI / 180.0); +#define R2D (180.0 / BOIDS_PI); + +// initial flight parameters +const size_t kNumBoids = 12; // number of boids +const size_t kNumNeighbors = 2; // must be <= kMaxNeighbors +const t_float kMinSpeed = 0.15; // boids' minimum speed +const t_float kMaxSpeed = 0.25; // boids' maximum speed +const t_float kCenterWeight = 0.25; // flock centering +const t_float kAttractWeight = 0.300; // attraction point seeking +const t_float kMatchWeight = 0.100; // neighbors velocity matching +const t_float kAvoidWeight = 0.10; // neighbors avoidance +const t_float kWallsWeight = 0.500; // wall avoidance [210] +const t_float kEdgeDist = 0.5; // vision distance to avoid wall edges [5] +const t_float kSpeedupFactor = 0.100; // alter animation speed +const t_float kInertiaFactor = 0.20; // willingness to change speed & direction +const t_float kAccelFactor = 0.1; // neighbor avoidance accel or decelerate rate +const t_float kPrefDist = 0.25; // preferred distance from neighbors +const t_float kFlyRectTop = 1.0; // fly rect boundaries +const t_float kFlyRectLeft = -1.0; +const t_float kFlyRectBottom = -1.0; +const t_float kFlyRectRight = 1.0; +const t_float kFlyRectFront = 1.0; +const t_float kFlyRectBack = -1.0; + +enum boid_output_mode +{ + BOID_NEWPOS = 0, + BOID_NEWOLD, + BOID_ALL +}; + +typedef struct _point +{ + size_t dimensions; + t_float *old; + t_float *new; +} t_point; + +typedef struct _neighbor +{ + size_t n_num_neighbors; + size_t *n_neighbor; + t_float *n_neighbor_dist_sqr; +} t_neighbor; + +typedef struct _boid +{ + t_point b_position; + t_point b_velocity; + t_float b_speed; + t_neighbor *b_neighbor; +} t_boid; + +typedef struct _boid_params +{ + t_float min_speed; + t_float max_speed; + t_float center_weight; + t_float attract_weight; + t_float match_weight; + t_float avoid_weight; + t_float walls_weight; + t_float edge_dist; + t_float speedup_factor; + t_float inertia_factor; + t_float accel_factor; + t_float pref_dist; + t_float pref_distSqr; +} t_boid_params; + +typedef struct _boids +{ + t_object x_obj; + t_outlet *x_out1, *x_out2; + + t_boid *x_boid; + + size_t x_dimensions; + t_float *x_position_center; + t_float *x_position_attract; + t_float *x_bounds; + + t_float d2r, r2d; + + size_t x_num_boids; + size_t x_num_neighbors; + + enum boid_output_mode x_mode; + t_boid_params *x_params; + +} t_boids; diff --git a/src/boids2d.c b/src/boids2d.c deleted file mode 100644 index ea2106f..0000000 --- a/src/boids2d.c +++ /dev/null @@ -1,1083 +0,0 @@ -/* - - 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 -#include - -// 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); - - logpost(NULL, 4, - "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 - { - pd_error(x, "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 - { - pd_error(x, "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); -} diff --git a/src/boids3d.c b/src/boids3d.c deleted file mode 100644 index ebdf59b..0000000 --- a/src/boids3d.c +++ /dev/null @@ -1,1094 +0,0 @@ -/* - - boids3d 2005 - 2006 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 -#include - -// constants -#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; -} t_velocity; - -typedef struct _point -{ - double x; - double y; - double z; -} t_point; - -typedef struct _box -{ - double left, right; - double top, bottom; - double front, back; -} t_box; - -typedef struct _boid -{ - t_point oldPos; - t_point newPos; - t_velocity oldDir; - t_velocity newDir; - double speed; - short neighbor[kMaxNeighbors]; - double neighborDistSqr[kMaxNeighbors]; -} t_boid; - -typedef struct _boids -{ - t_object ob; - void *out1, *out2; - short mode; - long numBoids; - long numNeighbors; - t_box 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; - t_point centerPt; - t_point attractPt; - t_boid *boid; - double d2r, r2d; -} t_boids; - -void *boids3d_class; -void *boids_new(t_symbol *s, long argc, t_atom *argv); -void boids_free(t_boids *x); -void boids_bang(t_boids *x); -void boids_dump(t_boids *x); -void boids_mode(t_boids *x, t_float arg); -void boids_numNeighbors(t_boids *x, t_float arg); -void boids_numBoids(t_boids *x, t_float arg); -void boids_minSpeed(t_boids *x, t_float arg); -void boids_maxSpeed(t_boids *x, t_float arg); -void boids_centerWeight(t_boids *x, t_float arg); -void boids_attractWeight(t_boids *x, t_float arg); -void boids_matchWeight(t_boids *x, t_float arg); -void boids_avoidWeight(t_boids *x, t_float arg); -void boids_wallsWeight(t_boids *x, t_float arg); -void boids_edgeDist(t_boids *x, t_float arg); -void boids_speedupFactor(t_boids *x, t_float arg); -void boids_inertiaFactor(t_boids *x, t_float arg); -void boids_accelFactor(t_boids *x, t_float arg); -void boids_prefDist(t_boids *x, t_float arg); -void boids_flyRect(t_boids *x, t_symbol *msg, short argc, t_atom *argv); -void boids_attractPt(t_boids *x, t_symbol *msg, short argc, t_atom *argv); -void boids_reset(t_boids *x); -void boids_resetBoids(t_boids *x); -void boids_init(t_boids *x); -void boids_flightStep(t_boids *x); - -t_point boids_findFlockCenter(t_boids *x); -t_float boids_matchAndAvoidNeighbors(t_boids *x, short boid, - t_velocity *matchNeighborVel, - t_velocity *avoidNeighborVel); -t_velocity boids_seekPoint(t_boids *x, short boid, t_point seekPt); -t_velocity boids_avoidWalls(t_boids *x, short boid); -t_int boids_inFront(t_boid *boid, t_boid *neighbor); - -static void velocity_normalize(t_velocity *direction); -static double random_integer(double minRange, double maxRange); -static double point_squareDistance(t_point firstPoint, t_point secondPoint); - -void boids3d_setup(void) -{ - boids3d_class = - class_new(gensym("boids3d"), (t_newmethod)boids_new, - (t_method)boids_free, sizeof(t_boids), 0, A_GIMME, 0); - class_addfloat(boids3d_class, (t_method)boids_numBoids); - class_addbang(boids3d_class, (t_method)boids_bang); - class_addmethod(boids3d_class, (t_method)boids_numNeighbors, - gensym("neighbors"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)boids_numBoids, gensym("number"), - A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)boids_mode, gensym("mode"), - A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)boids_minSpeed, gensym("minspeed"), - A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)boids_maxSpeed, gensym("maxspeed"), - A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)boids_centerWeight, - gensym("center"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)boids_attractWeight, - gensym("attract"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)boids_matchWeight, gensym("match"), - A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)boids_avoidWeight, gensym("avoid"), - A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)boids_wallsWeight, gensym("repel"), - A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)boids_edgeDist, gensym("edgedist"), - A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)boids_speedupFactor, - gensym("speed"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)boids_inertiaFactor, - gensym("inertia"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)boids_accelFactor, gensym("accel"), - A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)boids_prefDist, gensym("prefdist"), - A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method)boids_flyRect, gensym("flyrect"), - A_GIMME, 0); - class_addmethod(boids3d_class, (t_method)boids_attractPt, - gensym("attractpt"), A_GIMME, 0); - class_addmethod(boids3d_class, (t_method)boids_resetBoids, gensym("reset"), - 0); - class_addmethod(boids3d_class, (t_method)boids_reset, gensym("init"), 0); - class_addmethod(boids3d_class, (t_method)boids_dump, gensym("dump"), 0); - - logpost(NULL, 4, - "boids3d 2005-2006 a.sier / jasch © 1995-2003 eric l. singer " - " " __DATE__ " " __TIME__); -} - -void *boids_new(t_symbol *s, long argc, t_atom *argv) -{ - t_boids *x = (t_boids *)pd_new(boids3d_class); - x->out1 = outlet_new(&x->ob, NULL); - x->out2 = outlet_new(&x->ob, NULL); - - x->numBoids = kNumBoids; - if ((argc >= 1) && (argv[0].a_type == A_FLOAT)) - { - x->numBoids = argv[0].a_w.w_float; - } - x->boid = (t_boid *)malloc(sizeof(t_boid) * x->numBoids); - - boids_init(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 boids_free(t_boids *x) -{ - free(x->boid); -} - -void boids_bang(t_boids *x) -{ - short i; - t_atom outlist[10]; - t_atom *out; - - double tempNew_x, tempNew_y, tempNew_z; - double tempOld_x, tempOld_y, tempOld_z; - double delta_x, delta_y, delta_z; - double azi, ele, speed; - - out = outlist; - - boids_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, 4, 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 + 4, x->boid[i].oldPos.x); - SETFLOAT(out + 5, x->boid[i].oldPos.y); - SETFLOAT(out + 6, x->boid[i].oldPos.z); - outlet_list(x->out1, 0L, 7, 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 + 4, tempOld_x); - SETFLOAT(out + 5, tempOld_y); - SETFLOAT(out + 6, tempOld_z); - SETFLOAT(out + 7, speed); - SETFLOAT(out + 8, azi); - SETFLOAT(out + 9, ele); - outlet_list(x->out1, 0L, 10, out); - } - break; - } -} - -void boids_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"), 6, 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"), 3, 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 boids_mode(t_boids *x, t_float arg) -{ - long m = (long)arg; - x->mode = CLIP(m, 0, 2); -} - -void boids_numNeighbors(t_boids *x, t_float arg) -{ - x->numNeighbors = (long)arg; -} - -void boids_numBoids(t_boids *x, t_float arg) -{ - x->boid = (t_boid *)realloc(x->boid, sizeof(t_boid) * (long)arg); - x->numBoids = (long)arg; - boids_resetBoids(x); -} - -void boids_minSpeed(t_boids *x, t_float arg) -{ - x->minSpeed = MAX(arg, 0.000001); -} - -void boids_maxSpeed(t_boids *x, t_float arg) -{ - x->maxSpeed = (double)arg; -} - -void boids_centerWeight(t_boids *x, t_float arg) -{ - x->centerWeight = (double)arg; -} - -void boids_attractWeight(t_boids *x, t_float arg) -{ - x->attractWeight = (double)arg; -} - -void boids_matchWeight(t_boids *x, t_float arg) -{ - x->matchWeight = (double)arg; -} - -void boids_avoidWeight(t_boids *x, t_float arg) -{ - x->avoidWeight = (double)arg; -} - -void boids_wallsWeight(t_boids *x, t_float arg) -{ - x->wallsWeight = (double)arg; -} - -void boids_edgeDist(t_boids *x, t_float arg) -{ - x->edgeDist = (double)arg; -} - -void boids_speedupFactor(t_boids *x, t_float arg) -{ - x->speedupFactor = (double)arg; -} - -void boids_inertiaFactor(t_boids *x, t_float arg) -{ - if (arg == 0) - { - x->inertiaFactor = 0.000001; - } - else - { - x->inertiaFactor = (double)arg; - } -} - -void boids_accelFactor(t_boids *x, t_float arg) -{ - x->accelFactor = (double)arg; -} - -void boids_prefDist(t_boids *x, t_float arg) -{ - x->prefDist = (double)arg; -} - -void boids_flyRect(t_boids *x, t_symbol *msg, short argc, t_atom *argv) -{ - double temp[6]; - short i; - if (argc == 6) - { - for (i = 0; i < 6; 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 - { - pd_error(x, "boids3d: flyrect needs 6 values"); - } -} - -void boids_attractPt(t_boids *x, t_symbol *msg, short argc, t_atom *argv) -{ - double temp[3]; - short i; - if (argc == 3) - { - for (i = 0; i < 3; 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 - { - pd_error(x, "boids3d: attractPt needs 3 values"); - } -} - -void boids_reset(t_boids *x) -{ - boids_init(x); -} - -void boids_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 = random_integer( - x->flyRect.right, - x->flyRect.left); // set random location within flyRect - x->boid[i].newPos.y = x->boid[i].oldPos.y = - random_integer(x->flyRect.bottom, x->flyRect.top); - x->boid[i].newPos.z = x->boid[i].oldPos.z = - random_integer(x->flyRect.back, x->flyRect.front); - rndAngle = - random_integer(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 boids_init(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; - boids_resetBoids(x); -} - -void boids_flightStep(t_boids *x) -{ - t_velocity goCenterVel; - t_velocity goAttractVel; - t_velocity matchNeighborVel; - t_velocity avoidWallsVel; - t_velocity avoidNeighborVel; - t_float avoidNeighborSpeed; - const t_velocity zeroVel = {0.0, 0.0, 0.0}; - short i; - - x->centerPt = boids_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 = boids_matchAndAvoidNeighbors( - x, i, &matchNeighborVel, &avoidNeighborVel); - } - else - { - matchNeighborVel = zeroVel; - avoidNeighborVel = zeroVel; - avoidNeighborSpeed = 0; - } - goCenterVel = boids_seekPoint(x, i, x->centerPt); - goAttractVel = boids_seekPoint(x, i, x->attractPt); - avoidWallsVel = boids_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; - velocity_normalize( - &(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); - } -} - -t_point boids_findFlockCenter(t_boids *x) -{ - double totalH = 0, totalV = 0, totalD = 0; - t_point centerPoint; - register 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); -} - -t_float boids_matchAndAvoidNeighbors(t_boids *x, short boid, - t_velocity *matchNeighborVel, - t_velocity *avoidNeighborVel) -{ - short i, j, neighbor; - double distSqr; - double dist, distH, distV, distD; - double tempSpeed; - short numClose = 0; - t_velocity totalVel = {0.0, 0.0, 0.0}; - - /**********************/ - /* Find the neighbors */ - /**********************/ - - /* special case of one neighbor */ - if (x->numNeighbors == 1) - { - x->boid[boid].neighborDistSqr[0] = kMaxLong; - - for (i = 0; i < x->numBoids; i++) - { - if (i != boid) - { - distSqr = point_squareDistance(x->boid[boid].oldPos, - x->boid[i].oldPos); - - /* if this one is closer than the closest so far, then remember - * it */ - if (x->boid[boid].neighborDistSqr[0] > distSqr) - { - x->boid[boid].neighborDistSqr[0] = distSqr; - x->boid[boid].neighbor[0] = i; - } - } - } - } - /* more than one neighbor */ - else - { - for (j = 0; j < x->numNeighbors; j++) - x->boid[boid].neighborDistSqr[j] = kMaxLong; - - for (i = 0; i < x->numBoids; i++) - { - /* if this one is not me... */ - if (i != boid) - { - distSqr = point_squareDistance(x->boid[boid].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[boid].neighborDistSqr[x->numNeighbors - 1]) - { - j = x->numNeighbors - 1; - - /* sort distSqr in to keep array in size order, smallest - * first */ - while ((distSqr < x->boid[boid].neighborDistSqr[j - 1]) && - (j > 0)) - { - x->boid[boid].neighborDistSqr[j] = - x->boid[boid].neighborDistSqr[j - 1]; - x->boid[boid].neighbor[j] = - x->boid[boid].neighbor[j - 1]; - j--; - } - x->boid[boid].neighborDistSqr[j] = distSqr; - x->boid[boid].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[boid].speed; - - for (i = 0; i < x->numNeighbors; i++) - { - neighbor = x->boid[boid].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[boid].neighborDistSqr[i]; - if (distSqr < x->prefDistSqr) - { - dist = sqrt(distSqr); - - distH = x->boid[neighbor].oldPos.x - x->boid[boid].oldPos.x; - distV = x->boid[neighbor].oldPos.y - x->boid[boid].oldPos.y; - distD = x->boid[neighbor].oldPos.z - x->boid[boid].oldPos.z; - - if (dist == 0.0) - dist = 0.0000001; - totalVel.x = - totalVel.x - distH - (distH * ((t_float)x->prefDist / (dist))); - totalVel.y = - totalVel.y - distV - (distV * ((t_float)x->prefDist / (dist))); - totalVel.z = - totalVel.z - distD - (distV * ((t_float)x->prefDist / (dist))); - - numClose++; - } - if (boids_inFront(&(x->boid[boid]), &(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; - velocity_normalize(matchNeighborVel); - } - else - { - avoidNeighborVel->x = 0; - avoidNeighborVel->y = 0; - avoidNeighborVel->z = 0; - } - return (tempSpeed); -} - -t_velocity boids_seekPoint(t_boids *x, short boid, t_point seekPt) -{ - t_velocity tempDir; - tempDir.x = seekPt.x - x->boid[boid].oldPos.x; - tempDir.y = seekPt.y - x->boid[boid].oldPos.y; - tempDir.z = seekPt.z - x->boid[boid].oldPos.z; - velocity_normalize(&tempDir); - return (tempDir); -} - -t_velocity boids_avoidWalls(t_boids *x, short boid) -{ - t_point testPoint; - t_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[boid].oldPos.x + - x->boid[boid].oldDir.x * x->boid[boid].speed * x->edgeDist; - testPoint.y = x->boid[boid].oldPos.y + - x->boid[boid].oldDir.y * x->boid[boid].speed * x->edgeDist; - testPoint.z = x->boid[boid].oldPos.z + - x->boid[boid].oldDir.z * x->boid[boid].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[boid].oldDir.x); - else if (testPoint.x > x->flyRect.right) - tempVel.x = -fabs(x->boid[boid].oldDir.x); - - /* same with top and bottom */ - if (testPoint.y < x->flyRect.top) - tempVel.y = fabs(x->boid[boid].oldDir.y); - else if (testPoint.y > x->flyRect.bottom) - tempVel.y = -fabs(x->boid[boid].oldDir.y); - - /* same with front and back */ - if (testPoint.z < x->flyRect.front) - tempVel.z = fabs(x->boid[boid].oldDir.z); - else if (testPoint.z > x->flyRect.back) - tempVel.z = -fabs(x->boid[boid].oldDir.z); - - return (tempVel); -} - -t_int boids_inFront(t_boid *boid, t_boid *neighbor) -{ - t_float grad, intercept; - int result; - - /* - - Find the gradient and y-intercept of a line passing through boid's oldPos - perpendicular to its direction of motion. Another boid is in front of - boid if it is to the right or left of this linedepending on whether - boid is moving right or left. However, if boid is travelling - vertically then just compare their vertical coordinates. - - */ - // xy plane - - // if boid is not travelling vertically... - if (boid->oldDir.x != 0) - { - // calculate gradient of a line _perpendicular_ to its direction (hence - // the minus) - grad = -boid->oldDir.y / boid->oldDir.x; - - // calculate where this line hits the y axis (from y = mx + c) - intercept = boid->oldPos.y - (grad * boid->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 = (boid->oldDir.x > 0); - - if (result == 0) - return 0; - else - goto next; - } - else - { - /* return true if the first boid's horizontal movement is +ve */ - result = (boid->oldDir.x < 0); - if (result == 0) - return 0; - else - goto next; - } - } - /* else boid is travelling vertically, so just compare vertical - * coordinates - */ - else if (boid->oldDir.y > 0) - { - result = (neighbor->oldPos.y > boid->oldPos.y); - if (result == 0) - { - return 0; - } - else - { - goto next; - } - } - else - { - result = (neighbor->oldPos.y < boid->oldPos.y); - if (result == 0) - { - return 0; - } - else - { - goto next; - } - } -next: - // yz plane - - // if boid is not travelling vertically... - if (boid->oldDir.y != 0) - { - // calculate gradient of a line _perpendicular_ to its direction (hence - // the minus) - grad = -boid->oldDir.z / boid->oldDir.y; - - // calculate where this line hits the y axis (from y = mx + c) - intercept = boid->oldPos.z - (grad * boid->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 = (boid->oldDir.y > 0); - if (result == 0) - { - return 0; - } - else - { - goto next2; - } - } - else - { - // return true if the first boid's horizontal movement is +ve - result = (boid->oldDir.y < 0); - if (result == 0) - { - return 0; - } - else - { - goto next2; - } - } - } - // else boid is travelling vertically, so just compare vertical - // coordinates - else if (boid->oldDir.z > 0) - { - result = (neighbor->oldPos.z > boid->oldPos.z); - if (result == 0) - { - return 0; - } - else - { - goto next2; - } - } - else - { - result = (neighbor->oldPos.z < boid->oldPos.z); - if (result == 0) - { - return 0; - } - else - { - goto next2; - } - } -next2: - return 1; -} - -static void velocity_normalize(t_velocity *direction) -{ - t_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; - } -} - -static double random_integer(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); -} - -static double point_squareDistance(t_point firstPoint, t_point 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); -} diff --git a/tests/load-test.pd b/tests/load-test.pd new file mode 100644 index 0000000..54f9f36 --- /dev/null +++ b/tests/load-test.pd @@ -0,0 +1,19 @@ +#N canvas 0 0 450 300 12; +#X obj 37 37 boids2d; +#X obj 36 67 boids2d 5; +#X obj 35 95 boids2d 5 0; +#X obj 36 123 boids2d 5 1; +#X obj 35 149 boids2d 5 2; +#X obj 131 94 boids2d 15 0; +#X obj 131 148 boids2d 15 2; +#X obj 132 122 boids2d 15 1; +#X obj 137 64 boids2d 15; +#X obj 249 37 boids3d; +#X obj 248 67 boids3d 5; +#X obj 247 95 boids3d 5 0; +#X obj 248 123 boids3d 5 1; +#X obj 247 149 boids3d 5 2; +#X obj 349 64 boids3d 15; +#X obj 343 94 boids3d 15 0; +#X obj 344 122 boids3d 15 1; +#X obj 343 148 boids3d 15 2; From 5b47c31076ae5f8a029a833bd6573d0ce82cd15b Mon Sep 17 00:00:00 2001 From: fdch Date: Wed, 22 Apr 2026 10:32:05 +0200 Subject: [PATCH 05/19] stash --- Makefile | 17 +- src/boid_params.c | 109 ++++ src/boid_params.h | 62 ++ src/boids.c | 1362 ++++++++++++++++++-------------------------- src/boids.h | 123 ++-- src/point.c | 238 ++++++++ src/point.h | 57 ++ tests/load-test.pd | 11 +- 8 files changed, 1090 insertions(+), 889 deletions(-) create mode 100644 src/boid_params.c create mode 100644 src/boid_params.h create mode 100644 src/point.c create mode 100644 src/point.h diff --git a/Makefile b/Makefile index 44c8359..1e98cbc 100644 --- a/Makefile +++ b/Makefile @@ -4,22 +4,15 @@ # library name lib.name = boids - # input source file (class name == source file basename) -class.sources = \ - src/boids.c \ - $(empty) +class.sources = src/boids.c +common.sources = src/boid_params.c src/point.c + # all extra files to be included in binary distribution of the library -datafiles = \ - boids-meta.pd \ - help/boids2d-help.pd \ - help/boids3d-help.pd \ - README.txt LICENSE.txt +datafiles = boids-meta.pd help/boids2d-help.pd help/boids3d-help.pd README.txt LICENSE.txt -datadirs = \ - examples \ - $(empty) +datadirs = examples # include Makefile.pdlibbuilder from submodule directory 'pd-lib-builder' PDLIBBUILDER_DIR=pd-lib-builder/ diff --git a/src/boid_params.c b/src/boid_params.c new file mode 100644 index 0000000..2481e6b --- /dev/null +++ b/src/boid_params.c @@ -0,0 +1,109 @@ +/* + boids3d 2005 - 2006 a.sier / jasch + adapted from boids by eric singer © 1995-2003 eric l. singer + updated by fdch 2026 + + 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 "boid_params.h" + +/* initialize the params object with default values */ +t_boid_params *boid_params_new() +{ + t_boid_params *x = (t_boid_params *)getbytes(sizeof(t_boid_params)); + x->x_speed_min = 0.15; // boids' minimum speed + x->x_speed_max = 0.25; // boids' maximum speed + x->x_weight_center = 0.25; // flock centering + x->x_weight_attract = 0.3; // attraction point seeking + x->x_weight_match = 0.1; // neighbors velocity matching + x->x_weight_avoid = 0.1; // neighbors avoidance + x->x_weight_walls = 0.5; // wall avoidance [210] + x->x_distance_edge = 0.5; // vision distance to avoid wall edges [5] + x->x_factor_speedup = 0.1; // alter animation speed + x->x_factor_inertia = 0.2; // willingness to change speed & direction + x->x_factor_accel = 0.1; // neighbor avoidance accel or decelerate rate + x->x_pref_dist = 0.25; // preferred distance from neighbors + /* autofill these */ + x->x_pref_dist_sqr = x->x_pref_dist * x->x_pref_dist; + x->x_factor_accel_inv = 1.0 / (x->x_factor_accel + 1e-13); + return x; +} + +/* deallocate the params object */ +void boid_params_free(t_boid_params *x) +{ + if (!x) + return; + freebytes(x, sizeof(t_boid_params)); + x = NULL; +} + +/* dump all params to the given outlet as a sequenece of param name and value */ +void boid_params_dump(t_boid_params *x, t_outlet *out) +{ + t_atom *argv = (t_atom *)getbytes(sizeof(t_atom)); + SETFLOAT(argv, x->x_speed_min); + outlet_anything(out, gensym("minspeed"), 1, argv); + + SETFLOAT(argv, x->x_speed_max); + outlet_anything(out, gensym("maxspeed"), 1, argv); + + SETFLOAT(argv, x->x_weight_center); + outlet_anything(out, gensym("center"), 1, argv); + + SETFLOAT(argv, x->x_weight_attract); + outlet_anything(out, gensym("attract"), 1, argv); + + SETFLOAT(argv, x->x_weight_match); + outlet_anything(out, gensym("match"), 1, argv); + + SETFLOAT(argv, x->x_weight_avoid); + outlet_anything(out, gensym("avoid"), 1, argv); + + SETFLOAT(argv, x->x_weight_walls); + outlet_anything(out, gensym("repel"), 1, argv); + + SETFLOAT(argv, x->x_distance_edge); + outlet_anything(out, gensym("edgedist"), 1, argv); + + SETFLOAT(argv, x->x_factor_speedup); + outlet_anything(out, gensym("speed"), 1, argv); + + SETFLOAT(argv, x->x_factor_inertia); + outlet_anything(out, gensym("inertia"), 1, argv); + + SETFLOAT(argv, x->x_factor_accel); + outlet_anything(out, gensym("accel"), 1, argv); + + SETFLOAT(argv, x->x_pref_dist); + outlet_anything(out, gensym("prefdist"), 1, argv); + + freebytes(argv, sizeof(t_atom)); +} + +void boid_params_set_speed_min(t_boid_params *x, t_floatarg f) +{ + x->x_speed_min = f < 0.0 ? 0.000001 : f; +} + +void boid_params_set_factor_speedup(t_boid_params *x, t_floatarg f) +{ + x->x_factor_speedup = f / 100.0; +} + +void boid_params_set_factor_inertia(t_boid_params *x, t_floatarg f) +{ + x->x_factor_inertia = f == 0.0 ? 0.000001 : f; +} diff --git a/src/boid_params.h b/src/boid_params.h new file mode 100644 index 0000000..1fc3d9d --- /dev/null +++ b/src/boid_params.h @@ -0,0 +1,62 @@ +/* + boids3d 2005 - 2006 a.sier / jasch + adapted from boids by eric singer © 1995-2003 eric l. singer + updated by fdch 2026 + + 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 +*/ +#ifndef BOID_PARAMS_H +#define BOID_PARAMS_H + +#include "m_pd.h" + +typedef struct _boid_params +{ + t_float x_speed_min; + t_float x_speed_max; + + t_float x_weight_center; + t_float x_weight_attract; + t_float x_weight_match; + t_float x_weight_avoid; + t_float x_weight_walls; + + t_float x_factor_speedup; + t_float x_factor_inertia; + t_float x_factor_accel; + + t_float x_distance_edge; + t_float x_pref_dist; + + /* autofill these */ + t_float x_factor_accel_inv; + t_float x_pref_dist_sqr; +} t_boid_params; + +/* initialize the params object with default values */ +t_boid_params *boid_params_new(); + +/* deallocate the params object */ +void boid_params_free(t_boid_params *x); + +/* dump all params to the given outlet as a sequenece of param name and value */ +void boid_params_dump(t_boid_params *x, t_outlet *out); + +/* specific parameter setters */ +void boid_params_set_speed_min(t_boid_params *x, t_floatarg f); +void boid_params_set_factor_speedup(t_boid_params *x, t_floatarg f); +void boid_params_set_factor_inertia(t_boid_params *x, t_floatarg f); + +#endif diff --git a/src/boids.c b/src/boids.c index b94f02e..7434db8 100644 --- a/src/boids.c +++ b/src/boids.c @@ -1,7 +1,7 @@ /* - boids3d 2005 - 2006 a.sier / jasch adapted from boids by eric singer © 1995-2003 eric l. singer + updated by fdch 2026 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 @@ -22,1014 +22,763 @@ #include #include -static void *boids3d_class, *boids2d_class; - -/* forward declarations */ -static void boids_free(t_boids *x); -static void boids_alloc(t_boids *x, size_t numBoids); -static void boids_bang(t_boids *x); -static void boids_dump(t_boids *x); -static void boids_mode(t_boids *x, t_floatarg f); -static void boids_numNeighbors(t_boids *x, t_floatarg f); -static void boids_float(t_boids *x, t_floatarg arg); -static void boids_minSpeed(t_boids *x, t_floatarg f); -static void boids_maxSpeed(t_boids *x, t_floatarg f); -static void boids_centerWeight(t_boids *x, t_floatarg f); -static void boids_attractWeight(t_boids *x, t_floatarg f); -static void boids_matchWeight(t_boids *x, t_floatarg f); -static void boids_avoidWeight(t_boids *x, t_floatarg f); -static void boids_wallsWeight(t_boids *x, t_floatarg f); -static void boids_edgeDist(t_boids *x, t_floatarg f); -static void boids_speedupFactor(t_boids *x, t_floatarg f); -static void boids_inertiaFactor(t_boids *x, t_floatarg f); -static void boids_accelFactor(t_boids *x, t_floatarg f); -static void boids_prefDist(t_boids *x, t_floatarg f); -static void boids_flyRect(t_boids *x, t_symbol *s, int argc, t_atom *argv); -static void boids_attractPt(t_boids *x, t_symbol *s, int argc, t_atom *argv); -static void boids_reset(t_boids *x); -static void boids_resetBoids(t_boids *x); -static void boids_init(t_boids *x); -static void boids_step(t_boids *x); -static t_point boids_findFlockCenter(t_boids *x); -static t_float boids_matchAndAvoidNeighbors(t_boids *x, size_t boid, - t_velocity *matchNeighborVel, - t_velocity *avoidNeighborVel); -static t_velocity boids_seekPoint(t_boids *x, size_t boid, t_point seekPt); -static t_velocity boids_avoidWalls(t_boids *x, size_t boid); - -static t_int boids_inFront(t_boid *boid, t_boid *neighbor); - -static void velocity_normalize(t_velocity *direction); -static void boid_alloc(t_boid *x); -static void boid_free(t_boid *x); -static t_float random_integer(t_float minRange, t_float maxRange); -static t_float point_squareDistance(t_point firstPoint, t_point secondPoint); - -/* --------------------------- boids methods ------------------------------ */ +/* --------------------------- points structure ----------------------------- */ -static void boids_bang(t_boids *x) +t_points *points_new(size_t dimensions) { - t_atom outlist[10]; - t_atom *out; + t_points *points = (t_points *)getbytes(sizeof(t_points)); + points->avoidNeighborVel = point_new(dimensions); + points->avoidWallsVel = point_new(dimensions); + points->goAttractVel = point_new(dimensions); + points->goCenterVel = point_new(dimensions); + points->matchNeighborVel = point_new(dimensions); + return points; +} - t_float tempNew_x, tempNew_y, tempNew_z; - t_float tempOld_x, tempOld_y, tempOld_z; - t_float delta_x, delta_y, delta_z; - t_float azi, ele, speed; +void points_free(t_points *x) +{ + if (!x) + return; - out = outlist; + point_free(x->avoidNeighborVel); + point_free(x->avoidWallsVel); + point_free(x->goAttractVel); + point_free(x->goCenterVel); + point_free(x->matchNeighborVel); - boids_step(x); + freebytes(x, sizeof(t_points)); +} +static t_class *boids3d_class, *boids2d_class, *boids_class; - switch (x->mode) - { // newpos - case BOID_NEWPOS: - for (size_t i = 0; i < x->x_numBoids; i++) - { - SETFLOAT(out + 0, i); - SETFLOAT(out + 1, x->x_boid[i].newPos.x); - SETFLOAT(out + 2, x->x_boid[i].newPos.y); - if (!x->x_z) - outlet_list(x->x_out1, gensym("list"), 3, out); - else - { - SETFLOAT(out + 3, x->x_boid[i].newPos.z); - outlet_list(x->x_out1, gensym("list"), 4, out); - } - } - break; - case BOID_NEWOLD: // newpos + oldpos - for (size_t i = 0; i < x->x_numBoids; i++) - { - SETFLOAT(out + 0, i); - if (!x->x_z) - { - SETFLOAT(out + 1, x->x_boid[i].newPos.x); - SETFLOAT(out + 2, x->x_boid[i].newPos.y); - SETFLOAT(out + 3, x->x_boid[i].oldPos.x); - SETFLOAT(out + 4, x->x_boid[i].oldPos.y); - outlet_list(x->x_out1, gensym("list"), 5, out); - } - else - { - SETFLOAT(out + 1, x->x_boid[i].newPos.x); - SETFLOAT(out + 2, x->x_boid[i].newPos.y); - SETFLOAT(out + 3, x->x_boid[i].newPos.z); - SETFLOAT(out + 4, x->x_boid[i].oldPos.x); - SETFLOAT(out + 5, x->x_boid[i].oldPos.y); - SETFLOAT(out + 6, x->x_boid[i].oldPos.z); - outlet_list(x->x_out1, gensym("list"), 7, out); - } - } - break; - case BOID_ALL: - for (size_t i = 0; i < x->x_numBoids; i++) +/* ---------------------------- helper functions ---------------------------- */ + +/* + * calculate the velocity of a point with the weights and inertia factor + * (boid parameters) and the temporary points structure + */ +void point_velocity(t_point *x, t_boid_params *params, t_points *points) +{ + for (size_t i = 0; i < x->x_dimensions; i++) + x->x_new[i] = + params->x_factor_inertia * x->x_old[i] + + (params->x_weight_center * points->goCenterVel->x_new[i] + + params->x_weight_attract * points->goAttractVel->x_new[i] + + params->x_weight_match * points->matchNeighborVel->x_new[i] + + params->x_weight_avoid * points->avoidNeighborVel->x_new[i] + + params->x_weight_walls * points->avoidWallsVel->x_new[i]) / + params->x_factor_inertia; +} + +/* compute a target position from the norm dif between seek point and boid */ +static void boid_point_seek(t_boid *x, t_point *seek, t_point *target) +{ + for (size_t i = 0; i < seek->x_dimensions; i++) + target->x_new[i] = seek->x_new[i] - x->x_position.x_old[i]; + point_norm_square(target); +} + +static void boid_compute_neighbor_distances(t_boid *x) +{ + t_boids *flock = x->x_flock; + size_t num_boids = flock->x_num_boids; + size_t max_neighbors = flock->x_max_neighbors; + + if (num_boids <= 1 || max_neighbors == 0) + return; + + if (max_neighbors > num_boids - 1) + max_neighbors = num_boids - 1; + + /* initialize output slots */ + for (size_t i = 0; i < max_neighbors; ++i) + { + x->x_neighbors[i].x_boid = NULL; + x->x_neighbors[i].x_distance = (t_float)kMaxLong; + x->x_neighbors[i].x_next = + (i + 1 < max_neighbors) ? &x->x_neighbors[i + 1] : NULL; + } + + /* scan all boids in flock */ + for (size_t i = 0; i < num_boids; ++i) + { + t_boid *candidate = &flock->x_boid[i]; + t_float distance; + + if (candidate == x) + continue; + + point_square_distance(&x->x_position, &candidate->x_position, + &distance); + + /* only insert if better than current worst */ + if (distance < x->x_neighbors[max_neighbors - 1].x_distance) { - tempNew_x = x->x_boid[i].newPos.x; - tempNew_y = x->x_boid[i].newPos.y; - tempOld_x = x->x_boid[i].oldPos.x; - tempOld_y = x->x_boid[i].oldPos.y; - delta_x = tempNew_x - tempOld_x; - delta_y = tempNew_y - tempOld_y; - - if (!x->x_z) - delta_z = 0.0; - else - { - tempNew_z = x->x_boid[i].newPos.z; - tempOld_z = x->x_boid[i].oldPos.z; - delta_z = tempNew_z - tempOld_z; - } + size_t j = max_neighbors - 1; - azi = atan2(delta_y, delta_x) * R2D; - ele = atan2(delta_y, delta_x) * R2D; - speed = - sqrt(delta_x * delta_x + delta_y * delta_y + delta_z * delta_z); - SETFLOAT(out + 0, i); - if (!x->x_z) - { - SETFLOAT(out + 1, tempNew_x); - SETFLOAT(out + 2, tempNew_y); - SETFLOAT(out + 3, tempOld_x); - SETFLOAT(out + 4, tempOld_y); - SETFLOAT(out + 5, speed); - SETFLOAT(out + 6, azi); - SETFLOAT(out + 7, ele); - outlet_list(x->x_out1, gensym("list"), 8, out); - } - else + while ((j > 0) && (distance < x->x_neighbors[j - 1].x_distance)) { - SETFLOAT(out + 1, tempNew_x); - SETFLOAT(out + 2, tempNew_y); - SETFLOAT(out + 3, tempNew_z); - SETFLOAT(out + 4, tempOld_x); - SETFLOAT(out + 5, tempOld_y); - SETFLOAT(out + 6, tempOld_z); - SETFLOAT(out + 7, speed); - SETFLOAT(out + 8, azi); - SETFLOAT(out + 9, ele); - outlet_list(x->x_out1, gensym("list"), 10, out); + x->x_neighbors[j] = x->x_neighbors[j - 1]; + --j; } + + x->x_neighbors[j].x_boid = candidate; + x->x_neighbors[j].x_distance = distance; } - break; } } -static void boids_dump(t_boids *x) +static int boid_infront(t_boid *boid, t_boid *neighbor) { - t_atom outList[6]; - - SETFLOAT(outList, x->x_numNeighbors); - outlet_anything(x->x_out2, gensym("neighbors"), 1, outList); - - SETFLOAT(outList, x->minSpeed); - outlet_anything(x->x_out2, gensym("minspeed"), 1, outList); + t_float dot = point_infront_dot_old( + &boid->x_position, &neighbor->x_position, &boid->x_direction); + return (dot > 0.0); +} - SETFLOAT(outList, x->maxSpeed); - outlet_anything(x->x_out2, gensym("maxspeed"), 1, outList); +/*********************************/ +/* Match and avoid the neighbors */ +/*********************************/ +static t_float boid_match_and_avoid_neighbors(t_boid *x, + t_point *matchNeighborVel, + t_point *avoidNeighborVel) +{ + size_t num_close = 0; + size_t num_neighbors = 0; + t_float pref_dist_squared = x->x_flock->x_params->x_pref_dist_sqr; + t_float factor_accel = x->x_flock->x_params->x_factor_accel; + t_float inv_factor_accel = x->x_flock->x_params->x_factor_accel_inv; + t_float avoid_speed = x->x_speed; - SETFLOAT(outList, x->centerWeight); - outlet_anything(x->x_out2, gensym("center"), 1, outList); + point_fill(matchNeighborVel, 0.0); - SETFLOAT(outList, x->attractWeight); - outlet_anything(x->x_out2, gensym("attract"), 1, outList); + for (t_neighbor *neighbor = x->x_neighbors; neighbor; + neighbor = neighbor->x_next) + { + t_boid *other = neighbor->x_boid; + t_float dist_squared = neighbor->x_distance; + t_float adjust_speed; - SETFLOAT(outList, x->matchWeight); - outlet_anything(x->x_out2, gensym("match"), 1, outList); + if (!other) + continue; - SETFLOAT(outList, x->avoidWeight); - outlet_anything(x->x_out2, gensym("avoid"), 1, outList); + num_neighbors++; - SETFLOAT(outList, x->wallsWeight); - outlet_anything(x->x_out2, gensym("repel"), 1, outList); + int in_front = boid_infront(x, other); + adjust_speed = in_front ? factor_accel : inv_factor_accel; - SETFLOAT(outList, x->edgeDist); - outlet_anything(x->x_out2, gensym("edgedist"), 1, outList); + /* match: accumulate neighbor velocity/direction */ + point_add(matchNeighborVel, &other->x_direction); - SETFLOAT(outList, x->speedupFactor); - outlet_anything(x->x_out2, gensym("speed"), 1, outList); + /* avoid: react to close neighbors */ + if (dist_squared < pref_dist_squared) + { + t_float fstep = pref_dist_squared / (sqrt(dist_squared) + 1e-13); - SETFLOAT(outList, x->inertiaFactor); - outlet_anything(x->x_out2, gensym("inertia"), 1, outList); + /* use self - other for an "away from neighbor" vector */ + t_point *d = point_diff(&x->x_position, &other->x_position); + point_update_velocity(d, avoidNeighborVel, fstep); - SETFLOAT(outList, x->accelFactor); - outlet_anything(x->x_out2, gensym("accel"), 1, outList); + num_close++; - SETFLOAT(outList, x->prefDist); - outlet_anything(x->x_out2, gensym("prefdist"), 1, outList); + /* too close => flip speed adjustment */ + adjust_speed = in_front ? inv_factor_accel : factor_accel; + } - SETFLOAT(outList + 0, x->flyRect.left); - SETFLOAT(outList + 1, x->flyRect.top); - SETFLOAT(outList + 2, x->flyRect.right); - SETFLOAT(outList + 3, x->flyRect.bottom); - if (!x->x_z) - outlet_anything(x->x_out2, gensym("flyrect"), 4, outList); - else - { - SETFLOAT(outList + 4, x->flyRect.front); - SETFLOAT(outList + 5, x->flyRect.back); - outlet_anything(x->x_out2, gensym("flyrect"), 6, outList); + avoid_speed *= adjust_speed; } - SETFLOAT(outList + 0, x->attractPt.x); - SETFLOAT(outList + 1, x->attractPt.y); - if (!x->x_z) - outlet_anything(x->x_out2, gensym("attractpt"), 2, outList); - else - { - SETFLOAT(outList + 2, x->attractPt.z); - outlet_anything(x->x_out2, gensym("attractpt"), 3, outList); - } + if (num_neighbors) + point_normalize(matchNeighborVel, num_neighbors); - SETFLOAT(outList, x->mode); - outlet_anything(x->x_out2, gensym("mode"), 1, outList); + if (num_close) + point_normalize(avoidNeighborVel, num_close); - SETFLOAT(outList, x->x_numBoids); - outlet_anything(x->x_out2, gensym("number"), 1, outList); + return avoid_speed; } -static void boids_mode(t_boids *x, t_floatarg f) +static void boid_avoid_walls(t_boid *x, t_point *target, t_float distance_edge) { - const int m = (int)f; - x->mode = m < BOID_NEWPOS ? BOID_NEWPOS : BOID_ALL < m ? BOID_ALL : m; + size_t dimensions = x->x_flock->x_dimensions; + t_point *test_pt = point_new(dimensions); + + /* calculate test point in front of the nose of the boid */ + /* distance depends on the boid's speed and the avoid edge constant */ + for (size_t i = 0; i < dimensions; i++) + test_pt->x_new[i] = + x->x_position.x_old[i] + + x->x_speed * x->x_direction.x_old[i] * distance_edge; + + /* if test point is out of the left (right) side of x->flyRect, */ + /* return a positive (negative) horizontal velocity component */ + for (size_t i = 0; i < dimensions; i++) + if (test_pt->x_new[i] < x->x_flock->x_bounds[i * 2]) + target->x_new[i] = fabs(x->x_direction.x_old[i]); + else if (test_pt->x_new[i] > x->x_flock->x_bounds[i * 2 + 1]) + target->x_new[i] = -fabs(x->x_direction.x_old[i]); + + point_free(test_pt); } -static void boids_numNeighbors(t_boids *x, t_floatarg f) +static void boids_find_center(t_boids *x) { - x->x_numNeighbors = kMaxNeighbors < (size_t)f ? kMaxNeighbors : (size_t)f; - for (size_t i = 0; i < x->x_numNeighbors; i++) - { - x->x_boid[i].numNeighbors = x->x_numNeighbors; - boid_alloc(&x->x_boid[i]); - } + t_float inv_num_boids = x->x_num_boids ? 1.0 / x->x_num_boids : 1.0; + + for (size_t i = 0; i < x->x_num_boids; i++) + point_add(x->x_position_center, &x->x_boid[i].x_position); + + point_normalize(x->x_position_center, inv_num_boids); } -static void boid_free(t_boid *x) +static void boids_step(t_boids *x) { - if (x->neighbor) + t_points *points = points_new(x->x_dimensions); + + t_float avoid_speed; + + boids_find_center(x); + + // save position and velocity + for (size_t i = 0; i < x->x_num_boids; i++) { - freebytes(x->neighbor, sizeof(*x->neighbor) * x->numNeighbors); - x->neighbor = NULL; + point_step(&x->x_boid[i].x_position); + point_step(&x->x_boid[i].x_direction); } - if (x->neighborDistSqr) + /**********************/ + /* Find the neighbors */ + /**********************/ + for (size_t i = 0; i < x->x_num_boids; i++) { - freebytes(x->neighborDistSqr, - sizeof(*x->neighborDistSqr) * x->numNeighbors); - x->neighborDistSqr = NULL; + // get all velocity components + if (x->x_max_neighbors > 0) + { + boid_compute_neighbor_distances(&x->x_boid[i]); + avoid_speed = boid_match_and_avoid_neighbors( + &x->x_boid[i], points->matchNeighborVel, + points->avoidNeighborVel); + } + else + { + point_fill(points->matchNeighborVel, 0.0); + point_fill(points->avoidNeighborVel, 0.0); + avoid_speed = 0; + } + boid_point_seek(&x->x_boid[i], x->x_position_center, + points->goCenterVel); + boid_point_seek(&x->x_boid[i], x->x_position_attract, + points->goAttractVel); + boid_avoid_walls(&x->x_boid[i], points->avoidWallsVel, + x->x_params->x_distance_edge); + // compute resultant velocity using weights and inertia + point_velocity(&x->x_boid[i].x_direction, x->x_params, points); + + // normalize velocity so its length is unity + point_norm_square(&x->x_boid[i].x_direction); + + // set to avoid_speed bounded by minSpeed and maxSpeed + if ((avoid_speed >= x->x_params->x_speed_min) && + (avoid_speed <= x->x_params->x_speed_max)) + x->x_boid[i].x_speed = avoid_speed; + else if (avoid_speed > x->x_params->x_speed_max) + x->x_boid[i].x_speed = x->x_params->x_speed_max; + else + x->x_boid[i].x_speed = x->x_params->x_speed_min; + + // calculate new position, applying speedupFactor + for (size_t d = 0; d < x->x_dimensions; d++) + x->x_boid[i].x_position.x_new[d] += + x->x_boid[i].x_direction.x_new[d] * x->x_boid[i].x_speed * + x->x_params->x_factor_speedup; } } -static void boid_alloc(t_boid *x) +static void outlet_newpos(t_boids *x) { - boid_free(x); + size_t argc = x->x_dimensions + 1; + t_atom *argv = (t_atom *)getbytes(sizeof(*argv) * argc); - x->neighbor = (size_t *)getbytes(sizeof(*x->neighbor) * x->numNeighbors); - x->neighborDistSqr = (t_float *)getbytes(sizeof(t_float) * x->numNeighbors); + if (!argv) + return; - if (x->neighbor) - memset(x->neighbor, 0, sizeof(*x->neighbor) * x->numNeighbors); + for (size_t i = 0; i < x->x_num_boids; ++i) + { + SETFLOAT(argv + 0, (t_float)i); - if (x->neighborDistSqr) - memset(x->neighborDistSqr, 0, - sizeof(*x->neighborDistSqr) * x->numNeighbors); + for (size_t d = 0; d < x->x_dimensions; ++d) + SETFLOAT(argv + 1 + d, x->x_boid[i].x_position.x_new[d]); + + outlet_list(x->x_out1, gensym("list"), (int)argc, argv); + } + + freebytes(argv, sizeof(*argv) * argc); } -static void boids_free(t_boids *x) +static void outlet_newold(t_boids *x) { - if (!x->x_boid) + size_t argc = 1 + (2 * x->x_dimensions); + t_atom *argv = (t_atom *)getbytes(sizeof(*argv) * argc); + + if (!argv) + return; + + for (size_t i = 0; i < x->x_num_boids; ++i) { - x->x_numBoids = 0; + SETFLOAT(argv + 0, (t_float)i); + + /* new position */ + for (size_t d = 0; d < x->x_dimensions; ++d) + SETFLOAT(argv + 1 + d, x->x_boid[i].x_position.x_new[d]); + + /* old position */ + for (size_t d = 0; d < x->x_dimensions; ++d) + SETFLOAT(argv + 1 + x->x_dimensions + d, + x->x_boid[i].x_position.x_old[d]); + + outlet_list(x->x_out1, gensym("list"), (int)argc, argv); + } + + freebytes(argv, sizeof(*argv) * argc); +} + +/* + * BOID_ALL currently makes sense as a 2D/3D outlet format: + * + * 2D: [index new_x new_y old_x old_y speed azimuth elevation] + * 3D: [index new_x new_y new_z old_x old_y old_z speed azimuth elevation] + * + * For dimensions >= 3, this uses the first 3 coordinates. + */ +static void outlet_all(t_boids *x) +{ + t_atom out[10]; + int has_z = (x->x_dimensions >= 3); + + if (x->x_dimensions < 2) return; + + for (size_t i = 0; i < x->x_num_boids; ++i) + { + t_float new_x = x->x_boid[i].x_position.x_new[0]; + t_float new_y = x->x_boid[i].x_position.x_new[1]; + t_float old_x = x->x_boid[i].x_position.x_old[0]; + t_float old_y = x->x_boid[i].x_position.x_old[1]; + + t_float delta_x = new_x - old_x; + t_float delta_y = new_y - old_y; + t_float delta_z = 0.0; + + t_float new_z = 0.0; + t_float old_z = 0.0; + + t_float speed; + t_float azi; + t_float ele; + + if (has_z) + { + new_z = x->x_boid[i].x_position.x_new[2]; + old_z = x->x_boid[i].x_position.x_old[2]; + delta_z = new_z - old_z; + } + + speed = sqrt(delta_x * delta_x + delta_y * delta_y + delta_z * delta_z); + + azi = atan2(delta_y, delta_x) * R2D; + + if (has_z) + { + t_float horiz = sqrt(delta_x * delta_x + delta_y * delta_y); + ele = atan2(delta_z, horiz) * R2D; + } + else + { + ele = 0.0; + } + + SETFLOAT(out + 0, (t_float)i); + + if (!has_z) + { + SETFLOAT(out + 1, new_x); + SETFLOAT(out + 2, new_y); + SETFLOAT(out + 3, old_x); + SETFLOAT(out + 4, old_y); + SETFLOAT(out + 5, speed); + SETFLOAT(out + 6, azi); + SETFLOAT(out + 7, ele); + + outlet_list(x->x_out1, gensym("list"), 8, out); + } + else + { + SETFLOAT(out + 1, new_x); + SETFLOAT(out + 2, new_y); + SETFLOAT(out + 3, new_z); + SETFLOAT(out + 4, old_x); + SETFLOAT(out + 5, old_y); + SETFLOAT(out + 6, old_z); + SETFLOAT(out + 7, speed); + SETFLOAT(out + 8, azi); + SETFLOAT(out + 9, ele); + + outlet_list(x->x_out1, gensym("list"), 10, out); + } } +} - for (size_t i = 0; i < x->x_numBoids; i++) - boid_free(&x->x_boid[i]); +/* ---------------------------- boids methods ------------------------------- */ - freebytes(x->x_boid, sizeof(t_boid) * x->x_numBoids); - x->x_boid = NULL; - x->x_numBoids = 0; +static void boids_bang(t_boids *x) +{ + boids_step(x); + + switch (x->x_mode) + { + case BOID_NEWPOS: + default: + outlet_newpos(x); + break; + + case BOID_NEWOLD: + outlet_newold(x); + break; + + case BOID_ALL: + outlet_all(x); + break; + } } -static void boids_alloc(t_boids *x, size_t numBoids) +static void boids_dump(t_boids *x) { - boids_free(x); + /* keep the max size of the atom and release it later */ + size_t nbytes = sizeof(t_atom) * 2 * x->x_dimensions; + t_atom *argv = (t_atom *)getbytes(nbytes); - if (numBoids == 0) - return; + SETFLOAT(argv, x->x_max_neighbors); + outlet_anything(x->x_out2, gensym("neighbors"), 1, argv); + + boid_params_dump(x->x_params, x->x_out2); + + /* outlet all bounds as fly rectangle */ + for (size_t i = 0; i < 2 * x->x_dimensions; i++) + SETFLOAT(argv + i, x->x_bounds[i]); + outlet_anything(x->x_out2, gensym("flyrect"), 2 * x->x_dimensions, argv); + + /* outlet all attract position */ + for (size_t i = 0; i < x->x_dimensions; i++) + SETFLOAT(argv + i, x->x_position_attract->x_new[i]); + outlet_anything(x->x_out2, gensym("attractpt"), x->x_dimensions, argv); + + /* outlet all center position */ + for (size_t i = 0; i < x->x_dimensions; i++) + SETFLOAT(argv + i, x->x_position_center->x_new[i]); + outlet_anything(x->x_out2, gensym("centerpt"), x->x_dimensions, argv); - x->x_boid = (t_boid *)getbytes(sizeof(*x->x_boid) * numBoids); - x->x_numBoids = numBoids; + SETFLOAT(argv, x->x_mode); + outlet_anything(x->x_out2, gensym("mode"), 1, argv); - boids_resetBoids(x); + SETFLOAT(argv, x->x_num_boids); + outlet_anything(x->x_out2, gensym("number"), 1, argv); + + /* release the argv atom */ + freebytes(argv, nbytes); } -static void boids_float(t_boids *x, t_floatarg fnumBoids) +static void boids_num_neighbors(t_boids *x, t_floatarg f) { - size_t numBoids = fnumBoids < 0.0 ? 0 : (size_t)fnumBoids; - if (x->x_numBoids == numBoids) - return; - boids_alloc(x, numBoids); + x->x_max_neighbors = kMaxNeighbors < (size_t)f ? kMaxNeighbors : (size_t)f; } static void boids_minSpeed(t_boids *x, t_floatarg f) { - x->minSpeed = f < 0.0 ? 0.000001 : f; + boid_params_set_speed_min(x->x_params, f); } static void boids_maxSpeed(t_boids *x, t_floatarg f) { - x->maxSpeed = f; + x->x_params->x_speed_max = f; } static void boids_centerWeight(t_boids *x, t_floatarg f) { - x->centerWeight = f; + x->x_params->x_weight_center = f; } static void boids_attractWeight(t_boids *x, t_floatarg f) { - x->attractWeight = f; + x->x_params->x_weight_attract = f; } static void boids_matchWeight(t_boids *x, t_floatarg f) { - x->matchWeight = f; + x->x_params->x_weight_match = f; } static void boids_avoidWeight(t_boids *x, t_floatarg f) { - x->avoidWeight = f; + x->x_params->x_weight_avoid = f; } static void boids_wallsWeight(t_boids *x, t_floatarg f) { - x->wallsWeight = f; + x->x_params->x_weight_walls = f; } static void boids_edgeDist(t_boids *x, t_floatarg f) { - x->edgeDist = f; + x->x_params->x_distance_edge = f; } static void boids_speedupFactor(t_boids *x, t_floatarg f) { - x->speedupFactor = f; + boid_params_set_factor_speedup(x->x_params, f); } static void boids_inertiaFactor(t_boids *x, t_floatarg f) { - x->inertiaFactor = f == 0.0 ? 0.000001 : f; + boid_params_set_factor_inertia(x->x_params, f); } static void boids_accelFactor(t_boids *x, t_floatarg f) { - x->accelFactor = f; + x->x_params->x_factor_accel = f; } static void boids_prefDist(t_boids *x, t_floatarg f) { - x->prefDist = f; + x->x_params->x_pref_dist = f; } -static void boids_flyRect(t_boids *x, t_symbol *s, int argc, t_atom *argv) +static void boids_bounds(t_boids *x, t_symbol *s, int argc, t_atom *argv) { (void)s; - if (argc < 4) - return; - - if (argc == 4) - { - x->flyRect.left = atom_getfloat(argv + 0); - x->flyRect.top = atom_getfloat(argv + 1); - x->flyRect.right = atom_getfloat(argv + 2); - x->flyRect.bottom = atom_getfloat(argv + 3); - } - - if (argc == 6) + t_float *bounds_ptr = x->x_bounds; + while (argc) { - x->flyRect.front = atom_getfloat(argv + 5); - x->flyRect.back = atom_getfloat(argv + 6); + *bounds_ptr++ = atom_getfloat(argv++); + argc--; } } -static void boids_attractPt(t_boids *x, t_symbol *s, int argc, t_atom *argv) +static void boids_position_attract(t_boids *x, t_symbol *s, int argc, + t_atom *argv) { (void)s; - if (!argc || argc < 2) - return; - - x->attractPt.x = atom_getfloat(argv + 0); - x->attractPt.y = atom_getfloat(argv + 1); - if (argc == 3) - x->attractPt.z = atom_getfloat(argv + 2); + point_update(x->x_position_attract, argc, argv); } -static void boids_reset(t_boids *x) -{ - boids_init(x); -} +/* -------------------------- memory management ----------------------------- */ -static void boids_resetBoids(t_boids *x) +/* deallocate previous bounds if present */ +static void boids_bounds_free(t_boids *x) { - t_float rndAngle; - - for (size_t i = 0; i < x->x_numBoids; i++) - { // init everything to 0.0 - x->x_boid[i].oldPos.x = 0.0; - x->x_boid[i].oldPos.y = 0.0; - x->x_boid[i].oldPos.z = 0.0; - - x->x_boid[i].newPos.x = 0.0; - x->x_boid[i].newPos.y = 0.0; - x->x_boid[i].newPos.z = 0.0; - - x->x_boid[i].oldDir.x = 0.0; - x->x_boid[i].oldDir.y = 0.0; - x->x_boid[i].oldDir.z = 0.0; - - x->x_boid[i].newDir.x = 0.0; - x->x_boid[i].newDir.y = 0.0; - x->x_boid[i].newDir.z = 0.0; - - x->x_boid[i].speed = 0.0; - - x->x_boid[i].numNeighbors = x->x_numNeighbors; - x->x_boid[i].x_z = x->x_z; - boid_alloc(&x->x_boid[i]); - } - for (size_t i = 0; i < x->x_numBoids; i++) - { // set the initial locations and velocities of the boids - x->x_boid[i].newPos.x = x->x_boid[i].oldPos.x = random_integer( - x->flyRect.right, - x->flyRect.left); // set random location within flyRect - x->x_boid[i].newPos.y = x->x_boid[i].oldPos.y = - random_integer(x->flyRect.bottom, x->flyRect.top); - x->x_boid[i].newPos.z = x->x_boid[i].oldPos.z = - random_integer(x->flyRect.back, x->flyRect.front); - rndAngle = - random_integer(0, 360) * D2R; // set velocity from random angle - x->x_boid[i].newDir.x = sin(rndAngle); - x->x_boid[i].newDir.y = cos(rndAngle); - x->x_boid[i].newDir.z = x->x_z * (cos(rndAngle) + sin(rndAngle)) * 0.5; - x->x_boid[i].speed = (kMaxSpeed + kMinSpeed) * 0.5; - } -} - -static void boids_init(t_boids *x) -{ - 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; - boids_resetBoids(x); + if (!x->x_bounds) + return; + freebytes(x->x_bounds, sizeof(t_float) * 2 * x->x_dimensions); + x->x_bounds = NULL; } -static void boids_step(t_boids *x) +/* deallocate previous boid if present */ +static void boid_free(t_boids *x) { - t_velocity goCenterVel; - t_velocity goAttractVel; - t_velocity matchNeighborVel; - t_velocity avoidWallsVel; - t_velocity avoidNeighborVel; - t_float avoidNeighborSpeed; - const t_velocity zeroVel = {0.0, 0.0, 0.0}; - - x->centerPt = boids_findFlockCenter(x); - for (size_t i = 0; i < x->x_numBoids; i++) - { // save position and velocity - x->x_boid[i].oldPos.x = x->x_boid[i].newPos.x; - x->x_boid[i].oldPos.y = x->x_boid[i].newPos.y; - x->x_boid[i].oldPos.z = x->x_boid[i].newPos.z; - - x->x_boid[i].oldDir.x = x->x_boid[i].newDir.x; - x->x_boid[i].oldDir.y = x->x_boid[i].newDir.y; - x->x_boid[i].oldDir.z = x->x_boid[i].newDir.z; - } + if (!x->x_boid) + return; - for (size_t i = 0; i < x->x_numBoids; i++) + for (size_t i = 0; i < x->x_num_boids; i++) { - if (x->x_numNeighbors > 0) - { // get all velocity components - avoidNeighborSpeed = boids_matchAndAvoidNeighbors( - x, i, &matchNeighborVel, &avoidNeighborVel); - } - else + t_boid *boid = &x->x_boid[i]; + + if (boid->x_neighbors) { - matchNeighborVel = zeroVel; - avoidNeighborVel = zeroVel; - avoidNeighborSpeed = 0; + freebytes(boid->x_neighbors, + sizeof(*boid->x_neighbors) * (x->x_num_boids - 1)); + boid->x_neighbors = NULL; } - goCenterVel = boids_seekPoint(x, i, x->centerPt); - goAttractVel = boids_seekPoint(x, i, x->attractPt); - avoidWallsVel = boids_avoidWalls(x, i); - // compute resultant velocity using weights and inertia - x->x_boid[i].newDir.x = x->inertiaFactor * (x->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->x_boid[i].newDir.y = x->inertiaFactor * (x->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->x_boid[i].newDir.z = x->inertiaFactor * (x->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; - // normalize velocity so its length is unity - velocity_normalize(&(x->x_boid[i].newDir)); - - // set to avoidNeighborSpeed bounded by minSpeed and maxSpeed - if ((avoidNeighborSpeed >= x->minSpeed) && - (avoidNeighborSpeed <= x->maxSpeed)) - x->x_boid[i].speed = avoidNeighborSpeed; - else if (avoidNeighborSpeed > x->maxSpeed) - x->x_boid[i].speed = x->maxSpeed; - else - x->x_boid[i].speed = x->minSpeed; + point_free(&boid->x_position); + point_free(&boid->x_direction); - // calculate new position, applying speedupFactor - x->x_boid[i].newPos.x += x->x_boid[i].newDir.x * x->x_boid[i].speed * - (x->speedupFactor / 100.0); - x->x_boid[i].newPos.y += x->x_boid[i].newDir.y * x->x_boid[i].speed * - (x->speedupFactor / 100.0); - x->x_boid[i].newPos.z += x->x_boid[i].newDir.z * x->x_boid[i].speed * - (x->speedupFactor / 100.0); + boid->x_next = NULL; + boid->x_flock = NULL; } + + freebytes(x->x_boid, sizeof(*x->x_boid) * x->x_num_boids); + x->x_boid = NULL; + x->x_num_boids = 0; } -static t_point boids_findFlockCenter(t_boids *x) +/* free method to deallocate everything (used by Pd when deleting the object) */ +static void boids_free(t_boids *x) { - t_float totalH = 0, totalV = 0, totalD = 0; - t_point centerPoint; + /* deallocate previous boid if present */ + boid_free(x); + /* deallocate previous bounds if present */ + boids_bounds_free(x); + /* deallocate previous center and attract positions if present */ + point_free(x->x_position_attract); + point_free(x->x_position_center); + /* deallocate the parameters */ + boid_params_free(x->x_params); +} + +/* ---------------------------- initialization ------------------------------ */ - for (size_t i = 0; i < x->x_numBoids; i++) +static void boids_reset(t_boids *x) +{ + for (size_t i = 0; i < x->x_num_boids; ++i) { - totalH += x->x_boid[i].oldPos.x; - totalV += x->x_boid[i].oldPos.y; - totalD += x->x_boid[i].oldPos.z; - } - centerPoint.x = (t_float)(totalH / x->x_numBoids); - centerPoint.y = (t_float)(totalV / x->x_numBoids); - centerPoint.z = (t_float)(totalD / x->x_numBoids); + t_boid *boid = &x->x_boid[i]; - return centerPoint; + point_rand_from_range(&boid->x_position, &x->x_bounds[i * 2]); + point_rand_from_angle(&boid->x_direction); + boid->x_speed = + (x->x_params->x_speed_max + x->x_params->x_speed_min) * 0.5; + } } -static t_float boids_matchAndAvoidNeighbors(t_boids *x, size_t boid, - t_velocity *matchNeighborVel, - t_velocity *avoidNeighborVel) +static t_boid *boid_list_new(size_t num_boids) { - size_t neighbor; - t_float distSqr; - t_float dist, distH, distV, distD; - t_float tempSpeed; - size_t numClose = 0; - t_velocity totalVel = {0.0, 0.0, 0.0}; + if (!num_boids) + return NULL; - /**********************/ - /* Find the neighbors */ - /**********************/ + t_boid *x = (t_boid *)getbytes(num_boids * sizeof(*x)); + if (!x) + return NULL; - /* special case of one neighbor */ - if (x->x_numNeighbors == 1) + for (size_t i = 0; i < num_boids; i++) { - x->x_boid[boid].neighborDistSqr[0] = (t_float)kMaxLong; + x[i].x_flock = NULL; - for (size_t i = 0; i < x->x_numBoids; i++) - { - if (i != boid) - { - distSqr = point_squareDistance(x->x_boid[boid].oldPos, - x->x_boid[i].oldPos); - - /* if this one is closer than the closest so far, then remember - * it */ - if (x->x_boid[boid].neighborDistSqr[0] > distSqr) - { - x->x_boid[boid].neighborDistSqr[0] = distSqr; - x->x_boid[boid].neighbor[0] = i; - } - } - } - } - /* more than one neighbor */ - else - { - size_t j = 0; - for (; j < x->x_numNeighbors; j++) - x->x_boid[boid].neighborDistSqr[j] = (t_float)kMaxLong; + x[i].x_next = (i + 1 < num_boids) ? &x[i + 1] : NULL; - for (size_t i = 0; i < x->x_numBoids; i++) + x[i].x_neighbors = NULL; + if (num_boids > 1) { - /* if this one is not me... */ - if (i != boid) - { - distSqr = point_squareDistance(x->x_boid[boid].oldPos, - x->x_boid[i].oldPos); - - /* if distSqr is less than the distance at the bottom of the - * array, sort into array */ - if (distSqr < - x->x_boid[boid].neighborDistSqr[x->x_numNeighbors - 1]) - { - j = x->x_numNeighbors - 1; - - /* sort distSqr in to keep array in size order, smallest - * first */ - while ((distSqr < x->x_boid[boid].neighborDistSqr[j - 1]) && - (j > 0)) - { - x->x_boid[boid].neighborDistSqr[j] = - x->x_boid[boid].neighborDistSqr[j - 1]; - x->x_boid[boid].neighbor[j] = - x->x_boid[boid].neighbor[j - 1]; - j--; - } - x->x_boid[boid].neighborDistSqr[j] = distSqr; - x->x_boid[boid].neighbor[j] = i; - } - } - } - } + x[i].x_neighbors = (t_neighbor *)getbytes( + (num_boids - 1) * sizeof(*x[i].x_neighbors)); - /*********************************/ - /* Match and avoid the neighbors */ - /*********************************/ + for (size_t j = 0; j + 1 < num_boids - 1; j++) + x[i].x_neighbors[j].x_next = &x[i].x_neighbors[j + 1]; - matchNeighborVel->x = 0; - matchNeighborVel->y = 0; - matchNeighborVel->z = 0; - - // set tempSpeed to old speed - tempSpeed = x->x_boid[boid].speed; - - for (size_t i = 0; i < x->x_numNeighbors; i++) - { - neighbor = x->x_boid[boid].neighbor[i]; - - // calculate matchNeighborVel by averaging the neighbor velocities - matchNeighborVel->x += x->x_boid[neighbor].oldDir.x; - matchNeighborVel->y += x->x_boid[neighbor].oldDir.y; - matchNeighborVel->z += x->x_boid[neighbor].oldDir.z; - - // if distance is less than preferred distance, then neighbor influences - // boid - distSqr = x->x_boid[boid].neighborDistSqr[i]; - if (distSqr < x->prefDistSqr) - { - dist = sqrt(distSqr); - - distH = x->x_boid[neighbor].oldPos.x - x->x_boid[boid].oldPos.x; - distV = x->x_boid[neighbor].oldPos.y - x->x_boid[boid].oldPos.y; - distD = x->x_boid[neighbor].oldPos.z - x->x_boid[boid].oldPos.z; - - if (dist == 0.0) - dist = 0.0000001; - totalVel.x = - totalVel.x - distH - (distH * ((t_float)x->prefDist / (dist))); - totalVel.y = - totalVel.y - distV - (distV * ((t_float)x->prefDist / (dist))); - totalVel.z = - totalVel.z - distD - (distV * ((t_float)x->prefDist / (dist))); - - numClose++; - } - if (boids_inFront(&(x->x_boid[boid]), &(x->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); + x[i].x_neighbors[num_boids - 2].x_next = NULL; } } - if (numClose) - { - avoidNeighborVel->x = totalVel.x / numClose; - avoidNeighborVel->y = totalVel.y / numClose; - avoidNeighborVel->z = totalVel.z / numClose; - velocity_normalize(matchNeighborVel); - } - else - { - avoidNeighborVel->x = 0; - avoidNeighborVel->y = 0; - avoidNeighborVel->z = 0; - } - return tempSpeed; -} -static t_velocity boids_seekPoint(t_boids *x, size_t boid, t_point seekPt) -{ - t_velocity tempDir; - tempDir.x = seekPt.x - x->x_boid[boid].oldPos.x; - tempDir.y = seekPt.y - x->x_boid[boid].oldPos.y; - tempDir.z = seekPt.z - x->x_boid[boid].oldPos.z; - velocity_normalize(&tempDir); - return (tempDir); + return x; } -static t_velocity boids_avoidWalls(t_boids *x, size_t boid) +/* resize bounds and allocate */ +static void boids_bounds_alloc(t_boids *x) { - t_point testPoint; - t_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->x_boid[boid].oldPos.x + x->x_boid[boid].oldDir.x * - x->x_boid[boid].speed * - x->edgeDist; - testPoint.y = x->x_boid[boid].oldPos.y + x->x_boid[boid].oldDir.y * - x->x_boid[boid].speed * - x->edgeDist; - testPoint.z = x->x_boid[boid].oldPos.z + x->x_boid[boid].oldDir.z * - x->x_boid[boid].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->x_boid[boid].oldDir.x); - else if (testPoint.x > x->flyRect.right) - tempVel.x = -fabs(x->x_boid[boid].oldDir.x); - - /* same with top and bottom */ - if (testPoint.y < x->flyRect.top) - tempVel.y = fabs(x->x_boid[boid].oldDir.y); - else if (testPoint.y > x->flyRect.bottom) - tempVel.y = -fabs(x->x_boid[boid].oldDir.y); - - /* same with front and back */ - if (testPoint.z < x->flyRect.front) - tempVel.z = fabs(x->x_boid[boid].oldDir.z); - else if (testPoint.z > x->flyRect.back) - tempVel.z = -fabs(x->x_boid[boid].oldDir.z); - - return (tempVel); + size_t nbounds = 2 * x->x_dimensions; + x->x_bounds = (t_float *)getbytes(sizeof(t_float) * nbounds); + /* initialize bounds */ + for (size_t i = 0; i < nbounds; i += 2) + { + x->x_bounds[i] = -1.0; // nth dimension left side + x->x_bounds[i + 1] = 1.0; // nth dimension right side + } } -static t_int boids_inFront(t_boid *boid, t_boid *neighbor) +static void boids_init(t_boids *x, size_t dimensions, size_t num_boids) { - t_float grad, intercept; - int result; - - /* - - Find the gradient and y-intercept of a line passing through boid's oldPos - perpendicular to its direction of motion. Another boid is in front of - boid if it is to the right or left of this linedepending on whether - boid is moving right or left. However, if boid is travelling - vertically then just compare their vertical coordinates. - - */ - // xy plane - - // if boid is not travelling vertically... - if (boid->oldDir.x != 0) - { - // calculate gradient of a line _perpendicular_ to its direction (hence - // the minus) - grad = -boid->oldDir.y / boid->oldDir.x; + boids_free(x); - // calculate where this line hits the y axis (from y = mx + c) - intercept = boid->oldPos.y - (grad * boid->oldPos.x); + /* resize boids and allocate the list of boids */ + x->x_num_boids = num_boids; + x->x_boid = boid_list_new(num_boids); - /* 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 = (boid->oldDir.x > 0); - - if (result == 0) - return 0; - else - goto next; - } - else - { - /* return true if the first boid's horizontal movement is +ve */ - result = (boid->oldDir.x < 0); - if (result == 0) - return 0; - else - goto next; - } - } - /* else boid is travelling vertically, so just compare vertical - * coordinates - */ - else if (boid->oldDir.y > 0) - { - result = (neighbor->oldPos.y > boid->oldPos.y); - if (result == 0) - { - return 0; - } - else - { - goto next; - } - } - else - { - result = (neighbor->oldPos.y < boid->oldPos.y); - if (result == 0) - { - return 0; - } - else - { - goto next; - } - } -next: - // yz plane - if (!boid->x_z) - return 1; + /* define dimensions and allocate center and atract positions */ + x->x_dimensions = dimensions; + x->x_position_attract = point_new(dimensions); + x->x_position_center = point_new(dimensions); - // if boid is not travelling vertically... - if (boid->oldDir.y != 0) - { - // calculate gradient of a line _perpendicular_ to its direction (hence - // the minus) - grad = -boid->oldDir.z / boid->oldDir.y; + /* allocate the boundaries (depends on dimensions) */ + boids_bounds_alloc(x); - // calculate where this line hits the y axis (from y = mx + c) - intercept = boid->oldPos.z - (grad * boid->oldPos.y); + /* initialize the parameters */ + x->x_params = boid_params_new(); - // 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 = (boid->oldDir.y > 0); - if (result == 0) - { - return 0; - } - else - { - goto next2; - } - } - else - { - // return true if the first boid's horizontal movement is +ve - result = (boid->oldDir.y < 0); - if (result == 0) - { - return 0; - } - else - { - goto next2; - } - } - } - // else boid is travelling vertically, so just compare vertical - // coordinates - else if (boid->oldDir.z > 0) - { - result = (neighbor->oldPos.z > boid->oldPos.z); - if (result == 0) - { - return 0; - } - else - { - goto next2; - } - } - else - { - result = (neighbor->oldPos.z < boid->oldPos.z); - if (result == 0) - { - return 0; - } - else - { - goto next2; - } - } -next2: - return 1; + boids_reset(x); } -static void velocity_normalize(t_velocity *direction) +static void boids_dimensions(t_boids *x, t_floatarg fdimen) { - t_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; - } + size_t d = max_dimensions((size_t)fdimen); + if (x->x_dimensions == d) + return; + boids_init(x, d, x->x_max_neighbors); } -static t_float random_integer(t_float minRange, t_float maxRange) +static void boids_float(t_boids *x, t_floatarg fnum_boids) { - size_t qdRdm; - t_float t, result; - - qdRdm = rand(); - t = (t_float)qdRdm / 65536.0; // now 0 <= t <= 1 - result = (t * (maxRange - minRange)) + minRange; - return (result); + size_t num_boids = fnum_boids < 0.0 ? 0 : (size_t)fnum_boids; + if (x->x_num_boids == num_boids) + return; + boids_init(x, x->x_dimensions, num_boids); } -static t_float point_squareDistance(t_point firstPoint, t_point secondPoint) +static void boids_mode(t_boids *x, t_floatarg f) { - t_float 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); + const int m = (int)f; + x->x_mode = m < BOID_NEWPOS ? BOID_NEWPOS : BOID_ALL < m ? BOID_ALL : m; } -static void *boids_new(t_boids *x, t_floatarg f, t_floatarg g) +/* ----------------------- pd objects general initialization ---------------- */ + +static void *boids_donew(t_boids *x, t_floatarg f, t_floatarg g) { x->x_out1 = outlet_new(&x->x_obj, gensym("list")); x->x_out2 = outlet_new(&x->x_obj, gensym("list")); - boids_float(x, f ? f : (t_floatarg)kNumBoids); + /* initial number of boids */ + boids_float(x, f ? f : 12.); boids_mode(x, g ? g : 0.0); return x; } +static void *boids_new(t_floatarg f, t_floatarg g) +{ + t_boids *x = (t_boids *)pd_new(boids_class); + x->x_dimensions = 2; // default to 2 dimensions + return boids_donew(x, f, g); +} + +/* old creator for the boids2d object for backwards compatibility */ static void *boids2d_new(t_floatarg f, t_floatarg g) { t_boids *x = (t_boids *)pd_new(boids2d_class); - x->x_z = 0.0; - return boids_new(x, f, g); + x->x_dimensions = 2; + return boids_donew(x, f, g); } +/* old creator for the boids3d object for backwards compatibility */ static void *boids3d_new(t_floatarg f, t_floatarg g) { t_boids *x = (t_boids *)pd_new(boids3d_class); - x->x_z = 1.0; - return boids_new(x, f, g); + x->x_dimensions = 3; + return boids_donew(x, f, g); } void boids_setup(void) { - const char *boids_names[2] = {"boids2d", "boids3d"}; - t_newmethod *boids_newfun[2] = {(t_newmethod)boids2d_new, - (t_newmethod)boids3d_new}; - t_class **boids_class[2] = {&boids2d_class, &boids3d_class}; + const char *boids_names[3] = {"boids2d", "boids3d", "boids"}; + t_newmethod boids_newfun[3] = {(t_newmethod)boids2d_new, + (t_newmethod)boids3d_new, + (t_newmethod)boids_new}; + t_class **boid_classes[3] = {&boids2d_class, &boids3d_class, &boids_class}; - for (int i = 0; i < 2; i++) + for (int i = 0; i < 3; i++) { t_class *c = class_new(gensym(boids_names[i]), (t_newmethod)boids_newfun[i], (t_method)boids_free, sizeof(t_boids), 0, A_DEFFLOAT, A_DEFFLOAT, A_NULL); - *boids_class[i] = c; + *boid_classes[i] = c; class_sethelpsymbol(c, gensym(boids_names[i])); class_addfloat(c, (t_method)boids_float); class_addbang(c, (t_method)boids_bang); - class_addmethod(c, (t_method)boids_numNeighbors, gensym("neighbors"), + class_addmethod(c, (t_method)boids_num_neighbors, gensym("neighbors"), A_FLOAT, A_NULL); class_addmethod(c, (t_method)boids_float, gensym("number"), A_FLOAT, A_NULL); @@ -1059,16 +808,21 @@ void boids_setup(void) A_FLOAT, A_NULL); class_addmethod(c, (t_method)boids_prefDist, gensym("prefdist"), A_FLOAT, A_NULL); - class_addmethod(c, (t_method)boids_flyRect, gensym("flyrect"), A_GIMME, + class_addmethod(c, (t_method)boids_bounds, gensym("flyrect"), A_GIMME, A_NULL); - class_addmethod(c, (t_method)boids_attractPt, gensym("attractpt"), - A_GIMME, A_NULL); - class_addmethod(c, (t_method)boids_resetBoids, gensym("reset"), A_NULL); - class_addmethod(c, (t_method)boids_reset, gensym("init"), A_NULL); + class_addmethod(c, (t_method)boids_position_attract, + gensym("attractpt"), A_GIMME, A_NULL); + class_addmethod(c, (t_method)boids_reset, gensym("reset"), A_NULL); + class_addmethod(c, (t_method)boids_init, gensym("init"), A_NULL); class_addmethod(c, (t_method)boids_dump, gensym("dump"), A_NULL); } + /* add the dimensions method only to the new boids class */ + class_addmethod(boids_class, (t_method)boids_dimensions, + gensym("dimensions"), A_FLOAT, A_NULL); + logpost(NULL, 4, - "boids3d 2005-2006 a.sier / jasch © 1995-2003 eric l. singer " + "boids 2026 fdch / boids3d 2005-2006 a.sier / jasch © 1995-2003 " + "eric l. singer " " " __DATE__ " " __TIME__); } diff --git a/src/boids.h b/src/boids.h index d5a3417..e6b01bf 100644 --- a/src/boids.h +++ b/src/boids.h @@ -1,7 +1,7 @@ /* - boids3d 2005 - 2006 a.sier / jasch adapted from boids by eric singer © 1995-2003 eric l. singer + updated by fdch 2026 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 @@ -17,38 +17,17 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef BOIDS_H +#define BOIDS_H + +#include "boid_params.h" #include "m_pd.h" +#include "point.h" #include // constants #define kMaxLong 0xFFFFFFFF #define kMaxNeighbors 16 -#define BOIDS_PI \ - 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068 -#define D2R (BOIDS_PI / 180.0); -#define R2D (180.0 / BOIDS_PI); - -// initial flight parameters -const size_t kNumBoids = 12; // number of boids -const size_t kNumNeighbors = 2; // must be <= kMaxNeighbors -const t_float kMinSpeed = 0.15; // boids' minimum speed -const t_float kMaxSpeed = 0.25; // boids' maximum speed -const t_float kCenterWeight = 0.25; // flock centering -const t_float kAttractWeight = 0.300; // attraction point seeking -const t_float kMatchWeight = 0.100; // neighbors velocity matching -const t_float kAvoidWeight = 0.10; // neighbors avoidance -const t_float kWallsWeight = 0.500; // wall avoidance [210] -const t_float kEdgeDist = 0.5; // vision distance to avoid wall edges [5] -const t_float kSpeedupFactor = 0.100; // alter animation speed -const t_float kInertiaFactor = 0.20; // willingness to change speed & direction -const t_float kAccelFactor = 0.1; // neighbor avoidance accel or decelerate rate -const t_float kPrefDist = 0.25; // preferred distance from neighbors -const t_float kFlyRectTop = 1.0; // fly rect boundaries -const t_float kFlyRectLeft = -1.0; -const t_float kFlyRectBottom = -1.0; -const t_float kFlyRectRight = 1.0; -const t_float kFlyRectFront = 1.0; -const t_float kFlyRectBack = -1.0; enum boid_output_mode { @@ -57,63 +36,63 @@ enum boid_output_mode BOID_ALL }; -typedef struct _point -{ - size_t dimensions; - t_float *old; - t_float *new; -} t_point; +typedef struct _neighbor t_neighbor; +typedef struct _boid t_boid; +typedef struct _boids t_boids; typedef struct _neighbor { - size_t n_num_neighbors; - size_t *n_neighbor; - t_float *n_neighbor_dist_sqr; + t_neighbor *x_next; + t_boid *x_boid; + t_float x_distance; } t_neighbor; typedef struct _boid { - t_point b_position; - t_point b_velocity; - t_float b_speed; - t_neighbor *b_neighbor; + t_boid *x_next; // pointer to the next boid + t_boids *x_flock; // pointer to the main boids "flock" parent structure + t_neighbor *x_neighbors; // list of neighbors + t_point x_position; // position in space + t_point x_direction; // direction vector (velocity) + t_float x_speed; // total speed of this boid } t_boid; -typedef struct _boid_params -{ - t_float min_speed; - t_float max_speed; - t_float center_weight; - t_float attract_weight; - t_float match_weight; - t_float avoid_weight; - t_float walls_weight; - t_float edge_dist; - t_float speedup_factor; - t_float inertia_factor; - t_float accel_factor; - t_float pref_dist; - t_float pref_distSqr; -} t_boid_params; - +/* a "flock" parent structure for all boids */ typedef struct _boids { t_object x_obj; - t_outlet *x_out1, *x_out2; - - t_boid *x_boid; - - size_t x_dimensions; - t_float *x_position_center; - t_float *x_position_attract; - t_float *x_bounds; - - t_float d2r, r2d; - - size_t x_num_boids; - size_t x_num_neighbors; - + t_outlet *x_out1; + t_outlet *x_out2; + + /* temporary storage */ + t_boid *x_boid; // the list of boids belonging to this parent "flock" + t_point *x_position_center; // center position for this "flock" + t_point *x_position_attract; // attraction point for this "flock" + t_float *x_bounds; // boundaries in which the boids move + t_boid_params *x_params; // parameters of this "flock" + + /* general object settings */ + size_t x_dimensions; // number of spatial dimensions + size_t x_num_boids; // total number of boids + size_t x_max_neighbors; // max number of neighbors to look for enum boid_output_mode x_mode; - t_boid_params *x_params; } t_boids; + +/* --------------------------- points structure ----------------------------- */ + +/* a set of points used by the boids algorithm to move the boids */ +typedef struct _points +{ + t_point *avoidNeighborVel; + t_point *avoidWallsVel; + t_point *goAttractVel; + t_point *goCenterVel; + t_point *matchNeighborVel; +} t_points; + +t_points *points_new(size_t dimensions); +void points_free(t_points *x); +void point_velocity(t_point *x, t_boid_params *p, t_points *pts); + +#endif diff --git a/src/point.c b/src/point.c new file mode 100644 index 0000000..4af4a81 --- /dev/null +++ b/src/point.c @@ -0,0 +1,238 @@ +/* + boids3d 2005 - 2006 a.sier / jasch + adapted from boids by eric singer © 1995-2003 eric l. singer + updated by fdch 2026 + + 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 "point.h" +#include "boid_params.h" +#include "m_pd.h" +#include +#include +#include + +/* ---------------------------- helper clipper ----------------------------- */ + +size_t max_dimensions(size_t dimensions) +{ + return dimensions < 1 ? 1 : dimensions > 64 ? 64 : dimensions; +} + +t_float random_integer(t_float minRange, t_float maxRange) +{ + t_float x = (t_float)rand() / (t_float)RAND_MAX + 1.0; + return x * (maxRange - minRange) + minRange; +} + +/* ---------------------------- point structure ----------------------------- */ + +void point_fill(t_point *x, t_float c) +{ + memset(x->x_new, c, sizeof(t_float) * x->x_dimensions); + memset(x->x_old, c, sizeof(t_float) * x->x_dimensions); +} + +void point_init(t_point *x, size_t dimensions) +{ + if (x->x_dimensions == dimensions) + return; + x->x_dimensions = dimensions; + point_fill(x, 0.0); +} + +void point_rand_from_range(t_point *x, t_float *range) +{ + for (size_t i = 0; i < x->x_dimensions; i++) + { + x->x_new[i] = x->x_old[i] = random_integer(range[0], range[1]); + } +} + +void point_rand_from_angle(t_point *x) +{ + + if (!x->x_dimensions) + return; + + t_float rad_angle = random_integer(0, 360) * D2R; + + if (x->x_dimensions == 1) + { + x->x_new[0] = cos(rad_angle); + return; + } + if (x->x_dimensions == 2) + { + x->x_new[0] = sin(rad_angle); + x->x_new[1] = cos(rad_angle); + return; + } + if (x->x_dimensions == 3) + { + x->x_new[0] = sin(rad_angle); + x->x_new[1] = cos(rad_angle); + x->x_new[2] = (x->x_new[0] + x->x_new[1]) * 0.5; + return; + } + + /* if we venture into this space, here's a random approach */ + t_float len2 = 0.0; + + for (size_t i = 0; i < x->x_dimensions; ++i) + { + x->x_new[i] = random_integer(-12345, 54321) * rad_angle; + len2 += x->x_new[i] * x->x_new[i]; + } + + t_float len = sqrt(len2); + + if (len == 0.0) + { + x->x_new[0] = 1.0; + for (size_t i = 1; i < x->x_dimensions; ++i) + x->x_new[i] = 0.0; + return; + } + t_float inv_len = 1.0 / len; + + for (size_t i = 0; i < x->x_dimensions; ++i) + { + x->x_new[i] *= inv_len; + } +} + +void point_free(t_point *x) +{ + if (!x) + return; + freebytes(x, sizeof(t_point)); + x = NULL; +} + +t_point *point_new(size_t dimensions) +{ + t_point *x = (t_point *)getbytes(sizeof(t_point)); + size_t d = max_dimensions(dimensions); + x->x_new = (t_float *)getbytes(sizeof(t_float) * d); + x->x_old = (t_float *)getbytes(sizeof(t_float) * d); + point_init(x, d); + return x; +} + +/* update a point in all dimensions and advance old<-new */ +void point_update(t_point *x, int argc, t_atom *argv) +{ + if (!argc || argc != (int)x->x_dimensions) + return; + + t_float *old_ptr = x->x_old; + t_float *new_ptr = x->x_new; + while (argc) + { + *old_ptr++ = *new_ptr; + *new_ptr = atom_getfloat(argv++); + argc--, new_ptr++; + } +} + +/* advance a point in all dimensions old<-new (no update) */ +void point_step(t_point *x) +{ + for (size_t i = 0; i < x->x_dimensions; i++) + x->x_old[i] = x->x_new[i]; +} + +/* normalize a point to a given max value */ +void point_normalize(t_point *p, t_float fmax) +{ + t_float inv_max = 1.0 / (fmax + 1e-13); + for (size_t i = 0; i < p->x_dimensions; i++) + p->x_new[i] *= inv_max; +} + +/* normalize a point in all dimensions with their distance */ +void point_norm_square(t_point *p) +{ + t_float h = 0.0, x = 0.0; + + for (size_t i = 0; i < p->x_dimensions; i++) + x += (p->x_new[i] * p->x_new[i]); + + h = sqrt(x); + + if (h == 0.0) + return; + + point_normalize(p, h); +} + +/* compute the square distance between two points */ +void point_square_distance(t_point *a, t_point *b, t_float *distance) +{ + for (size_t i = 0; i < a->x_dimensions; i++) + { + t_float d = a->x_new[i] - b->x_new[i]; + *distance += (d * d); + } +} + +/* update a point new by adding another point old */ +void point_add(t_point *a, t_point *b) +{ + if (a->x_dimensions != b->x_dimensions) + return; + + for (size_t i = 0; i < a->x_dimensions; i++) + a->x_new[i] += b->x_old[i]; +} + +/* compute the difference between two points' old dimensions */ +t_point *point_diff(t_point *a, t_point *b) +{ + t_point *c = point_new(a->x_dimensions); + + if (a->x_dimensions != b->x_dimensions) + return c; + + for (size_t i = 0; i < a->x_dimensions; i++) + c->x_new[i] = a->x_old[i] - b->x_old[i]; + + return c; +} + +void point_update_velocity(t_point *diff, t_point *velocity, t_float fstep) +{ + + if (diff->x_dimensions != velocity->x_dimensions) + return; + + for (size_t i = 0; i < diff->x_dimensions; i++) + velocity->x_new[i] -= diff->x_new[i] - diff->x_new[i] * fstep; +} + +t_float point_infront_dot_old(t_point *a_pos, t_point *b_pos, t_point *a_dir) +{ + t_float dot = 0.0; + size_t n = a_pos->x_dimensions; + + for (size_t i = 0; i < n; i++) + { + t_float rel = b_pos->x_old[i] - a_pos->x_old[i]; + t_float dir = a_dir->x_old[i]; + dot += rel * dir; + } + return dot; +} diff --git a/src/point.h b/src/point.h new file mode 100644 index 0000000..888d8f5 --- /dev/null +++ b/src/point.h @@ -0,0 +1,57 @@ +/* + boids3d 2005 - 2006 a.sier / jasch + adapted from boids by eric singer © 1995-2003 eric l. singer + updated by fdch 2026 + + 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 +*/ +#ifndef POINT_H +#define POINT_H + +#include "m_pd.h" + +#define BOIDS_PI \ + 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068 +#define D2R (BOIDS_PI / 180.0) +#define R2D (180.0 / BOIDS_PI) + +size_t max_dimensions(size_t dimensions); +t_float random_integer(t_float minRange, t_float maxRange); + +/* a point structure in n-dimensional space */ +typedef struct _point +{ + size_t x_dimensions; // the number of dimensions (i.e., data points) + t_float *x_old; // the previous data of this point + t_float *x_new; // the current data of this point +} t_point; + +t_point *point_new(size_t dimensions); +t_point *point_diff(t_point *a, t_point *b); +void point_fill(t_point *x, t_float c); +void point_free(t_point *x); +void point_init(t_point *x, size_t dimensions); +void point_normalize(t_point *p, t_float fmax); +void point_norm_square(t_point *p); +void point_square_distance(t_point *a, t_point *b, t_float *distance); +void point_step(t_point *x); +void point_update(t_point *x, int argc, t_atom *argv); +void point_rand_from_range(t_point *x, t_float *range); +void point_rand_from_angle(t_point *x); +void point_add(t_point *a, t_point *b); +void point_update_velocity(t_point *distance, t_point *velocity, t_float fstep); +t_float point_infront_dot_old(t_point *a_pos, t_point *b_pos, t_point *a_dir); + +#endif diff --git a/tests/load-test.pd b/tests/load-test.pd index 54f9f36..b1ce273 100644 --- a/tests/load-test.pd +++ b/tests/load-test.pd @@ -1,4 +1,4 @@ -#N canvas 0 0 450 300 12; +#N canvas 0 0 530 402 12; #X obj 37 37 boids2d; #X obj 36 67 boids2d 5; #X obj 35 95 boids2d 5 0; @@ -17,3 +17,12 @@ #X obj 343 94 boids3d 15 0; #X obj 344 122 boids3d 15 1; #X obj 343 148 boids3d 15 2; +#X obj 43 207 boids; +#X obj 42 237 boids 5; +#X obj 41 265 boids 5 0; +#X obj 42 293 boids 5 1; +#X obj 41 319 boids 5 2; +#X obj 143 234 boids 15; +#X obj 137 264 boids 15 0; +#X obj 138 292 boids 15 1; +#X obj 137 318 boids 15 2; From 780df956ddc8939986064316da8d0a891424fdc9 Mon Sep 17 00:00:00 2001 From: fdch Date: Fri, 24 Apr 2026 16:19:09 +0200 Subject: [PATCH 06/19] add a CI --- .github/actions/setup-pd/action.yml | 17 ++++++ .github/workflows/main.yml | 83 +++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 .github/actions/setup-pd/action.yml create mode 100644 .github/workflows/main.yml diff --git a/.github/actions/setup-pd/action.yml b/.github/actions/setup-pd/action.yml new file mode 100644 index 0000000..c79b6aa --- /dev/null +++ b/.github/actions/setup-pd/action.yml @@ -0,0 +1,17 @@ +name: Setup Pure Data +description: Checkout code and setup Pure Data dependencies + +runs: + using: composite + steps: + - name: get pdlibbuilder + shell: bash + run: | + git submodule init + git submodule update + + - name: get pd + uses: actions/checkout@v6 + with: + repository: pure-data/pure-data + path: pure-data diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..0b726ea --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,83 @@ +name: Cross-Platform Compile +description: Compiles on multiple platforms and publishes to deken when tags are pushed + +on: + workflow_dispatch: + + push: + branches: + - main + paths: + - "include/**" + - "src/**" + - "Makefile" + - "config.sh" + + tags: + - 'v*' + + pull_request: + paths: + - "include/**" + - "src/**" + - "Makefile" + - "config.sh" + +jobs: + build: + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + + runs-on: ${{ matrix.os }} + + defaults: + run: + shell: bash + + env: + PDVERSION: pd-0.56-2 + + steps: + - uses: actions/checkout@v6 + + # ---- platform-specific setup ---- + - name: setup pd (unix) + if: matrix.os != 'windows-latest' + uses: ./.github/actions/setup-pd + + - name: install mac deps + if: matrix.os == 'macos-latest' + run: brew install automake autoconf libtool + + - name: setup windows deps + if: matrix.os == 'windows-latest' + run: | + echo "local_short_commands=true" >> $GITHUB_ENV + git submodule init && git submodule update + curl -O "http://msp.ucsd.edu/Software/$PDVERSION.msw.zip" + unzip "$PDVERSION.msw.zip" + + # ---- build ---- + - name: configure + run: bash config.sh + + - name: make (unix) + if: matrix.os != 'windows-latest' + run: make PDINCLUDEDIR=pure-data/src + + - name: make (windows) + if: matrix.os == 'windows-latest' + run: make pdbinpath="$PDVERSION/bin" PDINCLUDEDIR="$PDVERSION/src" CFLAGS=-march=x86-64 + + # ---- package ---- + - name: package library + run: | + bash scripts/package_lib.sh "${{ matrix.os }}" + + - name: upload artifact + uses: actions/upload-artifact@v6 + with: + name: "boids-${{ github.ref_name }}-${{ matrix.os }}-build" + path: "${{ matrix.os }}" + if-no-files-found: error From 693a9784bd0a9930091ad1c33d6d8976e32b4759 Mon Sep 17 00:00:00 2001 From: fdch Date: Sat, 25 Apr 2026 22:37:45 +0200 Subject: [PATCH 07/19] cleanup helpfiles and add example --- examples/boids2d-gem.pd | 164 ++++++++++++ examples/boids2d-struct.pd | 261 +++++++++++++++++++ examples/boids3d-gem.pd | 278 +++++++++++++++++++++ examples/gemboid.pd | 101 ++++++-- examples/struct-boid.pd | 74 ++++++ help/boids-params.pd | 82 ++++++ help/boids2d-help.pd | 465 +++++++++++++--------------------- help/boids3d-help.pd | 497 +++++++++++++++---------------------- 8 files changed, 1322 insertions(+), 600 deletions(-) create mode 100644 examples/boids2d-gem.pd create mode 100644 examples/boids2d-struct.pd create mode 100644 examples/boids3d-gem.pd create mode 100644 examples/struct-boid.pd create mode 100644 help/boids-params.pd diff --git a/examples/boids2d-gem.pd b/examples/boids2d-gem.pd new file mode 100644 index 0000000..2eac930 --- /dev/null +++ b/examples/boids2d-gem.pd @@ -0,0 +1,164 @@ +#N canvas 888 92 711 590 12; +#X declare -lib Gem; +#X msg 75 47 destroy; +#N canvas 494 140 629 324 gemwin 0; +#X obj 209 190 gemwin; +#X obj 67 194 outlet; +#X obj 67 10 inlet; +#X obj 67 41 route create; +#X msg 67 70 set destroy; +#X msg 157 70 set create; +#X msg 350 115 destroy \, reset; +#X obj 157 18 loadbang; +#X msg 212 146 create \, 1 \, frame 30 \, color 0 0 0.5; +#X msg 238 71 color 1 1 1; +#X connect 2 0 3 0; +#X connect 3 0 4 0; +#X connect 3 0 8 0; +#X connect 3 1 5 0; +#X connect 3 1 6 0; +#X connect 4 0 1 0; +#X connect 5 0 1 0; +#X connect 6 0 0 0; +#X connect 7 0 5 0; +#X connect 8 0 0 0; +#X connect 9 0 0 0; +#X restore 75 67 pd gemwin; +#N canvas 0 22 888 657 orbit 0; +#X obj 393 192 expr $f1 * (3.141593/180.); +#X msg 393 215 1.5 \$1; +#X obj 222 575 s \$0-orbit; +#X obj 333 59 gemhead; +#X obj 367 433 translateXYZ; +#X msg 399 498 draw line; +#X obj 402 470 loadbang; +#X obj 330 108 alpha; +#X obj 332 84 color 1 0.5 0 0.5; +#X obj 347 541 circle 0.1; +#X obj 416 403 unpack; +#X obj 397 373 t a a; +#X obj 334 136 t a b; +#X obj 454 267 t f f; +#X obj 451 295 cos; +#X obj 485 293 sin; +#X obj 404 318 * 1; +#X obj 394 266 t f f; +#X obj 435 318 * 0; +#X obj 402 348 pack; +#X obj 393 164 f; +#X obj 421 165 + 1; +#X obj 452 165 mod 360; +#X obj 391 240 unpack; +#X connect 0 0 1 0; +#X connect 1 0 23 0; +#X connect 3 0 8 0; +#X connect 4 0 9 0; +#X connect 5 0 9 0; +#X connect 6 0 5 0; +#X connect 7 0 12 0; +#X connect 8 0 7 0; +#X connect 10 0 4 1; +#X connect 10 1 4 2; +#X connect 11 0 2 0; +#X connect 11 1 10 0; +#X connect 12 0 4 0; +#X connect 12 1 20 0; +#X connect 13 0 14 0; +#X connect 13 1 15 0; +#X connect 14 0 16 1; +#X connect 15 0 18 1; +#X connect 16 0 19 0; +#X connect 17 0 16 0; +#X connect 17 1 18 0; +#X connect 18 0 19 1; +#X connect 19 0 11 0; +#X connect 20 0 21 0; +#X connect 20 0 0 0; +#X connect 21 0 22 0; +#X connect 22 0 20 1; +#X connect 23 0 17 0; +#X connect 23 1 13 0; +#X restore 77 158 pd orbit; +#X msg 70 321 attractpt \$1 \$2; +#X text 39 119 point to which boids are attracted (x/y), f 23; +#X obj 54 209 tgl 20 0 empty empty start\ flocking\ animation 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X text 24 15 create/destroy the GEM window; +#X obj 584 27 declare -lib Gem; +#X obj 322 67 help/boids-params \$0; +#X floatatom 295 149 5 0 0 0 left \$0-flyrect0 - 0; +#X floatatom 356 113 6 0 0 0 top \$0-flyrect1 - 0; +#X floatatom 444 143 5 0 0 0 right \$0-flyrect2 - 0; +#X floatatom 505 182 5 0 0 0 bottom \$0-flyrect3 - 0; +#N canvas 0 0 450 300 2D-bounding-box 0; +#X msg 58 156 flyrect \$1 \$2 \$3 \$4; +#X obj 58 181 s \$0-boids-params; +#X msg 262 41 -1 1 1 -1; +#X msg 262 91 \; \$1-flyrect0 \$2 \; \$1-flyrect1 \$3 \; \$1-flyrect2 \$4 \; \$1-flyrect3 \$5; +#X obj 262 66 list prepend \$0; +#X text 336 44 defaults; +#X obj 261 13 r \$0-reset; +#X obj 29 27 inlet; +#X obj 74 29 inlet; +#X obj 119 29 inlet; +#X obj 170 29 inlet; +#X obj 41 76 pack f f f f; +#X connect 0 0 1 0; +#X connect 2 0 4 0; +#X connect 4 0 3 0; +#X connect 6 0 2 0; +#X connect 7 0 11 0; +#X connect 8 0 11 1; +#X connect 9 0 11 2; +#X connect 10 0 11 3; +#X connect 11 0 0 0; +#X restore 331 208 pd 2D-bounding-box; +#X f 23; +#X obj 72 292 r \$0-orbit; +#X obj 598 58 loadbang; +#X obj 598 83 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; +#X obj 598 108 s \$0-reset; +#X msg 88 361 reset; +#X obj 98 413 r \$0-boids-params; +#X obj 51 456 boids2d 16; +#X obj 51 512 clone -x gemboid 16 \$0; +#X msg 93 386 dump; +#X obj 119 482 print dump; +#X text 255 41 Change parameters to see their effect:; +#X floatatom 109 226 5 0 0 0 - - - 0; +#X obj 51 252 metro 25; +#X text 150 226 animation speed; +#X floatatom 326 269 5 0 0 0 - - - 0; +#X obj 326 293 abs; +#X obj 326 318 t f f; +#X obj 326 343 * -1; +#X obj 326 368 pack; +#X msg 327 398 \$1 \$2 \$2 \$1; +#X msg 333 448 \; \$1-flyrect0 \$2 \; \$1-flyrect1 \$3 \; \$1-flyrect2 \$4 \; \$1-flyrect3 \$5; +#X obj 333 423 list prepend \$0; +#X text 375 270 symmetrical bounding box; +#X connect 0 0 1 0; +#X connect 1 0 0 0; +#X connect 3 0 20 0; +#X connect 5 0 26 0; +#X connect 9 0 13 0; +#X connect 10 0 13 1; +#X connect 11 0 13 2; +#X connect 12 0 13 3; +#X connect 14 0 3 0; +#X connect 15 0 16 0; +#X connect 16 0 17 0; +#X connect 18 0 20 0; +#X connect 19 0 20 0; +#X connect 20 0 21 0; +#X connect 20 1 23 0; +#X connect 22 0 20 0; +#X connect 25 0 26 1; +#X connect 26 0 20 0; +#X connect 28 0 29 0; +#X connect 29 0 30 0; +#X connect 30 0 31 0; +#X connect 30 1 32 1; +#X connect 31 0 32 0; +#X connect 32 0 33 0; +#X connect 33 0 35 0; +#X connect 35 0 34 0; diff --git a/examples/boids2d-struct.pd b/examples/boids2d-struct.pd new file mode 100644 index 0000000..a6a3ca7 --- /dev/null +++ b/examples/boids2d-struct.pd @@ -0,0 +1,261 @@ +#N canvas 780 192 827 545 12; +#N struct \$0-template float x float y float k float i; +#N struct \$0-attractpoint float x float y; +#N canvas 0 25 554 469 \$0-data 0; +#X scalar \$0-template -257 -271 46 15 \;; +#X scalar \$0-template -4 160 1 14 \;; +#X scalar \$0-template -157 -59 27 13 \;; +#X scalar \$0-template -22 -165 35 12 \;; +#X scalar \$0-template 121 -44 78 11 \;; +#X scalar \$0-template 138 -175 47 10 \;; +#X scalar \$0-template -184 248 84 9 \;; +#X scalar \$0-template 180 -140 8 8 \;; +#X scalar \$0-template 80 -121 63 7 \;; +#X scalar \$0-template 288 207 73 6 \;; +#X scalar \$0-template -200 10 1 5 \;; +#X scalar \$0-template 234 108 48 4 \;; +#X scalar \$0-template -137 293 91 3 \;; +#X scalar \$0-template -206 143 43 2 \;; +#X scalar \$0-template -118 -267 30 1 \;; +#X scalar \$0-template 77 39 48 0 \;; +#X scalar \$0-attractpoint 0 0 \;; +#X coords -300 -300 300 300 300 300 2 100 100; +#X restore 27 183 pd \$0-data; +#N canvas 167 269 524 337 \$0-template 0; +#X obj 54 46 filledpolygon k k 0 -10 0 0 10 10 0 0 -10; +#X text 93 161 Struct that defines each boid diamond; +#X text 125 200 color can be changed with k; +#X obj 40 20 struct \$0-template float x float y float k float i; +#X obj 60 84 r \$0-indices; +#X obj 60 116 drawnumber -n i 5 5 k; +#X connect 4 0 5 0; +#X restore 31 132 pd \$0-template; +#X floatatom 383 404 5 0 0 0 left \$0-flyrect0 - 0; +#X floatatom 425 380 5 0 0 0 top \$0-flyrect1 - 0; +#X floatatom 491 398 5 0 0 0 right \$0-flyrect2 - 0; +#X floatatom 559 416 5 0 0 0 bottom \$0-flyrect3 - 0; +#N canvas 0 0 450 300 2D-bounding-box 0; +#X msg 58 156 flyrect \$1 \$2 \$3 \$4; +#X obj 58 181 s \$0-boids-params; +#X obj 29 27 inlet; +#X obj 74 29 inlet; +#X obj 119 29 inlet; +#X obj 170 29 inlet; +#X obj 41 76 pack f f f f; +#X connect 0 0 1 0; +#X connect 2 0 6 0; +#X connect 3 0 6 1; +#X connect 4 0 6 2; +#X connect 5 0 6 3; +#X connect 6 0 0 0; +#X restore 391 443 pd 2D-bounding-box; +#X f 23; +#X obj 32 78 help/boids-params \$0; +#N canvas 1059 309 598 557 \$0-attractpoint 0; +#X obj 232 239 f \$0; +#X msg 232 264 traverse pd-\$1-data \, bang; +#X obj 232 289 pointer; +#X obj 90 138 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; +#X msg 443 234 clear; +#X obj 443 259 s pd-\$0-data; +#X obj 56 109 loadbang; +#X obj 63 165 t b b b b b, f 34; +#X obj 86 392 r \$0-attractpt; +#X obj 42 28 struct \$0-attractpoint float x float y; +#X obj 56 481 s \$0-init-boids; +#X obj 89 415 set \$0-attractpoint x y; +#X obj 124 324 append \$0-attractpoint x y; +#X msg 124 296 0 0; +#X obj 39 68 drawcurve 0 1 0 0 0 10 10 10 10 0 0 0; +#X obj 387 368 list prepend \$0; +#X obj 421 333 s \$0-reset; +#X obj 383 302 t b b; +#X msg 390 395 \; \$1-maxspeed 50 \; \$1-minspeed 10 \; \; \$1-flyrect0 -1 \; \$1-flyrect1 1 \; \$1-flyrect2 1 \; \$1-flyrect3 -1; +#X obj 130 108 r \$0-init; +#X text 267 116 Struct that defines the attraction circle; +#X connect 0 0 1 0; +#X connect 1 0 2 0; +#X connect 2 0 12 2; +#X connect 3 0 7 0; +#X connect 4 0 5 0; +#X connect 6 0 7 0; +#X connect 7 0 10 0; +#X connect 7 1 13 0; +#X connect 7 2 0 0; +#X connect 7 3 17 0; +#X connect 7 4 4 0; +#X connect 8 0 11 0; +#X connect 12 0 11 2; +#X connect 13 0 12 0; +#X connect 15 0 18 0; +#X connect 17 0 15 0; +#X connect 17 1 16 0; +#X connect 19 0 7 0; +#X restore 31 106 pd \$0-attractpoint; +#N canvas 323 118 689 551 random-walk 0; +#X obj 167 125 f; +#X obj 74 197 random 2; +#X obj 167 150 t b b f; +#X obj 195 351 +; +#X obj 140 276 + 1; +#X obj 122 332 *; +#X msg 64 305 -1; +#X obj 278 85 moses 0; +#X obj 324 115 moses 100; +#X obj 278 115 * -1; +#X obj 384 143 * -1; +#X obj 384 168 + 200; +#X msg 97 305 1; +#X text 80 223 sign; +#X text 142 240 magnitude; +#X text 228 340 add prev value; +#X text 227 355 to random increment; +#X obj 304 202 t f f; +#X obj 362 284 outlet; +#X obj 167 24 inlet; +#X obj 163 66 b; +#X text 97 461 Pure Data/2.control.examples/22.random-walk.pd, f 74; +#X text 140 439 open the browser and look for:; +#X obj 349 243 * 0.01; +#X obj 74 276 sel; +#X obj 140 200 random 2; +#X connect 0 0 2 0; +#X connect 1 0 24 0; +#X connect 2 0 1 0; +#X connect 2 1 25 0; +#X connect 2 2 3 1; +#X connect 3 0 7 0; +#X connect 4 0 5 1; +#X connect 5 0 3 0; +#X connect 6 0 5 0; +#X connect 7 0 9 0; +#X connect 7 1 8 0; +#X connect 8 0 17 0; +#X connect 8 1 10 0; +#X connect 9 0 17 0; +#X connect 10 0 11 0; +#X connect 11 0 17 0; +#X connect 12 0 5 0; +#X connect 17 0 0 1; +#X connect 17 1 23 0; +#X connect 19 0 20 0; +#X connect 20 0 0 0; +#X connect 23 0 18 0; +#X connect 24 0 6 0; +#X connect 24 1 12 0; +#X connect 25 0 4 0; +#X restore 366 209 pd random-walk; +#X obj 366 234 * 600; +#X obj 366 259 - 300; +#X obj 367 109 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#N canvas 657 108 689 551 random-walk 0; +#X obj 167 125 f; +#X obj 74 197 random 2; +#X obj 167 150 t b b f; +#X obj 195 351 +; +#X obj 140 276 + 1; +#X obj 122 332 *; +#X msg 64 305 -1; +#X obj 278 85 moses 0; +#X obj 324 115 moses 100; +#X obj 278 115 * -1; +#X obj 384 143 * -1; +#X obj 384 168 + 200; +#X msg 97 305 1; +#X text 80 223 sign; +#X text 145 221 magnitude; +#X text 228 340 add prev value; +#X text 227 355 to random increment; +#X obj 304 202 t f f; +#X obj 362 284 outlet; +#X obj 167 24 inlet; +#X obj 163 66 b; +#X text 97 461 Pure Data/2.control.examples/22.random-walk.pd, f 74; +#X text 140 439 open the browser and look for:; +#X obj 349 243 * 0.01; +#X obj 74 276 sel; +#X obj 140 198 random 2; +#X connect 0 0 2 0; +#X connect 1 0 24 0; +#X connect 2 0 1 0; +#X connect 2 1 25 0; +#X connect 2 2 3 1; +#X connect 3 0 7 0; +#X connect 4 0 5 1; +#X connect 5 0 3 0; +#X connect 6 0 5 0; +#X connect 7 0 9 0; +#X connect 7 1 8 0; +#X connect 8 0 17 0; +#X connect 8 1 10 0; +#X connect 9 0 17 0; +#X connect 10 0 11 0; +#X connect 11 0 17 0; +#X connect 12 0 5 0; +#X connect 17 0 0 1; +#X connect 17 1 23 0; +#X connect 19 0 20 0; +#X connect 20 0 0 0; +#X connect 23 0 18 0; +#X connect 24 0 6 0; +#X connect 24 1 12 0; +#X connect 25 0 4 0; +#X restore 410 233 pd random-walk; +#X obj 410 258 * 600; +#X obj 410 283 - 300; +#X obj 360 183 t b b; +#X obj 367 134 metro 50; +#X obj 366 284 pack; +#X obj 363 317 s \$0-attractpt; +#X floatatom 433 109 5 0 0 0 - - - 0; +#X msg 663 295 all bang; +#X obj 545 96 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 545 121 metro 10; +#X obj 545 256 boids2d; +#X obj 546 335 clone struct-boid 16 \$0; +#X msg 568 188 reset; +#X obj 614 224 r \$0-boids-params; +#X obj 605 289 print; +#X msg 561 161 dump; +#X msg 638 165 attractpt \$1 \$2; +#X obj 638 141 r \$0-attractpt; +#X obj 666 271 r \$0-init-boids; +#X obj 712 375 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; +#X obj 712 400 s \$0-init; +#X text 359 75 ATTRACTION POINT; +#X text 579 68 Update boids; +#X text 359 359 BOUNDING BOX; +#X floatatom 577 91 5 0 0 0 - - - 0; +#X obj 617 406 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 615 435 s \$0-indices; +#X text 239 24 A 2d boids example using data structures; +#X connect 2 0 6 0; +#X connect 3 0 6 1; +#X connect 4 0 6 2; +#X connect 5 0 6 3; +#X connect 9 0 10 0; +#X connect 10 0 11 0; +#X connect 11 0 18 0; +#X connect 12 0 17 0; +#X connect 13 0 14 0; +#X connect 14 0 15 0; +#X connect 15 0 18 1; +#X connect 16 0 9 0; +#X connect 16 1 13 0; +#X connect 17 0 16 0; +#X connect 18 0 19 0; +#X connect 20 0 17 1; +#X connect 21 0 25 1; +#X connect 22 0 23 0; +#X connect 23 0 24 0; +#X connect 24 0 25 0; +#X connect 24 1 28 0; +#X connect 26 0 24 0; +#X connect 27 0 24 0; +#X connect 29 0 24 0; +#X connect 30 0 24 0; +#X connect 31 0 30 0; +#X connect 32 0 21 0; +#X connect 33 0 34 0; +#X connect 38 0 23 1; +#X connect 39 0 40 0; diff --git a/examples/boids3d-gem.pd b/examples/boids3d-gem.pd new file mode 100644 index 0000000..eb9ca8e --- /dev/null +++ b/examples/boids3d-gem.pd @@ -0,0 +1,278 @@ +#N canvas 854 293 711 590 12; +#X declare -lib Gem; +#X msg 100 40 destroy; +#N canvas 803 136 629 324 gemwin 0; +#X obj 209 190 gemwin; +#X obj 67 194 outlet; +#X obj 67 10 inlet; +#X obj 67 41 route create; +#X msg 67 70 set destroy; +#X msg 157 70 set create; +#X msg 350 115 destroy \, reset; +#X obj 157 18 loadbang; +#X msg 238 71 color 1 1 1; +#X obj 496 28 gemhead; +#X obj 496 50 world_light; +#X msg 212 146 create \, 1 \, frame 30 \, color 0 0 0.5 \, lighting 1; +#X connect 2 0 3 0; +#X connect 3 0 4 0; +#X connect 3 0 11 0; +#X connect 3 1 5 0; +#X connect 3 1 6 0; +#X connect 4 0 1 0; +#X connect 5 0 1 0; +#X connect 6 0 0 0; +#X connect 7 0 5 0; +#X connect 8 0 0 0; +#X connect 9 0 10 0; +#X connect 11 0 0 0; +#X restore 100 60 pd gemwin; +#N canvas 850 212 692 479 orbit 0; +#X obj 63 290 translateXYZ; +#X obj 69 109 color 1 0.5 0 0.5; +#X obj 72 136 t a b; +#X obj 99 260 unpack f f f; +#X obj 402 108 color 1 0.5 0 0.5; +#X obj 416 337 loadbang; +#X obj 59 339 sphere 0.1; +#X obj 402 80 gemhead 58; +#X msg 416 364 draw line; +#X obj 396 302 translateXYZ; +#X obj 436 274 unpack f f f; +#X obj 400 215 translate -4 0 0 1; +#X obj 462 189 * -8; +#X obj 435 244 r \$0-orbit-translation; +#N canvas 0 0 782 606 orbit-translation 0; +#X obj 66 169 expr $f1 * (3.141593/180.); +#X msg 69 217 1.5 \$1; +#X obj 127 268 t f f; +#X obj 124 296 cos; +#X obj 158 294 sin; +#X obj 77 319 * 1; +#X obj 67 267 t f f; +#X obj 108 319 * 0; +#X obj 66 141 f; +#X obj 94 142 + 1; +#X obj 125 142 mod 360; +#X obj 64 241 unpack; +#X obj 66 193 t f f; +#X obj 252 381 pack f f f; +#X obj 192 318 * 2; +#X obj 191 292 sin; +#X obj 58 76 spigot 1; +#X obj 251 45 route float bang; +#X obj 488 130 spigot; +#X obj 542 130 spigot; +#X obj 548 76 t f f; +#X obj 517 35 gemmouse 1 1; +#A saved init; +#X obj 494 170 * 8; +#X obj 494 193 - 4; +#X obj 540 235 - 4; +#X text 566 184 invert y; +#X obj 540 212 * 8; +#X msg 540 153 1 \$1; +#X obj 540 177 -; +#X obj 647 232 spigot; +#X obj 647 257 t b f; +#X obj 556 104 t f f; +#X obj 651 184 * 8; +#X obj 652 206 - 4; +#X obj 250 471 s \$0-orbit-translation; +#X obj 265 14 inlet; +#X obj 55 10 inlet; +#X floatatom 77 344 5 0 0 0 - - - 0; +#X obj 300 82 random 360; +#X text 239 112 random position; +#X text 70 107 move in orbit; +#X text 497 11 mouse interaction; +#X text 591 321 middle click to enable Z motion (up/down), f 19; +#X connect 0 0 12 0; +#X connect 1 0 11 0; +#X connect 2 0 3 0; +#X connect 2 1 4 0; +#X connect 3 0 5 1; +#X connect 4 0 7 1; +#X connect 5 0 13 0; +#X connect 5 0 37 0; +#X connect 6 0 5 0; +#X connect 6 1 7 0; +#X connect 7 0 13 1; +#X connect 8 0 9 0; +#X connect 8 0 0 0; +#X connect 9 0 10 0; +#X connect 10 0 8 1; +#X connect 11 0 6 0; +#X connect 11 1 2 0; +#X connect 12 0 1 0; +#X connect 12 1 15 0; +#X connect 13 0 34 0; +#X connect 14 0 13 2; +#X connect 15 0 14 0; +#X connect 16 0 8 0; +#X connect 17 0 16 1; +#X connect 17 1 38 0; +#X connect 18 0 22 0; +#X connect 19 0 27 0; +#X connect 20 0 18 1; +#X connect 20 1 19 1; +#X connect 21 0 18 0; +#X connect 21 1 31 0; +#X connect 21 2 20 0; +#X connect 21 3 29 1; +#X connect 22 0 23 0; +#X connect 23 0 13 0; +#X connect 24 0 13 1; +#X connect 26 0 24 0; +#X connect 27 0 28 0; +#X connect 28 0 26 0; +#X connect 29 0 30 0; +#X connect 30 0 13 0; +#X connect 30 1 13 2; +#X connect 31 0 19 0; +#X connect 31 1 32 0; +#X connect 32 0 33 0; +#X connect 33 0 29 0; +#X connect 35 0 17 0; +#X connect 36 0 16 0; +#X connect 38 0 8 0; +#X restore 102 166 pd orbit-translation; +#X obj 103 229 r \$0-orbit-translation; +#X text 76 49 a circle; +#X obj 68 82 gemhead; +#X text 423 51 a bounding box; +#X obj 236 18 inlet; +#X obj 462 162 * 0.5; +#X obj 498 378 * 4; +#X obj 397 399 cube 4; +#X obj 504 341 r \$0-bounding-box; +#X obj 463 135 r \$0-bounding-box; +#X obj 46 28 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 383 29 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X connect 0 0 6 0; +#X connect 1 0 2 0; +#X connect 2 0 0 0; +#X connect 2 1 14 0; +#X connect 3 0 0 1; +#X connect 3 1 0 2; +#X connect 3 2 0 3; +#X connect 4 0 11 0; +#X connect 5 0 8 0; +#X connect 7 0 4 0; +#X connect 8 0 22 0; +#X connect 9 0 22 0; +#X connect 10 0 9 1; +#X connect 10 1 9 2; +#X connect 10 2 9 3; +#X connect 11 0 9 0; +#X connect 12 0 11 1; +#X connect 13 0 10 0; +#X connect 15 0 3 0; +#X connect 17 0 1 0; +#X connect 19 0 14 1; +#X connect 20 0 12 0; +#X connect 21 0 22 1; +#X connect 23 0 21 0; +#X connect 24 0 20 0; +#X connect 25 0 17 0; +#X connect 26 0 7 0; +#X restore 347 236 pd orbit; +#X obj 35 210 tgl 20 1 empty empty start\ flocking\ animation 0 -10 0 12 #fcfcfc #000000 #000000 1 1; +#X text 23 18 create/destroy the GEM window; +#X obj 349 24 declare -lib Gem; +#X obj 92 128 help/boids-params \$0; +#X obj 590 26 loadbang; +#X obj 590 51 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; +#X obj 590 76 s \$0-reset; +#X msg 132 348 reset; +#X obj 142 400 r \$0-boids-params; +#X msg 137 373 dump; +#X obj 103 459 print dump; +#X text 25 102 Change parameters to see their effect:; +#X floatatom 93 222 5 0 0 0 - - - 0; +#X obj 35 248 metro 25; +#X text 134 222 animation speed; +#X floatatom 395 312 5 0 2 0 - \$0-bounding-box-set \$0-bounding-box 0; +#X msg 74 319 attractpt \$1 \$2 \$3; +#X floatatom 364 383 5 0 0 0 left \$0-flyrect0 - 0; +#X floatatom 406 367 5 0 0 0 top \$0-flyrect1 - 0; +#X floatatom 459 389 5 0 0 0 right \$0-flyrect2 - 0; +#X floatatom 508 407 5 0 0 0 bottom \$0-flyrect3 - 0; +#N canvas 0 0 632 412 3D-bounding-box 0; +#X obj 58 181 s \$0-boids-params; +#X obj 365 210 list prepend \$0; +#X obj 349 25 r \$0-reset; +#X obj 29 27 inlet; +#X obj 74 29 inlet; +#X obj 119 29 inlet; +#X obj 170 29 inlet; +#X obj 41 76 pack f f f f f f; +#X obj 219 30 inlet; +#X obj 270 30 inlet; +#X msg 58 156 flyrect \$1 \$2 \$3 \$4 \$5 \$6; +#X obj 434 64 abs; +#X obj 372 102 t f f; +#X obj 372 127 * -1; +#X obj 372 152 pack; +#X msg 372 176 \$1 \$2 \$2 \$1 \$2 \$1; +#X obj 447 36 r \$0-bounding-box; +#X msg 349 50 1; +#X msg 365 235 \; \$1-flyrect0 \$2 \; \$1-flyrect1 \$3 \; \$1-flyrect2 \$4 \; \$1-flyrect3 \$5 \; \$1-flyrect4 \$6 \; \$1-flyrect5 \$7 \; \$1-bounding-box-set set \$3; +#X connect 1 0 18 0; +#X connect 2 0 17 0; +#X connect 3 0 7 0; +#X connect 4 0 7 1; +#X connect 5 0 7 2; +#X connect 6 0 7 3; +#X connect 7 0 10 0; +#X connect 8 0 7 4; +#X connect 9 0 7 5; +#X connect 10 0 0 0; +#X connect 11 0 12 0; +#X connect 12 0 13 0; +#X connect 12 1 14 1; +#X connect 13 0 14 0; +#X connect 14 0 15 0; +#X connect 15 0 1 0; +#X connect 16 0 11 0; +#X connect 17 0 12 0; +#X restore 381 462 pd 3D-bounding-box; +#X f 23; +#X floatatom 587 406 5 0 0 0 front \$0-flyrect4 - 0; +#X floatatom 589 430 5 0 0 0 back \$0-flyrect5 - 0; +#X obj 35 433 boids3d 16; +#X obj 347 172 tgl 20 1 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 1 1; +#X obj 357 200 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; +#X obj 76 290 r \$0-orbit-translation; +#X text 413 223 or click+drag for XY; +#X text 412 236 and middle-click to move Z; +#X text 339 133 ATTRACTION POINT, f 17; +#X text 381 199 random in orbit; +#X text 350 285 BOUNDING BOX; +#X text 371 172 move in an orbit; +#X text 437 313 (shift + drag 0..2); +#X obj 35 489 clone -x gemboid 16 \$0 1; +#X msg 238 342 mode 2; +#X connect 0 0 1 0; +#X connect 1 0 0 0; +#X connect 3 0 16 0; +#X connect 7 0 8 0; +#X connect 8 0 9 0; +#X connect 10 0 27 0; +#X connect 11 0 27 0; +#X connect 12 0 27 0; +#X connect 15 0 16 1; +#X connect 16 0 27 0; +#X connect 19 0 27 0; +#X connect 20 0 24 0; +#X connect 21 0 24 1; +#X connect 22 0 24 2; +#X connect 23 0 24 3; +#X connect 25 0 24 4; +#X connect 26 0 24 5; +#X connect 27 0 38 0; +#X connect 27 1 13 0; +#X connect 28 0 2 0; +#X connect 29 0 2 0; +#X connect 30 0 19 0; +#X connect 39 0 27 0; diff --git a/examples/gemboid.pd b/examples/gemboid.pd index 248dbaa..75320fa 100644 --- a/examples/gemboid.pd +++ b/examples/gemboid.pd @@ -1,7 +1,6 @@ -#N canvas 0 0 450 300 12; +#N canvas 822 81 719 539 12; #X obj 61 64 gemhead; #X obj 61 241 translateXYZ; -#X obj 152 202 unpack 0 0 0; #X obj 152 41 inlet; #X obj 61 195 alpha; #X obj 61 125 color 1 0.5 0 0.5; @@ -15,7 +14,7 @@ #X obj 47 83 t b b b; #X obj 47 256 outlet; #X obj 47 217 pack 0 0 0 0.5; -#X obj 47 26 r \$1-init; +#X obj 47 26 r \$1-reset; #X connect 0 0 1 0; #X connect 1 0 8 0; #X connect 2 0 3 0; @@ -28,19 +27,89 @@ #X connect 8 0 7 0; #X connect 9 0 6 0; #X restore 177 68 pd rand_color; -#X obj 61 268 circle 0.05; +#X obj 70 396 circle 0.05; #X obj 177 91 t a a; #X msg 209 120 1; #X text 34 14 helper abstraction for boids examples with Gem; -#X connect 0 0 5 0; -#X connect 1 0 7 0; -#X connect 2 0 1 1; -#X connect 2 1 1 2; -#X connect 2 2 1 3; -#X connect 3 0 2 0; -#X connect 4 0 1 0; -#X connect 5 0 4 0; -#X connect 6 0 8 0; -#X connect 8 0 5 1; -#X connect 8 1 9 0; -#X connect 9 0 4 1; +#X obj 152 202 unpack f f f; +#X obj 284 179 loadbang; +#X obj 284 204 f \$2; +#X obj 203 245 ==; +#X obj 73 371 spigot 1; +#X obj 60 266 t a a; +#X obj 216 332 spigot; +#X obj 254 244 == 1; +#X obj 152 164 list split 3; +#X obj 430 60 list split 3; +#X obj 474 88 list split 3; +#X obj 461 126 unpack f f f; +#X obj 431 258 atan2; +#X obj 506 305 atan2; +#X obj 454 158 t f f; +#X obj 538 199 t f f; +#X obj 538 224 *; +#X obj 608 207 t f f; +#X obj 606 237 *; +#X obj 542 153 t f f; +#X obj 538 249 +; +#X obj 538 274 sqrt; +#X obj 431 308 / 3.14159; +#X obj 501 356 / 3.14159; +#X obj 385 400 rotateXYZ; +#X obj 431 283 * 180; +#X obj 501 331 * 180; +#X text 426 36 with mode == 2; +#X text 403 355 yaw; +#X text 481 387 pitch; +#X obj 391 486 sphere3d 0.1 6; +#X obj 453 411 loadbang; +#X msg 453 436 setCartesian 0 0 0 0 2; +#X connect 0 0 4 0; +#X connect 1 0 15 0; +#X connect 2 0 18 0; +#X connect 3 0 1 0; +#X connect 4 0 3 0; +#X connect 5 0 7 0; +#X connect 7 0 4 1; +#X connect 7 1 8 0; +#X connect 8 0 3 1; +#X connect 10 0 1 1; +#X connect 10 1 1 2; +#X connect 10 2 1 3; +#X connect 11 0 12 0; +#X connect 12 0 17 0; +#X connect 13 0 14 1; +#X connect 14 0 6 0; +#X connect 15 0 14 0; +#X connect 15 1 16 0; +#X connect 16 0 34 0; +#X connect 17 0 13 0; +#X connect 17 0 16 1; +#X connect 18 0 10 0; +#X connect 18 1 19 0; +#X connect 19 1 20 0; +#X connect 20 0 21 0; +#X connect 21 0 24 0; +#X connect 21 1 23 0; +#X connect 21 2 29 0; +#X connect 22 0 35 0; +#X connect 23 0 36 0; +#X connect 24 0 22 0; +#X connect 24 1 25 0; +#X connect 25 0 26 0; +#X connect 25 1 26 1; +#X connect 26 0 30 0; +#X connect 27 0 28 0; +#X connect 27 1 28 1; +#X connect 28 0 30 1; +#X connect 29 0 22 1; +#X connect 29 1 27 0; +#X connect 30 0 31 0; +#X connect 31 0 23 1; +#X connect 32 0 34 1; +#X connect 33 0 34 2; +#X connect 34 0 40 0; +#X connect 35 0 32 0; +#X connect 36 0 33 0; +#X connect 41 0 42 0; +#X connect 42 0 40 0; diff --git a/examples/struct-boid.pd b/examples/struct-boid.pd new file mode 100644 index 0000000..934fe83 --- /dev/null +++ b/examples/struct-boid.pd @@ -0,0 +1,74 @@ +#N canvas 762 81 800 511 12; +#X msg 432 201 traverse pd-\$1-data \, bang; +#X obj 432 226 pointer; +#X obj 272 110 random 600; +#X obj 272 135 - 300; +#X obj 356 111 random 600; +#X obj 351 136 - 300; +#X obj 334 65 t b b b; +#X obj 447 119 random 100; +#X obj 284 171 pack f f f; +#X obj 280 220 t a b; +#X obj 333 21 inlet; +#X obj 432 176 f \$2; +#X obj 24 20 inlet; +#X obj 27 67 unpack; +#X obj 41 472 set \$2-template x y k; +#X obj 399 145 t f f; +#X obj 52 216 t f f; +#X obj 23 192 t f f; +#X obj 162 217 t f f; +#X obj 100 190 t f f; +#X obj 43 241 < -301; +#X obj 101 242 > 301; +#X obj 153 242 < -301; +#X obj 211 243 > 301; +#X obj 153 267 ||; +#X obj 43 266 ||; +#X obj 113 290 ||; +#X obj 128 431 f; +#X obj 117 345 sel 0 1; +#X msg 178 417 999; +#X obj 315 312 append \$2-template x y k i; +#X obj 297 266 list append \$1; +#X connect 0 0 1 0; +#X connect 1 0 30 4; +#X connect 2 0 3 0; +#X connect 3 0 8 0; +#X connect 4 0 5 0; +#X connect 5 0 8 1; +#X connect 6 0 2 0; +#X connect 6 1 4 0; +#X connect 6 2 7 0; +#X connect 7 0 15 0; +#X connect 8 0 9 0; +#X connect 9 0 31 0; +#X connect 9 1 11 0; +#X connect 10 0 6 0; +#X connect 11 0 0 0; +#X connect 12 0 13 0; +#X connect 13 0 17 0; +#X connect 13 1 19 0; +#X connect 15 0 8 2; +#X connect 15 1 27 1; +#X connect 16 0 20 0; +#X connect 16 1 21 0; +#X connect 17 0 14 0; +#X connect 17 1 16 0; +#X connect 18 0 22 0; +#X connect 18 1 23 0; +#X connect 19 0 14 1; +#X connect 19 1 18 0; +#X connect 20 0 25 0; +#X connect 21 0 25 1; +#X connect 22 0 24 0; +#X connect 23 0 24 1; +#X connect 24 0 26 1; +#X connect 25 0 26 0; +#X connect 26 0 28 0; +#X connect 27 0 14 2; +#X connect 28 0 27 0; +#X connect 28 1 29 0; +#X connect 29 0 14 2; +#X connect 30 0 14 3; +#X connect 31 0 30 0; diff --git a/help/boids-params.pd b/help/boids-params.pd new file mode 100644 index 0000000..903f90a --- /dev/null +++ b/help/boids-params.pd @@ -0,0 +1,82 @@ +#N canvas 787 227 856 738 12; +#X msg 258 167 neighbors \$1; +#X floatatom 213 148 5 0 4 0 - \$1-neighbors - 0; +#X floatatom 213 183 5 0 0 0 - \$1-maxspeed - 0; +#X msg 258 202 maxspeed \$1; +#X floatatom 213 218 5 0 0 0 - \$1-minspeed - 0; +#X msg 258 237 minspeed \$1; +#X floatatom 213 253 5 0 0 0 - \$1-center - 0; +#X msg 258 272 center \$1; +#X floatatom 213 288 5 0 0 0 - \$1-attract - 0; +#X msg 258 307 attract \$1; +#X floatatom 213 323 5 0 0 0 - \$1-match - 0; +#X msg 258 342 match \$1; +#X floatatom 213 358 5 0 0 0 - \$1-avoid - 0; +#X msg 258 377 avoid \$1; +#X floatatom 213 393 5 0 0 0 - \$1-repel - 0; +#X msg 258 412 repel \$1; +#X floatatom 213 428 5 0 0 0 - \$1-edgedist - 0; +#X msg 258 447 edgedist \$1; +#X floatatom 213 463 5 0 0 0 - \$1-speed - 0; +#X msg 258 482 speed \$1; +#X floatatom 213 498 5 0 0 0 - \$1-inertia - 0; +#X msg 258 517 inertia \$1; +#X floatatom 213 533 5 0 0 0 - \$1-accel - 0; +#X msg 258 552 accel \$1; +#X floatatom 213 568 5 0 0 0 - \$1-prefdist - 0; +#X msg 258 587 prefdist \$1; +#X text 349 202 maximum speed of speed range; +#X text 351 236 minimum speed of speed range; +#X text 348 271 strength of centering instinct; +#X text 350 482 overall speed; +#X text 351 553 speed of acceleration; +#X text 351 584 preferred distance from neighbors; +#X floatatom 213 113 5 0 0 0 - \$1-number - 0; +#X msg 258 132 number \$1; +#X text 337 133 number of boids; +#X text 349 165 number of neighbors each boid consults when flocking; +#X text 348 342 strength of neighbor speed matching instinct; +#X text 348 377 strength of neighbor avoidance instinct; +#X text 348 409 strength of wall avoidance instinct; +#X text 350 445 distance of vision for avoiding wall edges; +#X text 351 516 willingness to change speed and direction; +#X text 347 305 strength of attraction to 'attractpt'; +#X text 400 20 Boids Parameters; +#X obj 51 180 list prepend \$1; +#X msg 51 213 \; \$1-number 16 \; \$1-neighbors 4 \; \$1-maxspeed 1.5 \; \$1-minspeed 1.2 \; \$1-center 1.2 \; \$1-attract 1.25 \; \$1-match 0.3 \; \$1-avoid 3.5 \; \$1-repel 3.5 \; \$1-edgedist 3 \; \$1-speed 3 \; \$1-inertia 4.5 \; \$1-accel 2.5 \; \$1-prefdist 1.5, f 17; +#X obj 55 102 r \$1-reset; +#X obj 53 132 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; +#X text 82 135 defaults; +#X obj 258 620 s \$1-boids-params; +#X text 246 38 Here are all parameters you can send to the boids external. Their defaults are on the left-most message. You can also get the defaults by sending a "dump" message before changing them; +#X connect 0 0 48 0; +#X connect 1 0 0 0; +#X connect 2 0 3 0; +#X connect 3 0 48 0; +#X connect 4 0 5 0; +#X connect 5 0 48 0; +#X connect 6 0 7 0; +#X connect 7 0 48 0; +#X connect 8 0 9 0; +#X connect 9 0 48 0; +#X connect 10 0 11 0; +#X connect 11 0 48 0; +#X connect 12 0 13 0; +#X connect 13 0 48 0; +#X connect 14 0 15 0; +#X connect 15 0 48 0; +#X connect 16 0 17 0; +#X connect 17 0 48 0; +#X connect 18 0 19 0; +#X connect 19 0 48 0; +#X connect 20 0 21 0; +#X connect 21 0 48 0; +#X connect 22 0 23 0; +#X connect 23 0 48 0; +#X connect 24 0 25 0; +#X connect 25 0 48 0; +#X connect 32 0 33 0; +#X connect 33 0 48 0; +#X connect 43 0 44 0; +#X connect 45 0 46 0; +#X connect 46 0 43 0; diff --git a/help/boids2d-help.pd b/help/boids2d-help.pd index 331a09d..e888657 100644 --- a/help/boids2d-help.pd +++ b/help/boids2d-help.pd @@ -1,294 +1,177 @@ -#N canvas 369 326 1021 718 10; -#X declare -lib Gem; -#X msg 121 601 dump; -#X msg 486 113 neighbors \$1; -#X floatatom 446 96 5 0 4 0 - \$0-neighbors - 0; -#X floatatom 446 131 5 0 0 0 - \$0-maxspeed - 0; -#X msg 486 148 maxspeed \$1; -#X floatatom 446 166 5 0 0 0 - \$0-minspeed - 0; -#X msg 486 183 minspeed \$1; -#X floatatom 446 201 5 0 0 0 - \$0-center - 0; -#X msg 486 218 center \$1; -#X floatatom 446 236 5 0 0 0 - \$0-attract - 0; -#X msg 486 253 attract \$1; -#X floatatom 446 271 5 0 0 0 - \$0-match - 0; -#X msg 486 288 match \$1; -#X floatatom 446 306 5 0 0 0 - \$0-avoid - 0; -#X msg 486 323 avoid \$1; -#X floatatom 446 341 5 0 0 0 - \$0-repel - 0; -#X msg 486 358 repel \$1; -#X floatatom 446 376 5 0 0 0 - \$0-edgedist - 0; -#X msg 486 393 edgedist \$1; -#X floatatom 446 411 5 0 0 0 - \$0-speed - 0; -#X msg 486 428 speed \$1; -#X floatatom 446 446 5 0 0 0 - \$0-inertia - 0; -#X msg 486 463 inertia \$1; -#X floatatom 446 481 5 0 0 0 - \$0-accel - 0; -#X msg 486 498 accel \$1; -#X floatatom 446 516 5 0 0 0 - \$0-prefdist - 0; -#X msg 486 533 prefdist \$1; -#X msg 121 620 reset; -#X text 577 148 maximum speed of speed range; -#X text 579 182 minimum speed of speed range; -#X text 576 217 strength of centering instinct; -#X text 578 428 overall speed; -#X text 579 499 speed of acceleration; -#X text 579 530 preferred distance from neighbors; -#X floatatom 487 556 5 0 0 0 - \$0-flyrect0 - 0; -#X floatatom 526 556 5 0 0 0 - \$0-flyrect1 - 0; -#X floatatom 565 556 5 0 0 0 - \$0-flyrect2 - 0; -#X floatatom 604 556 5 0 0 0 - \$0-flyrect4 - 0; -#X floatatom 486 625 5 0 0 0 - - - 0; -#X floatatom 526 625 5 0 0 0 - - - 0; -#X floatatom 446 61 5 0 0 0 - \$0-number - 0; -#X msg 486 78 number \$1; -#X text 577 76 number of boids; -#X floatatom 121 567 5 0 0 0 - - - 0; -#X msg 121 582 mode \$1; -#X text 185 582 output mode; -#X text 185 601 parameter dump; -#X text 184 621 reset boids randomly inside flyrect; -#X text 577 111 number of neighbors each boid consults when flocking; -#X text 576 288 strength of neighbor speed matching instinct; -#X text 576 323 strength of neighbor avoidance instinct; -#X text 576 355 strength of wall avoidance instinct; -#X text 578 391 distance of vision for avoiding wall edges; -#X text 579 462 willingness to change speed and direction; -#X text 575 251 strength of attraction to 'attractpt'; -#X text 29 84 (c) 1995-98 Eric L. Singer (eric@ericsinger.com); -#X text 29 126 Based on Simon Fraser's implementation of Craig Reynolds' Boids algorithm. Boids is free for non-commercial use; -#X text 29 159 Boids is a bird flight and animal flock simulator. It is based on the same algorithm which was used in Jurassic Park for the herding dinosaurs.; -#X text 29 208 Boids takes an integer argument which is the number of boids. Each time Boids receives a bang \, it calculates and outputs the new positions of the boids. The output consists of thew coordiantes for each boid \, the number and type depending on the mode.; -#X text 30 282 The flight parameters can be changed with messages. Use the 'dump' message to output a list of the current parameter settings.; -#X text 30 328 For more information about the Boids algorithm \, see Craig Reynolds' Web site at http://www.red3d.com/cwr/boids/; -#X text 32 64 arguments: number of boids \, output mode; -#X obj 148 460 print dump; -#X obj 17 9 cnv 15 800 48 empty empty boids2d 20 12 2 24 #dce0c8 #404040 0; -#X obj 69 410 bng 15 250 50 0 empty empty empty 0 -6 0 8 #fcfcfc #000000 #000000; -#N canvas 845 12 635 438 gem_example 0; -#X msg 33 31 destroy; -#N canvas 494 140 629 324 gemwin 0; -#X obj 209 190 gemwin; -#X obj 67 194 outlet; -#X obj 67 10 inlet; -#X obj 67 41 route create; -#X msg 67 70 set destroy; -#X msg 157 70 set create; -#X msg 350 115 destroy \, reset; -#X obj 157 18 loadbang; -#X msg 212 146 create \, 1 \, frame 30 \, color 0 0 0.5; -#X msg 238 71 color 1 1 1; -#X connect 2 0 3 0; -#X connect 3 0 4 0; -#X connect 3 0 8 0; -#X connect 3 1 5 0; -#X connect 3 1 6 0; -#X connect 4 0 1 0; -#X connect 5 0 1 0; -#X connect 6 0 0 0; -#X connect 7 0 5 0; -#X connect 8 0 0 0; -#X connect 9 0 0 0; -#X restore 33 51 pd gemwin; -#X obj 33 91 tgl 15 0 empty empty start_flocking_animation 20 6 1 10 #fcfcfc #000000 #000000 0 1; -#X obj 33 112 metro 33; -#X floatatom 33 244 5 0 0 0 - - - 0; -#X floatatom 78 244 5 0 0 0 - - - 0; -#X text 96 30 create/destroy OpenGl context; -#X obj 33 181 spigot; -#X obj 69 160 tgl 15 0 empty empty empty 0 -6 0 8 #fcfcfc #000000 #000000 0 1; -#N canvas 0 22 418 379 center 0; -#X obj 101 37 gemhead; -#X obj 99 201 translateXYZ; -#X obj 124 166 unpack 0 0 0; -#X obj 147 94 inlet; -#X msg 240 193 draw line; -#X obj 252 106 loadbang; -#X obj 100 131 alpha; -#X obj 101 68 color 1 0.5 0 0.5; -#X obj 99 228 circle 0.1; -#X connect 0 0 7 0; -#X connect 1 0 8 0; -#X connect 2 0 1 1; -#X connect 2 1 1 2; -#X connect 2 2 1 3; -#X connect 3 0 2 0; -#X connect 4 0 8 0; -#X connect 5 0 4 0; -#X connect 6 0 1 0; -#X connect 7 0 6 0; -#X restore 33 342 pd center; -#X msg 85 295 attractpt \$1 \$2; -#X obj 33 267 pack 0 0; -#X obj 205 163 boids2d 10; -#N canvas 0 22 466 396 orbit 0; -#X floatatom 103 160 5 0 0 0 - - - 0; -#X obj 103 187 expr $f1 * (3.141593/180.); -#X obj 103 45 inlet; -#X obj 166 314 outlet; -#X obj 103 314 outlet; -#N canvas 0 0 450 300 pol2cart 0; -#X obj 79 42 inlet r; -#X obj 159 42 inlet phi; -#X obj 79 231 outlet x; -#X obj 146 231 outlet y; -#X obj 146 120 t f f; -#X obj 146 144 cos; -#X obj 176 144 sin; -#X obj 79 171 t f f, f 10; -#X obj 79 197 * 1; -#X obj 146 196 * 0; -#X obj 79 93 unpack 0 0; -#X obj 79 65 pack \$1 \$2; -#X connect 0 0 11 0; -#X connect 1 0 11 1; -#X connect 4 0 5 0; -#X connect 4 1 6 0; -#X connect 5 0 8 1; -#X connect 6 0 9 1; -#X connect 7 0 8 0; -#X connect 7 1 9 0; -#X connect 8 0 2 0; -#X connect 9 0 3 0; -#X connect 10 0 7 0; -#X connect 10 1 4 0; -#X connect 11 0 10 0; -#X restore 103 254 pd pol2cart; -#X msg 103 210 1.5 \$1; -#X obj 103 277 swap, f 11; -#X obj 103 68 i; -#X obj 103 91 + 1; -#X obj 103 114 % 360; -#X obj 103 137 t f f; -#X connect 0 0 1 0; -#X connect 1 0 6 0; -#X connect 2 0 8 0; -#X connect 5 0 7 0; -#X connect 5 1 7 1; -#X connect 6 0 5 0; -#X connect 7 0 4 0; -#X connect 7 1 3 0; -#X connect 8 0 9 0; -#X connect 9 0 10 0; -#X connect 10 0 11 0; -#X connect 11 0 0 0; -#X connect 11 1 8 1; -#X restore 33 205 pd orbit; -#X obj 322 61 t f b; -#X obj 322 13 loadbang; -#X msg 322 36 1; -#X obj 85 318 s \$0-boidParam; -#X obj 205 190 clone -x examples/gemboid 10 \$0; -#X obj 205 135 r \$0-boidParam; -#X obj 33 133 t b b; -#X obj 349 83 s \$0-init; -#X obj 33 290 t a a; +#N canvas 587 25 836 713 12; +#X floatatom 501 143 5 0 0 0 left \$0-flyrect0 - 0; +#X floatatom 562 107 5 0 0 0 top \$0-flyrect1 - 0; +#X floatatom 650 137 5 0 0 0 right \$0-flyrect2 - 0; +#X floatatom 711 176 5 0 0 0 bottom \$0-flyrect3 - 0; +#X floatatom 533 326 5 0 0 0 - - - 0; +#X floatatom 577 324 5 0 0 0 - - - 0; +#X msg 80 386 mode \$1; +#X text 145 424 reset boids randomly inside flyrect; +#X text 389 641 (c) 1995-98 Eric L. Singer (eric@ericsinger.com); +#X text 25 73 Based on Simon Fraser's implementation of Craig Reynolds' Boids algorithm. Boids is free for non-commercial use; +#X text 25 109 Boids is a bird flight and animal flock simulator. It is based on the same algorithm which was used in Jurassic Park for the herding dinosaurs.; +#X text 387 571 For more information about the Boids algorithm \, see Craig Reynolds' Web site at http://www.red3d.com/cwr/boids/; +#X text 392 619 arguments: number of boids \, output mode; +#X obj 78 536 print dump; +#X obj 19 10 cnv 15 800 48 empty empty boids2d 15 20 2 24 #dce0c8 #404040 0; +#X text 390 664 float/2d/3d adaptation 08/2005 by a. sier / jasch; +#X msg 562 396 attractpt \$1 \$2; +#X text 632 328 point to which boids are attracted (x/y), f 21; +#N canvas 88 105 494 344 META 0; +#X text 13 182 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; +#X text 13 160 AUTHOR Eric L. Singer; +#X text 13 6 KEYWORDS control; +#X text 13 50 DESCRIPTION bird flight and animal flock simulator; +#X text 13 72 INLET_0 bang dump mode reset number neighbors maxspeed minspeed center attract match avoid repel edgedist speed inertia accel prefdist flyrect attractpt; +#X text 13 116 OUTLET_0 list; +#X text 13 138 OUTLET_1 list; +#X text 13 28 LICENSE GPL v2; +#X restore 760 21 pd META; +#X obj 562 426 s \$0-boids-params; +#X text 156 633 ..., f 4; +#X obj 32 635 unpack; +#X floatatom 32 661 5 0 0 0 - - - 0; +#X floatatom 70 679 5 0 0 0 - - - 0; +#X obj 109 636 unpack; +#X floatatom 109 661 5 0 0 0 - - - 0; +#X floatatom 146 680 5 0 0 0 - - - 0; +#X obj 79 360 hradio 18 1 0 3 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0; +#X msg 53 316 dump; +#X msg 99 422 reset; +#X obj 32 228 bng 18 250 50 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000; +#N canvas 72 225 794 467 output-mode 0; +#X obj 198 262 unpack f f f f; +#X floatatom 190 288 5 0 0 0 - - - 0; +#X floatatom 220 314 5 0 0 0 - - - 0; +#X floatatom 252 294 5 0 0 0 - - - 0; +#X floatatom 278 317 5 0 0 0 - - - 0; +#X floatatom 343 254 5 0 0 0 - - - 0; +#X floatatom 373 279 5 0 0 0 - - - 0; +#X floatatom 405 260 5 0 0 0 - - - 0; +#X floatatom 431 283 5 0 0 0 - - - 0; +#X obj 343 229 unpack f f f f f f, f 25; +#X floatatom 471 265 5 0 0 0 - - - 0; +#X floatatom 497 288 5 0 0 0 - - - 0; +#X obj 233 84 list length; +#X obj 189 141 route 2 4 6; +#X obj 183 112 list prepend; +#X obj 186 66 t a a; +#X obj 109 205 unpack; +#X floatatom 109 230 5 0 0 0 - - - 0; +#X floatatom 146 249 5 0 0 0 - - - 0; +#X text 363 307 (2) new and old with delta positions; +#X text 217 339 (1) new and old positions; +#X text 39 267 (0) new position only; +#X obj 186 17 inlet; +#X text 298 14 this patch shows the different output modes of the boids external.; +#X msg 393 100 mode \$1; +#X obj 393 167 s \$0-boids-params; +#X obj 392 74 hradio 18 1 0 3 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0; +#X text 391 45 output mode:; +#X text 468 100 (1) new and old positions; +#X text 468 78 (0) new position only; +#X text 470 122 (2) new and old with delta positions; #X connect 0 0 1 0; -#X connect 1 0 0 0; -#X connect 2 0 3 0; -#X connect 3 0 20 0; -#X connect 4 0 11 0; -#X connect 5 0 11 1; -#X connect 7 0 13 0; -#X connect 8 0 7 1; -#X connect 10 0 17 0; -#X connect 11 0 22 0; -#X connect 12 0 18 0; -#X connect 13 0 4 0; -#X connect 13 1 5 0; -#X connect 14 0 8 0; -#X connect 14 1 21 0; -#X connect 15 0 16 0; -#X connect 16 0 14 0; -#X connect 19 0 12 0; -#X connect 20 0 7 0; -#X connect 20 1 12 0; -#X connect 22 0 9 0; -#X connect 22 1 10 0; -#X restore 277 437 pd gem_example; -#X obj 486 642 pack 0 0 0; -#X floatatom 565 625 5 0 0 0 - - - 0; -#X text 30 105 float/2d/3d adaptation 08/2005 by a. sier / jasch; -#N canvas 1146 116 222 383 init 0; -#X obj 34 21 loadbang; -#X obj 17 79 b; -#X obj 17 112 list prepend \$0; -#X msg 17 145 \; \$1-neighbors 4 \; \$1-maxspeed 1.5 \; \$1-minspeed 1.2 \; \$1-center 1.2 \; \$1-attract 1.25 \; \$1-match 0.3 \; \$1-avoid 3.5 \; \$1-repel 3.5 \; \$1-edgedist 3 \; \$1-speed 3 \; \$1-inertia 4.5 \; \$1-accel 2.5 \; \$1-prefdist 1.5, f 17; -#X obj 94 21 r \$0-reset; -#X obj 111 52 inlet; +#X connect 0 1 2 0; +#X connect 0 2 3 0; +#X connect 0 3 4 0; +#X connect 9 0 5 0; +#X connect 9 1 6 0; +#X connect 9 2 7 0; +#X connect 9 3 8 0; +#X connect 9 4 10 0; +#X connect 9 5 11 0; +#X connect 12 0 14 1; +#X connect 13 0 16 0; +#X connect 13 1 0 0; +#X connect 13 2 9 0; +#X connect 14 0 13 0; +#X connect 15 0 14 0; +#X connect 15 1 12 0; +#X connect 16 0 17 0; +#X connect 16 1 18 0; +#X connect 22 0 15 0; +#X connect 24 0 25 0; +#X connect 26 0 24 0; +#X restore 226 607 pd output-mode; +#X obj 193 635 unpack; +#X floatatom 193 661 5 0 0 0 - - - 0; +#X floatatom 231 679 5 0 0 0 - - - 0; +#X obj 32 572 route 0 1 2 3 4 10 15, f 27; +#X text 136 361 see [pd-output-mode]; +#X obj 272 262 boids-params \$0; +#X obj 109 453 r \$0-boids-params; +#X obj 563 370 pack; +#X obj 575 346 t b f; +#X text 98 308 Use the 'dump' message to output a list of the current parameter settings., f 42; +#X text 101 174 Each time Boids receives a bang \, it calculates and outputs the new positions of the boids. The output consists of the X \, Y coordiantes for each boid., f 49; +#X text 51 254 The flight parameters can be changed with messages -->, f 28; +#N canvas 0 0 450 300 2D-bounding-box 0; +#X msg 58 156 flyrect \$1 \$2 \$3 \$4; +#X obj 58 181 s \$0-boids-params; +#X msg 262 41 -1 1 1 -1; +#X msg 262 91 \; \$1-flyrect0 \$2 \; \$1-flyrect1 \$3 \; \$1-flyrect2 \$4 \; \$1-flyrect3 \$5; +#X obj 262 66 list prepend \$0; +#X text 336 44 defaults; +#X obj 261 13 r \$0-reset; +#X obj 29 27 inlet; +#X obj 74 29 inlet; +#X obj 119 29 inlet; +#X obj 170 29 inlet; +#X obj 41 76 pack f f f f; #X connect 0 0 1 0; -#X connect 1 0 2 0; -#X connect 2 0 3 0; -#X connect 4 0 1 0; -#X connect 5 0 1 0; -#X restore 277 407 pd init; -#X obj 69 438 boids2d 16 0; -#X obj 69 488 print boids2d; -#X msg 486 602 flyrect \$1 \$2 \$3 \$4; -#X msg 486 662 attractpt \$1 \$2; -#X text 609 614 point to which boids are attracted (x/y); -#X text 612 575 bounding box (walls) in which to fly (l/t/r/b); -#N canvas 88 105 494 344 META 0; -#X text 12 165 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; -#X text 12 145 AUTHOR Eric L. Singer; -#X text 12 5 KEYWORDS control; -#X text 12 45 DESCRIPTION bird flight and animal flock simulator; -#X text 12 65 INLET_0 bang dump mode reset number neighbors maxspeed minspeed center attract match avoid repel edgedist speed inertia accel prefdist flyrect attractpt; -#X text 12 105 OUTLET_0 list; -#X text 12 125 OUTLET_1 list; -#X text 12 25 LICENSE GPL v2; -#X restore 940 676 pd META; -#X obj 822 23 declare -lib Gem; -#X obj 121 641 s \$0-boidParam; -#X obj 95 411 r \$0-boidParam; -#X obj 486 686 s \$0-boidParam; -#X obj 486 584 pack 0 0 0 0, f 20; -#X obj 277 387 bng 18 250 50 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000; -#X connect 0 0 78 0; -#X connect 1 0 80 0; -#X connect 2 0 1 0; -#X connect 3 0 4 0; -#X connect 4 0 80 0; -#X connect 5 0 6 0; -#X connect 6 0 80 0; -#X connect 7 0 8 0; -#X connect 8 0 80 0; -#X connect 9 0 10 0; -#X connect 10 0 80 0; -#X connect 11 0 12 0; -#X connect 12 0 80 0; -#X connect 13 0 14 0; -#X connect 14 0 80 0; -#X connect 15 0 16 0; -#X connect 16 0 80 0; -#X connect 17 0 18 0; -#X connect 18 0 80 0; -#X connect 19 0 20 0; -#X connect 20 0 80 0; +#X connect 2 0 4 0; +#X connect 4 0 3 0; +#X connect 6 0 2 0; +#X connect 7 0 11 0; +#X connect 8 0 11 1; +#X connect 9 0 11 2; +#X connect 10 0 11 3; +#X connect 11 0 0 0; +#X restore 537 202 pd 2D-bounding-box; +#X f 23; +#X text 613 78 2D bounding box (walls) in which to fly, f 23; +#X text 465 245 ATTRACTION POINT; +#X text 473 75 BOUNDING BOX; +#X text 464 266 Usually \, the attraction point is what can be "moved" to cause the entire flock to follow it, f 39; +#X obj 32 493 boids2d; +#X text 98 492 optional arguments: integer number of boids (default is 16); +#X text 165 508 next optional argument is mode (default is 0); +#X obj 32 175 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 32 200 metro 10; +#X obj 567 503 bng 18 250 50 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000; +#X text 592 502 bang to reset to defaults; +#X obj 565 528 s \$0-reset; +#X obj 565 478 loadbang; +#X connect 0 0 44 0; +#X connect 1 0 44 1; +#X connect 2 0 44 2; +#X connect 3 0 44 3; +#X connect 4 0 39 0; +#X connect 5 0 40 0; +#X connect 6 0 49 0; +#X connect 16 0 19 0; #X connect 21 0 22 0; -#X connect 22 0 80 0; -#X connect 23 0 24 0; -#X connect 24 0 80 0; -#X connect 25 0 26 0; -#X connect 26 0 80 0; -#X connect 27 0 78 0; -#X connect 34 0 81 0; -#X connect 35 0 81 1; -#X connect 36 0 81 2; -#X connect 37 0 81 3; -#X connect 38 0 66 0; -#X connect 39 0 66 1; -#X connect 40 0 41 0; -#X connect 41 0 80 0; -#X connect 43 0 44 0; -#X connect 44 0 78 0; -#X connect 64 0 70 0; -#X connect 66 0 73 0; -#X connect 67 0 66 2; -#X connect 70 0 71 0; -#X connect 70 1 62 0; -#X connect 72 0 80 0; -#X connect 73 0 80 0; -#X connect 79 0 70 0; -#X connect 81 0 72 0; -#X connect 82 0 69 0; +#X connect 21 1 23 0; +#X connect 24 0 25 0; +#X connect 24 1 26 0; +#X connect 27 0 6 0; +#X connect 28 0 49 0; +#X connect 29 0 49 0; +#X connect 30 0 49 0; +#X connect 32 0 33 0; +#X connect 32 1 34 0; +#X connect 35 0 21 0; +#X connect 35 1 24 0; +#X connect 35 5 32 0; +#X connect 35 6 31 0; +#X connect 38 0 49 0; +#X connect 39 0 16 0; +#X connect 40 0 39 0; +#X connect 40 1 39 1; +#X connect 49 0 35 0; +#X connect 49 1 13 0; +#X connect 52 0 53 0; +#X connect 53 0 30 0; +#X connect 54 0 56 0; +#X connect 57 0 54 0; diff --git a/help/boids3d-help.pd b/help/boids3d-help.pd index 1324618..cde1de1 100644 --- a/help/boids3d-help.pd +++ b/help/boids3d-help.pd @@ -1,297 +1,208 @@ -#N canvas 625 11 988 743 10; -#X declare -lib Gem; -#X msg 121 611 dump; -#X msg 121 630 reset; -#X floatatom 487 566 5 0 0 0 - \$0-flyrect0 - 0; -#X floatatom 526 566 5 0 0 0 - \$0-flyrect1 - 0; -#X floatatom 565 566 5 0 0 0 - \$0-flyrect2 - 0; -#X floatatom 604 566 5 0 0 0 - - - 0; -#X floatatom 486 625 5 0 0 0 - - - 0; -#X floatatom 526 625 5 0 0 0 - - - 0; -#X floatatom 121 577 5 0 0 0 - - - 0; -#X msg 121 592 mode \$1; -#X text 185 592 output mode; -#X text 185 611 parameter dump; -#X text 184 631 reset boids randomly inside flyrect; -#X text 29 94 (c) 1995-98 Eric L. Singer (eric@ericsinger.com); -#X text 29 136 Based on Simon Fraser's implementation of Craig Reynolds' Boids algorithm. Boids is free for non-commercial use; -#X text 29 169 Boids is a bird flight and animal flock simulator. It is based on the same algorithm which was used in Jurassic Park for the herding dinosaurs.; -#X text 30 292 The flight parameters can be changed with messages. Use the 'dump' message to output a list of the current parameter settings.; -#X text 30 338 For more information about the Boids algorithm \, see Craig Reynolds' Web site at http://www.red3d.com/cwr/boids/; -#X text 32 74 arguments: number of boids \, output mode; -#X obj 148 470 print dump; -#X obj 17 19 cnv 15 800 48 empty empty boids3d 20 12 2 24 #dce0c8 #404040 0; -#X obj 69 420 bng 15 250 50 0 empty empty empty 0 -6 0 8 #fcfcfc #000000 #000000; -#N canvas 628 28 488 387 gem_example 0; -#X msg 33 31 destroy; -#N canvas 494 140 629 324 gemwin 0; -#X obj 219 190 gemwin; -#X obj 66 194 outlet; -#X obj 67 10 inlet; -#X obj 67 41 route create; -#X msg 67 70 set destroy; -#X msg 157 70 set create; -#X msg 350 115 destroy \, reset; -#X obj 157 38 loadbang; -#X msg 212 146 create \, 1 \, frame 30 \, color 0 0 0.5; -#X msg 238 71 color 1 1 1; -#X connect 2 0 3 0; -#X connect 3 0 4 0; -#X connect 3 0 8 0; -#X connect 3 1 5 0; -#X connect 3 1 6 0; -#X connect 4 0 1 0; -#X connect 5 0 1 0; -#X connect 6 0 0 0; -#X connect 7 0 5 0; -#X connect 8 0 0 0; -#X connect 9 0 0 0; -#X restore 33 51 pd gemwin; -#X obj 33 91 tgl 15 0 empty empty start_flocking_animation 20 6 1 10 #fcfcfc #000000 #000000 0 1; -#X obj 33 112 metro 33; -#X floatatom 33 234 5 0 0 0 - - - 0; -#X floatatom 84 234 5 0 0 0 - - - 0; -#X text 96 30 create/destroy OpenGl context; -#X obj 33 181 spigot; -#X obj 69 160 tgl 15 0 empty empty empty 0 -6 0 8 #fcfcfc #000000 #000000 0 1; -#X obj 291 44 loadbang; -#X obj 33 287 pack 0 0 0; -#X msg 85 315 attractpt \$1 \$2 \$3; -#N canvas 0 22 414 375 center 0; -#X obj 101 37 gemhead; -#X obj 99 201 translateXYZ; -#X obj 124 166 unpack 0 0 0; -#X obj 147 94 inlet; -#X msg 240 193 draw line; -#X obj 252 106 loadbang; -#X obj 100 131 alpha; -#X obj 101 68 color 1 0.5 0 0.5; -#X obj 99 228 circle 0.1; -#X connect 0 0 7 0; -#X connect 1 0 8 0; -#X connect 2 0 1 1; -#X connect 2 1 1 2; -#X connect 2 2 1 3; -#X connect 3 0 2 0; +#N canvas 587 25 836 757 12; +#X floatatom 520 123 5 0 0 0 left \$0-flyrect0 - 0; +#X floatatom 562 107 5 0 0 0 top \$0-flyrect1 - 0; +#X floatatom 615 129 5 0 0 0 right \$0-flyrect2 - 0; +#X floatatom 664 147 5 0 0 0 bottom \$0-flyrect3 - 0; +#X floatatom 465 338 5 0 0 0 - - - 0; +#X floatatom 509 336 5 0 0 0 - - - 0; +#X msg 80 386 mode \$1; +#X text 145 424 reset boids randomly inside flyrect; +#X text 394 639 (c) 1995-98 Eric L. Singer (eric@ericsinger.com); +#X text 25 73 Based on Simon Fraser's implementation of Craig Reynolds' Boids algorithm. Boids is free for non-commercial use; +#X text 25 109 Boids is a bird flight and animal flock simulator. It is based on the same algorithm which was used in Jurassic Park for the herding dinosaurs.; +#X text 387 571 For more information about the Boids algorithm \, see Craig Reynolds' Web site at http://www.red3d.com/cwr/boids/; +#X text 397 617 arguments: number of boids \, output mode; +#X obj 78 536 print dump; +#X obj 19 10 cnv 15 800 48 empty empty boids3d 15 20 2 24 #dce0c8 #404040 0; +#X text 395 662 float/2d/3d adaptation 08/2005 by a. sier / jasch; +#N canvas 88 105 494 344 META 0; +#X text 13 182 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; +#X text 13 160 AUTHOR Eric L. Singer; +#X text 13 6 KEYWORDS control; +#X text 13 50 DESCRIPTION bird flight and animal flock simulator; +#X text 13 72 INLET_0 bang dump mode reset number neighbors maxspeed minspeed center attract match avoid repel edgedist speed inertia accel prefdist flyrect attractpt; +#X text 13 116 OUTLET_0 list; +#X text 13 138 OUTLET_1 list; +#X text 13 28 LICENSE GPL v2; +#X restore 760 21 pd META; +#X obj 494 438 s \$0-boids-params; +#X text 225 654 ..., f 4; +#X floatatom 24 677 5 0 0 0 - - - 0; +#X floatatom 62 695 5 0 0 0 - - - 0; +#X floatatom 127 675 5 0 0 0 - - - 0; +#X floatatom 164 694 5 0 0 0 - - - 0; +#X obj 79 360 hradio 18 1 0 3 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0; +#X msg 53 316 dump; +#X msg 99 422 reset; +#X obj 32 228 bng 18 250 50 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000; +#N canvas 72 225 794 467 output-mode 0; +#X floatatom 156 318 5 0 0 0 - - - 0; +#X floatatom 186 344 5 0 0 0 - - - 0; +#X floatatom 219 367 5 0 0 0 - - - 0; +#X floatatom 252 325 5 0 0 0 - - - 0; +#X floatatom 343 254 5 0 0 0 - - - 0; +#X floatatom 373 279 5 0 0 0 - - - 0; +#X floatatom 390 302 5 0 0 0 - - - 0; +#X floatatom 457 297 5 0 0 0 - - - 0; +#X floatatom 468 321 5 0 0 0 - - - 0; +#X floatatom 492 351 5 0 0 0 - - - 0; +#X obj 252 63 list length; +#X obj 183 112 list prepend; +#X obj 186 66 t a a; +#X floatatom 49 228 5 0 0 0 - - - 0; +#X floatatom 86 247 5 0 0 0 - - - 0; +#X text 371 400 (2) new and old with delta positions; +#X text 141 407 (1) new and old positions; +#X text 39 267 (0) new position only; +#X obj 186 17 inlet; +#X text 298 14 this patch shows the different output modes of the boids external.; +#X msg 393 100 mode \$1; +#X obj 393 167 s \$0-boids-params; +#X obj 392 74 hradio 18 1 0 3 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0; +#X text 391 45 output mode:; +#X text 468 100 (1) new and old positions; +#X text 468 78 (0) new position only; +#X text 470 122 (2) new and old with delta positions; +#X obj 47 203 unpack f f f; +#X floatatom 129 228 5 0 0 0 - - - 0; +#X obj 198 262 unpack f f f f f f; +#X floatatom 274 354 5 0 0 0 - - - 0; +#X floatatom 300 380 5 0 0 0 - - - 0; +#X floatatom 552 307 5 0 0 0 - - - 0; +#X floatatom 563 331 5 0 0 0 - - - 0; +#X floatatom 587 361 5 0 0 0 - - - 0; +#X obj 343 229 unpack f f f f f f f f f, f 33; +#X obj 189 141 route 3 6 9; +#X connect 10 0 11 1; +#X connect 11 0 36 0; +#X connect 12 0 11 0; +#X connect 12 1 10 0; +#X connect 18 0 12 0; +#X connect 20 0 21 0; +#X connect 22 0 20 0; +#X connect 27 0 13 0; +#X connect 27 1 14 0; +#X connect 27 2 28 0; +#X connect 29 0 0 0; +#X connect 29 1 1 0; +#X connect 29 2 2 0; +#X connect 29 3 3 0; +#X connect 29 4 30 0; +#X connect 29 5 31 0; +#X connect 35 0 4 0; +#X connect 35 1 5 0; +#X connect 35 2 6 0; +#X connect 35 3 7 0; +#X connect 35 4 8 0; +#X connect 35 5 9 0; +#X connect 35 6 32 0; +#X connect 35 7 33 0; +#X connect 35 8 34 0; +#X connect 36 0 27 0; +#X connect 36 1 29 0; +#X connect 36 2 35 0; +#X restore 251 605 pd output-mode; +#X floatatom 279 690 5 0 0 0 - - - 0; +#X floatatom 317 708 5 0 0 0 - - - 0; +#X obj 32 572 route 0 1 2 3 4 10 15, f 27; +#X text 136 361 see [pd-output-mode]; +#X obj 272 262 boids-params \$0; +#X obj 109 453 r \$0-boids-params; +#X obj 507 358 t b f; +#X text 98 308 Use the 'dump' message to output a list of the current parameter settings., f 42; +#X text 51 254 The flight parameters can be changed with messages -->, f 28; +#X text 461 253 ATTRACTION POINT; +#X text 473 75 BOUNDING BOX; +#X text 460 274 Usually \, the attraction point is what can be "moved" to cause the entire flock to follow it, f 39; +#X text 98 492 optional arguments: integer number of boids (default is 16); +#X text 165 508 next optional argument is mode (default is 0); +#X obj 32 175 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 32 200 metro 10; +#X obj 567 503 bng 18 250 50 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000; +#X text 592 502 bang to reset to defaults; +#X obj 565 528 s \$0-reset; +#X obj 565 478 loadbang; +#X obj 32 493 boids3d; +#X obj 24 651 unpack f f f; +#X obj 127 650 unpack f f f; +#X obj 279 664 unpack f f f; +#X floatatom 102 703 5 0 0 0 - - - 0; +#X floatatom 209 701 5 0 0 0 - - - 0; +#X floatatom 373 692 5 0 0 0 - - - 0; +#X msg 494 408 attractpt \$1 \$2 \$3; +#X text 605 342 point to which boids are attracted (x/y/z), f 21; +#X floatatom 561 338 5 0 0 0 - - - 0; +#X obj 559 360 t b f; +#X obj 495 382 pack f f f; +#N canvas 0 0 561 332 3D-bounding-box 0; +#X obj 58 181 s \$0-boids-params; +#X obj 350 78 list prepend \$0; +#X text 459 54 defaults; +#X obj 349 25 r \$0-reset; +#X obj 29 27 inlet; +#X obj 74 29 inlet; +#X obj 119 29 inlet; +#X obj 170 29 inlet; +#X obj 41 76 pack f f f f f f; +#X obj 219 30 inlet; +#X obj 270 30 inlet; +#X msg 58 156 flyrect \$1 \$2 \$3 \$4 \$5 \$6; +#X msg 350 103 \; \$1-flyrect0 \$2 \; \$1-flyrect1 \$3 \; \$1-flyrect2 \$4 \; \$1-flyrect3 \$5 \; \$1-flyrect4 \$6 \; \$1-flyrect5 \$7; +#X msg 350 53 -1 1 1 -1 1 -1; +#X connect 1 0 12 0; +#X connect 3 0 13 0; #X connect 4 0 8 0; -#X connect 5 0 4 0; -#X connect 6 0 1 0; -#X connect 7 0 6 0; -#X restore 33 362 pd center; -#X obj 205 163 boids3d 40; -#N canvas 0 22 466 396 orbit 0; -#X floatatom 103 160 5 0 0 0 - - - 0; -#X obj 103 187 expr $f1 * (3.141593/180.); -#X obj 103 45 inlet; -#X obj 166 314 outlet; -#X obj 103 314 outlet; -#N canvas 0 0 450 300 pol2cart 0; -#X obj 79 42 inlet r; -#X obj 159 42 inlet phi; -#X obj 79 231 outlet x; -#X obj 146 231 outlet y; -#X obj 146 120 t f f; -#X obj 146 144 cos; -#X obj 176 144 sin; -#X obj 79 171 t f f, f 10; -#X obj 79 197 * 1; -#X obj 146 196 * 0; -#X obj 79 93 unpack 0 0; -#X obj 79 65 pack \$1 \$2; -#X connect 0 0 11 0; -#X connect 1 0 11 1; -#X connect 4 0 5 0; -#X connect 4 1 6 0; #X connect 5 0 8 1; -#X connect 6 0 9 1; -#X connect 7 0 8 0; -#X connect 7 1 9 0; -#X connect 8 0 2 0; -#X connect 9 0 3 0; -#X connect 10 0 7 0; -#X connect 10 1 4 0; -#X connect 11 0 10 0; -#X restore 103 254 pd pol2cart; -#X msg 103 210 1.5 \$1; -#X obj 103 277 swap, f 11; -#X obj 103 68 i; -#X obj 103 91 + 1; -#X obj 103 114 % 360; -#X obj 103 137 t f f; -#X connect 0 0 1 0; -#X connect 1 0 6 0; -#X connect 2 0 8 0; -#X connect 5 0 7 0; -#X connect 5 1 7 1; -#X connect 6 0 5 0; -#X connect 7 0 4 0; -#X connect 7 1 3 0; -#X connect 8 0 9 0; -#X connect 9 0 10 0; -#X connect 10 0 11 0; +#X connect 6 0 8 2; +#X connect 7 0 8 3; +#X connect 8 0 11 0; +#X connect 9 0 8 4; +#X connect 10 0 8 5; #X connect 11 0 0 0; -#X connect 11 1 8 1; -#X restore 33 205 pd orbit; -#X obj 33 256 t f f; -#X obj 86 338 s \$0-boidParam; -#X obj 318 164 s \$0-init; -#X obj 205 190 clone -x 40 examples/gemboid \$0; -#X msg 291 67 1; -#X obj 291 90 t f b; -#X obj 205 135 r \$0-boidParam; -#X connect 0 0 1 0; -#X connect 1 0 0 0; -#X connect 2 0 3 0; -#X connect 3 0 7 0; -#X connect 3 0 13 0; -#X connect 4 0 15 0; -#X connect 5 0 10 1; -#X connect 7 0 14 0; -#X connect 8 0 7 1; -#X connect 9 0 19 0; -#X connect 10 0 12 0; -#X connect 10 0 11 0; -#X connect 11 0 16 0; -#X connect 13 0 18 0; -#X connect 14 0 4 0; -#X connect 14 1 5 0; -#X connect 15 0 10 2; -#X connect 15 1 10 0; -#X connect 19 0 20 0; -#X connect 20 0 8 0; -#X connect 20 1 17 0; -#X connect 21 0 13 0; -#X restore 277 440 pd gem_example; -#X msg 486 602 flyrect \$1 \$2 \$3 \$4 \$5 \$6; -#X text 612 585 bounding box (walls) in which to fly (l/t/r/b/f/b); -#X text 609 624 point to which boids are attracted (x/y/z); -#X obj 486 584 pack 0 0 0 0 0 0; -#X floatatom 643 566 5 0 0 0 - - - 0; -#X floatatom 682 566 5 0 0 0 - - - 0; -#X obj 69 498 print boids3d; -#X msg 486 662 attractpt \$1 \$2 \$3; -#X obj 486 642 pack 0 0 0; -#X floatatom 565 625 5 0 0 0 - - - 0; -#X text 30 115 float/2d/3d adaptation 08/2005 by a. sier / jasch; -#N canvas 67 162 494 344 META 0; -#X text 12 165 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; -#X text 12 145 AUTHOR Eric L. Singer; -#X text 12 5 KEYWORDS control; -#X text 12 45 DESCRIPTION bird flight and animal flock simulator; -#X text 12 65 INLET_0 bang mode dump reset number neighbors maxspeed minspeed center attract match avoid repel edgedist speed inertia accel prefdist flyrect attractpt; -#X text 12 105 OUTLET_0 list; -#X text 12 125 OUTLET_1 list; -#X text 12 25 LICENSE GPL v2; -#X restore 930 684 pd META; -#X obj 69 448 boids3d 16 0; -#X text 29 218 Boids takes an integer argument which is the number of boids. Each time Boids receives a bang \, it calculates and outputs the new positions of the boids. The output consists of the coordinates for each boid \, the number and type depending on the mode.; -#X obj 824 20 declare -lib Gem; -#X obj 95 421 r \$0-boidParam; -#X obj 121 651 s \$0-boidParam; -#X obj 486 686 s \$0-boidParam; -#X msg 486 113 neighbors \$1; -#X floatatom 446 96 5 0 4 0 - \$0-neighbors - 0; -#X floatatom 446 131 5 0 0 0 - \$0-maxspeed - 0; -#X msg 486 148 maxspeed \$1; -#X floatatom 446 166 5 0 0 0 - \$0-minspeed - 0; -#X msg 486 183 minspeed \$1; -#X floatatom 446 201 5 0 0 0 - \$0-center - 0; -#X msg 486 218 center \$1; -#X floatatom 446 236 5 0 0 0 - \$0-attract - 0; -#X msg 486 253 attract \$1; -#X floatatom 446 271 5 0 0 0 - \$0-match - 0; -#X msg 486 288 match \$1; -#X floatatom 446 306 5 0 0 0 - \$0-avoid - 0; -#X msg 486 323 avoid \$1; -#X floatatom 446 341 5 0 0 0 - \$0-repel - 0; -#X msg 486 358 repel \$1; -#X floatatom 446 376 5 0 0 0 - \$0-edgedist - 0; -#X msg 486 393 edgedist \$1; -#X floatatom 446 411 5 0 0 0 - \$0-speed - 0; -#X msg 486 428 speed \$1; -#X floatatom 446 446 5 0 0 0 - \$0-inertia - 0; -#X msg 486 463 inertia \$1; -#X floatatom 446 481 5 0 0 0 - \$0-accel - 0; -#X msg 486 498 accel \$1; -#X floatatom 446 516 5 0 0 0 - \$0-prefdist - 0; -#X msg 486 533 prefdist \$1; -#X text 577 148 maximum speed of speed range; -#X text 579 182 minimum speed of speed range; -#X text 576 217 strength of centering instinct; -#X text 578 428 overall speed; -#X text 579 499 speed of acceleration; -#X text 579 530 preferred distance from neighbors; -#X floatatom 446 61 5 0 0 0 - \$0-number - 0; -#X msg 486 78 number \$1; -#X text 577 76 number of boids; -#X text 577 111 number of neighbors each boid consults when flocking; -#X text 576 288 strength of neighbor speed matching instinct; -#X text 576 323 strength of neighbor avoidance instinct; -#X text 576 355 strength of wall avoidance instinct; -#X text 578 391 distance of vision for avoiding wall edges; -#X text 579 462 willingness to change speed and direction; -#X text 575 251 strength of attraction to 'attractpt'; -#N canvas 1146 116 222 383 init 0; -#X obj 34 21 loadbang; -#X obj 17 79 b; -#X obj 17 112 list prepend \$0; -#X msg 17 145 \; \$1-neighbors 4 \; \$1-maxspeed 1.5 \; \$1-minspeed 1.2 \; \$1-center 1.2 \; \$1-attract 1.25 \; \$1-match 0.3 \; \$1-avoid 3.5 \; \$1-repel 3.5 \; \$1-edgedist 3 \; \$1-speed 3 \; \$1-inertia 4.5 \; \$1-accel 2.5 \; \$1-prefdist 1.5, f 17; -#X obj 94 21 r \$0-reset; -#X obj 111 52 inlet; -#X connect 0 0 1 0; -#X connect 1 0 2 0; -#X connect 2 0 3 0; -#X connect 4 0 1 0; -#X connect 5 0 1 0; -#X restore 277 407 pd init; -#X obj 277 387 bng 18 250 50 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000; -#X connect 0 0 39 0; -#X connect 1 0 39 0; -#X connect 2 0 26 0; -#X connect 3 0 26 1; -#X connect 4 0 26 2; -#X connect 5 0 26 3; -#X connect 6 0 31 0; -#X connect 7 0 31 1; -#X connect 8 0 9 0; -#X connect 9 0 39 0; -#X connect 21 0 35 0; -#X connect 23 0 40 0; -#X connect 26 0 23 0; -#X connect 27 0 26 4; -#X connect 28 0 26 5; -#X connect 30 0 40 0; -#X connect 31 0 30 0; -#X connect 32 0 31 2; -#X connect 35 0 29 0; -#X connect 35 1 19 0; -#X connect 38 0 35 0; -#X connect 41 0 40 0; -#X connect 42 0 41 0; -#X connect 43 0 44 0; -#X connect 44 0 40 0; -#X connect 45 0 46 0; -#X connect 46 0 40 0; -#X connect 47 0 48 0; -#X connect 48 0 40 0; -#X connect 49 0 50 0; -#X connect 50 0 40 0; -#X connect 51 0 52 0; -#X connect 52 0 40 0; -#X connect 53 0 54 0; -#X connect 54 0 40 0; -#X connect 55 0 56 0; -#X connect 56 0 40 0; +#X connect 13 0 1 0; +#X restore 537 202 pd 3D-bounding-box; +#X f 23; +#X floatatom 740 132 5 0 0 0 front \$0-flyrect4 - 0; +#X floatatom 745 170 5 0 0 0 back \$0-flyrect5 - 0; +#X text 602 76 3D bounding cube (walls) in which to fly, f 23; +#X text 101 174 Each time Boids receives a bang \, it calculates and outputs the new positions of the boids. The output consists of the X \, Y \, Z coordiantes for each boid., f 49; +#X connect 0 0 60 0; +#X connect 1 0 60 1; +#X connect 2 0 60 2; +#X connect 3 0 60 3; +#X connect 4 0 59 0; +#X connect 5 0 34 0; +#X connect 6 0 48 0; +#X connect 23 0 6 0; +#X connect 24 0 48 0; +#X connect 25 0 48 0; +#X connect 26 0 48 0; +#X connect 30 0 49 0; +#X connect 30 1 50 0; +#X connect 30 5 51 0; +#X connect 30 6 27 0; +#X connect 33 0 48 0; +#X connect 34 0 59 0; +#X connect 34 1 59 1; +#X connect 42 0 43 0; +#X connect 43 0 26 0; +#X connect 44 0 46 0; +#X connect 47 0 44 0; +#X connect 48 0 30 0; +#X connect 48 1 13 0; +#X connect 49 0 19 0; +#X connect 49 1 20 0; +#X connect 49 2 52 0; +#X connect 50 0 21 0; +#X connect 50 1 22 0; +#X connect 50 2 53 0; +#X connect 51 0 28 0; +#X connect 51 1 29 0; +#X connect 51 2 54 0; +#X connect 55 0 17 0; #X connect 57 0 58 0; -#X connect 58 0 40 0; -#X connect 59 0 60 0; -#X connect 60 0 40 0; -#X connect 61 0 62 0; -#X connect 62 0 40 0; -#X connect 63 0 64 0; -#X connect 64 0 40 0; -#X connect 65 0 66 0; -#X connect 66 0 40 0; -#X connect 73 0 74 0; -#X connect 74 0 40 0; -#X connect 84 0 83 0; +#X connect 58 0 59 0; +#X connect 58 1 59 2; +#X connect 59 0 55 0; +#X connect 61 0 60 4; +#X connect 62 0 60 5; From 238938b879403892165c5b30b4e0959250edb141 Mon Sep 17 00:00:00 2001 From: fdch Date: Sun, 26 Apr 2026 12:41:22 +0200 Subject: [PATCH 08/19] update 2d example with struct --- examples/boids2d-struct.pd | 65 ++++++++------- examples/point.pd | 92 +++++++++++++++++++++ examples/struct-boid.pd | 164 +++++++++++++++++++++---------------- 3 files changed, 221 insertions(+), 100 deletions(-) create mode 100644 examples/point.pd diff --git a/examples/boids2d-struct.pd b/examples/boids2d-struct.pd index a6a3ca7..2134805 100644 --- a/examples/boids2d-struct.pd +++ b/examples/boids2d-struct.pd @@ -1,34 +1,37 @@ -#N canvas 780 192 827 545 12; -#N struct \$0-template float x float y float k float i; +#N canvas 843 196 827 539 12; +#N struct \$0-template float k1 float k2 float k3 float x0 float y0 float x1 float y1 float x2 float y2 float x3 float y3 float i; #N struct \$0-attractpoint float x float y; #N canvas 0 25 554 469 \$0-data 0; -#X scalar \$0-template -257 -271 46 15 \;; -#X scalar \$0-template -4 160 1 14 \;; -#X scalar \$0-template -157 -59 27 13 \;; -#X scalar \$0-template -22 -165 35 12 \;; -#X scalar \$0-template 121 -44 78 11 \;; -#X scalar \$0-template 138 -175 47 10 \;; -#X scalar \$0-template -184 248 84 9 \;; -#X scalar \$0-template 180 -140 8 8 \;; -#X scalar \$0-template 80 -121 63 7 \;; -#X scalar \$0-template 288 207 73 6 \;; -#X scalar \$0-template -200 10 1 5 \;; -#X scalar \$0-template 234 108 48 4 \;; -#X scalar \$0-template -137 293 91 3 \;; -#X scalar \$0-template -206 143 43 2 \;; -#X scalar \$0-template -118 -267 30 1 \;; -#X scalar \$0-template 77 39 48 0 \;; -#X scalar \$0-attractpoint 0 0 \;; +#X scalar \$0-template 533 533 0 86.9479 35.7409 76.9079 25.7811 66.9481 35.8211 76.9882 45.7809 15 \;; +#X scalar \$0-template 808 808 0 90.5485 75.9537 100.38 86.1194 110.546 76.2879 100.714 66.1222 14 \;; +#X scalar \$0-template 103 103 0 40.6929 146.054 50.556 156.189 60.691 146.326 50.8278 136.191 13 \;; +#X scalar \$0-template 739 739 0 53.7212 105.345 63.5899 115.475 73.7195 105.606 63.8509 95.4764 12 \;; +#X scalar \$0-template 864 864 0 73.5339 87.1421 83.4075 97.2669 93.5323 87.3932 83.6587 77.2684 11 \;; +#X scalar \$0-template 233 233 0 248.225 85.3604 258.206 95.3787 268.225 85.397 258.243 75.3787 10 \;; +#X scalar \$0-template 352 352 0 42.824 146.478 52.6891 156.611 62.8222 146.746 52.9571 136.613 9 \;; +#X scalar \$0-template 224 224 0 27.0472 202.492 36.8898 212.647 47.0447 202.804 37.2021 192.649 8 \;; +#X scalar \$0-template 805 805 0 96.7556 53.4489 106.737 63.4679 116.756 53.4869 106.775 43.4679 7 \;; +#X scalar \$0-template 301 301 0 62.0925 26.3905 72.042 36.4408 82.0923 26.4913 72.1428 16.441 6 \;; +#X scalar \$0-template 857 857 0 29.2793 236.74 39.1356 246.882 49.2773 237.025 39.4211 226.884 5 \;; +#X scalar \$0-template 572 572 0 33.658 207.273 43.5156 217.414 53.656 207.556 43.7983 197.416 4 \;; +#X scalar \$0-template 231 231 0 70.6423 105.863 80.5215 115.983 90.6409 106.104 80.7618 95.9843 3 \;; +#X scalar \$0-template 357 357 0 87.0974 28.9955 77.0544 19.0387 67.0976 29.0818 77.1407 39.0385 2 \;; +#X scalar \$0-template 149 149 0 93.7927 58.4476 103.6 68.6362 113.789 58.8284 103.981 48.6398 1 \;; +#X scalar \$0-template 726 726 0 32.1594 178.317 42.0162 188.458 52.1574 178.601 42.3006 168.46 0 \;; +#X scalar \$0-attractpoint 288 288 \;; #X coords -300 -300 300 300 300 300 2 100 100; #X restore 27 183 pd \$0-data; -#N canvas 167 269 524 337 \$0-template 0; -#X obj 54 46 filledpolygon k k 0 -10 0 0 10 10 0 0 -10; -#X text 93 161 Struct that defines each boid diamond; -#X text 125 200 color can be changed with k; -#X obj 40 20 struct \$0-template float x float y float k float i; -#X obj 60 84 r \$0-indices; -#X obj 60 116 drawnumber -n i 5 5 k; -#X connect 4 0 5 0; +#N canvas 125 78 524 337 \$0-template 0; +#X text 59 231 Struct that defines each boid diamond; +#X text 91 270 color can be changed with k; +#X obj 48 145 r \$0-indices; +#X obj 41 95 filledpolygon k1 k2 k3 x0 y0 x1 y1 x2 y2 x3 y3; +#X obj 48 177 drawnumber -n i 5 5 k1; +#X msg 360 225 clear; +#X obj 360 250 s pd-\$0-data; +#X obj 40 20 struct \$0-template float k1 float k2 float k3 float x0 float y0 float x1 float y1 float x2 float y2 float x3 float y3 float i; +#X connect 2 0 4 0; +#X connect 5 0 6 0; #X restore 31 132 pd \$0-template; #X floatatom 383 404 5 0 0 0 left \$0-flyrect0 - 0; #X floatatom 425 380 5 0 0 0 top \$0-flyrect1 - 0; @@ -217,8 +220,8 @@ #X obj 614 224 r \$0-boids-params; #X obj 605 289 print; #X msg 561 161 dump; -#X msg 638 165 attractpt \$1 \$2; -#X obj 638 141 r \$0-attractpt; +#X msg 626 125 attractpt \$1 \$2; +#X obj 626 101 r \$0-attractpt; #X obj 666 271 r \$0-init-boids; #X obj 712 375 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; #X obj 712 400 s \$0-init; @@ -229,6 +232,8 @@ #X obj 617 406 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; #X obj 615 435 s \$0-indices; #X text 239 24 A 2d boids example using data structures; +#X msg 633 196 mode 2; +#X obj 628 169 loadbang; #X connect 2 0 6 0; #X connect 3 0 6 1; #X connect 4 0 6 2; @@ -259,3 +264,5 @@ #X connect 33 0 34 0; #X connect 38 0 23 1; #X connect 39 0 40 0; +#X connect 42 0 24 0; +#X connect 43 0 42 0; diff --git a/examples/point.pd b/examples/point.pd new file mode 100644 index 0000000..263a000 --- /dev/null +++ b/examples/point.pd @@ -0,0 +1,92 @@ +#N canvas 346 145 664 704 12; +#X obj 61 13 inlet; +#X obj 137 327 unpack; +#X obj 264 320 cos; +#X obj 296 320 sin; +#X obj 264 293 t f f; +#X obj 127 363 t f f; +#X obj 151 422 *; +#X obj 185 421 *; +#X obj 176 365 t f f; +#X obj 263 423 *; +#X obj 297 422 *; +#X obj 237 363 t f f; +#X obj 288 363 t f f; +#X obj 151 447 -; +#X obj 263 448 +; +#X obj 311 177 atan2; +#X msg 311 152 2 0; +#X obj 313 201 * 2; +#X obj 312 129 loadbang; +#X obj 267 257 / 180; +#X obj 263 527 +; +#X obj 375 528 +; +#X obj 446 329 unpack; +#X obj 265 233 * 3.14156; +#X obj 136 156 abs; +#X obj 134 206 * -1; +#X obj 134 231 pack; +#X obj 135 181 t f f; +#X msg 130 264 \$1 0 \, 0 \$2 \, \$2 0 \, 0 \$1, f 11; +#X obj 137 117 unpack; +#X obj 436 118 list split 2; +#X obj 113 80 list split 2; +#X obj 263 552 pack; +#X msg 96 537 append \$1 \$2; +#X obj 64 580 list store; +#X obj 58 44 t b a a, f 42; +#X obj 64 605 t a b; +#X obj 64 630 outlet; +#X listbox 151 472 20 0 0 0 - - - 0; +#X listbox 263 473 20 0 0 0 - - - 0; +#X connect 0 0 35 0; +#X connect 1 0 5 0; +#X connect 1 1 8 0; +#X connect 2 0 11 0; +#X connect 3 0 12 0; +#X connect 4 0 2 0; +#X connect 4 1 3 0; +#X connect 5 0 6 0; +#X connect 5 1 9 0; +#X connect 6 0 13 0; +#X connect 7 0 13 1; +#X connect 8 0 7 0; +#X connect 8 1 10 0; +#X connect 9 0 14 0; +#X connect 10 0 14 1; +#X connect 11 0 6 1; +#X connect 11 1 10 1; +#X connect 12 0 7 1; +#X connect 12 1 9 1; +#X connect 13 0 20 0; +#X connect 13 0 38 0; +#X connect 14 0 21 0; +#X connect 14 0 39 0; +#X connect 15 0 17 0; +#X connect 16 0 15 0; +#X connect 17 0 23 1; +#X connect 18 0 16 0; +#X connect 19 0 4 0; +#X connect 20 0 32 0; +#X connect 21 0 32 1; +#X connect 22 0 20 1; +#X connect 22 1 21 1; +#X connect 23 0 19 0; +#X connect 24 0 27 0; +#X connect 25 0 26 0; +#X connect 26 0 28 0; +#X connect 27 0 25 0; +#X connect 27 1 26 1; +#X connect 28 0 1 0; +#X connect 29 0 24 0; +#X connect 29 1 23 0; +#X connect 30 0 22 0; +#X connect 31 1 29 0; +#X connect 32 0 33 0; +#X connect 33 0 34 0; +#X connect 34 0 36 0; +#X connect 35 0 34 0; +#X connect 35 1 31 0; +#X connect 35 2 30 0; +#X connect 36 0 37 0; +#X connect 36 1 34 1; diff --git a/examples/struct-boid.pd b/examples/struct-boid.pd index 934fe83..1f849a8 100644 --- a/examples/struct-boid.pd +++ b/examples/struct-boid.pd @@ -1,74 +1,96 @@ -#N canvas 762 81 800 511 12; -#X msg 432 201 traverse pd-\$1-data \, bang; -#X obj 432 226 pointer; -#X obj 272 110 random 600; -#X obj 272 135 - 300; -#X obj 356 111 random 600; -#X obj 351 136 - 300; -#X obj 334 65 t b b b; -#X obj 447 119 random 100; -#X obj 284 171 pack f f f; -#X obj 280 220 t a b; -#X obj 333 21 inlet; -#X obj 432 176 f \$2; -#X obj 24 20 inlet; -#X obj 27 67 unpack; -#X obj 41 472 set \$2-template x y k; -#X obj 399 145 t f f; -#X obj 52 216 t f f; -#X obj 23 192 t f f; -#X obj 162 217 t f f; -#X obj 100 190 t f f; -#X obj 43 241 < -301; -#X obj 101 242 > 301; -#X obj 153 242 < -301; -#X obj 211 243 > 301; -#X obj 153 267 ||; -#X obj 43 266 ||; -#X obj 113 290 ||; -#X obj 128 431 f; -#X obj 117 345 sel 0 1; -#X msg 178 417 999; -#X obj 315 312 append \$2-template x y k i; -#X obj 297 266 list append \$1; +#N canvas 269 57 798 687 12; +#X msg 592 314 traverse pd-\$1-data \, bang; +#X obj 592 339 pointer; +#X obj 312 100 inlet; +#X obj 592 289 f \$2; +#X obj 42 112 inlet; +#X obj 17 174 unpack; +#X obj 42 323 t f f; +#X obj 13 299 t f f; +#X obj 152 324 t f f; +#X obj 90 297 t f f; +#X obj 33 348 < -301; +#X obj 91 349 > 301; +#X obj 143 349 < -301; +#X obj 201 350 > 301; +#X obj 143 374 ||; +#X obj 33 373 ||; +#X obj 103 397 ||; +#X obj 141 494 f; +#X obj 107 452 sel 0 1; +#X msg 231 481 999; +#X obj 324 324 point; +#X obj 249 158 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; +#X obj 410 286 s \$0-color; +#X obj 179 444 r \$0-color; +#X obj 410 336 r \$0-color; +#X obj 328 389 list prepend; +#X obj 329 420 list prepend \$1; +#X obj 326 463 append \$2-template i k1 k2 k3 x0 y0 x1 y1 x2 y2 x3 y3; +#X msg 410 361 list \$1 \$1 0; +#X obj 33 536 point; +#X obj 31 596 set \$2-template x0 y0 x1 y1 x2 y2 x3 y3 k1 k2 k3; +#X obj 142 231 atan2; +#X obj 142 281 / 3.14159; +#X obj 142 256 * 180; +#X obj 144 197 unpack; +#X obj 70 139 list split 2; +#X obj 118 164 list split 2; +#X obj 12 495 pack f f 10 0; +#X obj 236 553 t f f b; +#X msg 315 564 0; +#X msg 320 272 0 0 10 0; +#X obj 324 183 t b b b, f 8; +#X obj 412 255 random 998; #X connect 0 0 1 0; -#X connect 1 0 30 4; -#X connect 2 0 3 0; -#X connect 3 0 8 0; -#X connect 4 0 5 0; -#X connect 5 0 8 1; -#X connect 6 0 2 0; -#X connect 6 1 4 0; -#X connect 6 2 7 0; -#X connect 7 0 15 0; -#X connect 8 0 9 0; -#X connect 9 0 31 0; -#X connect 9 1 11 0; -#X connect 10 0 6 0; -#X connect 11 0 0 0; -#X connect 12 0 13 0; -#X connect 13 0 17 0; -#X connect 13 1 19 0; -#X connect 15 0 8 2; -#X connect 15 1 27 1; -#X connect 16 0 20 0; -#X connect 16 1 21 0; -#X connect 17 0 14 0; -#X connect 17 1 16 0; -#X connect 18 0 22 0; -#X connect 18 1 23 0; -#X connect 19 0 14 1; -#X connect 19 1 18 0; +#X connect 1 0 27 12; +#X connect 2 0 41 0; +#X connect 3 0 0 0; +#X connect 4 0 35 0; +#X connect 5 0 7 0; +#X connect 5 1 9 0; +#X connect 6 0 10 0; +#X connect 6 1 11 0; +#X connect 7 0 37 0; +#X connect 7 1 6 0; +#X connect 8 0 12 0; +#X connect 8 1 13 0; +#X connect 9 0 37 1; +#X connect 9 1 8 0; +#X connect 10 0 15 0; +#X connect 11 0 15 1; +#X connect 12 0 14 0; +#X connect 13 0 14 1; +#X connect 14 0 16 1; +#X connect 15 0 16 0; +#X connect 16 0 18 0; +#X connect 17 0 38 0; +#X connect 18 0 17 0; +#X connect 18 1 19 0; #X connect 20 0 25 0; -#X connect 21 0 25 1; -#X connect 22 0 24 0; -#X connect 23 0 24 1; -#X connect 24 0 26 1; +#X connect 21 0 41 0; +#X connect 23 0 17 1; +#X connect 24 0 28 0; #X connect 25 0 26 0; -#X connect 26 0 28 0; -#X connect 27 0 14 2; -#X connect 28 0 27 0; -#X connect 28 1 29 0; -#X connect 29 0 14 2; -#X connect 30 0 14 3; -#X connect 31 0 30 0; +#X connect 26 0 27 0; +#X connect 27 0 30 11; +#X connect 28 0 25 1; +#X connect 29 0 30 0; +#X connect 31 0 33 0; +#X connect 32 0 37 3; +#X connect 33 0 32 0; +#X connect 34 0 31 0; +#X connect 34 1 31 1; +#X connect 35 0 5 0; +#X connect 35 1 36 0; +#X connect 36 1 34 0; +#X connect 37 0 29 0; +#X connect 38 0 30 8; +#X connect 38 1 30 9; +#X connect 38 2 39 0; +#X connect 39 0 30 10; +#X connect 40 0 20 0; +#X connect 41 0 40 0; +#X connect 41 1 42 0; +#X connect 41 2 3 0; +#X connect 42 0 22 0; From bb4d07f7a969602b0838a6dfad8cc6d5cee83747 Mon Sep 17 00:00:00 2001 From: fdch Date: Sun, 26 Apr 2026 19:27:26 +0200 Subject: [PATCH 09/19] update examples and fixes --- Makefile | 4 +- examples/boids-gem.pd | 282 +++++++++++++++++++++++++++++++++++++++ examples/boids-struct.pd | 268 +++++++++++++++++++++++++++++++++++++ examples/gemboid.pd | 89 ++++++------ examples/struct-boid.pd | 38 +++--- help/boids-help.pd | 216 ++++++++++++++++++++++++++++++ src/boid_params.c | 1 + src/boid_params.h | 1 + src/boids.c | 205 ++++++++++++++++++---------- src/boids.h | 28 ++-- src/point.c | 66 +++++++-- src/point.h | 2 + 12 files changed, 1037 insertions(+), 163 deletions(-) create mode 100644 examples/boids-gem.pd create mode 100644 examples/boids-struct.pd create mode 100644 help/boids-help.pd diff --git a/Makefile b/Makefile index 1e98cbc..b62fa52 100644 --- a/Makefile +++ b/Makefile @@ -2,18 +2,20 @@ # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. + # library name lib.name = boids # input source file (class name == source file basename) class.sources = src/boids.c common.sources = src/boid_params.c src/point.c - # all extra files to be included in binary distribution of the library datafiles = boids-meta.pd help/boids2d-help.pd help/boids3d-help.pd README.txt LICENSE.txt datadirs = examples +cflags = -O0 -g3 -fno-inline -fno-omit-frame-pointer -Wall -Wextra -Wpedantic + # include Makefile.pdlibbuilder from submodule directory 'pd-lib-builder' PDLIBBUILDER_DIR=pd-lib-builder/ include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder diff --git a/examples/boids-gem.pd b/examples/boids-gem.pd new file mode 100644 index 0000000..d0e526d --- /dev/null +++ b/examples/boids-gem.pd @@ -0,0 +1,282 @@ +#N canvas 854 293 711 590 12; +#X declare -lib Gem; +#X msg 100 40 destroy; +#N canvas 803 136 629 324 gemwin 0; +#X obj 209 190 gemwin; +#X obj 67 194 outlet; +#X obj 67 10 inlet; +#X obj 67 41 route create; +#X msg 67 70 set destroy; +#X msg 157 70 set create; +#X msg 350 115 destroy \, reset; +#X obj 157 18 loadbang; +#X msg 238 71 color 1 1 1; +#X obj 496 28 gemhead; +#X obj 496 50 world_light; +#X msg 212 146 create \, 1 \, frame 30 \, color 0 0 0.5 \, lighting 1; +#X connect 2 0 3 0; +#X connect 3 0 4 0; +#X connect 3 0 11 0; +#X connect 3 1 5 0; +#X connect 3 1 6 0; +#X connect 4 0 1 0; +#X connect 5 0 1 0; +#X connect 6 0 0 0; +#X connect 7 0 5 0; +#X connect 8 0 0 0; +#X connect 9 0 10 0; +#X connect 11 0 0 0; +#X restore 100 60 pd gemwin; +#N canvas 850 212 692 479 orbit 0; +#X obj 63 290 translateXYZ; +#X obj 69 109 color 1 0.5 0 0.5; +#X obj 72 136 t a b; +#X obj 99 260 unpack f f f; +#X obj 402 108 color 1 0.5 0 0.5; +#X obj 416 337 loadbang; +#X obj 59 339 sphere 0.1; +#X obj 402 80 gemhead 58; +#X msg 416 364 draw line; +#X obj 396 302 translateXYZ; +#X obj 436 274 unpack f f f; +#X obj 400 215 translate -4 0 0 1; +#X obj 462 189 * -8; +#X obj 435 244 r \$0-orbit-translation; +#N canvas 0 0 782 606 orbit-translation 0; +#X obj 66 169 expr $f1 * (3.141593/180.); +#X msg 69 217 1.5 \$1; +#X obj 127 268 t f f; +#X obj 124 296 cos; +#X obj 158 294 sin; +#X obj 77 319 * 1; +#X obj 67 267 t f f; +#X obj 108 319 * 0; +#X obj 66 141 f; +#X obj 94 142 + 1; +#X obj 125 142 mod 360; +#X obj 64 241 unpack; +#X obj 66 193 t f f; +#X obj 252 381 pack f f f; +#X obj 192 318 * 2; +#X obj 191 292 sin; +#X obj 58 76 spigot 1; +#X obj 251 45 route float bang; +#X obj 488 130 spigot; +#X obj 542 130 spigot; +#X obj 548 76 t f f; +#X obj 517 35 gemmouse 1 1; +#A saved init; +#X obj 494 170 * 8; +#X obj 494 193 - 4; +#X obj 540 235 - 4; +#X text 566 184 invert y; +#X obj 540 212 * 8; +#X msg 540 153 1 \$1; +#X obj 540 177 -; +#X obj 647 232 spigot; +#X obj 647 257 t b f; +#X obj 556 104 t f f; +#X obj 651 184 * 8; +#X obj 652 206 - 4; +#X obj 250 471 s \$0-orbit-translation; +#X obj 265 14 inlet; +#X obj 55 10 inlet; +#X floatatom 77 344 5 0 0 0 - - - 0; +#X obj 300 82 random 360; +#X text 239 112 random position; +#X text 70 107 move in orbit; +#X text 497 11 mouse interaction; +#X text 591 321 middle click to enable Z motion (up/down), f 19; +#X connect 0 0 12 0; +#X connect 1 0 11 0; +#X connect 2 0 3 0; +#X connect 2 1 4 0; +#X connect 3 0 5 1; +#X connect 4 0 7 1; +#X connect 5 0 13 0; +#X connect 5 0 37 0; +#X connect 6 0 5 0; +#X connect 6 1 7 0; +#X connect 7 0 13 1; +#X connect 8 0 9 0; +#X connect 8 0 0 0; +#X connect 9 0 10 0; +#X connect 10 0 8 1; +#X connect 11 0 6 0; +#X connect 11 1 2 0; +#X connect 12 0 1 0; +#X connect 12 1 15 0; +#X connect 13 0 34 0; +#X connect 14 0 13 2; +#X connect 15 0 14 0; +#X connect 16 0 8 0; +#X connect 17 0 16 1; +#X connect 17 1 38 0; +#X connect 18 0 22 0; +#X connect 19 0 27 0; +#X connect 20 0 18 1; +#X connect 20 1 19 1; +#X connect 21 0 18 0; +#X connect 21 1 31 0; +#X connect 21 2 20 0; +#X connect 21 3 29 1; +#X connect 22 0 23 0; +#X connect 23 0 13 0; +#X connect 24 0 13 1; +#X connect 26 0 24 0; +#X connect 27 0 28 0; +#X connect 28 0 26 0; +#X connect 29 0 30 0; +#X connect 30 0 13 0; +#X connect 30 1 13 2; +#X connect 31 0 19 0; +#X connect 31 1 32 0; +#X connect 32 0 33 0; +#X connect 33 0 29 0; +#X connect 35 0 17 0; +#X connect 36 0 16 0; +#X connect 38 0 8 0; +#X restore 102 166 pd orbit-translation; +#X obj 103 229 r \$0-orbit-translation; +#X text 76 49 a circle; +#X obj 68 82 gemhead; +#X text 423 51 a bounding box; +#X obj 236 18 inlet; +#X obj 462 162 * 0.5; +#X obj 498 378 * 4; +#X obj 397 399 cube 4; +#X obj 504 341 r \$0-bounding-box; +#X obj 463 135 r \$0-bounding-box; +#X obj 46 28 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 383 29 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X connect 0 0 6 0; +#X connect 1 0 2 0; +#X connect 2 0 0 0; +#X connect 2 1 14 0; +#X connect 3 0 0 1; +#X connect 3 1 0 2; +#X connect 3 2 0 3; +#X connect 4 0 11 0; +#X connect 5 0 8 0; +#X connect 7 0 4 0; +#X connect 8 0 22 0; +#X connect 9 0 22 0; +#X connect 10 0 9 1; +#X connect 10 1 9 2; +#X connect 10 2 9 3; +#X connect 11 0 9 0; +#X connect 12 0 11 1; +#X connect 13 0 10 0; +#X connect 15 0 3 0; +#X connect 17 0 1 0; +#X connect 19 0 14 1; +#X connect 20 0 12 0; +#X connect 21 0 22 1; +#X connect 23 0 21 0; +#X connect 24 0 20 0; +#X connect 25 0 17 0; +#X connect 26 0 7 0; +#X restore 347 236 pd orbit; +#X obj 35 210 tgl 20 1 empty empty start\ flocking\ animation 0 -10 0 12 #fcfcfc #000000 #000000 1 1; +#X text 23 18 create/destroy the GEM window; +#X obj 349 24 declare -lib Gem; +#X obj 92 128 help/boids-params \$0; +#X obj 590 26 loadbang; +#X obj 590 51 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; +#X obj 590 76 s \$0-reset; +#X msg 132 348 reset; +#X obj 142 400 r \$0-boids-params; +#X msg 137 373 dump; +#X obj 103 459 print dump; +#X text 25 102 Change parameters to see their effect:; +#X floatatom 93 222 5 0 0 0 - - - 0; +#X obj 35 248 metro 25; +#X text 134 222 animation speed; +#X floatatom 395 312 5 0 2 0 - \$0-bounding-box-set \$0-bounding-box 0; +#X msg 74 319 attractpt \$1 \$2 \$3; +#X floatatom 364 383 5 0 0 0 left \$0-flyrect0 - 0; +#X floatatom 406 367 5 0 0 0 top \$0-flyrect1 - 0; +#X floatatom 459 389 5 0 0 0 right \$0-flyrect2 - 0; +#X floatatom 508 407 5 0 0 0 bottom \$0-flyrect3 - 0; +#N canvas 0 0 632 412 3D-bounding-box 0; +#X obj 58 181 s \$0-boids-params; +#X obj 365 210 list prepend \$0; +#X obj 349 25 r \$0-reset; +#X obj 29 27 inlet; +#X obj 74 29 inlet; +#X obj 119 29 inlet; +#X obj 170 29 inlet; +#X obj 41 76 pack f f f f f f; +#X obj 219 30 inlet; +#X obj 270 30 inlet; +#X msg 58 156 flyrect \$1 \$2 \$3 \$4 \$5 \$6; +#X obj 434 64 abs; +#X obj 372 102 t f f; +#X obj 372 127 * -1; +#X obj 372 152 pack; +#X msg 372 176 \$1 \$2 \$2 \$1 \$2 \$1; +#X obj 447 36 r \$0-bounding-box; +#X msg 349 50 1; +#X msg 365 235 \; \$1-flyrect0 \$2 \; \$1-flyrect1 \$3 \; \$1-flyrect2 \$4 \; \$1-flyrect3 \$5 \; \$1-flyrect4 \$6 \; \$1-flyrect5 \$7 \; \$1-bounding-box-set set \$3; +#X connect 1 0 18 0; +#X connect 2 0 17 0; +#X connect 3 0 7 0; +#X connect 4 0 7 1; +#X connect 5 0 7 2; +#X connect 6 0 7 3; +#X connect 7 0 10 0; +#X connect 8 0 7 4; +#X connect 9 0 7 5; +#X connect 10 0 0 0; +#X connect 11 0 12 0; +#X connect 12 0 13 0; +#X connect 12 1 14 1; +#X connect 13 0 14 0; +#X connect 14 0 15 0; +#X connect 15 0 1 0; +#X connect 16 0 11 0; +#X connect 17 0 12 0; +#X restore 381 462 pd 3D-bounding-box; +#X f 23; +#X floatatom 587 406 5 0 0 0 front \$0-flyrect4 - 0; +#X floatatom 589 430 5 0 0 0 back \$0-flyrect5 - 0; +#X obj 347 172 tgl 20 1 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 357 200 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; +#X obj 76 290 r \$0-orbit-translation; +#X text 413 223 or click+drag for XY; +#X text 412 236 and middle-click to move Z; +#X text 339 133 ATTRACTION POINT, f 17; +#X text 381 199 random in orbit; +#X text 350 285 BOUNDING BOX; +#X text 371 172 move in an orbit; +#X text 437 313 (shift + drag 0..2); +#X obj 35 489 clone -x gemboid 16 \$0 1; +#X msg 238 342 mode 2; +#X obj 253 279 loadbang; +#X msg 253 304 dimensions 3; +#X obj 35 433 boids 16; +#X connect 0 0 1 0; +#X connect 1 0 0 0; +#X connect 3 0 16 0; +#X connect 7 0 8 0; +#X connect 8 0 9 0; +#X connect 10 0 41 0; +#X connect 11 0 41 0; +#X connect 12 0 41 0; +#X connect 15 0 16 1; +#X connect 16 0 41 0; +#X connect 19 0 41 0; +#X connect 20 0 24 0; +#X connect 21 0 24 1; +#X connect 22 0 24 2; +#X connect 23 0 24 3; +#X connect 25 0 24 4; +#X connect 26 0 24 5; +#X connect 27 0 2 0; +#X connect 28 0 2 0; +#X connect 29 0 19 0; +#X connect 38 0 41 0; +#X connect 39 0 40 0; +#X connect 40 0 41 0; +#X connect 41 0 37 0; +#X connect 41 1 13 0; diff --git a/examples/boids-struct.pd b/examples/boids-struct.pd new file mode 100644 index 0000000..c361fd8 --- /dev/null +++ b/examples/boids-struct.pd @@ -0,0 +1,268 @@ +#N canvas 843 196 827 539 12; +#N struct \$0-template float k1 float k2 float k3 float x0 float y0 float x1 float y1 float x2 float y2 float x3 float y3 float i; +#N struct \$0-attractpoint float x float y; +#N canvas 0 25 554 469 \$0-data 0; +#X scalar \$0-template 167 167 0 -10 0 0 10 10 0 0 -10 15 \;; +#X scalar \$0-template 486 486 0 -10 0 0 10 10 0 0 -10 14 \;; +#X scalar \$0-template 678 678 0 -10 0 0 10 10 0 0 -10 13 \;; +#X scalar \$0-template 889 889 0 -10 0 0 10 10 0 0 -10 12 \;; +#X scalar \$0-template 916 916 0 -10 0 0 10 10 0 0 -10 11 \;; +#X scalar \$0-template 987 987 0 -10 0 0 10 10 0 0 -10 10 \;; +#X scalar \$0-template 271 271 0 -10 0 0 10 10 0 0 -10 9 \;; +#X scalar \$0-template 433 433 0 -10 0 0 10 10 0 0 -10 8 \;; +#X scalar \$0-template 737 737 0 -10 0 0 10 10 0 0 -10 7 \;; +#X scalar \$0-template 157 157 0 -10 0 0 10 10 0 0 -10 6 \;; +#X scalar \$0-template 300 300 0 -10 0 0 10 10 0 0 -10 5 \;; +#X scalar \$0-template 55 55 0 -10 0 0 10 10 0 0 -10 4 \;; +#X scalar \$0-template 304 304 0 -10 0 0 10 10 0 0 -10 3 \;; +#X scalar \$0-template 485 485 0 -10 0 0 10 10 0 0 -10 2 \;; +#X scalar \$0-template 565 565 0 -10 0 0 10 10 0 0 -10 1 \;; +#X scalar \$0-template 628 628 0 -10 0 0 10 10 0 0 -10 0 \;; +#X scalar \$0-attractpoint 0 0 \;; +#X coords -300 -300 300 300 300 300 2 100 100; +#X restore 27 183 pd \$0-data; +#N canvas 125 78 524 337 \$0-template 0; +#X text 59 231 Struct that defines each boid diamond; +#X text 91 270 color can be changed with k; +#X obj 48 145 r \$0-indices; +#X obj 41 95 filledpolygon k1 k2 k3 x0 y0 x1 y1 x2 y2 x3 y3; +#X obj 48 177 drawnumber -n i 5 5 k1; +#X msg 360 225 clear; +#X obj 360 250 s pd-\$0-data; +#X obj 40 20 struct \$0-template float k1 float k2 float k3 float x0 float y0 float x1 float y1 float x2 float y2 float x3 float y3 float i; +#X connect 2 0 4 0; +#X connect 5 0 6 0; +#X restore 31 132 pd \$0-template; +#X floatatom 383 404 5 0 0 0 left \$0-flyrect0 - 0; +#X floatatom 425 380 5 0 0 0 top \$0-flyrect1 - 0; +#X floatatom 491 398 5 0 0 0 right \$0-flyrect2 - 0; +#X floatatom 559 416 5 0 0 0 bottom \$0-flyrect3 - 0; +#N canvas 0 0 450 300 2D-bounding-box 0; +#X msg 58 156 flyrect \$1 \$2 \$3 \$4; +#X obj 58 181 s \$0-boids-params; +#X obj 29 27 inlet; +#X obj 74 29 inlet; +#X obj 119 29 inlet; +#X obj 170 29 inlet; +#X obj 41 76 pack f f f f; +#X connect 0 0 1 0; +#X connect 2 0 6 0; +#X connect 3 0 6 1; +#X connect 4 0 6 2; +#X connect 5 0 6 3; +#X connect 6 0 0 0; +#X restore 391 443 pd 2D-bounding-box; +#X f 23; +#X obj 32 78 help/boids-params \$0; +#N canvas 1059 309 598 557 \$0-attractpoint 0; +#X obj 232 239 f \$0; +#X msg 232 264 traverse pd-\$1-data \, bang; +#X obj 232 289 pointer; +#X obj 90 138 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; +#X msg 443 234 clear; +#X obj 443 259 s pd-\$0-data; +#X obj 56 109 loadbang; +#X obj 63 165 t b b b b b, f 34; +#X obj 86 392 r \$0-attractpt; +#X obj 42 28 struct \$0-attractpoint float x float y; +#X obj 56 481 s \$0-init-boids; +#X obj 89 415 set \$0-attractpoint x y; +#X obj 124 324 append \$0-attractpoint x y; +#X msg 124 296 0 0; +#X obj 39 68 drawcurve 0 1 0 0 0 10 10 10 10 0 0 0; +#X obj 387 368 list prepend \$0; +#X obj 421 333 s \$0-reset; +#X obj 383 302 t b b; +#X msg 390 395 \; \$1-maxspeed 50 \; \$1-minspeed 10 \; \; \$1-flyrect0 -1 \; \$1-flyrect1 1 \; \$1-flyrect2 1 \; \$1-flyrect3 -1; +#X obj 130 108 r \$0-init; +#X text 267 116 Struct that defines the attraction circle; +#X connect 0 0 1 0; +#X connect 1 0 2 0; +#X connect 2 0 12 2; +#X connect 3 0 7 0; +#X connect 4 0 5 0; +#X connect 6 0 7 0; +#X connect 7 0 10 0; +#X connect 7 1 13 0; +#X connect 7 2 0 0; +#X connect 7 3 17 0; +#X connect 7 4 4 0; +#X connect 8 0 11 0; +#X connect 12 0 11 2; +#X connect 13 0 12 0; +#X connect 15 0 18 0; +#X connect 17 0 15 0; +#X connect 17 1 16 0; +#X connect 19 0 7 0; +#X restore 31 106 pd \$0-attractpoint; +#N canvas 323 118 689 551 random-walk 0; +#X obj 167 125 f; +#X obj 74 197 random 2; +#X obj 167 150 t b b f; +#X obj 195 351 +; +#X obj 140 276 + 1; +#X obj 122 332 *; +#X msg 64 305 -1; +#X obj 278 85 moses 0; +#X obj 324 115 moses 100; +#X obj 278 115 * -1; +#X obj 384 143 * -1; +#X obj 384 168 + 200; +#X msg 97 305 1; +#X text 80 223 sign; +#X text 142 240 magnitude; +#X text 228 340 add prev value; +#X text 227 355 to random increment; +#X obj 304 202 t f f; +#X obj 362 284 outlet; +#X obj 167 24 inlet; +#X obj 163 66 b; +#X text 97 461 Pure Data/2.control.examples/22.random-walk.pd, f 74; +#X text 140 439 open the browser and look for:; +#X obj 349 243 * 0.01; +#X obj 74 276 sel; +#X obj 140 200 random 2; +#X connect 0 0 2 0; +#X connect 1 0 24 0; +#X connect 2 0 1 0; +#X connect 2 1 25 0; +#X connect 2 2 3 1; +#X connect 3 0 7 0; +#X connect 4 0 5 1; +#X connect 5 0 3 0; +#X connect 6 0 5 0; +#X connect 7 0 9 0; +#X connect 7 1 8 0; +#X connect 8 0 17 0; +#X connect 8 1 10 0; +#X connect 9 0 17 0; +#X connect 10 0 11 0; +#X connect 11 0 17 0; +#X connect 12 0 5 0; +#X connect 17 0 0 1; +#X connect 17 1 23 0; +#X connect 19 0 20 0; +#X connect 20 0 0 0; +#X connect 23 0 18 0; +#X connect 24 0 6 0; +#X connect 24 1 12 0; +#X connect 25 0 4 0; +#X restore 366 209 pd random-walk; +#X obj 366 234 * 600; +#X obj 366 259 - 300; +#X obj 367 109 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#N canvas 657 108 689 551 random-walk 0; +#X obj 167 125 f; +#X obj 74 197 random 2; +#X obj 167 150 t b b f; +#X obj 195 351 +; +#X obj 140 276 + 1; +#X obj 122 332 *; +#X msg 64 305 -1; +#X obj 278 85 moses 0; +#X obj 324 115 moses 100; +#X obj 278 115 * -1; +#X obj 384 143 * -1; +#X obj 384 168 + 200; +#X msg 97 305 1; +#X text 80 223 sign; +#X text 145 221 magnitude; +#X text 228 340 add prev value; +#X text 227 355 to random increment; +#X obj 304 202 t f f; +#X obj 362 284 outlet; +#X obj 167 24 inlet; +#X obj 163 66 b; +#X text 97 461 Pure Data/2.control.examples/22.random-walk.pd, f 74; +#X text 140 439 open the browser and look for:; +#X obj 349 243 * 0.01; +#X obj 74 276 sel; +#X obj 140 198 random 2; +#X connect 0 0 2 0; +#X connect 1 0 24 0; +#X connect 2 0 1 0; +#X connect 2 1 25 0; +#X connect 2 2 3 1; +#X connect 3 0 7 0; +#X connect 4 0 5 1; +#X connect 5 0 3 0; +#X connect 6 0 5 0; +#X connect 7 0 9 0; +#X connect 7 1 8 0; +#X connect 8 0 17 0; +#X connect 8 1 10 0; +#X connect 9 0 17 0; +#X connect 10 0 11 0; +#X connect 11 0 17 0; +#X connect 12 0 5 0; +#X connect 17 0 0 1; +#X connect 17 1 23 0; +#X connect 19 0 20 0; +#X connect 20 0 0 0; +#X connect 23 0 18 0; +#X connect 24 0 6 0; +#X connect 24 1 12 0; +#X connect 25 0 4 0; +#X restore 410 233 pd random-walk; +#X obj 410 258 * 600; +#X obj 410 283 - 300; +#X obj 360 183 t b b; +#X obj 367 134 metro 50; +#X obj 366 284 pack; +#X obj 363 317 s \$0-attractpt; +#X floatatom 433 109 5 0 0 0 - - - 0; +#X msg 663 295 all bang; +#X obj 545 96 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 545 121 metro 10; +#X obj 546 335 clone struct-boid 16 \$0; +#X msg 568 188 reset; +#X obj 614 224 r \$0-boids-params; +#X obj 605 289 print; +#X msg 561 161 dump; +#X msg 626 125 attractpt \$1 \$2; +#X obj 626 101 r \$0-attractpt; +#X obj 666 271 r \$0-init-boids; +#X obj 712 375 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; +#X obj 712 400 s \$0-init; +#X text 359 75 ATTRACTION POINT; +#X text 579 68 Update boids; +#X text 359 359 BOUNDING BOX; +#X floatatom 577 91 5 0 0 0 - - - 0; +#X obj 617 406 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 615 435 s \$0-indices; +#X text 239 24 A 2d boids example using data structures; +#X msg 633 196 mode 2; +#X obj 628 169 loadbang; +#X obj 545 256 boids 16; +#X connect 2 0 6 0; +#X connect 3 0 6 1; +#X connect 4 0 6 2; +#X connect 5 0 6 3; +#X connect 9 0 10 0; +#X connect 10 0 11 0; +#X connect 11 0 18 0; +#X connect 12 0 17 0; +#X connect 13 0 14 0; +#X connect 14 0 15 0; +#X connect 15 0 18 1; +#X connect 16 0 9 0; +#X connect 16 1 13 0; +#X connect 17 0 16 0; +#X connect 18 0 19 0; +#X connect 20 0 17 1; +#X connect 21 0 24 1; +#X connect 22 0 23 0; +#X connect 23 0 43 0; +#X connect 25 0 43 0; +#X connect 26 0 43 0; +#X connect 28 0 43 0; +#X connect 29 0 43 0; +#X connect 30 0 29 0; +#X connect 31 0 21 0; +#X connect 32 0 33 0; +#X connect 37 0 23 1; +#X connect 38 0 39 0; +#X connect 41 0 43 0; +#X connect 42 0 41 0; +#X connect 43 0 24 0; +#X connect 43 1 27 0; diff --git a/examples/gemboid.pd b/examples/gemboid.pd index 75320fa..ed62708 100644 --- a/examples/gemboid.pd +++ b/examples/gemboid.pd @@ -2,7 +2,6 @@ #X obj 61 64 gemhead; #X obj 61 241 translateXYZ; #X obj 152 41 inlet; -#X obj 61 195 alpha; #X obj 61 125 color 1 0.5 0 0.5; #N canvas 0 22 474 324 rand_color 0; #X obj 47 130 random 1000; @@ -64,52 +63,50 @@ #X obj 391 486 sphere3d 0.1 6; #X obj 453 411 loadbang; #X msg 453 436 setCartesian 0 0 0 0 2; -#X connect 0 0 4 0; -#X connect 1 0 15 0; -#X connect 2 0 18 0; +#X connect 0 0 3 0; +#X connect 1 0 14 0; +#X connect 2 0 17 0; #X connect 3 0 1 0; -#X connect 4 0 3 0; -#X connect 5 0 7 0; -#X connect 7 0 4 1; -#X connect 7 1 8 0; -#X connect 8 0 3 1; -#X connect 10 0 1 1; -#X connect 10 1 1 2; -#X connect 10 2 1 3; -#X connect 11 0 12 0; -#X connect 12 0 17 0; -#X connect 13 0 14 1; -#X connect 14 0 6 0; -#X connect 15 0 14 0; -#X connect 15 1 16 0; -#X connect 16 0 34 0; -#X connect 17 0 13 0; -#X connect 17 0 16 1; -#X connect 18 0 10 0; +#X connect 4 0 6 0; +#X connect 6 0 3 1; +#X connect 6 1 7 0; +#X connect 9 0 1 1; +#X connect 9 1 1 2; +#X connect 9 2 1 3; +#X connect 10 0 11 0; +#X connect 11 0 16 0; +#X connect 12 0 13 1; +#X connect 13 0 5 0; +#X connect 14 0 13 0; +#X connect 14 1 15 0; +#X connect 15 0 33 0; +#X connect 16 0 12 0; +#X connect 16 0 15 1; +#X connect 17 0 9 0; +#X connect 17 1 18 0; #X connect 18 1 19 0; -#X connect 19 1 20 0; -#X connect 20 0 21 0; -#X connect 21 0 24 0; -#X connect 21 1 23 0; -#X connect 21 2 29 0; +#X connect 19 0 20 0; +#X connect 20 0 23 0; +#X connect 20 1 22 0; +#X connect 20 2 28 0; +#X connect 21 0 34 0; #X connect 22 0 35 0; -#X connect 23 0 36 0; -#X connect 24 0 22 0; -#X connect 24 1 25 0; -#X connect 25 0 26 0; -#X connect 25 1 26 1; -#X connect 26 0 30 0; -#X connect 27 0 28 0; -#X connect 27 1 28 1; -#X connect 28 0 30 1; -#X connect 29 0 22 1; -#X connect 29 1 27 0; -#X connect 30 0 31 0; -#X connect 31 0 23 1; -#X connect 32 0 34 1; -#X connect 33 0 34 2; -#X connect 34 0 40 0; +#X connect 23 0 21 0; +#X connect 23 1 24 0; +#X connect 24 0 25 0; +#X connect 24 1 25 1; +#X connect 25 0 29 0; +#X connect 26 0 27 0; +#X connect 26 1 27 1; +#X connect 27 0 29 1; +#X connect 28 0 21 1; +#X connect 28 1 26 0; +#X connect 29 0 30 0; +#X connect 30 0 22 1; +#X connect 31 0 33 1; +#X connect 32 0 33 2; +#X connect 33 0 39 0; +#X connect 34 0 31 0; #X connect 35 0 32 0; -#X connect 36 0 33 0; -#X connect 41 0 42 0; -#X connect 42 0 40 0; +#X connect 40 0 41 0; +#X connect 41 0 39 0; diff --git a/examples/struct-boid.pd b/examples/struct-boid.pd index 1f849a8..f0209d7 100644 --- a/examples/struct-boid.pd +++ b/examples/struct-boid.pd @@ -35,27 +35,27 @@ #X obj 142 256 * 180; #X obj 144 197 unpack; #X obj 70 139 list split 2; -#X obj 118 164 list split 2; #X obj 12 495 pack f f 10 0; #X obj 236 553 t f f b; #X msg 315 564 0; #X msg 320 272 0 0 10 0; #X obj 324 183 t b b b, f 8; #X obj 412 255 random 998; +#X floatatom 218 309 5 0 0 0 - - - 0; #X connect 0 0 1 0; #X connect 1 0 27 12; -#X connect 2 0 41 0; +#X connect 2 0 40 0; #X connect 3 0 0 0; #X connect 4 0 35 0; #X connect 5 0 7 0; #X connect 5 1 9 0; #X connect 6 0 10 0; #X connect 6 1 11 0; -#X connect 7 0 37 0; +#X connect 7 0 36 0; #X connect 7 1 6 0; #X connect 8 0 12 0; #X connect 8 1 13 0; -#X connect 9 0 37 1; +#X connect 9 0 36 1; #X connect 9 1 8 0; #X connect 10 0 15 0; #X connect 11 0 15 1; @@ -64,11 +64,11 @@ #X connect 14 0 16 1; #X connect 15 0 16 0; #X connect 16 0 18 0; -#X connect 17 0 38 0; +#X connect 17 0 37 0; #X connect 18 0 17 0; #X connect 18 1 19 0; #X connect 20 0 25 0; -#X connect 21 0 41 0; +#X connect 21 0 40 0; #X connect 23 0 17 1; #X connect 24 0 28 0; #X connect 25 0 26 0; @@ -77,20 +77,20 @@ #X connect 28 0 25 1; #X connect 29 0 30 0; #X connect 31 0 33 0; -#X connect 32 0 37 3; +#X connect 32 0 36 3; +#X connect 32 0 42 0; #X connect 33 0 32 0; #X connect 34 0 31 0; #X connect 34 1 31 1; #X connect 35 0 5 0; -#X connect 35 1 36 0; -#X connect 36 1 34 0; -#X connect 37 0 29 0; -#X connect 38 0 30 8; -#X connect 38 1 30 9; -#X connect 38 2 39 0; -#X connect 39 0 30 10; -#X connect 40 0 20 0; -#X connect 41 0 40 0; -#X connect 41 1 42 0; -#X connect 41 2 3 0; -#X connect 42 0 22 0; +#X connect 35 1 34 0; +#X connect 36 0 29 0; +#X connect 37 0 30 8; +#X connect 37 1 30 9; +#X connect 37 2 38 0; +#X connect 38 0 30 10; +#X connect 39 0 20 0; +#X connect 40 0 39 0; +#X connect 40 1 41 0; +#X connect 40 2 3 0; +#X connect 41 0 22 0; diff --git a/help/boids-help.pd b/help/boids-help.pd new file mode 100644 index 0000000..5451985 --- /dev/null +++ b/help/boids-help.pd @@ -0,0 +1,216 @@ +#N canvas 587 25 836 757 12; +#X floatatom 520 123 5 0 0 0 left \$0-flyrect0 - 0; +#X floatatom 562 107 5 0 0 0 top \$0-flyrect1 - 0; +#X floatatom 615 129 5 0 0 0 right \$0-flyrect2 - 0; +#X floatatom 664 147 5 0 0 0 bottom \$0-flyrect3 - 0; +#X floatatom 465 338 5 0 0 0 - - - 0; +#X floatatom 509 336 5 0 0 0 - - - 0; +#X msg 80 386 mode \$1; +#X text 145 424 reset boids randomly inside flyrect; +#X text 394 639 (c) 1995-98 Eric L. Singer (eric@ericsinger.com); +#X text 25 73 Based on Simon Fraser's implementation of Craig Reynolds' Boids algorithm. Boids is free for non-commercial use; +#X text 25 109 Boids is a bird flight and animal flock simulator. It is based on the same algorithm which was used in Jurassic Park for the herding dinosaurs.; +#X text 387 571 For more information about the Boids algorithm \, see Craig Reynolds' Web site at http://www.red3d.com/cwr/boids/; +#X text 397 617 arguments: number of boids \, output mode; +#X obj 78 536 print dump; +#X obj 19 10 cnv 15 800 48 empty empty boids 15 20 2 24 #dce0c8 #404040 0; +#X text 395 662 float/2d/3d adaptation 08/2005 by a. sier / jasch; +#N canvas 88 105 494 344 META 0; +#X text 13 182 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; +#X text 13 160 AUTHOR Eric L. Singer; +#X text 13 6 KEYWORDS control; +#X text 13 50 DESCRIPTION bird flight and animal flock simulator; +#X text 13 72 INLET_0 bang dump mode reset number neighbors maxspeed minspeed center attract match avoid repel edgedist speed inertia accel prefdist flyrect attractpt; +#X text 13 116 OUTLET_0 list; +#X text 13 138 OUTLET_1 list; +#X text 13 28 LICENSE GPL v2; +#X restore 760 21 pd META; +#X obj 494 438 s \$0-boids-params; +#X text 225 654 ..., f 4; +#X floatatom 24 677 5 0 0 0 - - - 0; +#X floatatom 62 695 5 0 0 0 - - - 0; +#X floatatom 127 675 5 0 0 0 - - - 0; +#X floatatom 164 694 5 0 0 0 - - - 0; +#X obj 79 360 hradio 18 1 0 3 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0; +#X msg 53 316 dump; +#X msg 99 422 reset; +#X obj 32 228 bng 18 250 50 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000; +#N canvas 72 225 794 467 output-mode 0; +#X floatatom 156 318 5 0 0 0 - - - 0; +#X floatatom 186 344 5 0 0 0 - - - 0; +#X floatatom 219 367 5 0 0 0 - - - 0; +#X floatatom 252 325 5 0 0 0 - - - 0; +#X floatatom 343 254 5 0 0 0 - - - 0; +#X floatatom 373 279 5 0 0 0 - - - 0; +#X floatatom 390 302 5 0 0 0 - - - 0; +#X floatatom 457 297 5 0 0 0 - - - 0; +#X floatatom 468 321 5 0 0 0 - - - 0; +#X floatatom 492 351 5 0 0 0 - - - 0; +#X obj 252 63 list length; +#X obj 183 112 list prepend; +#X obj 186 66 t a a; +#X floatatom 49 228 5 0 0 0 - - - 0; +#X floatatom 86 247 5 0 0 0 - - - 0; +#X text 371 400 (2) new and old with delta positions; +#X text 141 407 (1) new and old positions; +#X text 39 267 (0) new position only; +#X obj 186 17 inlet; +#X text 298 14 this patch shows the different output modes of the boids external.; +#X msg 393 100 mode \$1; +#X obj 393 167 s \$0-boids-params; +#X obj 392 74 hradio 18 1 0 3 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0; +#X text 391 45 output mode:; +#X text 468 100 (1) new and old positions; +#X text 468 78 (0) new position only; +#X text 470 122 (2) new and old with delta positions; +#X obj 47 203 unpack f f f; +#X floatatom 129 228 5 0 0 0 - - - 0; +#X obj 198 262 unpack f f f f f f; +#X floatatom 274 354 5 0 0 0 - - - 0; +#X floatatom 300 380 5 0 0 0 - - - 0; +#X floatatom 552 307 5 0 0 0 - - - 0; +#X floatatom 563 331 5 0 0 0 - - - 0; +#X floatatom 587 361 5 0 0 0 - - - 0; +#X obj 343 229 unpack f f f f f f f f f, f 33; +#X obj 189 141 route 3 6 9; +#X connect 10 0 11 1; +#X connect 11 0 36 0; +#X connect 12 0 11 0; +#X connect 12 1 10 0; +#X connect 18 0 12 0; +#X connect 20 0 21 0; +#X connect 22 0 20 0; +#X connect 27 0 13 0; +#X connect 27 1 14 0; +#X connect 27 2 28 0; +#X connect 29 0 0 0; +#X connect 29 1 1 0; +#X connect 29 2 2 0; +#X connect 29 3 3 0; +#X connect 29 4 30 0; +#X connect 29 5 31 0; +#X connect 35 0 4 0; +#X connect 35 1 5 0; +#X connect 35 2 6 0; +#X connect 35 3 7 0; +#X connect 35 4 8 0; +#X connect 35 5 9 0; +#X connect 35 6 32 0; +#X connect 35 7 33 0; +#X connect 35 8 34 0; +#X connect 36 0 27 0; +#X connect 36 1 29 0; +#X connect 36 2 35 0; +#X restore 251 605 pd output-mode; +#X floatatom 279 690 5 0 0 0 - - - 0; +#X floatatom 317 708 5 0 0 0 - - - 0; +#X obj 32 572 route 0 1 2 3 4 10 15, f 27; +#X text 136 361 see [pd-output-mode]; +#X obj 272 262 boids-params \$0; +#X obj 109 453 r \$0-boids-params; +#X obj 507 358 t b f; +#X text 98 308 Use the 'dump' message to output a list of the current parameter settings., f 42; +#X text 51 254 The flight parameters can be changed with messages -->, f 28; +#X text 461 253 ATTRACTION POINT; +#X text 473 75 BOUNDING BOX; +#X text 460 274 Usually \, the attraction point is what can be "moved" to cause the entire flock to follow it, f 39; +#X text 98 492 optional arguments: integer number of boids (default is 16); +#X text 165 508 next optional argument is mode (default is 0); +#X obj 32 175 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 567 503 bng 18 250 50 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000; +#X text 592 502 bang to reset to defaults; +#X obj 565 528 s \$0-reset; +#X obj 565 478 loadbang; +#X obj 24 651 unpack f f f; +#X obj 127 650 unpack f f f; +#X obj 279 664 unpack f f f; +#X floatatom 102 703 5 0 0 0 - - - 0; +#X floatatom 209 701 5 0 0 0 - - - 0; +#X floatatom 373 692 5 0 0 0 - - - 0; +#X msg 494 408 attractpt \$1 \$2 \$3; +#X text 605 342 point to which boids are attracted (x/y/z), f 21; +#X floatatom 561 338 5 0 0 0 - - - 0; +#X obj 559 360 t b f; +#X obj 495 382 pack f f f; +#N canvas 0 0 561 332 3D-bounding-box 0; +#X obj 58 181 s \$0-boids-params; +#X obj 350 78 list prepend \$0; +#X text 459 54 defaults; +#X obj 349 25 r \$0-reset; +#X obj 29 27 inlet; +#X obj 74 29 inlet; +#X obj 119 29 inlet; +#X obj 170 29 inlet; +#X obj 41 76 pack f f f f f f; +#X obj 219 30 inlet; +#X obj 270 30 inlet; +#X msg 58 156 flyrect \$1 \$2 \$3 \$4 \$5 \$6; +#X msg 350 103 \; \$1-flyrect0 \$2 \; \$1-flyrect1 \$3 \; \$1-flyrect2 \$4 \; \$1-flyrect3 \$5 \; \$1-flyrect4 \$6 \; \$1-flyrect5 \$7; +#X msg 350 53 -1 1 1 -1 1 -1; +#X connect 1 0 12 0; +#X connect 3 0 13 0; +#X connect 4 0 8 0; +#X connect 5 0 8 1; +#X connect 6 0 8 2; +#X connect 7 0 8 3; +#X connect 8 0 11 0; +#X connect 9 0 8 4; +#X connect 10 0 8 5; +#X connect 11 0 0 0; +#X connect 13 0 1 0; +#X restore 537 202 pd 3D-bounding-box; +#X f 23; +#X floatatom 740 132 5 0 0 0 front \$0-flyrect4 - 0; +#X floatatom 745 170 5 0 0 0 back \$0-flyrect5 - 0; +#X text 602 76 3D bounding cube (walls) in which to fly, f 23; +#X text 101 174 Each time Boids receives a bang \, it calculates and outputs the new positions of the boids. The output consists of the X \, Y \, Z coordiantes for each boid., f 49; +#X obj 32 493 boids; +#X floatatom 287 371 5 0 0 0 - - - 0; +#X msg 287 395 dimensions \$1; +#X obj 32 200 metro 40; +#X obj 264 549 list length; +#X floatatom 264 574 5 0 0 0 - - - 0; +#X connect 0 0 58 0; +#X connect 1 0 58 1; +#X connect 2 0 58 2; +#X connect 3 0 58 3; +#X connect 4 0 57 0; +#X connect 5 0 34 0; +#X connect 6 0 63 0; +#X connect 23 0 6 0; +#X connect 24 0 63 0; +#X connect 25 0 63 0; +#X connect 26 0 63 0; +#X connect 30 0 47 0; +#X connect 30 1 48 0; +#X connect 30 5 49 0; +#X connect 30 6 27 0; +#X connect 30 6 67 0; +#X connect 33 0 63 0; +#X connect 34 0 57 0; +#X connect 34 1 57 1; +#X connect 42 0 66 0; +#X connect 43 0 45 0; +#X connect 46 0 43 0; +#X connect 47 0 19 0; +#X connect 47 1 20 0; +#X connect 47 2 50 0; +#X connect 48 0 21 0; +#X connect 48 1 22 0; +#X connect 48 2 51 0; +#X connect 49 0 28 0; +#X connect 49 1 29 0; +#X connect 49 2 52 0; +#X connect 53 0 17 0; +#X connect 55 0 56 0; +#X connect 56 0 57 0; +#X connect 56 1 57 2; +#X connect 57 0 53 0; +#X connect 59 0 58 4; +#X connect 60 0 58 5; +#X connect 63 0 30 0; +#X connect 63 1 13 0; +#X connect 64 0 65 0; +#X connect 65 0 63 0; +#X connect 66 0 26 0; +#X connect 67 0 68 0; diff --git a/src/boid_params.c b/src/boid_params.c index 2481e6b..09d5750 100644 --- a/src/boid_params.c +++ b/src/boid_params.c @@ -38,6 +38,7 @@ t_boid_params *boid_params_new() /* autofill these */ x->x_pref_dist_sqr = x->x_pref_dist * x->x_pref_dist; x->x_factor_accel_inv = 1.0 / (x->x_factor_accel + 1e-13); + x->x_factor_inertia_inv = 1.0 / (x->x_factor_inertia + 1e-13); return x; } diff --git a/src/boid_params.h b/src/boid_params.h index 1fc3d9d..fd4b083 100644 --- a/src/boid_params.h +++ b/src/boid_params.h @@ -43,6 +43,7 @@ typedef struct _boid_params /* autofill these */ t_float x_factor_accel_inv; t_float x_pref_dist_sqr; + t_float x_factor_inertia_inv; } t_boid_params; /* initialize the params object with default values */ diff --git a/src/boids.c b/src/boids.c index 7434db8..a347300 100644 --- a/src/boids.c +++ b/src/boids.c @@ -52,6 +52,18 @@ static t_class *boids3d_class, *boids2d_class, *boids_class; /* ---------------------------- helper functions ---------------------------- */ +static t_float apply_weighted_force(t_boid_params *params, t_points *points, + size_t dimension) +{ + t_float f = + (params->x_weight_center * points->goCenterVel->x_new[dimension] + + params->x_weight_attract * points->goAttractVel->x_new[dimension] + + params->x_weight_match * points->matchNeighborVel->x_new[dimension] + + params->x_weight_avoid * points->avoidNeighborVel->x_new[dimension] + + params->x_weight_walls * points->avoidWallsVel->x_new[dimension]); + return f * params->x_factor_inertia_inv; +} + /* * calculate the velocity of a point with the weights and inertia factor * (boid parameters) and the temporary points structure @@ -59,14 +71,8 @@ static t_class *boids3d_class, *boids2d_class, *boids_class; void point_velocity(t_point *x, t_boid_params *params, t_points *points) { for (size_t i = 0; i < x->x_dimensions; i++) - x->x_new[i] = - params->x_factor_inertia * x->x_old[i] + - (params->x_weight_center * points->goCenterVel->x_new[i] + - params->x_weight_attract * points->goAttractVel->x_new[i] + - params->x_weight_match * points->matchNeighborVel->x_new[i] + - params->x_weight_avoid * points->avoidNeighborVel->x_new[i] + - params->x_weight_walls * points->avoidWallsVel->x_new[i]) / - params->x_factor_inertia; + x->x_new[i] = params->x_factor_inertia * x->x_old[i] + + apply_weighted_force(params, points, i); } /* compute a target position from the norm dif between seek point and boid */ @@ -102,7 +108,7 @@ static void boid_compute_neighbor_distances(t_boid *x) for (size_t i = 0; i < num_boids; ++i) { t_boid *candidate = &flock->x_boid[i]; - t_float distance; + t_float distance = 0.0; if (candidate == x) continue; @@ -117,7 +123,10 @@ static void boid_compute_neighbor_distances(t_boid *x) while ((j > 0) && (distance < x->x_neighbors[j - 1].x_distance)) { - x->x_neighbors[j] = x->x_neighbors[j - 1]; + x->x_neighbors[j].x_boid = x->x_neighbors[j - 1].x_boid; + + x->x_neighbors[j].x_distance = x->x_neighbors[j - 1].x_distance; + --j; } @@ -148,8 +157,6 @@ static t_float boid_match_and_avoid_neighbors(t_boid *x, t_float inv_factor_accel = x->x_flock->x_params->x_factor_accel_inv; t_float avoid_speed = x->x_speed; - point_fill(matchNeighborVel, 0.0); - for (t_neighbor *neighbor = x->x_neighbors; neighbor; neighbor = neighbor->x_next) { @@ -218,23 +225,20 @@ static void boid_avoid_walls(t_boid *x, t_point *target, t_float distance_edge) point_free(test_pt); } -static void boids_find_center(t_boids *x) +static void boids_step(t_boids *x) { - t_float inv_num_boids = x->x_num_boids ? 1.0 / x->x_num_boids : 1.0; - - for (size_t i = 0; i < x->x_num_boids; i++) - point_add(x->x_position_center, &x->x_boid[i].x_position); + if (x->x_num_boids == 0) + return; - point_normalize(x->x_position_center, inv_num_boids); -} + t_float avoid_speed = 0.0; -static void boids_step(t_boids *x) -{ - t_points *points = points_new(x->x_dimensions); + /* find the center of mass of the flock */ + point_fill(&x->x_position_center, 0.0); - t_float avoid_speed; + for (size_t i = 0; i < x->x_num_boids; i++) + point_add(&x->x_position_center, &x->x_boid[i].x_position); - boids_find_center(x); + point_normalize(&x->x_position_center, (t_float)x->x_num_boids); // save position and velocity for (size_t i = 0; i < x->x_num_boids; i++) @@ -248,28 +252,27 @@ static void boids_step(t_boids *x) /**********************/ for (size_t i = 0; i < x->x_num_boids; i++) { + point_fill(x->x_points->matchNeighborVel, 0.0); + point_fill(x->x_points->avoidNeighborVel, 0.0); + avoid_speed = 0; + // get all velocity components if (x->x_max_neighbors > 0) { boid_compute_neighbor_distances(&x->x_boid[i]); avoid_speed = boid_match_and_avoid_neighbors( - &x->x_boid[i], points->matchNeighborVel, - points->avoidNeighborVel); + &x->x_boid[i], x->x_points->matchNeighborVel, + x->x_points->avoidNeighborVel); } - else - { - point_fill(points->matchNeighborVel, 0.0); - point_fill(points->avoidNeighborVel, 0.0); - avoid_speed = 0; - } - boid_point_seek(&x->x_boid[i], x->x_position_center, - points->goCenterVel); - boid_point_seek(&x->x_boid[i], x->x_position_attract, - points->goAttractVel); - boid_avoid_walls(&x->x_boid[i], points->avoidWallsVel, + + boid_point_seek(&x->x_boid[i], &x->x_position_center, + x->x_points->goCenterVel); + boid_point_seek(&x->x_boid[i], &x->x_position_attract, + x->x_points->goAttractVel); + boid_avoid_walls(&x->x_boid[i], x->x_points->avoidWallsVel, x->x_params->x_distance_edge); // compute resultant velocity using weights and inertia - point_velocity(&x->x_boid[i].x_direction, x->x_params, points); + point_velocity(&x->x_boid[i].x_direction, x->x_params, x->x_points); // normalize velocity so its length is unity point_norm_square(&x->x_boid[i].x_direction); @@ -425,6 +428,33 @@ static void outlet_all(t_boids *x) } } +static void outlet_posvel(t_boids *x) +{ + size_t argc = 1 + (2 * x->x_dimensions); + t_atom *argv = (t_atom *)getbytes(sizeof(*argv) * argc); + + if (!argv) + return; + + for (size_t i = 0; i < x->x_num_boids; ++i) + { + SETFLOAT(argv + 0, (t_float)i); + + /* new position */ + for (size_t d = 0; d < x->x_dimensions; ++d) + SETFLOAT(argv + 1 + d, x->x_boid[i].x_position.x_new[d]); + + /* new direction */ + for (size_t d = 0; d < x->x_dimensions; ++d) + SETFLOAT(argv + 1 + x->x_dimensions + d, + x->x_boid[i].x_direction.x_new[d]); + + outlet_list(x->x_out1, gensym("list"), (int)argc, argv); + } + + freebytes(argv, sizeof(*argv) * argc); +} + /* ---------------------------- boids methods ------------------------------- */ static void boids_bang(t_boids *x) @@ -445,6 +475,10 @@ static void boids_bang(t_boids *x) case BOID_ALL: outlet_all(x); break; + + case BOID_POSVEL: + outlet_posvel(x); + break; } } @@ -466,12 +500,12 @@ static void boids_dump(t_boids *x) /* outlet all attract position */ for (size_t i = 0; i < x->x_dimensions; i++) - SETFLOAT(argv + i, x->x_position_attract->x_new[i]); + SETFLOAT(argv + i, x->x_position_attract.x_new[i]); outlet_anything(x->x_out2, gensym("attractpt"), x->x_dimensions, argv); /* outlet all center position */ for (size_t i = 0; i < x->x_dimensions; i++) - SETFLOAT(argv + i, x->x_position_center->x_new[i]); + SETFLOAT(argv + i, x->x_position_center.x_new[i]); outlet_anything(x->x_out2, gensym("centerpt"), x->x_dimensions, argv); SETFLOAT(argv, x->x_mode); @@ -480,13 +514,18 @@ static void boids_dump(t_boids *x) SETFLOAT(argv, x->x_num_boids); outlet_anything(x->x_out2, gensym("number"), 1, argv); + SETFLOAT(argv, x->x_dimensions); + outlet_anything(x->x_out2, gensym("dimensions"), 1, argv); + /* release the argv atom */ freebytes(argv, nbytes); } static void boids_num_neighbors(t_boids *x, t_floatarg f) { - x->x_max_neighbors = kMaxNeighbors < (size_t)f ? kMaxNeighbors : (size_t)f; + x->x_max_neighbors = f < 0.0 ? 1 + : (size_t)f > x->x_num_boids ? x->x_num_boids + : (size_t)f; } static void boids_minSpeed(t_boids *x, t_floatarg f) @@ -552,11 +591,17 @@ static void boids_prefDist(t_boids *x, t_floatarg f) static void boids_bounds(t_boids *x, t_symbol *s, int argc, t_atom *argv) { (void)s; - t_float *bounds_ptr = x->x_bounds; - while (argc) + + size_t nbounds = 2 * x->x_dimensions; + + for (size_t i = 0; i < nbounds && i < (size_t)argc; ++i) + x->x_bounds[i] = atom_getfloat(argv + i); + + if ((size_t)argc > nbounds) { - *bounds_ptr++ = atom_getfloat(argv++); - argc--; + startpost("Ignoring extra args"); + postatom(argc - nbounds, argv + nbounds); + endpost(); } } @@ -564,7 +609,7 @@ static void boids_position_attract(t_boids *x, t_symbol *s, int argc, t_atom *argv) { (void)s; - point_update(x->x_position_attract, argc, argv); + point_update(&x->x_position_attract, argc, argv); } /* -------------------------- memory management ----------------------------- */ @@ -595,8 +640,8 @@ static void boid_free(t_boids *x) boid->x_neighbors = NULL; } - point_free(&boid->x_position); - point_free(&boid->x_direction); + point_clear(&boid->x_position); + point_clear(&boid->x_direction); boid->x_next = NULL; boid->x_flock = NULL; @@ -614,11 +659,10 @@ static void boids_free(t_boids *x) boid_free(x); /* deallocate previous bounds if present */ boids_bounds_free(x); - /* deallocate previous center and attract positions if present */ - point_free(x->x_position_attract); - point_free(x->x_position_center); /* deallocate the parameters */ boid_params_free(x->x_params); + /* deallocate the computation points */ + points_free(x->x_points); } /* ---------------------------- initialization ------------------------------ */ @@ -629,42 +673,49 @@ static void boids_reset(t_boids *x) { t_boid *boid = &x->x_boid[i]; - point_rand_from_range(&boid->x_position, &x->x_bounds[i * 2]); + point_rand_from_range(&boid->x_position, x->x_bounds); point_rand_from_angle(&boid->x_direction); boid->x_speed = (x->x_params->x_speed_max + x->x_params->x_speed_min) * 0.5; } } -static t_boid *boid_list_new(size_t num_boids) +static t_boid *boid_list_new(size_t num_boids, t_boids *flock) { if (!num_boids) return NULL; - t_boid *x = (t_boid *)getbytes(num_boids * sizeof(*x)); - if (!x) + t_boid *boid_list = (t_boid *)getbytes(num_boids * sizeof(t_boid)); + if (!boid_list) return NULL; for (size_t i = 0; i < num_boids; i++) { - x[i].x_flock = NULL; + t_boid *b = &boid_list[i]; + b->x_flock = flock; + point_alloc(&b->x_position, flock->x_dimensions); + point_alloc(&b->x_direction, flock->x_dimensions); + b->x_speed = 0.0; - x[i].x_next = (i + 1 < num_boids) ? &x[i + 1] : NULL; + b->x_next = (i + 1 < num_boids) ? &boid_list[i + 1] : NULL; - x[i].x_neighbors = NULL; + b->x_neighbors = NULL; if (num_boids > 1) { - x[i].x_neighbors = (t_neighbor *)getbytes( - (num_boids - 1) * sizeof(*x[i].x_neighbors)); + b->x_neighbors = + (t_neighbor *)getbytes((num_boids - 1) * sizeof(t_neighbor)); for (size_t j = 0; j + 1 < num_boids - 1; j++) - x[i].x_neighbors[j].x_next = &x[i].x_neighbors[j + 1]; + { + b->x_neighbors[j].x_next = &b->x_neighbors[j + 1]; + b->x_neighbors[j].x_distance = 0.0; + } - x[i].x_neighbors[num_boids - 2].x_next = NULL; + b->x_neighbors[num_boids - 2].x_next = NULL; } } - return x; + return boid_list; } /* resize bounds and allocate */ @@ -673,10 +724,10 @@ static void boids_bounds_alloc(t_boids *x) size_t nbounds = 2 * x->x_dimensions; x->x_bounds = (t_float *)getbytes(sizeof(t_float) * nbounds); /* initialize bounds */ - for (size_t i = 0; i < nbounds; i += 2) + for (size_t i = 0; i < x->x_dimensions; i++) { - x->x_bounds[i] = -1.0; // nth dimension left side - x->x_bounds[i + 1] = 1.0; // nth dimension right side + x->x_bounds[i * 2] = -1.0; // nth dimension left side + x->x_bounds[i * 2 + 1] = 1.0; // nth dimension right side } } @@ -684,17 +735,21 @@ static void boids_init(t_boids *x, size_t dimensions, size_t num_boids) { boids_free(x); + /* define dimensions */ + x->x_dimensions = dimensions; + /* resize boids and allocate the list of boids */ x->x_num_boids = num_boids; - x->x_boid = boid_list_new(num_boids); - - /* define dimensions and allocate center and atract positions */ - x->x_dimensions = dimensions; - x->x_position_attract = point_new(dimensions); - x->x_position_center = point_new(dimensions); + boids_num_neighbors(x, 4.0); + x->x_boid = boid_list_new(num_boids, x); /* allocate the boundaries (depends on dimensions) */ boids_bounds_alloc(x); + /* and allocate center and atract positions */ + point_alloc(&x->x_position_center, dimensions); + point_alloc(&x->x_position_attract, dimensions); + /* and allocate the calculation points */ + x->x_points = points_new(dimensions); /* initialize the parameters */ x->x_params = boid_params_new(); @@ -707,7 +762,7 @@ static void boids_dimensions(t_boids *x, t_floatarg fdimen) size_t d = max_dimensions((size_t)fdimen); if (x->x_dimensions == d) return; - boids_init(x, d, x->x_max_neighbors); + boids_init(x, d, x->x_num_boids); } static void boids_float(t_boids *x, t_floatarg fnum_boids) @@ -721,7 +776,9 @@ static void boids_float(t_boids *x, t_floatarg fnum_boids) static void boids_mode(t_boids *x, t_floatarg f) { const int m = (int)f; - x->x_mode = m < BOID_NEWPOS ? BOID_NEWPOS : BOID_ALL < m ? BOID_ALL : m; + x->x_mode = m < BOID_NEWPOS ? BOID_NEWPOS + : BOID_POSVEL < m ? BOID_POSVEL + : m; } /* ----------------------- pd objects general initialization ---------------- */ diff --git a/src/boids.h b/src/boids.h index e6b01bf..4ecd612 100644 --- a/src/boids.h +++ b/src/boids.h @@ -27,18 +27,19 @@ // constants #define kMaxLong 0xFFFFFFFF -#define kMaxNeighbors 16 enum boid_output_mode { BOID_NEWPOS = 0, BOID_NEWOLD, - BOID_ALL + BOID_ALL, + BOID_POSVEL }; typedef struct _neighbor t_neighbor; typedef struct _boid t_boid; typedef struct _boids t_boids; +typedef struct _points t_points; typedef struct _neighbor { @@ -65,16 +66,19 @@ typedef struct _boids t_outlet *x_out2; /* temporary storage */ - t_boid *x_boid; // the list of boids belonging to this parent "flock" - t_point *x_position_center; // center position for this "flock" - t_point *x_position_attract; // attraction point for this "flock" - t_float *x_bounds; // boundaries in which the boids move - t_boid_params *x_params; // parameters of this "flock" - - /* general object settings */ - size_t x_dimensions; // number of spatial dimensions - size_t x_num_boids; // total number of boids - size_t x_max_neighbors; // max number of neighbors to look for + t_boid *x_boid; // the list of boids belonging to this parent "flock" + t_float *x_bounds; // boundaries in which the boids move + t_boid_params *x_params; // parameters of this "flock" + + /* a set of points to use when calculating direction and velocity */ + t_points *x_points; + + /* general flock settings */ + t_point x_position_center; // center position for this "flock" + t_point x_position_attract; // attraction point for this "flock" + size_t x_dimensions; // number of spatial dimensions + size_t x_num_boids; // total number of boids + size_t x_max_neighbors; // max number of neighbors to look for enum boid_output_mode x_mode; } t_boids; diff --git a/src/point.c b/src/point.c index 4af4a81..1186181 100644 --- a/src/point.c +++ b/src/point.c @@ -41,8 +41,18 @@ t_float random_integer(t_float minRange, t_float maxRange) void point_fill(t_point *x, t_float c) { - memset(x->x_new, c, sizeof(t_float) * x->x_dimensions); - memset(x->x_old, c, sizeof(t_float) * x->x_dimensions); + if (c == 0.0) + { + memset(x->x_new, 0, x->x_dimensions); + memset(x->x_old, 0, x->x_dimensions); + return; + } + + for (size_t i = 0; i < x->x_dimensions; i++) + { + x->x_new[i] = c; + x->x_old[i] = c; + } } void point_init(t_point *x, size_t dimensions) @@ -57,7 +67,8 @@ void point_rand_from_range(t_point *x, t_float *range) { for (size_t i = 0; i < x->x_dimensions; i++) { - x->x_new[i] = x->x_old[i] = random_integer(range[0], range[1]); + x->x_new[i] = x->x_old[i] = + random_integer(range[i * 2], range[i * 2 + 1]); } } @@ -114,21 +125,46 @@ void point_rand_from_angle(t_point *x) } } +void point_clear(t_point *x) +{ + if (!x) + return; + + if (x->x_old) + freebytes(x->x_old, sizeof(*x->x_old) * x->x_dimensions); + + if (x->x_new) + freebytes(x->x_new, sizeof(*x->x_new) * x->x_dimensions); + + x->x_old = NULL; + x->x_new = NULL; + x->x_dimensions = 0; +} + void point_free(t_point *x) { if (!x) return; - freebytes(x, sizeof(t_point)); - x = NULL; + + point_clear(x); + freebytes(x, sizeof(*x)); } -t_point *point_new(size_t dimensions) +void point_alloc(t_point *x, size_t dimensions) { - t_point *x = (t_point *)getbytes(sizeof(t_point)); size_t d = max_dimensions(dimensions); + + x->x_dimensions = d; x->x_new = (t_float *)getbytes(sizeof(t_float) * d); x->x_old = (t_float *)getbytes(sizeof(t_float) * d); - point_init(x, d); + + point_fill(x, 0.0); +} + +t_point *point_new(size_t dimensions) +{ + t_point *x = (t_point *)getbytes(sizeof(t_point)); + point_alloc(x, dimensions); return x; } @@ -158,9 +194,14 @@ void point_step(t_point *x) /* normalize a point to a given max value */ void point_normalize(t_point *p, t_float fmax) { - t_float inv_max = 1.0 / (fmax + 1e-13); + t_float inv_max = 1.0; + if (fmax) + inv_max = 1.0 / fmax; for (size_t i = 0; i < p->x_dimensions; i++) + { p->x_new[i] *= inv_max; + p->x_old[i] *= inv_max; + } } /* normalize a point in all dimensions with their distance */ @@ -189,14 +230,17 @@ void point_square_distance(t_point *a, t_point *b, t_float *distance) } } -/* update a point new by adding another point old */ +/* update a point by adding another point to it */ void point_add(t_point *a, t_point *b) { if (a->x_dimensions != b->x_dimensions) return; for (size_t i = 0; i < a->x_dimensions; i++) - a->x_new[i] += b->x_old[i]; + { + a->x_new[i] += b->x_new[i]; + a->x_old[i] += b->x_old[i]; + } } /* compute the difference between two points' old dimensions */ diff --git a/src/point.h b/src/point.h index 888d8f5..2176e0e 100644 --- a/src/point.h +++ b/src/point.h @@ -40,7 +40,9 @@ typedef struct _point t_point *point_new(size_t dimensions); t_point *point_diff(t_point *a, t_point *b); +void point_alloc(t_point *x, size_t dimensions); void point_fill(t_point *x, t_float c); +void point_clear(t_point *x); void point_free(t_point *x); void point_init(t_point *x, size_t dimensions); void point_normalize(t_point *p, t_float fmax); From 73b4a84b2a2f3a96e77ce60eb490600b8cdbd688 Mon Sep 17 00:00:00 2001 From: fdch Date: Sun, 26 Apr 2026 20:19:13 +0200 Subject: [PATCH 10/19] small fixes --- src/boids.c | 13 +++++++++++-- src/point.c | 15 +++++++-------- src/point.h | 2 +- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/boids.c b/src/boids.c index a347300..74dae29 100644 --- a/src/boids.c +++ b/src/boids.c @@ -24,6 +24,15 @@ /* --------------------------- points structure ----------------------------- */ +void points_clear(t_points *x) +{ + point_fill(x->avoidNeighborVel, 0.0); + point_fill(x->avoidWallsVel, 0.0); + point_fill(x->goAttractVel, 0.0); + point_fill(x->goCenterVel, 0.0); + point_fill(x->matchNeighborVel, 0.0); +} + t_points *points_new(size_t dimensions) { t_points *points = (t_points *)getbytes(sizeof(t_points)); @@ -183,6 +192,7 @@ static t_float boid_match_and_avoid_neighbors(t_boid *x, /* use self - other for an "away from neighbor" vector */ t_point *d = point_diff(&x->x_position, &other->x_position); point_update_velocity(d, avoidNeighborVel, fstep); + point_free(d); num_close++; @@ -252,8 +262,7 @@ static void boids_step(t_boids *x) /**********************/ for (size_t i = 0; i < x->x_num_boids; i++) { - point_fill(x->x_points->matchNeighborVel, 0.0); - point_fill(x->x_points->avoidNeighborVel, 0.0); + points_clear(x->x_points); avoid_speed = 0; // get all velocity components diff --git a/src/point.c b/src/point.c index 1186181..e9bea10 100644 --- a/src/point.c +++ b/src/point.c @@ -18,7 +18,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "point.h" -#include "boid_params.h" #include "m_pd.h" #include #include @@ -31,9 +30,9 @@ size_t max_dimensions(size_t dimensions) return dimensions < 1 ? 1 : dimensions > 64 ? 64 : dimensions; } -t_float random_integer(t_float minRange, t_float maxRange) +t_float random_float_range(t_float minRange, t_float maxRange) { - t_float x = (t_float)rand() / (t_float)RAND_MAX + 1.0; + t_float x = (t_float)rand() / RAND_MAX; return x * (maxRange - minRange) + minRange; } @@ -43,8 +42,8 @@ void point_fill(t_point *x, t_float c) { if (c == 0.0) { - memset(x->x_new, 0, x->x_dimensions); - memset(x->x_old, 0, x->x_dimensions); + memset(x->x_new, 0, x->x_dimensions * sizeof(t_float)); + memset(x->x_old, 0, x->x_dimensions * sizeof(t_float)); return; } @@ -68,7 +67,7 @@ void point_rand_from_range(t_point *x, t_float *range) for (size_t i = 0; i < x->x_dimensions; i++) { x->x_new[i] = x->x_old[i] = - random_integer(range[i * 2], range[i * 2 + 1]); + random_float_range(range[i * 2], range[i * 2 + 1]); } } @@ -78,7 +77,7 @@ void point_rand_from_angle(t_point *x) if (!x->x_dimensions) return; - t_float rad_angle = random_integer(0, 360) * D2R; + t_float rad_angle = random_float_range(0, 360) * D2R; if (x->x_dimensions == 1) { @@ -104,7 +103,7 @@ void point_rand_from_angle(t_point *x) for (size_t i = 0; i < x->x_dimensions; ++i) { - x->x_new[i] = random_integer(-12345, 54321) * rad_angle; + x->x_new[i] = random_float_range(-12345, 54321) * rad_angle; len2 += x->x_new[i] * x->x_new[i]; } diff --git a/src/point.h b/src/point.h index 2176e0e..847eb61 100644 --- a/src/point.h +++ b/src/point.h @@ -28,7 +28,7 @@ #define R2D (180.0 / BOIDS_PI) size_t max_dimensions(size_t dimensions); -t_float random_integer(t_float minRange, t_float maxRange); +t_float random_float_range(t_float minRange, t_float maxRange); /* a point structure in n-dimensional space */ typedef struct _point From 70d9c63dd886f571109ff43f420db4d36d9ed199 Mon Sep 17 00:00:00 2001 From: fdch Date: Wed, 13 May 2026 16:22:45 +0200 Subject: [PATCH 11/19] use vec instead of point --- src/point.c | 281 --------------------------------------------- src/point.h | 59 ---------- src/vec.c | 325 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/vec.h | 77 +++++++++++++ 4 files changed, 402 insertions(+), 340 deletions(-) delete mode 100644 src/point.c delete mode 100644 src/point.h create mode 100644 src/vec.c create mode 100644 src/vec.h diff --git a/src/point.c b/src/point.c deleted file mode 100644 index e9bea10..0000000 --- a/src/point.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - boids3d 2005 - 2006 a.sier / jasch - adapted from boids by eric singer © 1995-2003 eric l. singer - updated by fdch 2026 - - 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 "point.h" -#include "m_pd.h" -#include -#include -#include - -/* ---------------------------- helper clipper ----------------------------- */ - -size_t max_dimensions(size_t dimensions) -{ - return dimensions < 1 ? 1 : dimensions > 64 ? 64 : dimensions; -} - -t_float random_float_range(t_float minRange, t_float maxRange) -{ - t_float x = (t_float)rand() / RAND_MAX; - return x * (maxRange - minRange) + minRange; -} - -/* ---------------------------- point structure ----------------------------- */ - -void point_fill(t_point *x, t_float c) -{ - if (c == 0.0) - { - memset(x->x_new, 0, x->x_dimensions * sizeof(t_float)); - memset(x->x_old, 0, x->x_dimensions * sizeof(t_float)); - return; - } - - for (size_t i = 0; i < x->x_dimensions; i++) - { - x->x_new[i] = c; - x->x_old[i] = c; - } -} - -void point_init(t_point *x, size_t dimensions) -{ - if (x->x_dimensions == dimensions) - return; - x->x_dimensions = dimensions; - point_fill(x, 0.0); -} - -void point_rand_from_range(t_point *x, t_float *range) -{ - for (size_t i = 0; i < x->x_dimensions; i++) - { - x->x_new[i] = x->x_old[i] = - random_float_range(range[i * 2], range[i * 2 + 1]); - } -} - -void point_rand_from_angle(t_point *x) -{ - - if (!x->x_dimensions) - return; - - t_float rad_angle = random_float_range(0, 360) * D2R; - - if (x->x_dimensions == 1) - { - x->x_new[0] = cos(rad_angle); - return; - } - if (x->x_dimensions == 2) - { - x->x_new[0] = sin(rad_angle); - x->x_new[1] = cos(rad_angle); - return; - } - if (x->x_dimensions == 3) - { - x->x_new[0] = sin(rad_angle); - x->x_new[1] = cos(rad_angle); - x->x_new[2] = (x->x_new[0] + x->x_new[1]) * 0.5; - return; - } - - /* if we venture into this space, here's a random approach */ - t_float len2 = 0.0; - - for (size_t i = 0; i < x->x_dimensions; ++i) - { - x->x_new[i] = random_float_range(-12345, 54321) * rad_angle; - len2 += x->x_new[i] * x->x_new[i]; - } - - t_float len = sqrt(len2); - - if (len == 0.0) - { - x->x_new[0] = 1.0; - for (size_t i = 1; i < x->x_dimensions; ++i) - x->x_new[i] = 0.0; - return; - } - t_float inv_len = 1.0 / len; - - for (size_t i = 0; i < x->x_dimensions; ++i) - { - x->x_new[i] *= inv_len; - } -} - -void point_clear(t_point *x) -{ - if (!x) - return; - - if (x->x_old) - freebytes(x->x_old, sizeof(*x->x_old) * x->x_dimensions); - - if (x->x_new) - freebytes(x->x_new, sizeof(*x->x_new) * x->x_dimensions); - - x->x_old = NULL; - x->x_new = NULL; - x->x_dimensions = 0; -} - -void point_free(t_point *x) -{ - if (!x) - return; - - point_clear(x); - freebytes(x, sizeof(*x)); -} - -void point_alloc(t_point *x, size_t dimensions) -{ - size_t d = max_dimensions(dimensions); - - x->x_dimensions = d; - x->x_new = (t_float *)getbytes(sizeof(t_float) * d); - x->x_old = (t_float *)getbytes(sizeof(t_float) * d); - - point_fill(x, 0.0); -} - -t_point *point_new(size_t dimensions) -{ - t_point *x = (t_point *)getbytes(sizeof(t_point)); - point_alloc(x, dimensions); - return x; -} - -/* update a point in all dimensions and advance old<-new */ -void point_update(t_point *x, int argc, t_atom *argv) -{ - if (!argc || argc != (int)x->x_dimensions) - return; - - t_float *old_ptr = x->x_old; - t_float *new_ptr = x->x_new; - while (argc) - { - *old_ptr++ = *new_ptr; - *new_ptr = atom_getfloat(argv++); - argc--, new_ptr++; - } -} - -/* advance a point in all dimensions old<-new (no update) */ -void point_step(t_point *x) -{ - for (size_t i = 0; i < x->x_dimensions; i++) - x->x_old[i] = x->x_new[i]; -} - -/* normalize a point to a given max value */ -void point_normalize(t_point *p, t_float fmax) -{ - t_float inv_max = 1.0; - if (fmax) - inv_max = 1.0 / fmax; - for (size_t i = 0; i < p->x_dimensions; i++) - { - p->x_new[i] *= inv_max; - p->x_old[i] *= inv_max; - } -} - -/* normalize a point in all dimensions with their distance */ -void point_norm_square(t_point *p) -{ - t_float h = 0.0, x = 0.0; - - for (size_t i = 0; i < p->x_dimensions; i++) - x += (p->x_new[i] * p->x_new[i]); - - h = sqrt(x); - - if (h == 0.0) - return; - - point_normalize(p, h); -} - -/* compute the square distance between two points */ -void point_square_distance(t_point *a, t_point *b, t_float *distance) -{ - for (size_t i = 0; i < a->x_dimensions; i++) - { - t_float d = a->x_new[i] - b->x_new[i]; - *distance += (d * d); - } -} - -/* update a point by adding another point to it */ -void point_add(t_point *a, t_point *b) -{ - if (a->x_dimensions != b->x_dimensions) - return; - - for (size_t i = 0; i < a->x_dimensions; i++) - { - a->x_new[i] += b->x_new[i]; - a->x_old[i] += b->x_old[i]; - } -} - -/* compute the difference between two points' old dimensions */ -t_point *point_diff(t_point *a, t_point *b) -{ - t_point *c = point_new(a->x_dimensions); - - if (a->x_dimensions != b->x_dimensions) - return c; - - for (size_t i = 0; i < a->x_dimensions; i++) - c->x_new[i] = a->x_old[i] - b->x_old[i]; - - return c; -} - -void point_update_velocity(t_point *diff, t_point *velocity, t_float fstep) -{ - - if (diff->x_dimensions != velocity->x_dimensions) - return; - - for (size_t i = 0; i < diff->x_dimensions; i++) - velocity->x_new[i] -= diff->x_new[i] - diff->x_new[i] * fstep; -} - -t_float point_infront_dot_old(t_point *a_pos, t_point *b_pos, t_point *a_dir) -{ - t_float dot = 0.0; - size_t n = a_pos->x_dimensions; - - for (size_t i = 0; i < n; i++) - { - t_float rel = b_pos->x_old[i] - a_pos->x_old[i]; - t_float dir = a_dir->x_old[i]; - dot += rel * dir; - } - return dot; -} diff --git a/src/point.h b/src/point.h deleted file mode 100644 index 847eb61..0000000 --- a/src/point.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - boids3d 2005 - 2006 a.sier / jasch - adapted from boids by eric singer © 1995-2003 eric l. singer - updated by fdch 2026 - - 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 -*/ -#ifndef POINT_H -#define POINT_H - -#include "m_pd.h" - -#define BOIDS_PI \ - 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068 -#define D2R (BOIDS_PI / 180.0) -#define R2D (180.0 / BOIDS_PI) - -size_t max_dimensions(size_t dimensions); -t_float random_float_range(t_float minRange, t_float maxRange); - -/* a point structure in n-dimensional space */ -typedef struct _point -{ - size_t x_dimensions; // the number of dimensions (i.e., data points) - t_float *x_old; // the previous data of this point - t_float *x_new; // the current data of this point -} t_point; - -t_point *point_new(size_t dimensions); -t_point *point_diff(t_point *a, t_point *b); -void point_alloc(t_point *x, size_t dimensions); -void point_fill(t_point *x, t_float c); -void point_clear(t_point *x); -void point_free(t_point *x); -void point_init(t_point *x, size_t dimensions); -void point_normalize(t_point *p, t_float fmax); -void point_norm_square(t_point *p); -void point_square_distance(t_point *a, t_point *b, t_float *distance); -void point_step(t_point *x); -void point_update(t_point *x, int argc, t_atom *argv); -void point_rand_from_range(t_point *x, t_float *range); -void point_rand_from_angle(t_point *x); -void point_add(t_point *a, t_point *b); -void point_update_velocity(t_point *distance, t_point *velocity, t_float fstep); -t_float point_infront_dot_old(t_point *a_pos, t_point *b_pos, t_point *a_dir); - -#endif diff --git a/src/vec.c b/src/vec.c new file mode 100644 index 0000000..afd268a --- /dev/null +++ b/src/vec.c @@ -0,0 +1,325 @@ +/* + boids3d 2005 - 2006 a.sier / jasch + adapted from boids by eric singer © 1995-2003 eric l. singer + updated by fdch 2026 + + 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. +*/ +#include "vec.h" +#include "m_pd.h" +#include +#include +#include + +#define BOIDS_EPS ((t_float)1e-12) + +size_t vec_dimensions_clamp(size_t dimensions) +{ + return dimensions < 1 ? 1 : dimensions > 64 ? 64 : dimensions; +} + +t_float random_float_range(t_float min, t_float max) +{ + if (max < min) + { + t_float tmp = min; + min = max; + max = tmp; + } + + t_float u = (t_float)rand() / (t_float)RAND_MAX; + return min + u * (max - min); +} + +void vec_alloc(t_vec *x, size_t dimensions) +{ + if (!x) + return; + + size_t d = vec_dimensions_clamp(dimensions); + x->x_dimensions = d; + x->x = (t_float *)getbytes(sizeof(*x->x) * d); + vec_fill(x, 0.0); +} + +t_vec *vec_new(size_t dimensions) +{ + t_vec *x = (t_vec *)getbytes(sizeof(*x)); + if (!x) + return NULL; + + vec_alloc(x, dimensions); + return x; +} + +void vec_clear(t_vec *x) +{ + if (!x) + return; + + if (x->x) + freebytes(x->x, sizeof(*x->x) * x->x_dimensions); + + x->x = NULL; + x->x_dimensions = 0; +} + +void vec_free(t_vec *x) +{ + if (!x) + return; + + vec_clear(x); + freebytes(x, sizeof(*x)); +} + +void vec_fill(t_vec *x, t_float c) +{ + if (!x || !x->x) + return; + + if (c == 0.0) + { + memset(x->x, 0, sizeof(*x->x) * x->x_dimensions); + return; + } + + for (size_t i = 0; i < x->x_dimensions; ++i) + x->x[i] = c; +} + +void vec_copy(t_vec *dst, const t_vec *src) +{ + if (!dst || !src || dst->x_dimensions != src->x_dimensions) + return; + + memcpy(dst->x, src->x, sizeof(*dst->x) * dst->x_dimensions); +} + +void vec_update(t_vec *x, int argc, t_atom *argv) +{ + if (!x || !argv || argc != (int)x->x_dimensions) + return; + + for (int i = 0; i < argc; ++i) + x->x[i] = atom_getfloat(argv + i); +} + +void vec_random_range(t_vec *x, const t_float *range) +{ + if (!x || !range) + return; + + for (size_t i = 0; i < x->x_dimensions; ++i) + x->x[i] = random_float_range(range[i * 2], range[i * 2 + 1]); +} + +void vec_random_unit(t_vec *x) +{ + if (!x || !x->x_dimensions) + return; + + if (x->x_dimensions == 1) + { + x->x[0] = rand() & 1 ? 1.0 : -1.0; + return; + } + + if (x->x_dimensions == 2) + { + t_float angle = random_float_range(0.0, 360.0) * D2R; + x->x[0] = cos(angle); + x->x[1] = sin(angle); + return; + } + + /* Random point in a hypercube, normalized. Retry to avoid a zero vector. + */ + for (int tries = 0; tries < 8; ++tries) + { + for (size_t i = 0; i < x->x_dimensions; ++i) + x->x[i] = random_float_range(-1.0, 1.0); + + if (vec_normalize(x)) + return; + } + + vec_fill(x, 0.0); + x->x[0] = 1.0; +} + +void vec_add(t_vec *dst, const t_vec *src) +{ + if (!dst || !src || dst->x_dimensions != src->x_dimensions) + return; + + for (size_t i = 0; i < dst->x_dimensions; ++i) + dst->x[i] += src->x[i]; +} + +void vec_add_scaled(t_vec *dst, const t_vec *src, t_float scale) +{ + if (!dst || !src || dst->x_dimensions != src->x_dimensions) + return; + + for (size_t i = 0; i < dst->x_dimensions; ++i) + dst->x[i] += src->x[i] * scale; +} + +void vec_add_delta_unit_scaled(t_vec *dst, const t_vec *a, const t_vec *b, + t_float scale) +{ + if (!dst || !a || !b || dst->x_dimensions != a->x_dimensions || + a->x_dimensions != b->x_dimensions) + return; + + t_float len2 = 0.0; + for (size_t i = 0; i < a->x_dimensions; ++i) + { + t_float d = a->x[i] - b->x[i]; + len2 += d * d; + } + + if (len2 <= BOIDS_EPS) + return; + + t_float inv_len = 1.0 / sqrt(len2); + for (size_t i = 0; i < dst->x_dimensions; ++i) + dst->x[i] += (a->x[i] - b->x[i]) * inv_len * scale; +} + +void vec_scale(t_vec *x, t_float scale) +{ + if (!x) + return; + + for (size_t i = 0; i < x->x_dimensions; ++i) + x->x[i] *= scale; +} + +t_float vec_length_squared(const t_vec *x) +{ + if (!x) + return 0.0; + + t_float len2 = 0.0; + for (size_t i = 0; i < x->x_dimensions; ++i) + len2 += x->x[i] * x->x[i]; + return len2; +} + +t_float vec_length(const t_vec *x) +{ + return sqrt(vec_length_squared(x)); +} + +int vec_normalize(t_vec *x) +{ + t_float len = vec_length(x); + if (len <= BOIDS_EPS) + return 0; + + vec_scale(x, 1.0 / len); + return 1; +} + +void vec_average(t_vec *x, size_t count) +{ + if (!count) + return; + + vec_scale(x, 1.0 / (t_float)count); +} + +t_float vec_square_distance(const t_vec *a, const t_vec *b) +{ + if (!a || !b || a->x_dimensions != b->x_dimensions) + return 0.0; + + t_float distance = 0.0; + for (size_t i = 0; i < a->x_dimensions; ++i) + { + t_float d = a->x[i] - b->x[i]; + distance += d * d; + } + return distance; +} + +t_float vec_dot_offset_dir(const t_vec *a_pos, const t_vec *b_pos, + const t_vec *a_dir) +{ + if (!a_pos || !b_pos || !a_dir || + a_pos->x_dimensions != b_pos->x_dimensions || + a_pos->x_dimensions != a_dir->x_dimensions) + return 0.0; + + t_float dot = 0.0; + for (size_t i = 0; i < a_pos->x_dimensions; ++i) + dot += (b_pos->x[i] - a_pos->x[i]) * a_dir->x[i]; + return dot; +} + +void vec_state_alloc(t_vec_state *x, size_t dimensions) +{ + if (!x) + return; + + vec_alloc(&x->x_old, dimensions); + vec_alloc(&x->x_new, dimensions); +} + +void vec_state_clear(t_vec_state *x) +{ + if (!x) + return; + + vec_clear(&x->x_old); + vec_clear(&x->x_new); +} + +void vec_state_fill(t_vec_state *x, t_float c) +{ + if (!x) + return; + + vec_fill(&x->x_old, c); + vec_fill(&x->x_new, c); +} + +void vec_state_step(t_vec_state *x) +{ + if (!x) + return; + + vec_copy(&x->x_old, &x->x_new); +} + +void vec_state_update(t_vec_state *x, int argc, t_atom *argv) +{ + if (!x) + return; + + vec_state_step(x); + vec_update(&x->x_new, argc, argv); +} + +void vec_state_random_range(t_vec_state *x, const t_float *range) +{ + if (!x) + return; + + vec_random_range(&x->x_new, range); + vec_copy(&x->x_old, &x->x_new); +} + +void vec_state_random_unit(t_vec_state *x) +{ + if (!x) + return; + + vec_random_unit(&x->x_new); + vec_copy(&x->x_old, &x->x_new); +} diff --git a/src/vec.h b/src/vec.h new file mode 100644 index 0000000..bc667fa --- /dev/null +++ b/src/vec.h @@ -0,0 +1,77 @@ +/* + boids3d 2005 - 2006 a.sier / jasch + adapted from boids by eric singer © 1995-2003 eric l. singer + updated by fdch 2026 + + 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. +*/ +#ifndef VEC_H +#define VEC_H + +#include "m_pd.h" +#include + +#define BOIDS_PI \ + 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068 +#define D2R (BOIDS_PI / 180.0) +#define R2D (180.0 / BOIDS_PI) + +/* + * This file is still named vec.* so existing build files do not have to + * change, but the type is now a plain vector. Old/new state belongs at the + * boid/state level, not inside every temporary vector. + */ + +typedef struct _vec +{ + size_t x_dimensions; + t_float *x; +} t_vec; + +typedef struct _vec_state +{ + t_vec x_old; + t_vec x_new; +} t_vec_state; + +size_t vec_dimensions_clamp(size_t dimensions); +t_float random_float_range(t_float min, t_float max); + +void vec_alloc(t_vec *x, size_t dimensions); +t_vec *vec_new(size_t dimensions); +void vec_clear(t_vec *x); +void vec_free(t_vec *x); +void vec_fill(t_vec *x, t_float c); +void vec_copy(t_vec *dst, const t_vec *src); +void vec_update(t_vec *x, int argc, t_atom *argv); +void vec_random_range(t_vec *x, const t_float *range); +void vec_random_unit(t_vec *x); + +void vec_add(t_vec *dst, const t_vec *src); +void vec_add_scaled(t_vec *dst, const t_vec *src, t_float scale); +void vec_add_delta_unit_scaled(t_vec *dst, const t_vec *a, const t_vec *b, + t_float scale); +void vec_scale(t_vec *x, t_float scale); +t_float vec_length_squared(const t_vec *x); +t_float vec_length(const t_vec *x); +int vec_normalize(t_vec *x); +void vec_average(t_vec *x, size_t count); +t_float vec_square_distance(const t_vec *a, const t_vec *b); +t_float vec_dot_offset_dir(const t_vec *a_pos, const t_vec *b_pos, + const t_vec *a_dir); + +void vec_state_alloc(t_vec_state *x, size_t dimensions); +void vec_state_clear(t_vec_state *x); +void vec_state_fill(t_vec_state *x, t_float c); +void vec_state_step(t_vec_state *x); +void vec_state_update(t_vec_state *x, int argc, t_atom *argv); +void vec_state_random_range(t_vec_state *x, const t_float *range); +void vec_state_random_unit(t_vec_state *x); + +/* Keep the old helper name around because boids.c and older callers used it. */ +#define max_dimensions vec_dimensions_clamp + +#endif From 3693268e95a8d5ca3427fa26e0d9f2dcdc7047bb Mon Sep 17 00:00:00 2001 From: fdch Date: Wed, 13 May 2026 16:23:15 +0200 Subject: [PATCH 12/19] refactor to use vec --- src/boid_params.c | 168 +++++++----- src/boid_params.h | 24 +- src/boids.c | 651 ++++++++++++++++++++++++---------------------- src/boids.h | 93 +++---- 4 files changed, 501 insertions(+), 435 deletions(-) diff --git a/src/boid_params.c b/src/boid_params.c index 09d5750..ce836b2 100644 --- a/src/boid_params.c +++ b/src/boid_params.c @@ -7,104 +7,154 @@ 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 "boid_params.h" -/* initialize the params object with default values */ -t_boid_params *boid_params_new() +static t_float boids_clip_min(t_float value, t_float min) +{ + return value < min ? min : value; +} + +static t_float boids_clip01(t_float value) { - t_boid_params *x = (t_boid_params *)getbytes(sizeof(t_boid_params)); - x->x_speed_min = 0.15; // boids' minimum speed - x->x_speed_max = 0.25; // boids' maximum speed - x->x_weight_center = 0.25; // flock centering - x->x_weight_attract = 0.3; // attraction point seeking - x->x_weight_match = 0.1; // neighbors velocity matching - x->x_weight_avoid = 0.1; // neighbors avoidance - x->x_weight_walls = 0.5; // wall avoidance [210] - x->x_distance_edge = 0.5; // vision distance to avoid wall edges [5] - x->x_factor_speedup = 0.1; // alter animation speed - x->x_factor_inertia = 0.2; // willingness to change speed & direction - x->x_factor_accel = 0.1; // neighbor avoidance accel or decelerate rate - x->x_pref_dist = 0.25; // preferred distance from neighbors - /* autofill these */ + return value < 0.0 ? 0.0 : value > 1.0 ? 1.0 : value; +} + +void boid_params_refresh(t_boid_params *x) +{ + if (!x) + return; + + x->x_speed_min = boids_clip_min(x->x_speed_min, 0.000001); + x->x_speed_max = boids_clip_min(x->x_speed_max, x->x_speed_min); + x->x_factor_accel = boids_clip_min(x->x_factor_accel, 0.000001); + x->x_factor_inertia = boids_clip01(x->x_factor_inertia); + x->x_distance_edge = boids_clip_min(x->x_distance_edge, 0.000001); + x->x_pref_dist = boids_clip_min(x->x_pref_dist, 0.000001); + x->x_pref_dist_sqr = x->x_pref_dist * x->x_pref_dist; - x->x_factor_accel_inv = 1.0 / (x->x_factor_accel + 1e-13); - x->x_factor_inertia_inv = 1.0 / (x->x_factor_inertia + 1e-13); + x->x_factor_accel_inv = 1.0 / x->x_factor_accel; + x->x_factor_inertia_inv = 1.0 - x->x_factor_inertia; +} + +t_boid_params *boid_params_new(void) +{ + t_boid_params *x = (t_boid_params *)getbytes(sizeof(*x)); + if (!x) + return NULL; + + x->x_speed_min = 0.15; + x->x_speed_max = 0.25; + + /* Defaults are tuned for normalized [-1, 1] bounds. The old defaults + pulled every boid to the origin via attract=0.3, which caused clumping. */ + x->x_weight_center = 0.03; + x->x_weight_attract = 0.0; + x->x_weight_match = 0.15; + x->x_weight_avoid = 0.75; + x->x_weight_walls = 1.0; + + x->x_factor_speedup = 0.1; + x->x_factor_inertia = 0.85; + x->x_factor_accel = 0.05; + + x->x_distance_edge = 0.25; + x->x_pref_dist = 0.25; + + boid_params_refresh(x); return x; } -/* deallocate the params object */ void boid_params_free(t_boid_params *x) { if (!x) return; - freebytes(x, sizeof(t_boid_params)); - x = NULL; + + freebytes(x, sizeof(*x)); } -/* dump all params to the given outlet as a sequenece of param name and value */ void boid_params_dump(t_boid_params *x, t_outlet *out) { - t_atom *argv = (t_atom *)getbytes(sizeof(t_atom)); - SETFLOAT(argv, x->x_speed_min); - outlet_anything(out, gensym("minspeed"), 1, argv); + if (!x || !out) + return; - SETFLOAT(argv, x->x_speed_max); - outlet_anything(out, gensym("maxspeed"), 1, argv); + t_atom argv; - SETFLOAT(argv, x->x_weight_center); - outlet_anything(out, gensym("center"), 1, argv); + SETFLOAT(&argv, x->x_speed_min); + outlet_anything(out, gensym("minspeed"), 1, &argv); - SETFLOAT(argv, x->x_weight_attract); - outlet_anything(out, gensym("attract"), 1, argv); + SETFLOAT(&argv, x->x_speed_max); + outlet_anything(out, gensym("maxspeed"), 1, &argv); - SETFLOAT(argv, x->x_weight_match); - outlet_anything(out, gensym("match"), 1, argv); + SETFLOAT(&argv, x->x_weight_center); + outlet_anything(out, gensym("center"), 1, &argv); - SETFLOAT(argv, x->x_weight_avoid); - outlet_anything(out, gensym("avoid"), 1, argv); + SETFLOAT(&argv, x->x_weight_attract); + outlet_anything(out, gensym("attract"), 1, &argv); - SETFLOAT(argv, x->x_weight_walls); - outlet_anything(out, gensym("repel"), 1, argv); + SETFLOAT(&argv, x->x_weight_match); + outlet_anything(out, gensym("match"), 1, &argv); - SETFLOAT(argv, x->x_distance_edge); - outlet_anything(out, gensym("edgedist"), 1, argv); + SETFLOAT(&argv, x->x_weight_avoid); + outlet_anything(out, gensym("avoid"), 1, &argv); - SETFLOAT(argv, x->x_factor_speedup); - outlet_anything(out, gensym("speed"), 1, argv); + SETFLOAT(&argv, x->x_weight_walls); + outlet_anything(out, gensym("repel"), 1, &argv); - SETFLOAT(argv, x->x_factor_inertia); - outlet_anything(out, gensym("inertia"), 1, argv); + SETFLOAT(&argv, x->x_distance_edge); + outlet_anything(out, gensym("edgedist"), 1, &argv); - SETFLOAT(argv, x->x_factor_accel); - outlet_anything(out, gensym("accel"), 1, argv); + SETFLOAT(&argv, x->x_factor_speedup * 100.0); + outlet_anything(out, gensym("speed"), 1, &argv); - SETFLOAT(argv, x->x_pref_dist); - outlet_anything(out, gensym("prefdist"), 1, argv); + SETFLOAT(&argv, x->x_factor_inertia); + outlet_anything(out, gensym("inertia"), 1, &argv); - freebytes(argv, sizeof(t_atom)); + SETFLOAT(&argv, x->x_factor_accel); + outlet_anything(out, gensym("accel"), 1, &argv); + + SETFLOAT(&argv, x->x_pref_dist); + outlet_anything(out, gensym("prefdist"), 1, &argv); } void boid_params_set_speed_min(t_boid_params *x, t_floatarg f) { - x->x_speed_min = f < 0.0 ? 0.000001 : f; + x->x_speed_min = f; + boid_params_refresh(x); +} + +void boid_params_set_speed_max(t_boid_params *x, t_floatarg f) +{ + x->x_speed_max = f; + boid_params_refresh(x); } void boid_params_set_factor_speedup(t_boid_params *x, t_floatarg f) { x->x_factor_speedup = f / 100.0; + boid_params_refresh(x); } void boid_params_set_factor_inertia(t_boid_params *x, t_floatarg f) { - x->x_factor_inertia = f == 0.0 ? 0.000001 : f; + x->x_factor_inertia = f; + boid_params_refresh(x); +} + +void boid_params_set_factor_accel(t_boid_params *x, t_floatarg f) +{ + x->x_factor_accel = f; + boid_params_refresh(x); +} + +void boid_params_set_pref_dist(t_boid_params *x, t_floatarg f) +{ + x->x_pref_dist = f; + boid_params_refresh(x); +} + +void boid_params_set_edge_dist(t_boid_params *x, t_floatarg f) +{ + x->x_distance_edge = f; + boid_params_refresh(x); } diff --git a/src/boid_params.h b/src/boid_params.h index fd4b083..7b5ab65 100644 --- a/src/boid_params.h +++ b/src/boid_params.h @@ -7,15 +7,6 @@ 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 */ #ifndef BOID_PARAMS_H #define BOID_PARAMS_H @@ -40,24 +31,23 @@ typedef struct _boid_params t_float x_distance_edge; t_float x_pref_dist; - /* autofill these */ + /* cached/derived values */ t_float x_factor_accel_inv; t_float x_pref_dist_sqr; t_float x_factor_inertia_inv; } t_boid_params; -/* initialize the params object with default values */ -t_boid_params *boid_params_new(); - -/* deallocate the params object */ +t_boid_params *boid_params_new(void); void boid_params_free(t_boid_params *x); - -/* dump all params to the given outlet as a sequenece of param name and value */ void boid_params_dump(t_boid_params *x, t_outlet *out); +void boid_params_refresh(t_boid_params *x); -/* specific parameter setters */ void boid_params_set_speed_min(t_boid_params *x, t_floatarg f); +void boid_params_set_speed_max(t_boid_params *x, t_floatarg f); void boid_params_set_factor_speedup(t_boid_params *x, t_floatarg f); void boid_params_set_factor_inertia(t_boid_params *x, t_floatarg f); +void boid_params_set_factor_accel(t_boid_params *x, t_floatarg f); +void boid_params_set_pref_dist(t_boid_params *x, t_floatarg f); +void boid_params_set_edge_dist(t_boid_params *x, t_floatarg f); #endif diff --git a/src/boids.c b/src/boids.c index 74dae29..7c7d52d 100644 --- a/src/boids.c +++ b/src/boids.c @@ -7,89 +7,115 @@ 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 "boids.h" #include "m_pd.h" #include #include -/* --------------------------- points structure ----------------------------- */ +#define BOIDS_EPS ((t_float)1e-12) + +static t_class *boids3d_class, *boids2d_class, *boids_class; -void points_clear(t_points *x) +static t_newmethod boids_newmethod_cast(void *(*fn)(t_floatarg, t_floatarg)) { - point_fill(x->avoidNeighborVel, 0.0); - point_fill(x->avoidWallsVel, 0.0); - point_fill(x->goAttractVel, 0.0); - point_fill(x->goCenterVel, 0.0); - point_fill(x->matchNeighborVel, 0.0); +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + t_newmethod result = (t_newmethod)fn; +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + return result; } -t_points *points_new(size_t dimensions) +/* ----------------------------- force vectors ------------------------------ */ + +t_boid_forces *boid_forces_new(size_t dimensions) { - t_points *points = (t_points *)getbytes(sizeof(t_points)); - points->avoidNeighborVel = point_new(dimensions); - points->avoidWallsVel = point_new(dimensions); - points->goAttractVel = point_new(dimensions); - points->goCenterVel = point_new(dimensions); - points->matchNeighborVel = point_new(dimensions); - return points; + t_boid_forces *forces = (t_boid_forces *)getbytes(sizeof(*forces)); + if (!forces) + return NULL; + + vec_alloc(&forces->x_avoid_neighbors, dimensions); + vec_alloc(&forces->x_avoid_walls, dimensions); + vec_alloc(&forces->x_go_attract, dimensions); + vec_alloc(&forces->x_go_center, dimensions); + vec_alloc(&forces->x_match_neighbors, dimensions); + return forces; } -void points_free(t_points *x) +void boid_forces_clear(t_boid_forces *x) { if (!x) return; - point_free(x->avoidNeighborVel); - point_free(x->avoidWallsVel); - point_free(x->goAttractVel); - point_free(x->goCenterVel); - point_free(x->matchNeighborVel); + vec_fill(&x->x_avoid_neighbors, 0.0); + vec_fill(&x->x_avoid_walls, 0.0); + vec_fill(&x->x_go_attract, 0.0); + vec_fill(&x->x_go_center, 0.0); + vec_fill(&x->x_match_neighbors, 0.0); +} + +void boid_forces_free(t_boid_forces *x) +{ + if (!x) + return; - freebytes(x, sizeof(t_points)); + vec_clear(&x->x_avoid_neighbors); + vec_clear(&x->x_avoid_walls); + vec_clear(&x->x_go_attract); + vec_clear(&x->x_go_center); + vec_clear(&x->x_match_neighbors); + freebytes(x, sizeof(*x)); } -static t_class *boids3d_class, *boids2d_class, *boids_class; -/* ---------------------------- helper functions ---------------------------- */ +static t_float boids_force_at(t_boid_params *params, t_boid_forces *forces, + size_t d) +{ + return params->x_weight_center * forces->x_go_center.x[d] + + params->x_weight_attract * forces->x_go_attract.x[d] + + params->x_weight_match * forces->x_match_neighbors.x[d] + + params->x_weight_avoid * forces->x_avoid_neighbors.x[d] + + params->x_weight_walls * forces->x_avoid_walls.x[d]; +} -static t_float apply_weighted_force(t_boid_params *params, t_points *points, - size_t dimension) +void boid_direction_update(t_vec_state *direction, t_boid_params *params, + t_boid_forces *forces) { - t_float f = - (params->x_weight_center * points->goCenterVel->x_new[dimension] + - params->x_weight_attract * points->goAttractVel->x_new[dimension] + - params->x_weight_match * points->matchNeighborVel->x_new[dimension] + - params->x_weight_avoid * points->avoidNeighborVel->x_new[dimension] + - params->x_weight_walls * points->avoidWallsVel->x_new[dimension]); - return f * params->x_factor_inertia_inv; + t_vec *old = &direction->x_old; + t_vec *new = &direction->x_new; + + for (size_t d = 0; d < new->x_dimensions; ++d) + new->x[d] = old->x[d] * params->x_factor_inertia + + boids_force_at(params, forces, d) * + params->x_factor_inertia_inv; + + if (!vec_normalize(new)) + { + vec_copy(new, old); + if (!vec_normalize(new)) + vec_random_unit(new); + } } -/* - * calculate the velocity of a point with the weights and inertia factor - * (boid parameters) and the temporary points structure - */ -void point_velocity(t_point *x, t_boid_params *params, t_points *points) +/* ---------------------------- helper functions ---------------------------- */ + +static t_float boids_clip(t_float value, t_float min, t_float max) { - for (size_t i = 0; i < x->x_dimensions; i++) - x->x_new[i] = params->x_factor_inertia * x->x_old[i] + - apply_weighted_force(params, points, i); + return value < min ? min : value > max ? max : value; } -/* compute a target position from the norm dif between seek point and boid */ -static void boid_point_seek(t_boid *x, t_point *seek, t_point *target) +static void boid_seek(const t_boid *x, const t_vec *seek, t_vec *target) { - for (size_t i = 0; i < seek->x_dimensions; i++) - target->x_new[i] = seek->x_new[i] - x->x_position.x_old[i]; - point_norm_square(target); + if (!x || !seek || !target) + return; + + for (size_t d = 0; d < seek->x_dimensions; ++d) + target->x[d] = seek->x[d] - x->x_position.x_old.x[d]; + + vec_normalize(target); } static void boid_compute_neighbor_distances(t_boid *x) @@ -98,13 +124,12 @@ static void boid_compute_neighbor_distances(t_boid *x) size_t num_boids = flock->x_num_boids; size_t max_neighbors = flock->x_max_neighbors; - if (num_boids <= 1 || max_neighbors == 0) + if (!x->x_neighbors || num_boids <= 1 || max_neighbors == 0) return; if (max_neighbors > num_boids - 1) max_neighbors = num_boids - 1; - /* initialize output slots */ for (size_t i = 0; i < max_neighbors; ++i) { x->x_neighbors[i].x_boid = NULL; @@ -113,29 +138,24 @@ static void boid_compute_neighbor_distances(t_boid *x) (i + 1 < max_neighbors) ? &x->x_neighbors[i + 1] : NULL; } - /* scan all boids in flock */ for (size_t i = 0; i < num_boids; ++i) { t_boid *candidate = &flock->x_boid[i]; - t_float distance = 0.0; - if (candidate == x) continue; - point_square_distance(&x->x_position, &candidate->x_position, - &distance); + t_float distance = vec_square_distance(&x->x_position.x_old, + &candidate->x_position.x_old); - /* only insert if better than current worst */ if (distance < x->x_neighbors[max_neighbors - 1].x_distance) { size_t j = max_neighbors - 1; - while ((j > 0) && (distance < x->x_neighbors[j - 1].x_distance)) + while (j > 0 && distance < x->x_neighbors[j - 1].x_distance) { x->x_neighbors[j].x_boid = x->x_neighbors[j - 1].x_boid; - - x->x_neighbors[j].x_distance = x->x_neighbors[j - 1].x_distance; - + x->x_neighbors[j].x_distance = + x->x_neighbors[j - 1].x_distance; --j; } @@ -147,162 +167,184 @@ static void boid_compute_neighbor_distances(t_boid *x) static int boid_infront(t_boid *boid, t_boid *neighbor) { - t_float dot = point_infront_dot_old( - &boid->x_position, &neighbor->x_position, &boid->x_direction); - return (dot > 0.0); + t_float dot = vec_dot_offset_dir(&boid->x_position.x_old, + &neighbor->x_position.x_old, + &boid->x_direction.x_old); + return dot > 0.0; +} + +static void boid_add_zero_distance_escape(t_boid *x, t_vec *avoid, + t_float strength) +{ + /* If two boids occupy exactly the same position, there is no usable + position delta. Push opposite to the current direction as a stable + deterministic fallback. */ + vec_add_scaled(avoid, &x->x_direction.x_old, -strength); } -/*********************************/ -/* Match and avoid the neighbors */ -/*********************************/ static t_float boid_match_and_avoid_neighbors(t_boid *x, - t_point *matchNeighborVel, - t_point *avoidNeighborVel) + t_vec *match_neighbors, + t_vec *avoid_neighbors) { - size_t num_close = 0; + t_boid_params *params = x->x_flock->x_params; + t_float pref_dist = params->x_pref_dist; + t_float pref_dist_sqr = params->x_pref_dist_sqr; + t_float speed = x->x_speed; size_t num_neighbors = 0; - t_float pref_dist_squared = x->x_flock->x_params->x_pref_dist_sqr; - t_float factor_accel = x->x_flock->x_params->x_factor_accel; - t_float inv_factor_accel = x->x_flock->x_params->x_factor_accel_inv; - t_float avoid_speed = x->x_speed; + size_t num_close = 0; + size_t close_in_front = 0; + size_t close_behind = 0; for (t_neighbor *neighbor = x->x_neighbors; neighbor; neighbor = neighbor->x_next) { t_boid *other = neighbor->x_boid; - t_float dist_squared = neighbor->x_distance; - t_float adjust_speed; + t_float dist_sqr = neighbor->x_distance; if (!other) continue; - num_neighbors++; - - int in_front = boid_infront(x, other); - adjust_speed = in_front ? factor_accel : inv_factor_accel; - - /* match: accumulate neighbor velocity/direction */ - point_add(matchNeighborVel, &other->x_direction); + ++num_neighbors; + vec_add(match_neighbors, &other->x_direction.x_old); - /* avoid: react to close neighbors */ - if (dist_squared < pref_dist_squared) + if (dist_sqr < pref_dist_sqr) { - t_float fstep = pref_dist_squared / (sqrt(dist_squared) + 1e-13); - - /* use self - other for an "away from neighbor" vector */ - t_point *d = point_diff(&x->x_position, &other->x_position); - point_update_velocity(d, avoidNeighborVel, fstep); - point_free(d); - - num_close++; - - /* too close => flip speed adjustment */ - adjust_speed = in_front ? inv_factor_accel : factor_accel; + t_float dist = sqrt(dist_sqr); + t_float strength = (pref_dist - dist) / pref_dist; + + if (dist <= BOIDS_EPS) + boid_add_zero_distance_escape(x, avoid_neighbors, strength); + else + vec_add_delta_unit_scaled(avoid_neighbors, &x->x_position.x_old, + &other->x_position.x_old, strength); + + ++num_close; + if (boid_infront(x, other)) + ++close_in_front; + else + ++close_behind; } - - avoid_speed *= adjust_speed; } if (num_neighbors) - point_normalize(matchNeighborVel, num_neighbors); + { + vec_average(match_neighbors, num_neighbors); + vec_normalize(match_neighbors); + } if (num_close) - point_normalize(avoidNeighborVel, num_close); + { + vec_average(avoid_neighbors, num_close); + + /* Simple, bounded speed response: slow down for close boids in front, + speed up slightly if crowded from behind. */ + if (close_in_front >= close_behind) + speed *= 1.0 - params->x_factor_accel; + else + speed *= 1.0 + params->x_factor_accel; + } - return avoid_speed; + return boids_clip(speed, params->x_speed_min, params->x_speed_max); } -static void boid_avoid_walls(t_boid *x, t_point *target, t_float distance_edge) +static void boid_avoid_walls(t_boid *x, t_vec *target, t_float distance_edge) { - size_t dimensions = x->x_flock->x_dimensions; - t_point *test_pt = point_new(dimensions); + t_boids *flock = x->x_flock; + + vec_fill(target, 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 */ - for (size_t i = 0; i < dimensions; i++) - test_pt->x_new[i] = - x->x_position.x_old[i] + - x->x_speed * x->x_direction.x_old[i] * distance_edge; + for (size_t d = 0; d < flock->x_dimensions; ++d) + { + t_float lo = flock->x_bounds[d * 2]; + t_float hi = flock->x_bounds[d * 2 + 1]; + t_float span = hi - lo; + t_float edge = distance_edge; + t_float pos = x->x_position.x_old.x[d]; + + if (span <= 0.0) + continue; - /* if test point is out of the left (right) side of x->flyRect, */ - /* return a positive (negative) horizontal velocity component */ - for (size_t i = 0; i < dimensions; i++) - if (test_pt->x_new[i] < x->x_flock->x_bounds[i * 2]) - target->x_new[i] = fabs(x->x_direction.x_old[i]); - else if (test_pt->x_new[i] > x->x_flock->x_bounds[i * 2 + 1]) - target->x_new[i] = -fabs(x->x_direction.x_old[i]); + if (edge > span * 0.5) + edge = span * 0.5; - point_free(test_pt); + if (pos < lo + edge) + target->x[d] += (lo + edge - pos) / edge; + else if (pos > hi - edge) + target->x[d] -= (pos - (hi - edge)) / edge; + } } -static void boids_step(t_boids *x) +static void boid_keep_inside_bounds(t_boid *b) { - if (x->x_num_boids == 0) - return; + t_boids *flock = b->x_flock; - t_float avoid_speed = 0.0; + for (size_t d = 0; d < flock->x_dimensions; ++d) + { + t_float lo = flock->x_bounds[d * 2]; + t_float hi = flock->x_bounds[d * 2 + 1]; - /* find the center of mass of the flock */ - point_fill(&x->x_position_center, 0.0); + if (b->x_position.x_new.x[d] < lo) + { + b->x_position.x_new.x[d] = lo; + b->x_direction.x_new.x[d] = fabs(b->x_direction.x_new.x[d]); + } + else if (b->x_position.x_new.x[d] > hi) + { + b->x_position.x_new.x[d] = hi; + b->x_direction.x_new.x[d] = -fabs(b->x_direction.x_new.x[d]); + } + } - for (size_t i = 0; i < x->x_num_boids; i++) - point_add(&x->x_position_center, &x->x_boid[i].x_position); + vec_normalize(&b->x_direction.x_new); +} - point_normalize(&x->x_position_center, (t_float)x->x_num_boids); +static void boids_step(t_boids *x) +{ + if (!x || x->x_num_boids == 0) + return; - // save position and velocity - for (size_t i = 0; i < x->x_num_boids; i++) + for (size_t i = 0; i < x->x_num_boids; ++i) { - point_step(&x->x_boid[i].x_position); - point_step(&x->x_boid[i].x_direction); + vec_state_step(&x->x_boid[i].x_position); + vec_state_step(&x->x_boid[i].x_direction); } - /**********************/ - /* Find the neighbors */ - /**********************/ - for (size_t i = 0; i < x->x_num_boids; i++) + vec_fill(&x->x_position_center, 0.0); + for (size_t i = 0; i < x->x_num_boids; ++i) + vec_add(&x->x_position_center, &x->x_boid[i].x_position.x_old); + vec_average(&x->x_position_center, x->x_num_boids); + + for (size_t i = 0; i < x->x_num_boids; ++i) { - points_clear(x->x_points); - avoid_speed = 0; + t_boid *boid = &x->x_boid[i]; + t_boid_forces *forces = x->x_forces; + + boid_forces_clear(forces); - // get all velocity components if (x->x_max_neighbors > 0) { - boid_compute_neighbor_distances(&x->x_boid[i]); - avoid_speed = boid_match_and_avoid_neighbors( - &x->x_boid[i], x->x_points->matchNeighborVel, - x->x_points->avoidNeighborVel); + boid_compute_neighbor_distances(boid); + boid->x_speed = boid_match_and_avoid_neighbors( + boid, &forces->x_match_neighbors, &forces->x_avoid_neighbors); } - boid_point_seek(&x->x_boid[i], &x->x_position_center, - x->x_points->goCenterVel); - boid_point_seek(&x->x_boid[i], &x->x_position_attract, - x->x_points->goAttractVel); - boid_avoid_walls(&x->x_boid[i], x->x_points->avoidWallsVel, + boid_seek(boid, &x->x_position_center, &forces->x_go_center); + boid_seek(boid, &x->x_position_attract, &forces->x_go_attract); + boid_avoid_walls(boid, &forces->x_avoid_walls, x->x_params->x_distance_edge); - // compute resultant velocity using weights and inertia - point_velocity(&x->x_boid[i].x_direction, x->x_params, x->x_points); - - // normalize velocity so its length is unity - point_norm_square(&x->x_boid[i].x_direction); - - // set to avoid_speed bounded by minSpeed and maxSpeed - if ((avoid_speed >= x->x_params->x_speed_min) && - (avoid_speed <= x->x_params->x_speed_max)) - x->x_boid[i].x_speed = avoid_speed; - else if (avoid_speed > x->x_params->x_speed_max) - x->x_boid[i].x_speed = x->x_params->x_speed_max; - else - x->x_boid[i].x_speed = x->x_params->x_speed_min; - // calculate new position, applying speedupFactor - for (size_t d = 0; d < x->x_dimensions; d++) - x->x_boid[i].x_position.x_new[d] += - x->x_boid[i].x_direction.x_new[d] * x->x_boid[i].x_speed * - x->x_params->x_factor_speedup; + boid_direction_update(&boid->x_direction, x->x_params, forces); + + vec_copy(&boid->x_position.x_new, &boid->x_position.x_old); + vec_add_scaled(&boid->x_position.x_new, &boid->x_direction.x_new, + boid->x_speed * x->x_params->x_factor_speedup); + + boid_keep_inside_bounds(boid); } } +/* -------------------------------- outlets --------------------------------- */ + static void outlet_newpos(t_boids *x) { size_t argc = x->x_dimensions + 1; @@ -316,7 +358,7 @@ static void outlet_newpos(t_boids *x) SETFLOAT(argv + 0, (t_float)i); for (size_t d = 0; d < x->x_dimensions; ++d) - SETFLOAT(argv + 1 + d, x->x_boid[i].x_position.x_new[d]); + SETFLOAT(argv + 1 + d, x->x_boid[i].x_position.x_new.x[d]); outlet_list(x->x_out1, gensym("list"), (int)argc, argv); } @@ -336,14 +378,12 @@ static void outlet_newold(t_boids *x) { SETFLOAT(argv + 0, (t_float)i); - /* new position */ for (size_t d = 0; d < x->x_dimensions; ++d) - SETFLOAT(argv + 1 + d, x->x_boid[i].x_position.x_new[d]); + SETFLOAT(argv + 1 + d, x->x_boid[i].x_position.x_new.x[d]); - /* old position */ for (size_t d = 0; d < x->x_dimensions; ++d) SETFLOAT(argv + 1 + x->x_dimensions + d, - x->x_boid[i].x_position.x_old[d]); + x->x_boid[i].x_position.x_old.x[d]); outlet_list(x->x_out1, gensym("list"), (int)argc, argv); } @@ -351,14 +391,6 @@ static void outlet_newold(t_boids *x) freebytes(argv, sizeof(*argv) * argc); } -/* - * BOID_ALL currently makes sense as a 2D/3D outlet format: - * - * 2D: [index new_x new_y old_x old_y speed azimuth elevation] - * 3D: [index new_x new_y new_z old_x old_y old_z speed azimuth elevation] - * - * For dimensions >= 3, this uses the first 3 coordinates. - */ static void outlet_all(t_boids *x) { t_atom out[10]; @@ -369,42 +401,30 @@ static void outlet_all(t_boids *x) for (size_t i = 0; i < x->x_num_boids; ++i) { - t_float new_x = x->x_boid[i].x_position.x_new[0]; - t_float new_y = x->x_boid[i].x_position.x_new[1]; - t_float old_x = x->x_boid[i].x_position.x_old[0]; - t_float old_y = x->x_boid[i].x_position.x_old[1]; - + t_float new_x = x->x_boid[i].x_position.x_new.x[0]; + t_float new_y = x->x_boid[i].x_position.x_new.x[1]; + t_float old_x = x->x_boid[i].x_position.x_old.x[0]; + t_float old_y = x->x_boid[i].x_position.x_old.x[1]; t_float delta_x = new_x - old_x; t_float delta_y = new_y - old_y; t_float delta_z = 0.0; - t_float new_z = 0.0; t_float old_z = 0.0; - t_float speed; - t_float azi; - t_float ele; - if (has_z) { - new_z = x->x_boid[i].x_position.x_new[2]; - old_z = x->x_boid[i].x_position.x_old[2]; + new_z = x->x_boid[i].x_position.x_new.x[2]; + old_z = x->x_boid[i].x_position.x_old.x[2]; delta_z = new_z - old_z; } - speed = sqrt(delta_x * delta_x + delta_y * delta_y + delta_z * delta_z); - - azi = atan2(delta_y, delta_x) * R2D; - - if (has_z) - { - t_float horiz = sqrt(delta_x * delta_x + delta_y * delta_y); - ele = atan2(delta_z, horiz) * R2D; - } - else - { - ele = 0.0; - } + t_float speed = + sqrt(delta_x * delta_x + delta_y * delta_y + delta_z * delta_z); + t_float azi = atan2(delta_y, delta_x) * R2D; + t_float ele = has_z ? atan2(delta_z, sqrt(delta_x * delta_x + + delta_y * delta_y)) * + R2D + : 0.0; SETFLOAT(out + 0, (t_float)i); @@ -417,7 +437,6 @@ static void outlet_all(t_boids *x) SETFLOAT(out + 5, speed); SETFLOAT(out + 6, azi); SETFLOAT(out + 7, ele); - outlet_list(x->x_out1, gensym("list"), 8, out); } else @@ -431,7 +450,6 @@ static void outlet_all(t_boids *x) SETFLOAT(out + 7, speed); SETFLOAT(out + 8, azi); SETFLOAT(out + 9, ele); - outlet_list(x->x_out1, gensym("list"), 10, out); } } @@ -449,14 +467,12 @@ static void outlet_posvel(t_boids *x) { SETFLOAT(argv + 0, (t_float)i); - /* new position */ for (size_t d = 0; d < x->x_dimensions; ++d) - SETFLOAT(argv + 1 + d, x->x_boid[i].x_position.x_new[d]); + SETFLOAT(argv + 1 + d, x->x_boid[i].x_position.x_new.x[d]); - /* new direction */ for (size_t d = 0; d < x->x_dimensions; ++d) SETFLOAT(argv + 1 + x->x_dimensions + d, - x->x_boid[i].x_direction.x_new[d]); + x->x_boid[i].x_direction.x_new.x[d]); outlet_list(x->x_out1, gensym("list"), (int)argc, argv); } @@ -476,15 +492,12 @@ static void boids_bang(t_boids *x) default: outlet_newpos(x); break; - case BOID_NEWOLD: outlet_newold(x); break; - case BOID_ALL: outlet_all(x); break; - case BOID_POSVEL: outlet_posvel(x); break; @@ -493,28 +506,27 @@ static void boids_bang(t_boids *x) static void boids_dump(t_boids *x) { - /* keep the max size of the atom and release it later */ size_t nbytes = sizeof(t_atom) * 2 * x->x_dimensions; t_atom *argv = (t_atom *)getbytes(nbytes); + if (!argv) + return; + SETFLOAT(argv, x->x_max_neighbors); outlet_anything(x->x_out2, gensym("neighbors"), 1, argv); boid_params_dump(x->x_params, x->x_out2); - /* outlet all bounds as fly rectangle */ - for (size_t i = 0; i < 2 * x->x_dimensions; i++) + for (size_t i = 0; i < 2 * x->x_dimensions; ++i) SETFLOAT(argv + i, x->x_bounds[i]); outlet_anything(x->x_out2, gensym("flyrect"), 2 * x->x_dimensions, argv); - /* outlet all attract position */ - for (size_t i = 0; i < x->x_dimensions; i++) - SETFLOAT(argv + i, x->x_position_attract.x_new[i]); + for (size_t i = 0; i < x->x_dimensions; ++i) + SETFLOAT(argv + i, x->x_position_attract.x[i]); outlet_anything(x->x_out2, gensym("attractpt"), x->x_dimensions, argv); - /* outlet all center position */ - for (size_t i = 0; i < x->x_dimensions; i++) - SETFLOAT(argv + i, x->x_position_center.x_new[i]); + for (size_t i = 0; i < x->x_dimensions; ++i) + SETFLOAT(argv + i, x->x_position_center.x[i]); outlet_anything(x->x_out2, gensym("centerpt"), x->x_dimensions, argv); SETFLOAT(argv, x->x_mode); @@ -526,15 +538,14 @@ static void boids_dump(t_boids *x) SETFLOAT(argv, x->x_dimensions); outlet_anything(x->x_out2, gensym("dimensions"), 1, argv); - /* release the argv atom */ freebytes(argv, nbytes); } static void boids_num_neighbors(t_boids *x, t_floatarg f) { - x->x_max_neighbors = f < 0.0 ? 1 - : (size_t)f > x->x_num_boids ? x->x_num_boids - : (size_t)f; + size_t n = f <= 0.0 ? 0 : (size_t)f; + size_t max = x->x_num_boids > 0 ? x->x_num_boids - 1 : 0; + x->x_max_neighbors = n > max ? max : n; } static void boids_minSpeed(t_boids *x, t_floatarg f) @@ -544,7 +555,7 @@ static void boids_minSpeed(t_boids *x, t_floatarg f) static void boids_maxSpeed(t_boids *x, t_floatarg f) { - x->x_params->x_speed_max = f; + boid_params_set_speed_max(x->x_params, f); } static void boids_centerWeight(t_boids *x, t_floatarg f) @@ -574,7 +585,7 @@ static void boids_wallsWeight(t_boids *x, t_floatarg f) static void boids_edgeDist(t_boids *x, t_floatarg f) { - x->x_params->x_distance_edge = f; + boid_params_set_edge_dist(x->x_params, f); } static void boids_speedupFactor(t_boids *x, t_floatarg f) @@ -589,12 +600,12 @@ static void boids_inertiaFactor(t_boids *x, t_floatarg f) static void boids_accelFactor(t_boids *x, t_floatarg f) { - x->x_params->x_factor_accel = f; + boid_params_set_factor_accel(x->x_params, f); } static void boids_prefDist(t_boids *x, t_floatarg f) { - x->x_params->x_pref_dist = f; + boid_params_set_pref_dist(x->x_params, f); } static void boids_bounds(t_boids *x, t_symbol *s, int argc, t_atom *argv) @@ -606,10 +617,24 @@ static void boids_bounds(t_boids *x, t_symbol *s, int argc, t_atom *argv) for (size_t i = 0; i < nbounds && i < (size_t)argc; ++i) x->x_bounds[i] = atom_getfloat(argv + i); + for (size_t d = 0; d < x->x_dimensions; ++d) + { + t_float *lo = &x->x_bounds[d * 2]; + t_float *hi = &x->x_bounds[d * 2 + 1]; + if (*hi < *lo) + { + t_float tmp = *lo; + *lo = *hi; + *hi = tmp; + } + if (*hi == *lo) + *hi = *lo + 1.0; + } + if ((size_t)argc > nbounds) { startpost("Ignoring extra args"); - postatom(argc - nbounds, argv + nbounds); + postatom(argc - (int)nbounds, argv + nbounds); endpost(); } } @@ -618,27 +643,32 @@ static void boids_position_attract(t_boids *x, t_symbol *s, int argc, t_atom *argv) { (void)s; - point_update(&x->x_position_attract, argc, argv); + vec_update(&x->x_position_attract, argc, argv); } /* -------------------------- memory management ----------------------------- */ -/* deallocate previous bounds if present */ static void boids_bounds_free(t_boids *x) { if (!x->x_bounds) return; - freebytes(x->x_bounds, sizeof(t_float) * 2 * x->x_dimensions); + + freebytes(x->x_bounds, sizeof(*x->x_bounds) * 2 * x->x_dimensions); x->x_bounds = NULL; } -/* deallocate previous boid if present */ -static void boid_free(t_boids *x) +static void boids_vecs_free(t_boids *x) +{ + vec_clear(&x->x_position_center); + vec_clear(&x->x_position_attract); +} + +static void boids_boid_free(t_boids *x) { if (!x->x_boid) return; - for (size_t i = 0; i < x->x_num_boids; i++) + for (size_t i = 0; i < x->x_num_boids; ++i) { t_boid *boid = &x->x_boid[i]; @@ -649,9 +679,8 @@ static void boid_free(t_boids *x) boid->x_neighbors = NULL; } - point_clear(&boid->x_position); - point_clear(&boid->x_direction); - + vec_state_clear(&boid->x_position); + vec_state_clear(&boid->x_direction); boid->x_next = NULL; boid->x_flock = NULL; } @@ -661,29 +690,30 @@ static void boid_free(t_boids *x) x->x_num_boids = 0; } -/* free method to deallocate everything (used by Pd when deleting the object) */ static void boids_free(t_boids *x) { - /* deallocate previous boid if present */ - boid_free(x); - /* deallocate previous bounds if present */ + boids_boid_free(x); boids_bounds_free(x); - /* deallocate the parameters */ + boids_vecs_free(x); boid_params_free(x->x_params); - /* deallocate the computation points */ - points_free(x->x_points); + boid_forces_free(x->x_forces); + x->x_params = NULL; + x->x_forces = NULL; } /* ---------------------------- initialization ------------------------------ */ static void boids_reset(t_boids *x) { + if (!x || !x->x_boid) + return; + for (size_t i = 0; i < x->x_num_boids; ++i) { t_boid *boid = &x->x_boid[i]; - point_rand_from_range(&boid->x_position, x->x_bounds); - point_rand_from_angle(&boid->x_direction); + vec_state_random_range(&boid->x_position, x->x_bounds); + vec_state_random_unit(&boid->x_direction); boid->x_speed = (x->x_params->x_speed_max + x->x_params->x_speed_min) * 0.5; } @@ -694,49 +724,52 @@ static t_boid *boid_list_new(size_t num_boids, t_boids *flock) if (!num_boids) return NULL; - t_boid *boid_list = (t_boid *)getbytes(num_boids * sizeof(t_boid)); + t_boid *boid_list = (t_boid *)getbytes(num_boids * sizeof(*boid_list)); if (!boid_list) return NULL; - for (size_t i = 0; i < num_boids; i++) + for (size_t i = 0; i < num_boids; ++i) { t_boid *b = &boid_list[i]; + memset(b, 0, sizeof(*b)); + b->x_flock = flock; - point_alloc(&b->x_position, flock->x_dimensions); - point_alloc(&b->x_direction, flock->x_dimensions); + b->x_next = (i + 1 < num_boids) ? &boid_list[i + 1] : NULL; b->x_speed = 0.0; - b->x_next = (i + 1 < num_boids) ? &boid_list[i + 1] : NULL; + vec_state_alloc(&b->x_position, flock->x_dimensions); + vec_state_alloc(&b->x_direction, flock->x_dimensions); - b->x_neighbors = NULL; if (num_boids > 1) { - b->x_neighbors = - (t_neighbor *)getbytes((num_boids - 1) * sizeof(t_neighbor)); - - for (size_t j = 0; j + 1 < num_boids - 1; j++) + b->x_neighbors = (t_neighbor *)getbytes((num_boids - 1) * + sizeof(*b->x_neighbors)); + if (b->x_neighbors) { - b->x_neighbors[j].x_next = &b->x_neighbors[j + 1]; - b->x_neighbors[j].x_distance = 0.0; + for (size_t j = 0; j < num_boids - 1; ++j) + { + b->x_neighbors[j].x_next = + (j + 1 < num_boids - 1) ? &b->x_neighbors[j + 1] + : NULL; + b->x_neighbors[j].x_boid = NULL; + b->x_neighbors[j].x_distance = (t_float)kMaxLong; + } } - - b->x_neighbors[num_boids - 2].x_next = NULL; } } return boid_list; } -/* resize bounds and allocate */ static void boids_bounds_alloc(t_boids *x) { size_t nbounds = 2 * x->x_dimensions; - x->x_bounds = (t_float *)getbytes(sizeof(t_float) * nbounds); - /* initialize bounds */ - for (size_t i = 0; i < x->x_dimensions; i++) + x->x_bounds = (t_float *)getbytes(sizeof(*x->x_bounds) * nbounds); + + for (size_t d = 0; d < x->x_dimensions; ++d) { - x->x_bounds[i * 2] = -1.0; // nth dimension left side - x->x_bounds[i * 2 + 1] = 1.0; // nth dimension right side + x->x_bounds[d * 2] = -1.0; + x->x_bounds[d * 2 + 1] = 1.0; } } @@ -744,31 +777,29 @@ static void boids_init(t_boids *x, size_t dimensions, size_t num_boids) { boids_free(x); - /* define dimensions */ - x->x_dimensions = dimensions; - - /* resize boids and allocate the list of boids */ + x->x_dimensions = vec_dimensions_clamp(dimensions); x->x_num_boids = num_boids; + + x->x_params = boid_params_new(); boids_num_neighbors(x, 4.0); - x->x_boid = boid_list_new(num_boids, x); - /* allocate the boundaries (depends on dimensions) */ boids_bounds_alloc(x); - /* and allocate center and atract positions */ - point_alloc(&x->x_position_center, dimensions); - point_alloc(&x->x_position_attract, dimensions); - /* and allocate the calculation points */ - x->x_points = points_new(dimensions); - - /* initialize the parameters */ - x->x_params = boid_params_new(); + vec_alloc(&x->x_position_center, x->x_dimensions); + vec_alloc(&x->x_position_attract, x->x_dimensions); + x->x_forces = boid_forces_new(x->x_dimensions); + x->x_boid = boid_list_new(x->x_num_boids, x); boids_reset(x); } +static void boids_reinit(t_boids *x) +{ + boids_init(x, x->x_dimensions, x->x_num_boids); +} + static void boids_dimensions(t_boids *x, t_floatarg fdimen) { - size_t d = max_dimensions((size_t)fdimen); + size_t d = vec_dimensions_clamp((size_t)fdimen); if (x->x_dimensions == d) return; boids_init(x, d, x->x_num_boids); @@ -792,12 +823,27 @@ static void boids_mode(t_boids *x, t_floatarg f) /* ----------------------- pd objects general initialization ---------------- */ +static void boids_init_fields(t_boids *x, size_t dimensions) +{ + x->x_boid = NULL; + x->x_bounds = NULL; + x->x_params = NULL; + x->x_forces = NULL; + x->x_dimensions = vec_dimensions_clamp(dimensions); + x->x_num_boids = 0; + x->x_max_neighbors = 0; + x->x_mode = BOID_NEWPOS; + x->x_position_center.x = NULL; + x->x_position_center.x_dimensions = 0; + x->x_position_attract.x = NULL; + x->x_position_attract.x_dimensions = 0; +} + static void *boids_donew(t_boids *x, t_floatarg f, t_floatarg g) { x->x_out1 = outlet_new(&x->x_obj, gensym("list")); x->x_out2 = outlet_new(&x->x_obj, gensym("list")); - /* initial number of boids */ - boids_float(x, f ? f : 12.); + boids_float(x, f ? f : 12.0); boids_mode(x, g ? g : 0.0); return x; } @@ -805,38 +851,36 @@ static void *boids_donew(t_boids *x, t_floatarg f, t_floatarg g) static void *boids_new(t_floatarg f, t_floatarg g) { t_boids *x = (t_boids *)pd_new(boids_class); - x->x_dimensions = 2; // default to 2 dimensions + boids_init_fields(x, 2); return boids_donew(x, f, g); } -/* old creator for the boids2d object for backwards compatibility */ static void *boids2d_new(t_floatarg f, t_floatarg g) { t_boids *x = (t_boids *)pd_new(boids2d_class); - x->x_dimensions = 2; + boids_init_fields(x, 2); return boids_donew(x, f, g); } -/* old creator for the boids3d object for backwards compatibility */ static void *boids3d_new(t_floatarg f, t_floatarg g) { t_boids *x = (t_boids *)pd_new(boids3d_class); - x->x_dimensions = 3; + boids_init_fields(x, 3); return boids_donew(x, f, g); } void boids_setup(void) { const char *boids_names[3] = {"boids2d", "boids3d", "boids"}; - t_newmethod boids_newfun[3] = {(t_newmethod)boids2d_new, - (t_newmethod)boids3d_new, - (t_newmethod)boids_new}; + t_newmethod boids_newfun[3] = {boids_newmethod_cast(boids2d_new), + boids_newmethod_cast(boids3d_new), + boids_newmethod_cast(boids_new)}; t_class **boid_classes[3] = {&boids2d_class, &boids3d_class, &boids_class}; - for (int i = 0; i < 3; i++) + for (int i = 0; i < 3; ++i) { t_class *c = - class_new(gensym(boids_names[i]), (t_newmethod)boids_newfun[i], + class_new(gensym(boids_names[i]), boids_newfun[i], (t_method)boids_free, sizeof(t_boids), 0, A_DEFFLOAT, A_DEFFLOAT, A_NULL); @@ -879,11 +923,10 @@ void boids_setup(void) class_addmethod(c, (t_method)boids_position_attract, gensym("attractpt"), A_GIMME, A_NULL); class_addmethod(c, (t_method)boids_reset, gensym("reset"), A_NULL); - class_addmethod(c, (t_method)boids_init, gensym("init"), A_NULL); + class_addmethod(c, (t_method)boids_reinit, gensym("init"), A_NULL); class_addmethod(c, (t_method)boids_dump, gensym("dump"), A_NULL); } - /* add the dimensions method only to the new boids class */ class_addmethod(boids_class, (t_method)boids_dimensions, gensym("dimensions"), A_FLOAT, A_NULL); diff --git a/src/boids.h b/src/boids.h index 4ecd612..80b43ab 100644 --- a/src/boids.h +++ b/src/boids.h @@ -7,25 +7,15 @@ 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 */ #ifndef BOIDS_H #define BOIDS_H #include "boid_params.h" #include "m_pd.h" -#include "point.h" +#include "vec.h" #include -// constants #define kMaxLong 0xFFFFFFFF enum boid_output_mode @@ -39,64 +29,57 @@ enum boid_output_mode typedef struct _neighbor t_neighbor; typedef struct _boid t_boid; typedef struct _boids t_boids; -typedef struct _points t_points; +typedef struct _boid_forces t_boid_forces; -typedef struct _neighbor +struct _neighbor { t_neighbor *x_next; t_boid *x_boid; t_float x_distance; -} t_neighbor; +}; + +struct _boid +{ + t_boid *x_next; + t_boids *x_flock; + t_neighbor *x_neighbors; + t_vec_state x_position; + t_vec_state x_direction; + t_float x_speed; +}; -typedef struct _boid +struct _boid_forces { - t_boid *x_next; // pointer to the next boid - t_boids *x_flock; // pointer to the main boids "flock" parent structure - t_neighbor *x_neighbors; // list of neighbors - t_point x_position; // position in space - t_point x_direction; // direction vector (velocity) - t_float x_speed; // total speed of this boid -} t_boid; + t_vec x_avoid_neighbors; + t_vec x_avoid_walls; + t_vec x_go_attract; + t_vec x_go_center; + t_vec x_match_neighbors; +}; -/* a "flock" parent structure for all boids */ -typedef struct _boids +struct _boids { t_object x_obj; t_outlet *x_out1; t_outlet *x_out2; - /* temporary storage */ - t_boid *x_boid; // the list of boids belonging to this parent "flock" - t_float *x_bounds; // boundaries in which the boids move - t_boid_params *x_params; // parameters of this "flock" - - /* a set of points to use when calculating direction and velocity */ - t_points *x_points; - - /* general flock settings */ - t_point x_position_center; // center position for this "flock" - t_point x_position_attract; // attraction point for this "flock" - size_t x_dimensions; // number of spatial dimensions - size_t x_num_boids; // total number of boids - size_t x_max_neighbors; // max number of neighbors to look for + t_boid *x_boid; + t_float *x_bounds; + t_boid_params *x_params; + t_boid_forces *x_forces; + + t_vec x_position_center; + t_vec x_position_attract; + size_t x_dimensions; + size_t x_num_boids; + size_t x_max_neighbors; enum boid_output_mode x_mode; +}; -} t_boids; - -/* --------------------------- points structure ----------------------------- */ - -/* a set of points used by the boids algorithm to move the boids */ -typedef struct _points -{ - t_point *avoidNeighborVel; - t_point *avoidWallsVel; - t_point *goAttractVel; - t_point *goCenterVel; - t_point *matchNeighborVel; -} t_points; - -t_points *points_new(size_t dimensions); -void points_free(t_points *x); -void point_velocity(t_point *x, t_boid_params *p, t_points *pts); +t_boid_forces *boid_forces_new(size_t dimensions); +void boid_forces_free(t_boid_forces *x); +void boid_forces_clear(t_boid_forces *x); +void boid_direction_update(t_vec_state *direction, t_boid_params *params, + t_boid_forces *forces); #endif From 8ab201ad5536c1cf6b21418ac8d6c9ee9e110d0a Mon Sep 17 00:00:00 2001 From: fdch Date: Wed, 13 May 2026 16:23:51 +0200 Subject: [PATCH 13/19] create a boids params abstraction and add a helpfile --- help/boids-params-help.pd | 40 +++++ help/boids-params.pd | 362 ++++++++++++++++++++++++++++++-------- 2 files changed, 324 insertions(+), 78 deletions(-) create mode 100644 help/boids-params-help.pd diff --git a/help/boids-params-help.pd b/help/boids-params-help.pd new file mode 100644 index 0000000..ff27bb4 --- /dev/null +++ b/help/boids-params-help.pd @@ -0,0 +1,40 @@ +#N canvas 747 25 677 686 12; +#X text 263 38 Boids Parameters; +#X obj 82 259 boids-params \$0; +#A saved number 16; +#A saved neighbors 4; +#A saved maxspeed 1.47; +#A saved minspeed 1.2; +#A saved center 1.21; +#A saved attract 1.25; +#A saved match 0.3; +#A saved avoid 3.32; +#A saved repel 3.5; +#A saved edgedist 3.03; +#A saved speed 0.560001; +#A saved inertia 4.5; +#A saved accel 2.5; +#A saved prefdist 1.5; +#X text 331 296 <-- right-click open to se more info; +#X text 78 81 All available 14 parameters can be set using this abstraction. The parameters are stored after saving the main patch and can be reset to default with the "defaults" bang.; +#X obj 356 369 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 356 454 boids; +#X obj 388 488 print dump; +#X obj 356 522 route 0; +#X listbox 356 547 20 0 0 0 - - - 0; +#X obj 356 401 metro 10; +#X obj 445 371 r \$0-boids-params; +#X obj 445 398 list trim; +#X listbox 82 536 20 0 0 0 - - - 0; +#X text 78 143 To use the parameters \, connect and trim the list outlet to the [boids] object or receive with a trimmed [r \$0-boids-params].; +#X text 79 201 Note the \$0 as first argument \, which is simply a number to identify this unique set of parameters.; +#X text 78 599 To write or read parameters from disk \, send \$1-parameters the usual "write" or "read" you would send to [text]; +#X connect 1 0 12 0; +#X connect 4 0 9 0; +#X connect 5 0 7 0; +#X connect 5 1 6 0; +#X connect 7 0 8 0; +#X connect 9 0 5 0; +#X connect 10 0 11 0; +#X connect 11 0 5 0; +#X coords 0 686 1 685 230 270 0; diff --git a/help/boids-params.pd b/help/boids-params.pd index 903f90a..43d152c 100644 --- a/help/boids-params.pd +++ b/help/boids-params.pd @@ -1,82 +1,288 @@ -#N canvas 787 227 856 738 12; -#X msg 258 167 neighbors \$1; -#X floatatom 213 148 5 0 4 0 - \$1-neighbors - 0; -#X floatatom 213 183 5 0 0 0 - \$1-maxspeed - 0; -#X msg 258 202 maxspeed \$1; -#X floatatom 213 218 5 0 0 0 - \$1-minspeed - 0; -#X msg 258 237 minspeed \$1; -#X floatatom 213 253 5 0 0 0 - \$1-center - 0; -#X msg 258 272 center \$1; -#X floatatom 213 288 5 0 0 0 - \$1-attract - 0; -#X msg 258 307 attract \$1; -#X floatatom 213 323 5 0 0 0 - \$1-match - 0; -#X msg 258 342 match \$1; -#X floatatom 213 358 5 0 0 0 - \$1-avoid - 0; -#X msg 258 377 avoid \$1; -#X floatatom 213 393 5 0 0 0 - \$1-repel - 0; -#X msg 258 412 repel \$1; -#X floatatom 213 428 5 0 0 0 - \$1-edgedist - 0; -#X msg 258 447 edgedist \$1; -#X floatatom 213 463 5 0 0 0 - \$1-speed - 0; -#X msg 258 482 speed \$1; -#X floatatom 213 498 5 0 0 0 - \$1-inertia - 0; -#X msg 258 517 inertia \$1; -#X floatatom 213 533 5 0 0 0 - \$1-accel - 0; -#X msg 258 552 accel \$1; -#X floatatom 213 568 5 0 0 0 - \$1-prefdist - 0; -#X msg 258 587 prefdist \$1; -#X text 349 202 maximum speed of speed range; -#X text 351 236 minimum speed of speed range; -#X text 348 271 strength of centering instinct; -#X text 350 482 overall speed; -#X text 351 553 speed of acceleration; -#X text 351 584 preferred distance from neighbors; -#X floatatom 213 113 5 0 0 0 - \$1-number - 0; -#X msg 258 132 number \$1; -#X text 337 133 number of boids; -#X text 349 165 number of neighbors each boid consults when flocking; -#X text 348 342 strength of neighbor speed matching instinct; -#X text 348 377 strength of neighbor avoidance instinct; -#X text 348 409 strength of wall avoidance instinct; -#X text 350 445 distance of vision for avoiding wall edges; -#X text 351 516 willingness to change speed and direction; -#X text 347 305 strength of attraction to 'attractpt'; -#X text 400 20 Boids Parameters; -#X obj 51 180 list prepend \$1; -#X msg 51 213 \; \$1-number 16 \; \$1-neighbors 4 \; \$1-maxspeed 1.5 \; \$1-minspeed 1.2 \; \$1-center 1.2 \; \$1-attract 1.25 \; \$1-match 0.3 \; \$1-avoid 3.5 \; \$1-repel 3.5 \; \$1-edgedist 3 \; \$1-speed 3 \; \$1-inertia 4.5 \; \$1-accel 2.5 \; \$1-prefdist 1.5, f 17; -#X obj 55 102 r \$1-reset; -#X obj 53 132 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; -#X text 82 135 defaults; -#X obj 258 620 s \$1-boids-params; -#X text 246 38 Here are all parameters you can send to the boids external. Their defaults are on the left-most message. You can also get the defaults by sending a "dump" message before changing them; -#X connect 0 0 48 0; -#X connect 1 0 0 0; -#X connect 2 0 3 0; -#X connect 3 0 48 0; +#N canvas 74 74 1255 607 12; +#X text 487 26 Boids Parameters; +#N canvas 112 25 779 393 glue 0; +#X obj 48 57 r \$1-number; +#X obj 48 107 s \$1-boids-params; +#X obj 48 82 list prepend number; +#X obj 219 57 r \$1-neighbors; +#X obj 219 107 s \$1-boids-params; +#X obj 219 82 list prepend neighbors; +#X obj 387 57 r \$1-inertia; +#X obj 387 107 s \$1-boids-params; +#X obj 387 82 list prepend inertia; +#X obj 558 57 r \$1-speed; +#X obj 558 107 s \$1-boids-params; +#X obj 558 82 list prepend speed; +#X obj 47 135 r \$1-maxspeed; +#X obj 47 185 s \$1-boids-params; +#X obj 47 160 list prepend maxspeed; +#X obj 218 135 r \$1-minspeed; +#X obj 218 185 s \$1-boids-params; +#X obj 218 160 list prepend minspeed; +#X obj 388 140 r \$1-accel; +#X obj 388 190 s \$1-boids-params; +#X obj 388 165 list prepend accel; +#X obj 559 140 r \$1-match; +#X obj 559 190 s \$1-boids-params; +#X obj 559 165 list prepend match; +#X obj 46 218 r \$1-avoid; +#X obj 46 268 s \$1-boids-params; +#X obj 46 243 list prepend avoid; +#X obj 217 218 r \$1-repel; +#X obj 217 268 s \$1-boids-params; +#X obj 217 243 list prepend repel; +#X obj 385 218 r \$1-edgedist; +#X obj 385 268 s \$1-boids-params; +#X obj 385 243 list prepend edgedist; +#X obj 556 218 r \$1-prefdist; +#X obj 556 268 s \$1-boids-params; +#X obj 556 243 list prepend prefdist; +#X obj 45 296 r \$1-center; +#X obj 45 346 s \$1-boids-params; +#X obj 45 321 list prepend center; +#X obj 216 296 r \$1-attract; +#X obj 216 346 s \$1-boids-params; +#X obj 216 321 list prepend attract; +#X text 55 22 prepend the parameter name to the parameter values and send them to the global receiver, f 88; +#N canvas 192 66 1405 689 flyrect-dimensions 0; +#X obj 352 423 * -1; +#X obj 352 448 pack; +#X obj 55 109 r \$1-dimensions; +#X msg 353 243 symbol flyrect; +#X obj 353 268 text search \$1-parameters; +#X obj 353 293 sel -1; +#X msg 353 318 1; +#X obj 392 317 text get \$1-parameters; +#X obj 352 374 abs; +#X obj 124 523 list store, f 16; +#X obj 124 442 until; +#X obj 124 469 list; +#X msg 124 494 append \$1 \$2; +#X obj 78 417 t b f; +#X obj 124 549 t a b; +#X obj 124 574 list prepend flyrect; +#X obj 83 639 s \$1-boids-params; +#X obj 55 166 t f f b; +#X obj 392 343 list split 1; +#X obj 432 368 list split 1; +#X obj 55 606 list prepend dimensions; +#X text 176 548 -bound \, +bound \, -bound \, +bound \, etc; +#X text 32 60 bounds is interpreted as a pair -bound \, +bound per dimension to build the flying rectangle (or cube \, etc) \, so they are interlinked with dimensions, f 77; +#X text 184 16 Special treatment for dimensions and bounds (flyrect); +#X listbox 106 138 20 0 0 0 - - - 0; +#X listbox 354 479 20 0 0 0 - - - 0; +#X obj 134 268 text search \$1-parameters; +#X obj 134 293 sel -1; +#X obj 173 317 text get \$1-parameters; +#X obj 173 343 list split 1; +#X msg 134 243 symbol dimensions; +#X msg 134 318 2; +#X obj 571 244 list split 1; +#X obj 339 119 r \$1-bounds; +#X obj 353 350 t f; +#X obj 353 215 sel 0; +#X obj 353 190 f 0; +#X obj 352 398 t f f f; +#X obj 398 452 s \$1-bounds-set; +#X obj 55 138 max 1; +#X obj 137 391 s \$1-dimensions; +#X obj 337 143 t b f; +#X msg 407 427 set \$1; +#X floatatom 399 182 5 0 0 0 - - - 0; +#X floatatom 508 406 5 0 0 0 - - - 0; +#X obj 571 219 r \$1-flyrect-set; +#X obj 571 269 abs; +#X obj 571 294 s \$1-bounds-set; +#X connect 0 0 1 0; +#X connect 1 0 11 1; +#X connect 1 0 25 0; +#X connect 2 0 39 0; +#X connect 3 0 4 0; #X connect 4 0 5 0; -#X connect 5 0 48 0; -#X connect 6 0 7 0; -#X connect 7 0 48 0; -#X connect 8 0 9 0; -#X connect 9 0 48 0; +#X connect 5 0 6 0; +#X connect 5 1 7 0; +#X connect 6 0 34 0; +#X connect 7 0 18 0; +#X connect 8 0 37 0; +#X connect 9 0 14 0; #X connect 10 0 11 0; -#X connect 11 0 48 0; -#X connect 12 0 13 0; -#X connect 13 0 48 0; +#X connect 11 0 12 0; +#X connect 12 0 9 0; +#X connect 13 0 9 0; +#X connect 13 1 10 0; #X connect 14 0 15 0; -#X connect 15 0 48 0; -#X connect 16 0 17 0; -#X connect 17 0 48 0; -#X connect 18 0 19 0; -#X connect 19 0 48 0; -#X connect 20 0 21 0; -#X connect 21 0 48 0; -#X connect 22 0 23 0; -#X connect 23 0 48 0; -#X connect 24 0 25 0; -#X connect 25 0 48 0; -#X connect 32 0 33 0; -#X connect 33 0 48 0; -#X connect 43 0 44 0; +#X connect 14 1 9 1; +#X connect 15 0 16 0; +#X connect 17 0 20 0; +#X connect 17 1 13 0; +#X connect 17 2 36 0; +#X connect 18 1 19 0; +#X connect 19 0 34 0; +#X connect 19 0 44 0; +#X connect 20 0 16 0; +#X connect 26 0 27 0; +#X connect 27 0 31 0; +#X connect 27 1 28 0; +#X connect 28 0 29 0; +#X connect 29 1 40 0; +#X connect 30 0 26 0; +#X connect 31 0 40 0; +#X connect 32 0 46 0; +#X connect 33 0 41 0; +#X connect 34 0 8 0; +#X connect 35 0 3 0; +#X connect 35 1 34 0; +#X connect 36 0 35 0; +#X connect 37 0 0 0; +#X connect 37 1 1 1; +#X connect 37 2 42 0; +#X connect 39 0 17 0; +#X connect 39 0 24 0; +#X connect 41 0 30 0; +#X connect 41 1 36 1; +#X connect 41 1 43 0; +#X connect 42 0 38 0; +#X connect 45 0 32 0; +#X connect 46 0 47 0; +#X restore 476 327 pd flyrect-dimensions; +#X connect 0 0 2 0; +#X connect 2 0 1 0; +#X connect 3 0 5 0; +#X connect 5 0 4 0; +#X connect 6 0 8 0; +#X connect 8 0 7 0; +#X connect 9 0 11 0; +#X connect 11 0 10 0; +#X connect 12 0 14 0; +#X connect 14 0 13 0; +#X connect 15 0 17 0; +#X connect 17 0 16 0; +#X connect 18 0 20 0; +#X connect 20 0 19 0; +#X connect 21 0 23 0; +#X connect 23 0 22 0; +#X connect 24 0 26 0; +#X connect 26 0 25 0; +#X connect 27 0 29 0; +#X connect 29 0 28 0; +#X connect 30 0 32 0; +#X connect 32 0 31 0; +#X connect 33 0 35 0; +#X connect 35 0 34 0; +#X connect 36 0 38 0; +#X connect 38 0 37 0; +#X connect 39 0 41 0; +#X connect 41 0 40 0; +#X restore 841 95 pd glue; +#X obj 104 451 r \$1-boids-params; +#X obj 105 479 outlet; +#N canvas 0 0 577 425 defaults 0; +#X obj 108 113 list prepend \$1; +#X obj 112 82 r \$1-defaults; +#X msg 103 139 \; \$1-dimensions-set 2 \; \$1-number-set 16 \; \$1-neighbors-set 4 \; \$1-maxspeed-set 1.5 \; \$1-minspeed-set 1.2 \; \$1-center-set 1.2 \; \$1-attract-set 1.25 \; \$1-match-set 0.3 \; \$1-avoid-set 3.5 \; \$1-repel-set 3.5 \; \$1-edgedist-set 3 \; \$1-speed-set 3 \; \$1-inertia-set 4.5 \; \$1-accel-set 2.5 \; \$1-prefdist-set 1.5 \; \$1-bounds-set 1 \;, f 36; +#X text 62 27 keep a list of default parameter values reflecting the internal initial state of the object; +#X connect 0 0 2 0; +#X connect 1 0 0 0; +#X restore 841 128 pd defaults; +#N canvas 133 208 1066 594 storage 0; +#X obj 646 299 savestate; +#X obj 68 187 r \$1-boids-params; +#X obj 65 239 list split 1; +#X obj 73 339 text search \$1-parameters; +#X obj 135 446 text set \$1-parameters 0 1; +#X obj 73 368 sel -1; +#X obj 139 392 t b f; +#X obj 731 337 text sequence \$1-parameters; +#X msg 732 309 line 0 \, auto; +#X obj 66 214 t a a; +#X obj 71 408 list; +#X obj 72 445 t a b; +#X msg 100 481 1e+10; +#X obj 66 506 text set \$1-parameters; +#X obj 137 421 list; +#X obj 535 208 text sequence \$1-parameters; +#X msg 536 180 line 0 \, auto; +#X obj 538 150 r \$1-output; +#X obj 532 355 t a a; +#X obj 589 420 list split 1; +#X obj 532 389 list split 1; +#X obj 571 485 s; +#X obj 589 445 makefilename \$1-%s-set; +#X text 533 96 this updates the number boxes with the stored parameters in the text (and subsequently outputs the parameters); +#X text 636 257 this saves the parameter text when saving the main patch (outputs it on load); +#X text 28 288 if the param is already in the text \, update it. Otherwise \, we create a new line for that parameter, f 51; +#X text 30 87 store the parameters on the text on a dictionary: a single line per parameter \, with the prepended parameter name and the values in the subsequent fields; +#X text 537 44 retrieval; +#X text 31 36 storage; +#X connect 0 0 18 0; +#X connect 0 1 8 0; +#X connect 1 0 9 0; +#X connect 2 0 3 0; +#X connect 2 1 14 1; +#X connect 3 0 5 0; +#X connect 5 0 10 0; +#X connect 5 1 6 0; +#X connect 6 0 14 0; +#X connect 6 1 4 1; +#X connect 7 0 0 0; +#X connect 8 0 7 0; +#X connect 9 0 2 0; +#X connect 9 1 10 1; +#X connect 10 0 11 0; +#X connect 11 0 13 0; +#X connect 11 1 12 0; +#X connect 12 0 13 1; +#X connect 14 0 4 0; +#X connect 15 0 18 0; +#X connect 16 0 15 0; +#X connect 17 0 16 0; +#X connect 18 0 20 0; +#X connect 18 1 19 0; +#X connect 19 0 22 0; +#X connect 20 1 21 0; +#X connect 22 0 21 1; +#X restore 841 64 pd storage; +#X text 399 178 FLOCK PARAMETERS -----------------------------; +#X text 787 179 NEIGHBORS -----------------------------; +#X text 404 347 BOID MOVEMENT -----------------------------; +#X text 786 397 WALL BEHAVIOR -----------------------------; +#X obj 184 134 nbx 5 18 -1e+37 1e+37 0 0 \$1-number \$1-number-set number 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 184 174 nbx 5 18 -1e+37 1e+37 0 0 \$1-center \$1-center-set center 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 109 174 nbx 5 18 -1e+37 1e+37 0 0 \$1-attract \$1-attract-set attract 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 259 213 nbx 5 18 -1e+37 1e+37 0 0 \$1-prefdist \$1-prefdist-set prefdist 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 259 134 nbx 5 18 -1e+37 1e+37 0 0 \$1-neighbors \$1-neighbors-set neighbors 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 109 213 nbx 5 18 -1e+37 1e+37 0 0 \$1-match \$1-match-set match 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 184 213 nbx 5 18 -1e+37 1e+37 0 0 \$1-avoid \$1-avoid-set avoid 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 259 252 nbx 5 18 -1e+37 1e+37 0 0 \$1-maxspeed \$1-maxspeed-set maxspeed 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 109 252 nbx 5 18 -1e+37 1e+37 0 0 \$1-speed \$1-speed-set speed 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 109 291 nbx 5 18 -1e+37 1e+37 0 0 \$1-inertia \$1-inertia-set inertia 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 184 291 nbx 5 18 -1e+37 1e+37 0 0 \$1-accel \$1-accel-set accel 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 184 252 nbx 5 18 -1e+37 1e+37 0 0 \$1-minspeed \$1-minspeed-set minspeed 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 184 330 nbx 5 18 -1e+37 1e+37 0 0 \$1-repel \$1-repel-set repel 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 109 330 nbx 5 18 -1e+37 1e+37 0 0 \$1-edgedist \$1-edgedist-set edgedist 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X text 393 60 Here are all parameters you can send to the boids external. You can also get the defaults by sending a "dump" message before changing them; +#X obj 259 291 bng 20 250 50 0 \$1-defaults \$1-defaults defaults 0 -10 0 12 #fcfcfc #000000 #000000; +#X obj 259 330 bng 20 250 50 0 \$1-output \$1-output output 0 -10 0 12 #fcfcfc #000000 #000000; +#X obj 109 134 nbx 5 18 -1e+37 1e+37 0 0 \$1-dimensions \$1-dimensions-set dimensions 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 260 174 nbx 5 18 -1e+37 1e+37 0 0 \$1-bounds \$1-bounds-set bounds 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X text 395 215 number: number of boids; +#X text 393 294 center: strength of centering instinct; +#X text 395 252 attractpt: strength of attraction to 'attractpt'; +#X text 404 389 inertia: willingness to change speed and direction; +#X text 403 431 speed: overall speed; +#X text 404 473 min/max speed: speed range; +#X text 406 515 accel: speed of acceleration; +#X text 799 219 neighbors: number of neighbors each boid consults when flocking; +#X text 793 266 match: strength of neighbor speed matching instinct; +#X text 789 308 avoid: strength of neighbor avoidance instinct; +#X text 796 350 prefdist: preferred distance from neighbors; +#X text 794 438 edgedist: distance of vision for avoiding wall edges; +#X text 791 481 repel: strength of wall avoidance instinct; +#X text 789 522 bounds: size of the equally space bounding box as in: -bound +bound \, one pair per dimension, f 45; +#X text 397 132 dimensions: number of dimensions: 1 \, 2 \, 3 \, ...; +#X obj 983 67 text define \$1-parameters; +#X obj 103 387 loadbang; +#X obj 103 412 s \$1-output; +#X connect 2 0 3 0; #X connect 45 0 46 0; -#X connect 46 0 43 0; +#X coords 0 -1 1 1 230 270 1 100 100; From 31158c0d093bf74badfc81597140bc04a7d6218b Mon Sep 17 00:00:00 2001 From: fdch Date: Wed, 13 May 2026 16:24:09 +0200 Subject: [PATCH 14/19] modify examples and fix them --- examples/boids-gem.pd | 604 ++++++++++++++++++++++++--------------- examples/boids-struct.pd | 272 +++++++++--------- examples/gemboid.pd | 147 ++++------ examples/point.pd | 81 +++--- examples/struct-boid.pd | 144 ++++------ 5 files changed, 661 insertions(+), 587 deletions(-) diff --git a/examples/boids-gem.pd b/examples/boids-gem.pd index d0e526d..736bdbf 100644 --- a/examples/boids-gem.pd +++ b/examples/boids-gem.pd @@ -1,6 +1,6 @@ -#N canvas 854 293 711 590 12; +#N canvas 741 52 738 578 12; #X declare -lib Gem; -#X msg 100 40 destroy; +#X msg 100 40 create; #N canvas 803 136 629 324 gemwin 0; #X obj 209 190 gemwin; #X obj 67 194 outlet; @@ -27,256 +27,398 @@ #X connect 9 0 10 0; #X connect 11 0 0 0; #X restore 100 60 pd gemwin; -#N canvas 850 212 692 479 orbit 0; -#X obj 63 290 translateXYZ; -#X obj 69 109 color 1 0.5 0 0.5; -#X obj 72 136 t a b; -#X obj 99 260 unpack f f f; -#X obj 402 108 color 1 0.5 0 0.5; -#X obj 416 337 loadbang; -#X obj 59 339 sphere 0.1; -#X obj 402 80 gemhead 58; -#X msg 416 364 draw line; -#X obj 396 302 translateXYZ; -#X obj 436 274 unpack f f f; -#X obj 400 215 translate -4 0 0 1; -#X obj 462 189 * -8; -#X obj 435 244 r \$0-orbit-translation; -#N canvas 0 0 782 606 orbit-translation 0; -#X obj 66 169 expr $f1 * (3.141593/180.); -#X msg 69 217 1.5 \$1; -#X obj 127 268 t f f; -#X obj 124 296 cos; -#X obj 158 294 sin; -#X obj 77 319 * 1; -#X obj 67 267 t f f; -#X obj 108 319 * 0; -#X obj 66 141 f; -#X obj 94 142 + 1; -#X obj 125 142 mod 360; -#X obj 64 241 unpack; -#X obj 66 193 t f f; -#X obj 252 381 pack f f f; -#X obj 192 318 * 2; -#X obj 191 292 sin; -#X obj 58 76 spigot 1; -#X obj 251 45 route float bang; -#X obj 488 130 spigot; -#X obj 542 130 spigot; -#X obj 548 76 t f f; -#X obj 517 35 gemmouse 1 1; +#N canvas 319 40 953 920 orbit 0; +#X obj 97 624 translateXYZ; +#X obj 83 334 t a b; +#X obj 668 260 color 1 0.5 0 0.5; +#X obj 690 297 loadbang; +#X obj 668 232 gemhead 58; +#X msg 690 324 draw line; +#X obj 89 277 gemhead; +#X obj 89 48 inlet; +#X obj 674 405 cube 4; +#X obj 84 249 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 81 108 sel 0; +#X obj 720 374 r \$0-bounds; +#X msg 81 133 0 0 0; +#X obj 661 163 r \$0-vis-bounds; +#X obj 822 161 loadbang; +#X msg 822 186 0; +#X obj 329 27 help/boids-params \$0-2; +#A saved flyrect -2 2 -2 2; +#A saved dimensions 3; +#A saved number 3; +#A saved neighbors 2; +#A saved speed 2; +#A saved minspeed 4; +#A saved maxspeed 19; +#A saved inertia 1.08; +#A saved accel 1.29; +#A saved edgedist 2; +#A saved repel 5; +#A saved match 0.31; +#A saved avoid 1.39; +#A saved attract -1.84; +#A saved center 0.460001; +#A saved prefdist 5; +#X obj 338 311 list trim; +#X obj 674 849 pack f f f; +#X obj 646 578 spigot; +#X obj 700 578 spigot; +#X obj 706 524 t f f; +#X obj 675 483 gemmouse 1 1; #A saved init; -#X obj 494 170 * 8; -#X obj 494 193 - 4; -#X obj 540 235 - 4; -#X text 566 184 invert y; -#X obj 540 212 * 8; -#X msg 540 153 1 \$1; -#X obj 540 177 -; -#X obj 647 232 spigot; -#X obj 647 257 t b f; -#X obj 556 104 t f f; -#X obj 651 184 * 8; -#X obj 652 206 - 4; -#X obj 250 471 s \$0-orbit-translation; -#X obj 265 14 inlet; -#X obj 55 10 inlet; -#X floatatom 77 344 5 0 0 0 - - - 0; -#X obj 300 82 random 360; -#X text 239 112 random position; -#X text 70 107 move in orbit; -#X text 497 11 mouse interaction; -#X text 591 321 middle click to enable Z motion (up/down), f 19; -#X connect 0 0 12 0; -#X connect 1 0 11 0; -#X connect 2 0 3 0; -#X connect 2 1 4 0; -#X connect 3 0 5 1; -#X connect 4 0 7 1; -#X connect 5 0 13 0; -#X connect 5 0 37 0; -#X connect 6 0 5 0; -#X connect 6 1 7 0; -#X connect 7 0 13 1; -#X connect 8 0 9 0; -#X connect 8 0 0 0; -#X connect 9 0 10 0; -#X connect 10 0 8 1; -#X connect 11 0 6 0; -#X connect 11 1 2 0; -#X connect 12 0 1 0; -#X connect 12 1 15 0; -#X connect 13 0 34 0; -#X connect 14 0 13 2; -#X connect 15 0 14 0; -#X connect 16 0 8 0; -#X connect 17 0 16 1; -#X connect 17 1 38 0; -#X connect 18 0 22 0; -#X connect 19 0 27 0; -#X connect 20 0 18 1; -#X connect 20 1 19 1; -#X connect 21 0 18 0; -#X connect 21 1 31 0; -#X connect 21 2 20 0; -#X connect 21 3 29 1; -#X connect 22 0 23 0; -#X connect 23 0 13 0; -#X connect 24 0 13 1; -#X connect 26 0 24 0; -#X connect 27 0 28 0; -#X connect 28 0 26 0; -#X connect 29 0 30 0; -#X connect 30 0 13 0; -#X connect 30 1 13 2; -#X connect 31 0 19 0; -#X connect 31 1 32 0; -#X connect 32 0 33 0; -#X connect 33 0 29 0; -#X connect 35 0 17 0; -#X connect 36 0 16 0; -#X connect 38 0 8 0; -#X restore 102 166 pd orbit-translation; -#X obj 103 229 r \$0-orbit-translation; -#X text 76 49 a circle; -#X obj 68 82 gemhead; -#X text 423 51 a bounding box; -#X obj 236 18 inlet; -#X obj 462 162 * 0.5; -#X obj 498 378 * 4; -#X obj 397 399 cube 4; -#X obj 504 341 r \$0-bounding-box; -#X obj 463 135 r \$0-bounding-box; -#X obj 46 28 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; -#X obj 383 29 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; -#X connect 0 0 6 0; -#X connect 1 0 2 0; -#X connect 2 0 0 0; -#X connect 2 1 14 0; -#X connect 3 0 0 1; -#X connect 3 1 0 2; -#X connect 3 2 0 3; -#X connect 4 0 11 0; +#X obj 652 618 * 8; +#X obj 652 641 - 4; +#X obj 698 683 - 4; +#X text 724 632 invert y; +#X obj 698 660 * 8; +#X msg 698 601 1 \$1; +#X obj 698 625 -; +#X obj 805 680 spigot; +#X obj 805 705 t b f; +#X obj 714 552 t f f; +#X obj 809 632 * 8; +#X obj 810 654 - 4; +#X obj 673 875 s \$0-orbit-translation; +#X text 655 459 mouse interaction; +#X text 749 769 middle click to enable Z motion (up/down), f 19; +#X obj 235 451 route 0; +#X obj 233 512 s \$0-orbit-translation; +#X obj 239 423 boids; +#X obj 385 412 r \$0-mass-center; +#X msg 385 437 attractpt \$1 \$2 \$3; +#X obj 567 35 r \$0-bounds; +#X obj 567 60 s \$0-2-bounds-set; +#X msg 383 370 mode 2; +#X obj 128 581 unpack f f f; +#X obj 236 482 list split 3; +#X obj 309 655 list split 3; +#X obj 230 731 rotateXYZ; +#X obj 303 690 unpack f f f; +#X obj 219 772 sphere 0.3 3; +#X obj 374 347 loadbang; +#X obj 201 381 spigot 1; +#X obj 85 74 t f f; +#X obj 144 555 r \$0-orbit-translation; +#X obj 81 159 s \$0-orbit-translation; +#X text 676 99 see the bounding box; +#X text 80 213 move like a pray; +#X text 425 471 this boids has an attract point which is the mass center of the other flock. also \, the attract weight is set to negative \, so that it rejects this attract point whenever it can. Thus \, it may behave like a pray, f 18; +#X obj 90 304 color 1 0 0; +#X connect 0 0 49 0; +#X connect 1 0 0 0; +#X connect 1 1 53 0; +#X connect 2 0 8 0; +#X connect 3 0 5 0; +#X connect 4 0 2 0; #X connect 5 0 8 0; -#X connect 7 0 4 0; -#X connect 8 0 22 0; -#X connect 9 0 22 0; -#X connect 10 0 9 1; -#X connect 10 1 9 2; -#X connect 10 2 9 3; -#X connect 11 0 9 0; -#X connect 12 0 11 1; -#X connect 13 0 10 0; -#X connect 15 0 3 0; -#X connect 17 0 1 0; -#X connect 19 0 14 1; -#X connect 20 0 12 0; -#X connect 21 0 22 1; -#X connect 23 0 21 0; -#X connect 24 0 20 0; -#X connect 25 0 17 0; -#X connect 26 0 7 0; +#X connect 6 0 60 0; +#X connect 7 0 54 0; +#X connect 9 0 6 0; +#X connect 10 0 12 0; +#X connect 11 0 8 1; +#X connect 12 0 56 0; +#X connect 13 0 4 0; +#X connect 14 0 15 0; +#X connect 15 0 4 0; +#X connect 16 0 17 0; +#X connect 17 0 40 0; +#X connect 18 0 35 0; +#X connect 19 0 23 0; +#X connect 20 0 28 0; +#X connect 21 0 19 1; +#X connect 21 1 20 1; +#X connect 22 0 19 0; +#X connect 22 1 32 0; +#X connect 22 2 21 0; +#X connect 22 3 30 1; +#X connect 23 0 24 0; +#X connect 24 0 18 0; +#X connect 25 0 18 1; +#X connect 27 0 25 0; +#X connect 28 0 29 0; +#X connect 29 0 27 0; +#X connect 30 0 31 0; +#X connect 31 0 18 0; +#X connect 31 1 18 2; +#X connect 32 0 20 0; +#X connect 32 1 33 0; +#X connect 33 0 34 0; +#X connect 34 0 30 0; +#X connect 38 0 47 0; +#X connect 40 0 38 0; +#X connect 41 0 42 0; +#X connect 42 0 40 0; +#X connect 43 0 44 0; +#X connect 45 0 40 0; +#X connect 46 0 0 1; +#X connect 46 1 0 2; +#X connect 46 2 0 3; +#X connect 47 0 39 0; +#X connect 47 1 48 0; +#X connect 48 1 50 0; +#X connect 49 0 51 0; +#X connect 50 1 49 1; +#X connect 50 2 49 3; +#X connect 52 0 45 0; +#X connect 53 0 40 0; +#X connect 54 0 10 0; +#X connect 54 1 53 1; +#X connect 55 0 46 0; +#X connect 60 0 1 0; #X restore 347 236 pd orbit; #X obj 35 210 tgl 20 1 empty empty start\ flocking\ animation 0 -10 0 12 #fcfcfc #000000 #000000 1 1; #X text 23 18 create/destroy the GEM window; #X obj 349 24 declare -lib Gem; -#X obj 92 128 help/boids-params \$0; +#X obj 345 288 help/boids-params \$0; +#A saved flyrect -2 2 -2 2; +#A saved dimensions 3; +#A saved number 16; +#A saved neighbors 4; +#A saved maxspeed 12.99; +#A saved minspeed 2.42; +#A saved center 0.520001; +#A saved attract 0.860001; +#A saved match 0.420001; +#A saved avoid 1.3; +#A saved repel 0.670002; +#A saved edgedist 0.36; +#A saved speed 2.3; +#A saved inertia 0.78; +#A saved accel 0.640001; +#A saved prefdist 2.3; #X obj 590 26 loadbang; #X obj 590 51 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; #X obj 590 76 s \$0-reset; -#X msg 132 348 reset; -#X obj 142 400 r \$0-boids-params; -#X msg 137 373 dump; +#X msg 73 348 reset; +#X obj 198 366 r \$0-boids-params; +#X msg 78 373 dump; #X obj 103 459 print dump; #X text 25 102 Change parameters to see their effect:; #X floatatom 93 222 5 0 0 0 - - - 0; #X obj 35 248 metro 25; #X text 134 222 animation speed; -#X floatatom 395 312 5 0 2 0 - \$0-bounding-box-set \$0-bounding-box 0; -#X msg 74 319 attractpt \$1 \$2 \$3; -#X floatatom 364 383 5 0 0 0 left \$0-flyrect0 - 0; -#X floatatom 406 367 5 0 0 0 top \$0-flyrect1 - 0; -#X floatatom 459 389 5 0 0 0 right \$0-flyrect2 - 0; -#X floatatom 508 407 5 0 0 0 bottom \$0-flyrect3 - 0; -#N canvas 0 0 632 412 3D-bounding-box 0; -#X obj 58 181 s \$0-boids-params; -#X obj 365 210 list prepend \$0; -#X obj 349 25 r \$0-reset; -#X obj 29 27 inlet; -#X obj 74 29 inlet; -#X obj 119 29 inlet; -#X obj 170 29 inlet; -#X obj 41 76 pack f f f f f f; -#X obj 219 30 inlet; -#X obj 270 30 inlet; -#X msg 58 156 flyrect \$1 \$2 \$3 \$4 \$5 \$6; -#X obj 434 64 abs; -#X obj 372 102 t f f; -#X obj 372 127 * -1; -#X obj 372 152 pack; -#X msg 372 176 \$1 \$2 \$2 \$1 \$2 \$1; -#X obj 447 36 r \$0-bounding-box; -#X msg 349 50 1; -#X msg 365 235 \; \$1-flyrect0 \$2 \; \$1-flyrect1 \$3 \; \$1-flyrect2 \$4 \; \$1-flyrect3 \$5 \; \$1-flyrect4 \$6 \; \$1-flyrect5 \$7 \; \$1-bounding-box-set set \$3; -#X connect 1 0 18 0; -#X connect 2 0 17 0; -#X connect 3 0 7 0; -#X connect 4 0 7 1; -#X connect 5 0 7 2; -#X connect 6 0 7 3; -#X connect 7 0 10 0; -#X connect 8 0 7 4; -#X connect 9 0 7 5; -#X connect 10 0 0 0; -#X connect 11 0 12 0; -#X connect 12 0 13 0; -#X connect 12 1 14 1; -#X connect 13 0 14 0; -#X connect 14 0 15 0; -#X connect 15 0 1 0; -#X connect 16 0 11 0; -#X connect 17 0 12 0; -#X restore 381 462 pd 3D-bounding-box; -#X f 23; -#X floatatom 587 406 5 0 0 0 front \$0-flyrect4 - 0; -#X floatatom 589 430 5 0 0 0 back \$0-flyrect5 - 0; -#X obj 347 172 tgl 20 1 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; -#X obj 357 200 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; -#X obj 76 290 r \$0-orbit-translation; +#X msg 52 313 attractpt \$1 \$2 \$3; +#X obj 347 172 tgl 20 1 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 1 1; +#X obj 52 287 r \$0-orbit-translation; #X text 413 223 or click+drag for XY; #X text 412 236 and middle-click to move Z; #X text 339 133 ATTRACTION POINT, f 17; -#X text 381 199 random in orbit; -#X text 350 285 BOUNDING BOX; -#X text 371 172 move in an orbit; -#X text 437 313 (shift + drag 0..2); #X obj 35 489 clone -x gemboid 16 \$0 1; -#X msg 238 342 mode 2; -#X obj 253 279 loadbang; -#X msg 253 304 dimensions 3; -#X obj 35 433 boids 16; +#X obj 226 279 loadbang; +#X obj 198 392 list trim; +#X floatatom 591 411 5 0 0 0 - - - 0; +#X obj 592 466 s \$0-size; +#X obj 591 438 / 100; +#X obj 593 497 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 593 522 s \$0-vis-bounds; +#N canvas 404 138 622 848 flock 0; +#X obj 96 29 inlet; +#X obj 96 54 route 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; +#X obj 96 79 unpack f f f; +#X obj 113 106 unpack f f f; +#X obj 143 136 unpack f f f; +#X obj 160 163 unpack f f f; +#X obj 191 192 unpack f f f; +#X obj 208 219 unpack f f f; +#X obj 238 249 unpack f f f; +#X obj 255 276 unpack f f f; +#X obj 291 312 unpack f f f; +#X obj 308 339 unpack f f f; +#X obj 338 369 unpack f f f; +#X obj 355 396 unpack f f f; +#X obj 386 425 unpack f f f; +#X obj 403 452 unpack f f f; +#X obj 428 479 unpack f f f; +#X obj 442 508 unpack f f f; +#X obj 38 279 +; +#X obj 38 304 +; +#X obj 38 329 +; +#X obj 38 354 +; +#X obj 39 381 +; +#X obj 39 406 +; +#X obj 39 431 +; +#X obj 39 456 +; +#X obj 38 483 +; +#X obj 38 508 +; +#X obj 38 533 +; +#X obj 38 558 +; +#X obj 39 585 +; +#X obj 39 610 +; +#X obj 39 635 +; +#X obj 78 279 +; +#X obj 78 304 +; +#X obj 78 329 +; +#X obj 78 354 +; +#X obj 79 381 +; +#X obj 79 406 +; +#X obj 79 431 +; +#X obj 79 456 +; +#X obj 78 483 +; +#X obj 78 508 +; +#X obj 78 533 +; +#X obj 78 558 +; +#X obj 79 585 +; +#X obj 79 610 +; +#X obj 79 635 +; +#X obj 112 283 +; +#X obj 112 308 +; +#X obj 112 333 +; +#X obj 112 358 +; +#X obj 113 385 +; +#X obj 113 410 +; +#X obj 113 435 +; +#X obj 113 460 +; +#X obj 112 487 +; +#X obj 112 512 +; +#X obj 112 537 +; +#X obj 112 562 +; +#X obj 113 589 +; +#X obj 113 614 +; +#X obj 113 639 +; +#X obj 39 660 / 16; +#X obj 84 668 / 16; +#X obj 128 670 / 16; +#X obj 49 723 pack f f f; +#X obj 48 755 s \$0-mass-center; +#X connect 0 0 1 0; +#X connect 1 0 2 0; +#X connect 1 1 3 0; +#X connect 1 2 4 0; +#X connect 1 3 5 0; +#X connect 1 4 6 0; +#X connect 1 5 7 0; +#X connect 1 6 8 0; +#X connect 1 7 9 0; +#X connect 1 8 10 0; +#X connect 1 9 11 0; +#X connect 1 10 12 0; +#X connect 1 11 13 0; +#X connect 1 12 14 0; +#X connect 1 13 15 0; +#X connect 1 14 16 0; +#X connect 1 15 17 0; +#X connect 2 0 18 0; +#X connect 2 1 33 0; +#X connect 2 2 48 0; +#X connect 3 0 18 1; +#X connect 3 1 33 1; +#X connect 3 2 48 1; +#X connect 4 0 19 1; +#X connect 4 1 34 1; +#X connect 4 2 49 1; +#X connect 5 0 20 1; +#X connect 5 1 35 1; +#X connect 5 2 50 1; +#X connect 6 0 21 1; +#X connect 6 1 36 1; +#X connect 6 2 51 1; +#X connect 7 0 22 1; +#X connect 7 1 37 1; +#X connect 7 2 52 1; +#X connect 8 0 23 1; +#X connect 8 1 38 1; +#X connect 8 2 53 1; +#X connect 9 0 24 1; +#X connect 9 1 39 1; +#X connect 9 2 54 1; +#X connect 10 0 25 1; +#X connect 10 1 40 1; +#X connect 10 2 55 1; +#X connect 11 0 26 1; +#X connect 11 1 41 1; +#X connect 11 2 56 1; +#X connect 12 0 27 1; +#X connect 12 1 42 1; +#X connect 12 2 57 1; +#X connect 13 0 28 1; +#X connect 13 1 43 1; +#X connect 13 2 58 1; +#X connect 14 0 29 1; +#X connect 14 1 44 1; +#X connect 14 2 59 1; +#X connect 15 0 30 1; +#X connect 15 1 45 1; +#X connect 15 2 60 1; +#X connect 16 0 31 1; +#X connect 16 1 46 1; +#X connect 16 2 61 1; +#X connect 17 0 32 1; +#X connect 17 1 47 1; +#X connect 17 2 62 1; +#X connect 18 0 19 0; +#X connect 19 0 20 0; +#X connect 20 0 21 0; +#X connect 21 0 22 0; +#X connect 22 0 23 0; +#X connect 23 0 24 0; +#X connect 24 0 25 0; +#X connect 25 0 26 0; +#X connect 26 0 27 0; +#X connect 27 0 28 0; +#X connect 28 0 29 0; +#X connect 29 0 30 0; +#X connect 30 0 31 0; +#X connect 31 0 32 0; +#X connect 32 0 63 0; +#X connect 33 0 34 0; +#X connect 34 0 35 0; +#X connect 35 0 36 0; +#X connect 36 0 37 0; +#X connect 37 0 38 0; +#X connect 38 0 39 0; +#X connect 39 0 40 0; +#X connect 40 0 41 0; +#X connect 41 0 42 0; +#X connect 42 0 43 0; +#X connect 43 0 44 0; +#X connect 44 0 45 0; +#X connect 45 0 46 0; +#X connect 46 0 47 0; +#X connect 47 0 64 0; +#X connect 48 0 49 0; +#X connect 49 0 50 0; +#X connect 50 0 51 0; +#X connect 51 0 52 0; +#X connect 52 0 53 0; +#X connect 53 0 54 0; +#X connect 54 0 55 0; +#X connect 55 0 56 0; +#X connect 56 0 57 0; +#X connect 57 0 58 0; +#X connect 58 0 59 0; +#X connect 59 0 60 0; +#X connect 60 0 61 0; +#X connect 61 0 62 0; +#X connect 62 0 65 0; +#X connect 63 0 66 0; +#X connect 64 0 66 1; +#X connect 65 0 66 2; +#X connect 66 0 67 0; +#X restore 35 514 pd flock; +#X text 371 172 move around (like a pray); +#X msg 225 305 mode 2; +#X obj 35 433 boids; #X connect 0 0 1 0; #X connect 1 0 0 0; #X connect 3 0 16 0; #X connect 7 0 8 0; #X connect 8 0 9 0; -#X connect 10 0 41 0; -#X connect 11 0 41 0; -#X connect 12 0 41 0; +#X connect 10 0 35 0; +#X connect 11 0 26 0; +#X connect 12 0 35 0; #X connect 15 0 16 1; -#X connect 16 0 41 0; -#X connect 19 0 41 0; -#X connect 20 0 24 0; -#X connect 21 0 24 1; -#X connect 22 0 24 2; -#X connect 23 0 24 3; -#X connect 25 0 24 4; -#X connect 26 0 24 5; -#X connect 27 0 2 0; -#X connect 28 0 2 0; -#X connect 29 0 19 0; -#X connect 38 0 41 0; -#X connect 39 0 40 0; -#X connect 40 0 41 0; -#X connect 41 0 37 0; -#X connect 41 1 13 0; +#X connect 16 0 35 0; +#X connect 18 0 35 0; +#X connect 19 0 2 0; +#X connect 20 0 18 0; +#X connect 24 0 32 0; +#X connect 25 0 34 0; +#X connect 26 0 35 0; +#X connect 27 0 29 0; +#X connect 29 0 28 0; +#X connect 30 0 31 0; +#X connect 34 0 35 0; +#X connect 35 0 24 0; +#X connect 35 1 13 0; diff --git a/examples/boids-struct.pd b/examples/boids-struct.pd index c361fd8..4aa9cb9 100644 --- a/examples/boids-struct.pd +++ b/examples/boids-struct.pd @@ -1,59 +1,35 @@ -#N canvas 843 196 827 539 12; -#N struct \$0-template float k1 float k2 float k3 float x0 float y0 float x1 float y1 float x2 float y2 float x3 float y3 float i; +#N canvas 986 25 614 803 12; +#N struct \$0-template float k1 float k2 float k3 float x0 float y0 float x1 float y1 float x2 float y2; #N struct \$0-attractpoint float x float y; #N canvas 0 25 554 469 \$0-data 0; -#X scalar \$0-template 167 167 0 -10 0 0 10 10 0 0 -10 15 \;; -#X scalar \$0-template 486 486 0 -10 0 0 10 10 0 0 -10 14 \;; -#X scalar \$0-template 678 678 0 -10 0 0 10 10 0 0 -10 13 \;; -#X scalar \$0-template 889 889 0 -10 0 0 10 10 0 0 -10 12 \;; -#X scalar \$0-template 916 916 0 -10 0 0 10 10 0 0 -10 11 \;; -#X scalar \$0-template 987 987 0 -10 0 0 10 10 0 0 -10 10 \;; -#X scalar \$0-template 271 271 0 -10 0 0 10 10 0 0 -10 9 \;; -#X scalar \$0-template 433 433 0 -10 0 0 10 10 0 0 -10 8 \;; -#X scalar \$0-template 737 737 0 -10 0 0 10 10 0 0 -10 7 \;; -#X scalar \$0-template 157 157 0 -10 0 0 10 10 0 0 -10 6 \;; -#X scalar \$0-template 300 300 0 -10 0 0 10 10 0 0 -10 5 \;; -#X scalar \$0-template 55 55 0 -10 0 0 10 10 0 0 -10 4 \;; -#X scalar \$0-template 304 304 0 -10 0 0 10 10 0 0 -10 3 \;; -#X scalar \$0-template 485 485 0 -10 0 0 10 10 0 0 -10 2 \;; -#X scalar \$0-template 565 565 0 -10 0 0 10 10 0 0 -10 1 \;; -#X scalar \$0-template 628 628 0 -10 0 0 10 10 0 0 -10 0 \;; -#X scalar \$0-attractpoint 0 0 \;; +#X scalar \$0-template 742 742 0 275.48 -49.293 258.119 -41.638 267.414 -58.1785 \;; +#X scalar \$0-template 927 927 0 163.482 55.4854 159.598 74.0572 151.562 56.8691 \;; +#X scalar \$0-template 726 726 0 217.116 -13.7983 201.19 -3.48502 207.742 -21.2912 \;; +#X scalar \$0-template 918 918 0 243.825 45.4079 254.069 61.3782 236.291 54.7486 \;; +#X scalar \$0-template 628 628 0 260.875 52.712 271.161 36.7685 272.498 55.6949 \;; +#X scalar \$0-template 565 565 0 217.633 40.0772 204.939 25.9747 223.555 29.6408 \;; +#X scalar \$0-template 485 485 0 257.057 86.5212 250.709 68.6409 266.515 79.1364 \;; +#X scalar \$0-template 304 304 0 232.187 15.8991 221.68 0.10034 239.565 6.4351 \;; +#X scalar \$0-template 55 55 0 237.134 69.9051 253.274 59.9298 246.347 77.5939 \;; +#X scalar \$0-template 300 300 0 279.961 21.6578 261.023 20.5076 276.864 10.0645 \;; +#X scalar \$0-template 157 157 0 209.088 46.0908 226.16 37.8112 217.471 54.678 \;; +#X scalar \$0-template 737 737 0 195.919 39.62 178.241 32.7288 196.518 27.6349 \;; +#X scalar \$0-template 433 433 0 248.386 31.6761 255.371 49.3172 239.199 39.3954 \;; +#X scalar \$0-template 271 271 0 260.908 38.3317 242.039 36.335 258.332 26.6114 \;; +#X scalar \$0-template 987 987 0 222.288 51.8083 208.69 65.0403 211.629 46.2957 \;; +#X scalar \$0-template 916 916 0 181.009 62.21 187.325 44.3183 193.007 62.421 \;; +#X scalar \$0-attractpoint 228 42 \;; #X coords -300 -300 300 300 300 300 2 100 100; -#X restore 27 183 pd \$0-data; +#X restore 24 69 pd \$0-data; #N canvas 125 78 524 337 \$0-template 0; #X text 59 231 Struct that defines each boid diamond; #X text 91 270 color can be changed with k; -#X obj 48 145 r \$0-indices; -#X obj 41 95 filledpolygon k1 k2 k3 x0 y0 x1 y1 x2 y2 x3 y3; -#X obj 48 177 drawnumber -n i 5 5 k1; #X msg 360 225 clear; #X obj 360 250 s pd-\$0-data; -#X obj 40 20 struct \$0-template float k1 float k2 float k3 float x0 float y0 float x1 float y1 float x2 float y2 float x3 float y3 float i; -#X connect 2 0 4 0; -#X connect 5 0 6 0; -#X restore 31 132 pd \$0-template; -#X floatatom 383 404 5 0 0 0 left \$0-flyrect0 - 0; -#X floatatom 425 380 5 0 0 0 top \$0-flyrect1 - 0; -#X floatatom 491 398 5 0 0 0 right \$0-flyrect2 - 0; -#X floatatom 559 416 5 0 0 0 bottom \$0-flyrect3 - 0; -#N canvas 0 0 450 300 2D-bounding-box 0; -#X msg 58 156 flyrect \$1 \$2 \$3 \$4; -#X obj 58 181 s \$0-boids-params; -#X obj 29 27 inlet; -#X obj 74 29 inlet; -#X obj 119 29 inlet; -#X obj 170 29 inlet; -#X obj 41 76 pack f f f f; -#X connect 0 0 1 0; -#X connect 2 0 6 0; -#X connect 3 0 6 1; -#X connect 4 0 6 2; -#X connect 5 0 6 3; -#X connect 6 0 0 0; -#X restore 391 443 pd 2D-bounding-box; -#X f 23; -#X obj 32 78 help/boids-params \$0; +#X obj 41 95 filledpolygon k1 k2 k3 x0 y0 x1 y1 x2 y2; +#X obj 40 20 struct \$0-template float k1 float k2 float k3 float x0 float y0 float x1 float y1 float x2 float y2; +#X connect 2 0 3 0; +#X restore 340 364 pd \$0-template; #N canvas 1059 309 598 557 \$0-attractpoint 0; #X obj 232 239 f \$0; #X msg 232 264 traverse pd-\$1-data \, bang; @@ -70,10 +46,6 @@ #X obj 124 324 append \$0-attractpoint x y; #X msg 124 296 0 0; #X obj 39 68 drawcurve 0 1 0 0 0 10 10 10 10 0 0 0; -#X obj 387 368 list prepend \$0; -#X obj 421 333 s \$0-reset; -#X obj 383 302 t b b; -#X msg 390 395 \; \$1-maxspeed 50 \; \$1-minspeed 10 \; \; \$1-flyrect0 -1 \; \$1-flyrect1 1 \; \$1-flyrect2 1 \; \$1-flyrect3 -1; #X obj 130 108 r \$0-init; #X text 267 116 Struct that defines the attraction circle; #X connect 0 0 1 0; @@ -85,16 +57,55 @@ #X connect 7 0 10 0; #X connect 7 1 13 0; #X connect 7 2 0 0; -#X connect 7 3 17 0; #X connect 7 4 4 0; #X connect 8 0 11 0; #X connect 12 0 11 2; #X connect 13 0 12 0; -#X connect 15 0 18 0; -#X connect 17 0 15 0; -#X connect 17 1 16 0; -#X connect 19 0 7 0; -#X restore 31 106 pd \$0-attractpoint; +#X connect 15 0 7 0; +#X restore 341 341 pd \$0-attractpoint; +#X obj 325 436 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 325 497 metro 10; +#X obj 326 711 clone struct-boid 16 \$0; +#X msg 348 564 reset; +#X obj 469 583 r \$0-boids-params; +#X obj 385 665 print; +#X msg 341 537 dump; +#X msg 485 546 attractpt \$1 \$2; +#X obj 499 372 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; +#X obj 499 397 s \$0-init; +#X text 48 411 ATTRACTION POINT; +#X text 354 430 Update boids; +#X floatatom 357 467 5 0 0 0 - - - 0; +#X text 155 26 A 2d boids example using data structures; +#X obj 408 545 loadbang; +#X obj 325 632 boids 16; +#X obj 470 606 list trim; +#X floatatom 113 557 6 0 0 0 xpos - - 0; +#X floatatom 202 560 5 0 0 0 ypos - - 0; +#X obj 117 597 / 100; +#X obj 195 595 / 100; +#X msg 413 572 mode 2; +#X obj 339 58 help/boids-params \$0; +#A saved flyrect -300 300 -300 300; +#A saved dimensions 2; +#A saved number 16; +#A saved neighbors 4; +#A saved attract 0.25; +#A saved center 0.02; +#A saved match 0.0500007; +#A saved avoid 0.919994; +#A saved prefdist 55; +#A saved speed 42; +#A saved minspeed 4; +#A saved maxspeed 46; +#A saved inertia 0.47; +#A saved accel 0.230001; +#A saved edgedist 15; +#A saved repel 0.410001; +#X obj 58 443 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 61 489 metro 50; +#X floatatom 132 479 5 0 0 0 - - - 0; +#N canvas 0 0 450 300 atract-point 0; #N canvas 323 118 689 551 random-walk 0; #X obj 167 125 f; #X obj 74 197 random 2; @@ -110,7 +121,7 @@ #X obj 384 168 + 200; #X msg 97 305 1; #X text 80 223 sign; -#X text 142 240 magnitude; +#X text 153 180 magnitude; #X text 228 340 add prev value; #X text 227 355 to random increment; #X obj 304 202 t f f; @@ -121,7 +132,10 @@ #X text 140 439 open the browser and look for:; #X obj 349 243 * 0.01; #X obj 74 276 sel; -#X obj 140 200 random 2; +#X obj 140 200 random 10; +#X obj 140 238 moses 6; +#X obj 203 241 b; +#X obj 203 266 random 30; #X connect 0 0 2 0; #X connect 1 0 24 0; #X connect 2 0 1 0; @@ -146,11 +160,14 @@ #X connect 23 0 18 0; #X connect 24 0 6 0; #X connect 24 1 12 0; -#X connect 25 0 4 0; -#X restore 366 209 pd random-walk; -#X obj 366 234 * 600; -#X obj 366 259 - 300; -#X obj 367 109 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X connect 25 0 26 0; +#X connect 26 0 4 0; +#X connect 26 1 27 0; +#X connect 27 0 28 0; +#X connect 28 0 4 0; +#X restore 90 121 pd random-walk; +#X obj 88 163 * 600; +#X obj 88 188 - 300; #N canvas 657 108 689 551 random-walk 0; #X obj 167 125 f; #X obj 74 197 random 2; @@ -177,7 +194,10 @@ #X text 140 439 open the browser and look for:; #X obj 349 243 * 0.01; #X obj 74 276 sel; -#X obj 140 198 random 2; +#X obj 140 198 random 10; +#X obj 140 238 moses 6; +#X obj 203 241 b; +#X obj 203 266 random 30; #X connect 0 0 2 0; #X connect 1 0 24 0; #X connect 2 0 1 0; @@ -202,67 +222,59 @@ #X connect 23 0 18 0; #X connect 24 0 6 0; #X connect 24 1 12 0; -#X connect 25 0 4 0; -#X restore 410 233 pd random-walk; -#X obj 410 258 * 600; -#X obj 410 283 - 300; -#X obj 360 183 t b b; -#X obj 367 134 metro 50; -#X obj 366 284 pack; -#X obj 363 317 s \$0-attractpt; -#X floatatom 433 109 5 0 0 0 - - - 0; -#X msg 663 295 all bang; -#X obj 545 96 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; -#X obj 545 121 metro 10; -#X obj 546 335 clone struct-boid 16 \$0; -#X msg 568 188 reset; -#X obj 614 224 r \$0-boids-params; -#X obj 605 289 print; -#X msg 561 161 dump; -#X msg 626 125 attractpt \$1 \$2; -#X obj 626 101 r \$0-attractpt; -#X obj 666 271 r \$0-init-boids; -#X obj 712 375 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; -#X obj 712 400 s \$0-init; -#X text 359 75 ATTRACTION POINT; -#X text 579 68 Update boids; -#X text 359 359 BOUNDING BOX; -#X floatatom 577 91 5 0 0 0 - - - 0; -#X obj 617 406 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; -#X obj 615 435 s \$0-indices; -#X text 239 24 A 2d boids example using data structures; -#X msg 633 196 mode 2; -#X obj 628 169 loadbang; -#X obj 545 256 boids 16; -#X connect 2 0 6 0; -#X connect 3 0 6 1; -#X connect 4 0 6 2; -#X connect 5 0 6 3; -#X connect 9 0 10 0; -#X connect 10 0 11 0; -#X connect 11 0 18 0; -#X connect 12 0 17 0; -#X connect 13 0 14 0; -#X connect 14 0 15 0; -#X connect 15 0 18 1; -#X connect 16 0 9 0; -#X connect 16 1 13 0; -#X connect 17 0 16 0; -#X connect 18 0 19 0; -#X connect 20 0 17 1; -#X connect 21 0 24 1; -#X connect 22 0 23 0; -#X connect 23 0 43 0; -#X connect 25 0 43 0; -#X connect 26 0 43 0; -#X connect 28 0 43 0; -#X connect 29 0 43 0; -#X connect 30 0 29 0; -#X connect 31 0 21 0; -#X connect 32 0 33 0; -#X connect 37 0 23 1; -#X connect 38 0 39 0; -#X connect 41 0 43 0; -#X connect 42 0 41 0; -#X connect 43 0 24 0; -#X connect 43 1 27 0; +#X connect 25 0 26 0; +#X connect 26 0 4 0; +#X connect 26 1 27 0; +#X connect 27 0 28 0; +#X connect 28 0 4 0; +#X restore 134 145 pd random-walk; +#X obj 132 187 * 600; +#X obj 132 212 - 300; +#X obj 84 95 t b b; +#X obj 88 213 pack; +#X obj 85 246 s \$0-attractpt; +#X obj 59 10 inlet; +#X obj 206 15 inlet; +#X obj 268 19 inlet; +#X obj 243 72 t b f; +#X obj 207 65 f; +#X connect 0 0 1 0; +#X connect 1 0 2 0; +#X connect 2 0 7 0; +#X connect 3 0 4 0; +#X connect 4 0 5 0; +#X connect 5 0 7 1; +#X connect 6 0 0 0; +#X connect 6 1 3 0; +#X connect 7 0 8 0; +#X connect 9 0 6 0; +#X connect 10 0 13 0; +#X connect 11 0 12 0; +#X connect 12 0 13 0; +#X connect 12 1 4 0; +#X connect 13 0 1 0; +#X restore 65 629 pd atract-point; +#X text 79 443 random walk; +#X obj 486 518 r \$0-attractpt; +#X text 80 518 manual input (turn random off first), f 18; +#X connect 3 0 4 0; +#X connect 4 0 18 0; +#X connect 6 0 18 0; +#X connect 7 0 19 0; +#X connect 9 0 18 0; +#X connect 10 0 18 0; +#X connect 11 0 12 0; +#X connect 15 0 4 1; +#X connect 17 0 24 0; +#X connect 18 0 5 0; +#X connect 18 1 8 0; +#X connect 19 0 18 0; +#X connect 20 0 22 0; +#X connect 21 0 23 0; +#X connect 22 0 29 1; +#X connect 23 0 29 2; +#X connect 24 0 18 0; +#X connect 26 0 27 0; +#X connect 27 0 29 0; +#X connect 28 0 27 1; +#X connect 31 0 10 0; diff --git a/examples/gemboid.pd b/examples/gemboid.pd index ed62708..31a7e6b 100644 --- a/examples/gemboid.pd +++ b/examples/gemboid.pd @@ -1,34 +1,37 @@ -#N canvas 822 81 719 539 12; +#N canvas 92 179 719 539 12; #X obj 61 64 gemhead; #X obj 61 241 translateXYZ; #X obj 152 41 inlet; -#X obj 61 125 color 1 0.5 0 0.5; #N canvas 0 22 474 324 rand_color 0; -#X obj 47 130 random 1000; -#X obj 47 171 * 0.001; -#X obj 131 130 random 1000; -#X obj 131 171 * 0.001; -#X obj 214 131 random 1000; -#X obj 214 172 * 0.001; -#X obj 47 83 t b b b; -#X obj 47 256 outlet; -#X obj 47 217 pack 0 0 0 0.5; -#X obj 47 26 r \$1-reset; +#X obj 158 105 random 1000; +#X obj 158 146 * 0.001; +#X obj 224 140 random 1000; +#X obj 224 181 * 0.001; +#X obj 307 141 random 1000; +#X obj 307 182 * 0.001; +#X obj 189 44 t b b b; +#X obj 141 285 outlet; +#X obj 185 19 r \$1-reset; +#X obj 137 8 inlet; +#X obj 139 189 *; +#X obj 143 230 pack f f f; +#X msg 143 255 \$2 \$3 \$1 0; #X connect 0 0 1 0; -#X connect 1 0 8 0; +#X connect 1 0 10 1; #X connect 2 0 3 0; -#X connect 3 0 8 1; +#X connect 3 0 11 1; #X connect 4 0 5 0; -#X connect 5 0 8 2; +#X connect 5 0 11 2; #X connect 6 0 0 0; #X connect 6 1 2 0; #X connect 6 2 4 0; -#X connect 8 0 7 0; -#X connect 9 0 6 0; -#X restore 177 68 pd rand_color; -#X obj 70 396 circle 0.05; -#X obj 177 91 t a a; -#X msg 209 120 1; +#X connect 8 0 6 0; +#X connect 9 0 10 0; +#X connect 10 0 11 0; +#X connect 11 0 12 0; +#X connect 12 0 7 0; +#X restore 195 121 pd rand_color; +#X obj 72 433 circle 0.05; #X text 34 14 helper abstraction for boids examples with Gem; #X obj 152 202 unpack f f f; #X obj 284 179 loadbang; @@ -39,74 +42,46 @@ #X obj 216 332 spigot; #X obj 254 244 == 1; #X obj 152 164 list split 3; -#X obj 430 60 list split 3; -#X obj 474 88 list split 3; -#X obj 461 126 unpack f f f; -#X obj 431 258 atan2; -#X obj 506 305 atan2; -#X obj 454 158 t f f; -#X obj 538 199 t f f; -#X obj 538 224 *; -#X obj 608 207 t f f; -#X obj 606 237 *; -#X obj 542 153 t f f; -#X obj 538 249 +; -#X obj 538 274 sqrt; -#X obj 431 308 / 3.14159; -#X obj 501 356 / 3.14159; -#X obj 385 400 rotateXYZ; -#X obj 431 283 * 180; -#X obj 501 331 * 180; +#X obj 394 94 list split 3; +#X obj 432 124 unpack f f f; +#X obj 382 391 rotateXYZ; #X text 426 36 with mode == 2; -#X text 403 355 yaw; -#X text 481 387 pitch; #X obj 391 486 sphere3d 0.1 6; #X obj 453 411 loadbang; +#X obj 61 125 color 1 0.5 0 0; +#X obj 438 463 r \$1-size; #X msg 453 436 setCartesian 0 0 0 0 2; -#X connect 0 0 3 0; -#X connect 1 0 14 0; -#X connect 2 0 17 0; -#X connect 3 0 1 0; -#X connect 4 0 6 0; -#X connect 6 0 3 1; -#X connect 6 1 7 0; -#X connect 9 0 1 1; -#X connect 9 1 1 2; -#X connect 9 2 1 3; -#X connect 10 0 11 0; -#X connect 11 0 16 0; -#X connect 12 0 13 1; -#X connect 13 0 5 0; -#X connect 14 0 13 0; +#X text 356 120 speed; +#X text 397 145 yaw = azimuth; +#X text 449 369 pitch = elevation; +#X obj 152 103 t a a; +#X obj 228 467 outlet; +#X connect 0 0 21 0; +#X connect 1 0 11 0; +#X connect 2 0 27 0; +#X connect 3 0 21 1; +#X connect 6 0 1 1; +#X connect 6 1 1 2; +#X connect 6 2 1 3; +#X connect 7 0 8 0; +#X connect 8 0 13 0; +#X connect 9 0 10 1; +#X connect 10 0 4 0; +#X connect 11 0 10 0; +#X connect 11 1 12 0; +#X connect 12 0 17 0; +#X connect 13 0 9 0; +#X connect 13 0 12 1; +#X connect 14 0 6 0; #X connect 14 1 15 0; -#X connect 15 0 33 0; -#X connect 16 0 12 0; -#X connect 16 0 15 1; -#X connect 17 0 9 0; -#X connect 17 1 18 0; -#X connect 18 1 19 0; -#X connect 19 0 20 0; +#X connect 15 1 16 0; +#X connect 16 0 3 0; +#X connect 16 1 17 1; +#X connect 16 2 17 3; +#X connect 17 0 19 0; #X connect 20 0 23 0; -#X connect 20 1 22 0; -#X connect 20 2 28 0; -#X connect 21 0 34 0; -#X connect 22 0 35 0; -#X connect 23 0 21 0; -#X connect 23 1 24 0; -#X connect 24 0 25 0; -#X connect 24 1 25 1; -#X connect 25 0 29 0; -#X connect 26 0 27 0; -#X connect 26 1 27 1; -#X connect 27 0 29 1; -#X connect 28 0 21 1; -#X connect 28 1 26 0; -#X connect 29 0 30 0; -#X connect 30 0 22 1; -#X connect 31 0 33 1; -#X connect 32 0 33 2; -#X connect 33 0 39 0; -#X connect 34 0 31 0; -#X connect 35 0 32 0; -#X connect 40 0 41 0; -#X connect 41 0 39 0; +#X connect 21 0 1 0; +#X connect 22 0 19 1; +#X connect 23 0 19 0; +#X connect 27 0 14 0; +#X connect 27 1 28 0; diff --git a/examples/point.pd b/examples/point.pd index 263a000..bef68c4 100644 --- a/examples/point.pd +++ b/examples/point.pd @@ -1,9 +1,9 @@ -#N canvas 346 145 664 704 12; +#N canvas 825 51 664 704 12; #X obj 61 13 inlet; #X obj 137 327 unpack; #X obj 264 320 cos; #X obj 296 320 sin; -#X obj 264 293 t f f; +#X obj 275 215 t f f; #X obj 127 363 t f f; #X obj 151 422 *; #X obj 185 421 *; @@ -14,20 +14,11 @@ #X obj 288 363 t f f; #X obj 151 447 -; #X obj 263 448 +; -#X obj 311 177 atan2; -#X msg 311 152 2 0; -#X obj 313 201 * 2; -#X obj 312 129 loadbang; -#X obj 267 257 / 180; #X obj 263 527 +; #X obj 375 528 +; #X obj 446 329 unpack; -#X obj 265 233 * 3.14156; #X obj 136 156 abs; #X obj 134 206 * -1; -#X obj 134 231 pack; -#X obj 135 181 t f f; -#X msg 130 264 \$1 0 \, 0 \$2 \, \$2 0 \, 0 \$1, f 11; #X obj 137 117 unpack; #X obj 436 118 list split 2; #X obj 113 80 list split 2; @@ -37,9 +28,13 @@ #X obj 58 44 t b a a, f 42; #X obj 64 605 t a b; #X obj 64 630 outlet; -#X listbox 151 472 20 0 0 0 - - - 0; +#X listbox 152 497 20 0 0 0 - - - 0; #X listbox 263 473 20 0 0 0 - - - 0; -#X connect 0 0 35 0; +#X obj 134 231 pack f f f; +#X obj 135 181 t f f f; +#X msg 130 264 \$1 0 \, 0 \$3 \, \$2 0, f 11; +#X obj 195 203 * -3; +#X connect 0 0 26 0; #X connect 1 0 5 0; #X connect 1 1 8 0; #X connect 2 0 11 0; @@ -58,35 +53,31 @@ #X connect 11 1 10 1; #X connect 12 0 7 1; #X connect 12 1 9 1; -#X connect 13 0 20 0; -#X connect 13 0 38 0; -#X connect 14 0 21 0; -#X connect 14 0 39 0; -#X connect 15 0 17 0; -#X connect 16 0 15 0; -#X connect 17 0 23 1; -#X connect 18 0 16 0; -#X connect 19 0 4 0; -#X connect 20 0 32 0; -#X connect 21 0 32 1; -#X connect 22 0 20 1; -#X connect 22 1 21 1; -#X connect 23 0 19 0; -#X connect 24 0 27 0; -#X connect 25 0 26 0; -#X connect 26 0 28 0; -#X connect 27 0 25 0; -#X connect 27 1 26 1; -#X connect 28 0 1 0; -#X connect 29 0 24 0; -#X connect 29 1 23 0; -#X connect 30 0 22 0; -#X connect 31 1 29 0; -#X connect 32 0 33 0; -#X connect 33 0 34 0; -#X connect 34 0 36 0; -#X connect 35 0 34 0; -#X connect 35 1 31 0; -#X connect 35 2 30 0; -#X connect 36 0 37 0; -#X connect 36 1 34 1; +#X connect 13 0 15 0; +#X connect 13 0 29 0; +#X connect 14 0 16 0; +#X connect 14 0 30 0; +#X connect 15 0 23 0; +#X connect 16 0 23 1; +#X connect 17 0 15 1; +#X connect 17 1 16 1; +#X connect 18 0 32 0; +#X connect 19 0 31 0; +#X connect 20 0 18 0; +#X connect 20 1 4 0; +#X connect 21 0 17 0; +#X connect 22 1 20 0; +#X connect 23 0 24 0; +#X connect 24 0 25 0; +#X connect 25 0 27 0; +#X connect 26 0 25 0; +#X connect 26 1 22 0; +#X connect 26 2 21 0; +#X connect 27 0 28 0; +#X connect 27 1 25 1; +#X connect 31 0 33 0; +#X connect 32 0 19 0; +#X connect 32 1 31 1; +#X connect 32 2 34 0; +#X connect 33 0 1 0; +#X connect 34 0 31 2; diff --git a/examples/struct-boid.pd b/examples/struct-boid.pd index f0209d7..ae05b5d 100644 --- a/examples/struct-boid.pd +++ b/examples/struct-boid.pd @@ -1,96 +1,50 @@ -#N canvas 269 57 798 687 12; -#X msg 592 314 traverse pd-\$1-data \, bang; -#X obj 592 339 pointer; -#X obj 312 100 inlet; -#X obj 592 289 f \$2; -#X obj 42 112 inlet; -#X obj 17 174 unpack; -#X obj 42 323 t f f; -#X obj 13 299 t f f; -#X obj 152 324 t f f; -#X obj 90 297 t f f; -#X obj 33 348 < -301; -#X obj 91 349 > 301; -#X obj 143 349 < -301; -#X obj 201 350 > 301; -#X obj 143 374 ||; -#X obj 33 373 ||; -#X obj 103 397 ||; -#X obj 141 494 f; -#X obj 107 452 sel 0 1; -#X msg 231 481 999; -#X obj 324 324 point; -#X obj 249 158 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; -#X obj 410 286 s \$0-color; -#X obj 179 444 r \$0-color; -#X obj 410 336 r \$0-color; -#X obj 328 389 list prepend; -#X obj 329 420 list prepend \$1; -#X obj 326 463 append \$2-template i k1 k2 k3 x0 y0 x1 y1 x2 y2 x3 y3; -#X msg 410 361 list \$1 \$1 0; -#X obj 33 536 point; -#X obj 31 596 set \$2-template x0 y0 x1 y1 x2 y2 x3 y3 k1 k2 k3; -#X obj 142 231 atan2; -#X obj 142 281 / 3.14159; -#X obj 142 256 * 180; -#X obj 144 197 unpack; -#X obj 70 139 list split 2; -#X obj 12 495 pack f f 10 0; -#X obj 236 553 t f f b; -#X msg 315 564 0; -#X msg 320 272 0 0 10 0; -#X obj 324 183 t b b b, f 8; -#X obj 412 255 random 998; -#X floatatom 218 309 5 0 0 0 - - - 0; +#N canvas 576 120 648 513 12; +#X msg 430 259 traverse pd-\$1-data \, bang, f 21; +#X obj 429 315 pointer; +#X obj 430 219 f \$2; +#X obj 48 39 inlet; +#X obj 238 265 point; +#X obj 305 238 s \$0-color; +#X obj 324 277 r \$0-color; +#X obj 242 330 list prepend; +#X msg 324 302 list \$1 \$1 0; +#X obj 59 313 point; +#X obj 237 158 t b b b, f 8; +#X obj 307 207 random 998; +#X obj 52 403 set \$2-template x0 y0 x1 y1 x2 y2, f 16; +#X msg 234 213 0 0 6 0; +#X obj 42 87 list split 2; +#X obj 77 209 list; +#X obj 78 115 list split 2; +#X obj 99 144 unpack f f f; +#X msg 63 257 \$1 \$2 6 \$3; +#X obj 140 168 / 180; +#X obj 134 192 * 3.14156; +#X obj 135 212 * 2; +#X obj 240 120 r \$2-init-boids; +#X obj 240 404 append \$2-template k1 k2 k3 x0 y0 x1 y1 x2 y2, f 25; #X connect 0 0 1 0; -#X connect 1 0 27 12; -#X connect 2 0 40 0; -#X connect 3 0 0 0; -#X connect 4 0 35 0; -#X connect 5 0 7 0; -#X connect 5 1 9 0; -#X connect 6 0 10 0; -#X connect 6 1 11 0; -#X connect 7 0 36 0; -#X connect 7 1 6 0; -#X connect 8 0 12 0; -#X connect 8 1 13 0; -#X connect 9 0 36 1; -#X connect 9 1 8 0; -#X connect 10 0 15 0; -#X connect 11 0 15 1; -#X connect 12 0 14 0; -#X connect 13 0 14 1; -#X connect 14 0 16 1; -#X connect 15 0 16 0; -#X connect 16 0 18 0; -#X connect 17 0 37 0; -#X connect 18 0 17 0; -#X connect 18 1 19 0; -#X connect 20 0 25 0; -#X connect 21 0 40 0; -#X connect 23 0 17 1; -#X connect 24 0 28 0; -#X connect 25 0 26 0; -#X connect 26 0 27 0; -#X connect 27 0 30 11; -#X connect 28 0 25 1; -#X connect 29 0 30 0; -#X connect 31 0 33 0; -#X connect 32 0 36 3; -#X connect 32 0 42 0; -#X connect 33 0 32 0; -#X connect 34 0 31 0; -#X connect 34 1 31 1; -#X connect 35 0 5 0; -#X connect 35 1 34 0; -#X connect 36 0 29 0; -#X connect 37 0 30 8; -#X connect 37 1 30 9; -#X connect 37 2 38 0; -#X connect 38 0 30 10; -#X connect 39 0 20 0; -#X connect 40 0 39 0; -#X connect 40 1 41 0; -#X connect 40 2 3 0; -#X connect 41 0 22 0; +#X connect 1 0 23 9; +#X connect 2 0 0 0; +#X connect 3 0 14 0; +#X connect 4 0 7 0; +#X connect 6 0 8 0; +#X connect 7 0 23 0; +#X connect 8 0 7 1; +#X connect 9 0 12 0; +#X connect 10 0 13 0; +#X connect 10 1 11 0; +#X connect 10 2 2 0; +#X connect 11 0 5 0; +#X connect 13 0 4 0; +#X connect 14 0 15 0; +#X connect 14 1 16 0; +#X connect 15 0 18 0; +#X connect 16 1 17 0; +#X connect 17 1 19 0; +#X connect 18 0 9 0; +#X connect 19 0 20 0; +#X connect 20 0 21 0; +#X connect 21 0 15 1; +#X connect 22 0 10 0; +#X connect 23 0 12 6; From 18b08a3b4f928d10b0ac49efebeb3f01dc29fec5 Mon Sep 17 00:00:00 2001 From: fdch Date: Wed, 13 May 2026 16:24:21 +0200 Subject: [PATCH 15/19] use vec in makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b62fa52..bccbcae 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ lib.name = boids # input source file (class name == source file basename) class.sources = src/boids.c -common.sources = src/boid_params.c src/point.c +common.sources = src/boid_params.c src/vec.c # all extra files to be included in binary distribution of the library datafiles = boids-meta.pd help/boids2d-help.pd help/boids3d-help.pd README.txt LICENSE.txt From a23d675ec5b5ad056876f0983215b0ccd4e59c76 Mon Sep 17 00:00:00 2001 From: fdch Date: Wed, 13 May 2026 16:43:04 +0200 Subject: [PATCH 16/19] update the gemlist example --- examples/boids-with-gemlist.pd | 238 ++++++++++++++++++--------------- 1 file changed, 129 insertions(+), 109 deletions(-) diff --git a/examples/boids-with-gemlist.pd b/examples/boids-with-gemlist.pd index ebc993f..2c31db7 100644 --- a/examples/boids-with-gemlist.pd +++ b/examples/boids-with-gemlist.pd @@ -1,7 +1,7 @@ -#N canvas 521 28 520 660 10; +#N canvas 1018 93 597 774 10; #X declare -path boids -lib Gem; -#X msg 432 52 create; -#N canvas 494 140 629 324 gemwin 0; +#X msg 432 52 destroy; +#N canvas 1028 103 629 324 gemwin 0; #X obj 219 190 gemwin; #X obj 66 194 outlet; #X obj 67 10 inlet; @@ -10,30 +10,55 @@ #X msg 157 70 set create; #X msg 350 115 destroy \, reset; #X msg 238 71 color 0 0 0.5; -#X msg 212 146 create \, 1 \, frame 30 \, color 1 1 1; #X obj 157 39 loadbang; +#N canvas 840 316 597 390 light 0; +#X obj 24 116 tgl 15 0 empty empty empty 0 -6 0 10 #fcfcfc #000000 #000000 0 1; +#X msg 24 134 lighting \$1; +#X msg 144 226 fogcolor 0.0787402 0.417323 0.748031; +#X msg 61 200 fog 0.0393701; +#X obj 24 345 s \$0-gemwin-in; +#X obj 28 40 gemhead; +#X obj 28 63 world_light; +#X msg 54 112 1; +#X msg 46 164 fogmode 1; +#X obj 144 40 inlet; +#X connect 0 0 1 0; +#X connect 1 0 4 0; +#X connect 2 0 4 0; +#X connect 3 0 4 0; +#X connect 5 0 6 0; +#X connect 7 0 0 0; +#X connect 8 0 4 0; +#X connect 9 0 7 0; +#X connect 9 0 8 0; +#X connect 9 0 3 0; +#X connect 9 0 2 0; +#X restore 199 264 pd light; +#X obj 292 186 r \$0-gemwin-in; +#X msg 212 146 create \, 1 \, frame 30 \, color 0 0 0.1 0; +#X obj 161 103 t b b; #X connect 2 0 3 0; #X connect 3 0 4 0; -#X connect 3 0 8 0; +#X connect 3 0 12 0; #X connect 3 1 5 0; #X connect 3 1 6 0; #X connect 4 0 1 0; #X connect 5 0 1 0; #X connect 6 0 0 0; #X connect 7 0 0 0; -#X connect 8 0 0 0; -#X connect 9 0 5 0; +#X connect 8 0 5 0; +#X connect 10 0 0 0; +#X connect 11 0 0 0; +#X connect 12 0 9 0; +#X connect 12 1 11 0; #X restore 432 72 pd gemwin; #X text 27 61 There is more information about the technique used in this patch in the Gem documentation \, mainly at the end of the 02.advanced section.; #X text 29 32 manage lots of boids using [gemlist]; -#X floatatom 314 241 5 0 0 0 - - - 0; -#X floatatom 359 241 5 0 0 0 - - - 0; #N canvas 0 22 466 396 orbit 0; #X floatatom 103 160 5 0 0 0 - - - 0; #X obj 103 187 expr $f1 * (3.141593/180.); #X obj 103 45 inlet; -#X obj 166 314 outlet; -#X obj 103 314 outlet; +#X obj 107 342 outlet; #N canvas 0 0 450 300 pol2cart 0; #X obj 79 42 inlet r; #X obj 159 42 inlet phi; @@ -62,78 +87,40 @@ #X connect 11 0 10 0; #X restore 103 254 pd pol2cart; #X msg 103 210 1.5 \$1; -#X obj 103 277 swap, f 11; +#X obj 103 277 swap, f 5; #X obj 103 68 i; #X obj 103 91 + 1; #X obj 103 114 % 360; #X obj 103 137 t f f; +#X obj 196 259 sin; +#X obj 107 314 pack f f f; +#X obj 180 287 * 3; +#X obj 196 236 * 0.5; #X connect 0 0 1 0; -#X connect 1 0 6 0; -#X connect 2 0 8 0; -#X connect 5 0 7 0; -#X connect 5 1 7 1; -#X connect 6 0 5 0; -#X connect 7 0 4 0; -#X connect 7 1 3 0; +#X connect 1 0 5 0; +#X connect 1 0 14 0; +#X connect 2 0 7 0; +#X connect 4 0 6 0; +#X connect 4 1 6 1; +#X connect 5 0 4 0; +#X connect 6 0 12 0; +#X connect 6 1 12 1; +#X connect 7 0 8 0; #X connect 8 0 9 0; #X connect 9 0 10 0; -#X connect 10 0 11 0; -#X connect 11 0 0 0; -#X connect 11 1 8 1; +#X connect 10 0 0 0; +#X connect 10 1 7 1; +#X connect 11 0 13 0; +#X connect 12 0 3 0; +#X connect 13 0 12 2; +#X connect 14 0 11 0; #X restore 314 219 pd orbit; -#X obj 314 188 spigot; -#X obj 350 167 tgl 15 0 empty empty empty 0 -6 0 8 #fcfcfc #000000 #000000 0 1; -#X msg 128 313 attractpt \$1 \$2; -#X obj 314 264 pack 0 0; +#X obj 359 154 tgl 15 0 empty empty empty 0 -6 0 8 #fcfcfc #000000 #000000 0 1; #X obj 47 133 gemhead; #X obj 47 590 translateXYZ; #X obj 47 509 alpha; -#X obj 47 616 circle 0.05; #X obj 47 394 gemlist; #X obj 47 420 separator; -#N canvas 754 114 494 546 init 0; -#X obj 34 20 inlet; -#X msg 198 102 neighbors 4; -#X msg 203 389 speed 3; -#X msg 203 479 prefdist 1.5; -#X msg 203 149 maxspeed 1.5; -#X msg 203 179 minspeed 1.2; -#X msg 203 209 center 1.2; -#X msg 203 239 attract 1.25; -#X msg 203 269 match 0.3; -#X msg 203 329 repel 3.5; -#X msg 203 299 avoid 3.5; -#X msg 203 359 edgedist 3; -#X msg 203 420 inertia 4.5; -#X msg 203 449 accel 2.5; -#X obj 34 520 outlet; -#X connect 0 0 1 0; -#X connect 0 0 2 0; -#X connect 0 0 3 0; -#X connect 0 0 4 0; -#X connect 0 0 5 0; -#X connect 0 0 6 0; -#X connect 0 0 7 0; -#X connect 0 0 8 0; -#X connect 0 0 9 0; -#X connect 0 0 10 0; -#X connect 0 0 11 0; -#X connect 0 0 12 0; -#X connect 0 0 13 0; -#X connect 1 0 14 0; -#X connect 2 0 14 0; -#X connect 3 0 14 0; -#X connect 4 0 14 0; -#X connect 5 0 14 0; -#X connect 6 0 14 0; -#X connect 7 0 14 0; -#X connect 8 0 14 0; -#X connect 9 0 14 0; -#X connect 10 0 14 0; -#X connect 11 0 14 0; -#X connect 12 0 14 0; -#X connect 13 0 14 0; -#X restore 60 220 pd init; #N canvas 0 22 418 379 circle 0; #X obj 101 37 gemhead; #X obj 99 201 translateXYZ; @@ -154,7 +141,7 @@ #X connect 5 0 4 0; #X connect 6 0 1 0; #X connect 7 0 6 0; -#X restore 314 299 pd circle to follow; +#X restore 337 287 pd circle to follow; #X obj 47 158 trigger bang anything bang; #N canvas 1 98 474 324 random 0; #X obj 47 130 random 1000; @@ -191,45 +178,78 @@ #X restore 200 394 pd random color lists; #X obj 47 368 trigger bang anything bang; #X obj 200 449 unpack 0 0 0; -#X obj 77 548 unpack 0 0 0; -#X obj 47 342 boids2d 100; #X obj 47 459 color; #X obj 265 6 declare -path boids -lib Gem; -#X obj 323 93 loadbang; -#X msg 323 115 1; -#X obj 323 137 t b f; +#X obj 47 342 boids 100; +#X obj 125 508 list split 1; +#X obj 75 565 unpack f f f; +#X obj 158 531 list split 3; +#X msg 74 309 attractpt \$1 \$2 \$3; +#X obj 310 262 t a a; +#X listbox 321 239 30 0 0 0 - - - 0; +#X obj 309 458 help/boids-params \$0; +#A saved flyrect -3 3 -3 3; +#A saved dimensions 3; +#A saved number 100; +#A saved neighbors 10; +#A saved maxspeed 1.5; +#A saved minspeed 1.2; +#A saved center 0.8; +#A saved attract 0.97; +#A saved match 0.93; +#A saved avoid 0.920002; +#A saved repel 5.23; +#A saved edgedist 2.48; +#A saved speed 3; +#A saved inertia 0.970001; +#A saved accel 0.740001; +#A saved prefdist 52.49; +#X obj 60 220 r \$0-boids-params; +#X obj 53 246 list trim; +#X obj 314 188 spigot 1; +#X obj 50 711 sphere 0.05 3; +#X obj 48 667 rotateXYZ; +#X obj 182 216 loadbang; +#X msg 182 239 mode 2; +#X obj 194 570 list split 3; +#X obj 130 622 unpack f f f; #X connect 0 0 1 0; #X connect 1 0 0 0; -#X connect 4 0 10 0; -#X connect 5 0 10 1; -#X connect 6 0 4 0; -#X connect 6 1 5 0; -#X connect 7 0 6 0; -#X connect 8 0 7 1; -#X connect 9 0 24 0; -#X connect 10 0 9 0; -#X connect 10 0 18 0; -#X connect 11 0 19 0; -#X connect 12 0 14 0; -#X connect 13 0 12 0; -#X connect 15 0 16 0; -#X connect 16 0 25 0; -#X connect 17 0 24 0; -#X connect 19 0 24 0; -#X connect 19 1 15 1; -#X connect 19 2 7 0; -#X connect 19 2 20 1; -#X connect 20 0 22 0; -#X connect 20 0 25 1; -#X connect 21 0 15 0; -#X connect 21 1 23 0; -#X connect 21 2 20 0; -#X connect 22 0 13 1; -#X connect 23 1 12 1; -#X connect 23 2 12 2; -#X connect 24 0 21 0; -#X connect 25 0 13 0; -#X connect 27 0 28 0; -#X connect 28 0 29 0; -#X connect 29 0 17 0; -#X connect 29 1 8 0; +#X connect 4 0 23 0; +#X connect 4 0 24 0; +#X connect 5 0 28 1; +#X connect 6 0 12 0; +#X connect 7 0 30 0; +#X connect 8 0 7 0; +#X connect 9 0 10 0; +#X connect 10 0 16 0; +#X connect 12 0 18 0; +#X connect 12 1 9 1; +#X connect 12 2 13 1; +#X connect 12 2 28 0; +#X connect 13 0 15 0; +#X connect 13 0 16 1; +#X connect 14 0 9 0; +#X connect 14 1 19 0; +#X connect 14 2 13 0; +#X connect 15 0 8 1; +#X connect 16 0 8 0; +#X connect 18 0 14 0; +#X connect 19 1 21 0; +#X connect 20 0 7 1; +#X connect 20 1 7 2; +#X connect 20 2 7 3; +#X connect 21 0 20 0; +#X connect 21 1 33 0; +#X connect 22 0 18 0; +#X connect 23 0 22 0; +#X connect 23 1 11 0; +#X connect 26 0 27 0; +#X connect 27 0 18 0; +#X connect 28 0 4 0; +#X connect 30 0 29 0; +#X connect 31 0 32 0; +#X connect 32 0 18 0; +#X connect 33 1 34 0; +#X connect 34 1 30 1; +#X connect 34 2 30 3; From a88c08a4ef33b13c117031e1bfef0fa6abab948b Mon Sep 17 00:00:00 2001 From: fdch Date: Wed, 13 May 2026 17:04:27 +0200 Subject: [PATCH 17/19] cleanup helpfiles and abstractions --- Makefile | 3 +- examples/boids-gem.pd | 4 +- ...boids-with-gemlist.pd => boids-gemlist.pd} | 51 +--- examples/boids-struct.pd | 56 ++-- examples/boids2d-gem.pd | 164 ---------- examples/boids2d-struct.pd | 268 ---------------- examples/boids3d-gem.pd | 278 ----------------- examples/gemboid.pd | 87 ------ examples/point.pd | 83 ----- examples/struct-boid.pd | 50 --- help/boids-params.pd | 288 ------------------ 11 files changed, 44 insertions(+), 1288 deletions(-) rename examples/{boids-with-gemlist.pd => boids-gemlist.pd} (83%) delete mode 100644 examples/boids2d-gem.pd delete mode 100644 examples/boids2d-struct.pd delete mode 100644 examples/boids3d-gem.pd delete mode 100644 examples/gemboid.pd delete mode 100644 examples/point.pd delete mode 100644 examples/struct-boid.pd delete mode 100644 help/boids-params.pd diff --git a/Makefile b/Makefile index bccbcae..db3167d 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ # library name lib.name = boids +lib.setup.sources = src/boids.c # input source file (class name == source file basename) class.sources = src/boids.c common.sources = src/boid_params.c src/vec.c @@ -12,7 +13,7 @@ common.sources = src/boid_params.c src/vec.c # all extra files to be included in binary distribution of the library datafiles = boids-meta.pd help/boids2d-help.pd help/boids3d-help.pd README.txt LICENSE.txt -datadirs = examples +datadirs = examples boids cflags = -O0 -g3 -fno-inline -fno-omit-frame-pointer -Wall -Wextra -Wpedantic diff --git a/examples/boids-gem.pd b/examples/boids-gem.pd index 736bdbf..0a1b3ad 100644 --- a/examples/boids-gem.pd +++ b/examples/boids-gem.pd @@ -44,7 +44,7 @@ #X obj 661 163 r \$0-vis-bounds; #X obj 822 161 loadbang; #X msg 822 186 0; -#X obj 329 27 help/boids-params \$0-2; +#X obj 329 27 boids-params \$0-2; #A saved flyrect -2 2 -2 2; #A saved dimensions 3; #A saved number 3; @@ -171,7 +171,7 @@ #X obj 35 210 tgl 20 1 empty empty start\ flocking\ animation 0 -10 0 12 #fcfcfc #000000 #000000 1 1; #X text 23 18 create/destroy the GEM window; #X obj 349 24 declare -lib Gem; -#X obj 345 288 help/boids-params \$0; +#X obj 345 288 boids-params \$0; #A saved flyrect -2 2 -2 2; #A saved dimensions 3; #A saved number 16; diff --git a/examples/boids-with-gemlist.pd b/examples/boids-gemlist.pd similarity index 83% rename from examples/boids-with-gemlist.pd rename to examples/boids-gemlist.pd index 2c31db7..66e8bb1 100644 --- a/examples/boids-with-gemlist.pd +++ b/examples/boids-gemlist.pd @@ -1,56 +1,29 @@ #N canvas 1018 93 597 774 10; #X declare -path boids -lib Gem; -#X msg 432 52 destroy; +#X msg 432 52 create; #N canvas 1028 103 629 324 gemwin 0; -#X obj 219 190 gemwin; +#X obj 170 199 gemwin; #X obj 66 194 outlet; #X obj 67 10 inlet; #X obj 67 41 route create; #X msg 67 70 set destroy; #X msg 157 70 set create; -#X msg 350 115 destroy \, reset; -#X msg 238 71 color 0 0 0.5; +#X msg 160 114 destroy \, reset; #X obj 157 39 loadbang; -#N canvas 840 316 597 390 light 0; -#X obj 24 116 tgl 15 0 empty empty empty 0 -6 0 10 #fcfcfc #000000 #000000 0 1; -#X msg 24 134 lighting \$1; -#X msg 144 226 fogcolor 0.0787402 0.417323 0.748031; -#X msg 61 200 fog 0.0393701; -#X obj 24 345 s \$0-gemwin-in; -#X obj 28 40 gemhead; -#X obj 28 63 world_light; -#X msg 54 112 1; -#X msg 46 164 fogmode 1; -#X obj 144 40 inlet; -#X connect 0 0 1 0; -#X connect 1 0 4 0; -#X connect 2 0 4 0; -#X connect 3 0 4 0; -#X connect 5 0 6 0; -#X connect 7 0 0 0; -#X connect 8 0 4 0; -#X connect 9 0 7 0; -#X connect 9 0 8 0; -#X connect 9 0 3 0; -#X connect 9 0 2 0; -#X restore 199 264 pd light; -#X obj 292 186 r \$0-gemwin-in; -#X msg 212 146 create \, 1 \, frame 30 \, color 0 0 0.1 0; -#X obj 161 103 t b b; +#X obj 359 38 gemhead; +#X obj 359 61 world_light; +#X msg 138 145 reset \, create \, lighting 1 \, fogmode 1 \, fog 0.04 \, fogcolor 0.07 0.41 0.74 \, 1 \, frame 30 \, color 0 0 0.1 0; #X connect 2 0 3 0; #X connect 3 0 4 0; -#X connect 3 0 12 0; +#X connect 3 0 10 0; #X connect 3 1 5 0; #X connect 3 1 6 0; #X connect 4 0 1 0; #X connect 5 0 1 0; #X connect 6 0 0 0; -#X connect 7 0 0 0; -#X connect 8 0 5 0; +#X connect 7 0 5 0; +#X connect 8 0 9 0; #X connect 10 0 0 0; -#X connect 11 0 0 0; -#X connect 12 0 9 0; -#X connect 12 1 11 0; #X restore 432 72 pd gemwin; #X text 27 61 There is more information about the technique used in this patch in the Gem documentation \, mainly at the end of the 02.advanced section.; #X text 29 32 manage lots of boids using [gemlist]; @@ -187,11 +160,11 @@ #X msg 74 309 attractpt \$1 \$2 \$3; #X obj 310 262 t a a; #X listbox 321 239 30 0 0 0 - - - 0; -#X obj 309 458 help/boids-params \$0; +#X obj 309 458 boids-params \$0; #A saved flyrect -3 3 -3 3; #A saved dimensions 3; -#A saved number 100; -#A saved neighbors 10; +#A saved number 1000; +#A saved neighbors 7; #A saved maxspeed 1.5; #A saved minspeed 1.2; #A saved center 0.8; diff --git a/examples/boids-struct.pd b/examples/boids-struct.pd index 4aa9cb9..3486b90 100644 --- a/examples/boids-struct.pd +++ b/examples/boids-struct.pd @@ -2,23 +2,23 @@ #N struct \$0-template float k1 float k2 float k3 float x0 float y0 float x1 float y1 float x2 float y2; #N struct \$0-attractpoint float x float y; #N canvas 0 25 554 469 \$0-data 0; -#X scalar \$0-template 742 742 0 275.48 -49.293 258.119 -41.638 267.414 -58.1785 \;; -#X scalar \$0-template 927 927 0 163.482 55.4854 159.598 74.0572 151.562 56.8691 \;; -#X scalar \$0-template 726 726 0 217.116 -13.7983 201.19 -3.48502 207.742 -21.2912 \;; -#X scalar \$0-template 918 918 0 243.825 45.4079 254.069 61.3782 236.291 54.7486 \;; -#X scalar \$0-template 628 628 0 260.875 52.712 271.161 36.7685 272.498 55.6949 \;; -#X scalar \$0-template 565 565 0 217.633 40.0772 204.939 25.9747 223.555 29.6408 \;; -#X scalar \$0-template 485 485 0 257.057 86.5212 250.709 68.6409 266.515 79.1364 \;; -#X scalar \$0-template 304 304 0 232.187 15.8991 221.68 0.10034 239.565 6.4351 \;; -#X scalar \$0-template 55 55 0 237.134 69.9051 253.274 59.9298 246.347 77.5939 \;; -#X scalar \$0-template 300 300 0 279.961 21.6578 261.023 20.5076 276.864 10.0645 \;; -#X scalar \$0-template 157 157 0 209.088 46.0908 226.16 37.8112 217.471 54.678 \;; -#X scalar \$0-template 737 737 0 195.919 39.62 178.241 32.7288 196.518 27.6349 \;; -#X scalar \$0-template 433 433 0 248.386 31.6761 255.371 49.3172 239.199 39.3954 \;; -#X scalar \$0-template 271 271 0 260.908 38.3317 242.039 36.335 258.332 26.6114 \;; -#X scalar \$0-template 987 987 0 222.288 51.8083 208.69 65.0403 211.629 46.2957 \;; -#X scalar \$0-template 916 916 0 181.009 62.21 187.325 44.3183 193.007 62.421 \;; -#X scalar \$0-attractpoint 228 42 \;; +#X scalar \$0-template 559 559 0 65.0746 -56.696 69.5656 -38.2615 54.9121 -50.3145 \;; +#X scalar \$0-template 662 662 0 33.1008 -167.948 52.0493 -168.924 37.4763 -156.774 \;; +#X scalar \$0-template 653 653 0 -21.2323 -123.544 -18.132 -142.263 -9.38101 -125.427 \;; +#X scalar \$0-template 354 354 0 -73.2501 -110.582 -91.9465 -113.814 -75.0502 -122.446 \;; +#X scalar \$0-template 292 292 0 -51.1678 -110.237 -44.863 -128.132 -39.1696 -110.033 \;; +#X scalar \$0-template 591 591 0 -38.161 -124.099 -32.7755 -142.292 -26.1679 -124.506 \;; +#X scalar \$0-template 620 620 0 -42.069 -70.8646 -58.9269 -62.1576 -50.6647 -79.2379 \;; +#X scalar \$0-template 278 278 0 -7.71273 -73.7757 -19.6283 -59.0102 -18.9551 -77.9719 \;; +#X scalar \$0-template 687 687 0 -5.51123 -150.007 11.1193 -140.873 -7.66542 -138.202 \;; +#X scalar \$0-template 767 767 0 160.597 -182.205 149.207 -197.38 167.424 -192.074 \;; +#X scalar \$0-template 867 867 0 -47.1116 -146.392 -54.0828 -164.038 -37.9179 -154.104 \;; +#X scalar \$0-template 476 476 0 92.4542 -13.669 92.6008 5.3041 81.0997 -9.78638 \;; +#X scalar \$0-template 40 40 0 92.258 -129.968 105.908 -143.147 102.895 -124.414 \;; +#X scalar \$0-template 41 41 0 -45.82 -185.435 -28.9757 -194.168 -37.2112 -177.075 \;; +#X scalar \$0-template 501 501 0 -14.1743 -157.58 -8.5463 -175.7 -2.17688 -157.827 \;; +#X scalar \$0-template 839 839 0 123.069 12.6053 105.359 5.7973 123.612 0.61761 \;; +#X scalar \$0-attractpoint -12 -138 \;; #X coords -300 -300 300 300 300 300 2 100 100; #X restore 24 69 pd \$0-data; #N canvas 125 78 524 337 \$0-template 0; @@ -85,7 +85,7 @@ #X obj 117 597 / 100; #X obj 195 595 / 100; #X msg 413 572 mode 2; -#X obj 339 58 help/boids-params \$0; +#X obj 339 58 boids-params \$0; #A saved flyrect -300 300 -300 300; #A saved dimensions 2; #A saved number 16; @@ -133,9 +133,9 @@ #X obj 349 243 * 0.01; #X obj 74 276 sel; #X obj 140 200 random 10; -#X obj 140 238 moses 6; #X obj 203 241 b; #X obj 203 266 random 30; +#X obj 140 238 moses 8; #X connect 0 0 2 0; #X connect 1 0 24 0; #X connect 2 0 1 0; @@ -160,11 +160,11 @@ #X connect 23 0 18 0; #X connect 24 0 6 0; #X connect 24 1 12 0; -#X connect 25 0 26 0; -#X connect 26 0 4 0; -#X connect 26 1 27 0; -#X connect 27 0 28 0; +#X connect 25 0 28 0; +#X connect 26 0 27 0; +#X connect 27 0 4 0; #X connect 28 0 4 0; +#X connect 28 1 26 0; #X restore 90 121 pd random-walk; #X obj 88 163 * 600; #X obj 88 188 - 300; @@ -195,9 +195,9 @@ #X obj 349 243 * 0.01; #X obj 74 276 sel; #X obj 140 198 random 10; -#X obj 140 238 moses 6; #X obj 203 241 b; #X obj 203 266 random 30; +#X obj 140 238 moses 8; #X connect 0 0 2 0; #X connect 1 0 24 0; #X connect 2 0 1 0; @@ -222,11 +222,11 @@ #X connect 23 0 18 0; #X connect 24 0 6 0; #X connect 24 1 12 0; -#X connect 25 0 26 0; -#X connect 26 0 4 0; -#X connect 26 1 27 0; -#X connect 27 0 28 0; +#X connect 25 0 28 0; +#X connect 26 0 27 0; +#X connect 27 0 4 0; #X connect 28 0 4 0; +#X connect 28 1 26 0; #X restore 134 145 pd random-walk; #X obj 132 187 * 600; #X obj 132 212 - 300; diff --git a/examples/boids2d-gem.pd b/examples/boids2d-gem.pd deleted file mode 100644 index 2eac930..0000000 --- a/examples/boids2d-gem.pd +++ /dev/null @@ -1,164 +0,0 @@ -#N canvas 888 92 711 590 12; -#X declare -lib Gem; -#X msg 75 47 destroy; -#N canvas 494 140 629 324 gemwin 0; -#X obj 209 190 gemwin; -#X obj 67 194 outlet; -#X obj 67 10 inlet; -#X obj 67 41 route create; -#X msg 67 70 set destroy; -#X msg 157 70 set create; -#X msg 350 115 destroy \, reset; -#X obj 157 18 loadbang; -#X msg 212 146 create \, 1 \, frame 30 \, color 0 0 0.5; -#X msg 238 71 color 1 1 1; -#X connect 2 0 3 0; -#X connect 3 0 4 0; -#X connect 3 0 8 0; -#X connect 3 1 5 0; -#X connect 3 1 6 0; -#X connect 4 0 1 0; -#X connect 5 0 1 0; -#X connect 6 0 0 0; -#X connect 7 0 5 0; -#X connect 8 0 0 0; -#X connect 9 0 0 0; -#X restore 75 67 pd gemwin; -#N canvas 0 22 888 657 orbit 0; -#X obj 393 192 expr $f1 * (3.141593/180.); -#X msg 393 215 1.5 \$1; -#X obj 222 575 s \$0-orbit; -#X obj 333 59 gemhead; -#X obj 367 433 translateXYZ; -#X msg 399 498 draw line; -#X obj 402 470 loadbang; -#X obj 330 108 alpha; -#X obj 332 84 color 1 0.5 0 0.5; -#X obj 347 541 circle 0.1; -#X obj 416 403 unpack; -#X obj 397 373 t a a; -#X obj 334 136 t a b; -#X obj 454 267 t f f; -#X obj 451 295 cos; -#X obj 485 293 sin; -#X obj 404 318 * 1; -#X obj 394 266 t f f; -#X obj 435 318 * 0; -#X obj 402 348 pack; -#X obj 393 164 f; -#X obj 421 165 + 1; -#X obj 452 165 mod 360; -#X obj 391 240 unpack; -#X connect 0 0 1 0; -#X connect 1 0 23 0; -#X connect 3 0 8 0; -#X connect 4 0 9 0; -#X connect 5 0 9 0; -#X connect 6 0 5 0; -#X connect 7 0 12 0; -#X connect 8 0 7 0; -#X connect 10 0 4 1; -#X connect 10 1 4 2; -#X connect 11 0 2 0; -#X connect 11 1 10 0; -#X connect 12 0 4 0; -#X connect 12 1 20 0; -#X connect 13 0 14 0; -#X connect 13 1 15 0; -#X connect 14 0 16 1; -#X connect 15 0 18 1; -#X connect 16 0 19 0; -#X connect 17 0 16 0; -#X connect 17 1 18 0; -#X connect 18 0 19 1; -#X connect 19 0 11 0; -#X connect 20 0 21 0; -#X connect 20 0 0 0; -#X connect 21 0 22 0; -#X connect 22 0 20 1; -#X connect 23 0 17 0; -#X connect 23 1 13 0; -#X restore 77 158 pd orbit; -#X msg 70 321 attractpt \$1 \$2; -#X text 39 119 point to which boids are attracted (x/y), f 23; -#X obj 54 209 tgl 20 0 empty empty start\ flocking\ animation 0 -10 0 12 #fcfcfc #000000 #000000 0 1; -#X text 24 15 create/destroy the GEM window; -#X obj 584 27 declare -lib Gem; -#X obj 322 67 help/boids-params \$0; -#X floatatom 295 149 5 0 0 0 left \$0-flyrect0 - 0; -#X floatatom 356 113 6 0 0 0 top \$0-flyrect1 - 0; -#X floatatom 444 143 5 0 0 0 right \$0-flyrect2 - 0; -#X floatatom 505 182 5 0 0 0 bottom \$0-flyrect3 - 0; -#N canvas 0 0 450 300 2D-bounding-box 0; -#X msg 58 156 flyrect \$1 \$2 \$3 \$4; -#X obj 58 181 s \$0-boids-params; -#X msg 262 41 -1 1 1 -1; -#X msg 262 91 \; \$1-flyrect0 \$2 \; \$1-flyrect1 \$3 \; \$1-flyrect2 \$4 \; \$1-flyrect3 \$5; -#X obj 262 66 list prepend \$0; -#X text 336 44 defaults; -#X obj 261 13 r \$0-reset; -#X obj 29 27 inlet; -#X obj 74 29 inlet; -#X obj 119 29 inlet; -#X obj 170 29 inlet; -#X obj 41 76 pack f f f f; -#X connect 0 0 1 0; -#X connect 2 0 4 0; -#X connect 4 0 3 0; -#X connect 6 0 2 0; -#X connect 7 0 11 0; -#X connect 8 0 11 1; -#X connect 9 0 11 2; -#X connect 10 0 11 3; -#X connect 11 0 0 0; -#X restore 331 208 pd 2D-bounding-box; -#X f 23; -#X obj 72 292 r \$0-orbit; -#X obj 598 58 loadbang; -#X obj 598 83 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; -#X obj 598 108 s \$0-reset; -#X msg 88 361 reset; -#X obj 98 413 r \$0-boids-params; -#X obj 51 456 boids2d 16; -#X obj 51 512 clone -x gemboid 16 \$0; -#X msg 93 386 dump; -#X obj 119 482 print dump; -#X text 255 41 Change parameters to see their effect:; -#X floatatom 109 226 5 0 0 0 - - - 0; -#X obj 51 252 metro 25; -#X text 150 226 animation speed; -#X floatatom 326 269 5 0 0 0 - - - 0; -#X obj 326 293 abs; -#X obj 326 318 t f f; -#X obj 326 343 * -1; -#X obj 326 368 pack; -#X msg 327 398 \$1 \$2 \$2 \$1; -#X msg 333 448 \; \$1-flyrect0 \$2 \; \$1-flyrect1 \$3 \; \$1-flyrect2 \$4 \; \$1-flyrect3 \$5; -#X obj 333 423 list prepend \$0; -#X text 375 270 symmetrical bounding box; -#X connect 0 0 1 0; -#X connect 1 0 0 0; -#X connect 3 0 20 0; -#X connect 5 0 26 0; -#X connect 9 0 13 0; -#X connect 10 0 13 1; -#X connect 11 0 13 2; -#X connect 12 0 13 3; -#X connect 14 0 3 0; -#X connect 15 0 16 0; -#X connect 16 0 17 0; -#X connect 18 0 20 0; -#X connect 19 0 20 0; -#X connect 20 0 21 0; -#X connect 20 1 23 0; -#X connect 22 0 20 0; -#X connect 25 0 26 1; -#X connect 26 0 20 0; -#X connect 28 0 29 0; -#X connect 29 0 30 0; -#X connect 30 0 31 0; -#X connect 30 1 32 1; -#X connect 31 0 32 0; -#X connect 32 0 33 0; -#X connect 33 0 35 0; -#X connect 35 0 34 0; diff --git a/examples/boids2d-struct.pd b/examples/boids2d-struct.pd deleted file mode 100644 index 2134805..0000000 --- a/examples/boids2d-struct.pd +++ /dev/null @@ -1,268 +0,0 @@ -#N canvas 843 196 827 539 12; -#N struct \$0-template float k1 float k2 float k3 float x0 float y0 float x1 float y1 float x2 float y2 float x3 float y3 float i; -#N struct \$0-attractpoint float x float y; -#N canvas 0 25 554 469 \$0-data 0; -#X scalar \$0-template 533 533 0 86.9479 35.7409 76.9079 25.7811 66.9481 35.8211 76.9882 45.7809 15 \;; -#X scalar \$0-template 808 808 0 90.5485 75.9537 100.38 86.1194 110.546 76.2879 100.714 66.1222 14 \;; -#X scalar \$0-template 103 103 0 40.6929 146.054 50.556 156.189 60.691 146.326 50.8278 136.191 13 \;; -#X scalar \$0-template 739 739 0 53.7212 105.345 63.5899 115.475 73.7195 105.606 63.8509 95.4764 12 \;; -#X scalar \$0-template 864 864 0 73.5339 87.1421 83.4075 97.2669 93.5323 87.3932 83.6587 77.2684 11 \;; -#X scalar \$0-template 233 233 0 248.225 85.3604 258.206 95.3787 268.225 85.397 258.243 75.3787 10 \;; -#X scalar \$0-template 352 352 0 42.824 146.478 52.6891 156.611 62.8222 146.746 52.9571 136.613 9 \;; -#X scalar \$0-template 224 224 0 27.0472 202.492 36.8898 212.647 47.0447 202.804 37.2021 192.649 8 \;; -#X scalar \$0-template 805 805 0 96.7556 53.4489 106.737 63.4679 116.756 53.4869 106.775 43.4679 7 \;; -#X scalar \$0-template 301 301 0 62.0925 26.3905 72.042 36.4408 82.0923 26.4913 72.1428 16.441 6 \;; -#X scalar \$0-template 857 857 0 29.2793 236.74 39.1356 246.882 49.2773 237.025 39.4211 226.884 5 \;; -#X scalar \$0-template 572 572 0 33.658 207.273 43.5156 217.414 53.656 207.556 43.7983 197.416 4 \;; -#X scalar \$0-template 231 231 0 70.6423 105.863 80.5215 115.983 90.6409 106.104 80.7618 95.9843 3 \;; -#X scalar \$0-template 357 357 0 87.0974 28.9955 77.0544 19.0387 67.0976 29.0818 77.1407 39.0385 2 \;; -#X scalar \$0-template 149 149 0 93.7927 58.4476 103.6 68.6362 113.789 58.8284 103.981 48.6398 1 \;; -#X scalar \$0-template 726 726 0 32.1594 178.317 42.0162 188.458 52.1574 178.601 42.3006 168.46 0 \;; -#X scalar \$0-attractpoint 288 288 \;; -#X coords -300 -300 300 300 300 300 2 100 100; -#X restore 27 183 pd \$0-data; -#N canvas 125 78 524 337 \$0-template 0; -#X text 59 231 Struct that defines each boid diamond; -#X text 91 270 color can be changed with k; -#X obj 48 145 r \$0-indices; -#X obj 41 95 filledpolygon k1 k2 k3 x0 y0 x1 y1 x2 y2 x3 y3; -#X obj 48 177 drawnumber -n i 5 5 k1; -#X msg 360 225 clear; -#X obj 360 250 s pd-\$0-data; -#X obj 40 20 struct \$0-template float k1 float k2 float k3 float x0 float y0 float x1 float y1 float x2 float y2 float x3 float y3 float i; -#X connect 2 0 4 0; -#X connect 5 0 6 0; -#X restore 31 132 pd \$0-template; -#X floatatom 383 404 5 0 0 0 left \$0-flyrect0 - 0; -#X floatatom 425 380 5 0 0 0 top \$0-flyrect1 - 0; -#X floatatom 491 398 5 0 0 0 right \$0-flyrect2 - 0; -#X floatatom 559 416 5 0 0 0 bottom \$0-flyrect3 - 0; -#N canvas 0 0 450 300 2D-bounding-box 0; -#X msg 58 156 flyrect \$1 \$2 \$3 \$4; -#X obj 58 181 s \$0-boids-params; -#X obj 29 27 inlet; -#X obj 74 29 inlet; -#X obj 119 29 inlet; -#X obj 170 29 inlet; -#X obj 41 76 pack f f f f; -#X connect 0 0 1 0; -#X connect 2 0 6 0; -#X connect 3 0 6 1; -#X connect 4 0 6 2; -#X connect 5 0 6 3; -#X connect 6 0 0 0; -#X restore 391 443 pd 2D-bounding-box; -#X f 23; -#X obj 32 78 help/boids-params \$0; -#N canvas 1059 309 598 557 \$0-attractpoint 0; -#X obj 232 239 f \$0; -#X msg 232 264 traverse pd-\$1-data \, bang; -#X obj 232 289 pointer; -#X obj 90 138 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; -#X msg 443 234 clear; -#X obj 443 259 s pd-\$0-data; -#X obj 56 109 loadbang; -#X obj 63 165 t b b b b b, f 34; -#X obj 86 392 r \$0-attractpt; -#X obj 42 28 struct \$0-attractpoint float x float y; -#X obj 56 481 s \$0-init-boids; -#X obj 89 415 set \$0-attractpoint x y; -#X obj 124 324 append \$0-attractpoint x y; -#X msg 124 296 0 0; -#X obj 39 68 drawcurve 0 1 0 0 0 10 10 10 10 0 0 0; -#X obj 387 368 list prepend \$0; -#X obj 421 333 s \$0-reset; -#X obj 383 302 t b b; -#X msg 390 395 \; \$1-maxspeed 50 \; \$1-minspeed 10 \; \; \$1-flyrect0 -1 \; \$1-flyrect1 1 \; \$1-flyrect2 1 \; \$1-flyrect3 -1; -#X obj 130 108 r \$0-init; -#X text 267 116 Struct that defines the attraction circle; -#X connect 0 0 1 0; -#X connect 1 0 2 0; -#X connect 2 0 12 2; -#X connect 3 0 7 0; -#X connect 4 0 5 0; -#X connect 6 0 7 0; -#X connect 7 0 10 0; -#X connect 7 1 13 0; -#X connect 7 2 0 0; -#X connect 7 3 17 0; -#X connect 7 4 4 0; -#X connect 8 0 11 0; -#X connect 12 0 11 2; -#X connect 13 0 12 0; -#X connect 15 0 18 0; -#X connect 17 0 15 0; -#X connect 17 1 16 0; -#X connect 19 0 7 0; -#X restore 31 106 pd \$0-attractpoint; -#N canvas 323 118 689 551 random-walk 0; -#X obj 167 125 f; -#X obj 74 197 random 2; -#X obj 167 150 t b b f; -#X obj 195 351 +; -#X obj 140 276 + 1; -#X obj 122 332 *; -#X msg 64 305 -1; -#X obj 278 85 moses 0; -#X obj 324 115 moses 100; -#X obj 278 115 * -1; -#X obj 384 143 * -1; -#X obj 384 168 + 200; -#X msg 97 305 1; -#X text 80 223 sign; -#X text 142 240 magnitude; -#X text 228 340 add prev value; -#X text 227 355 to random increment; -#X obj 304 202 t f f; -#X obj 362 284 outlet; -#X obj 167 24 inlet; -#X obj 163 66 b; -#X text 97 461 Pure Data/2.control.examples/22.random-walk.pd, f 74; -#X text 140 439 open the browser and look for:; -#X obj 349 243 * 0.01; -#X obj 74 276 sel; -#X obj 140 200 random 2; -#X connect 0 0 2 0; -#X connect 1 0 24 0; -#X connect 2 0 1 0; -#X connect 2 1 25 0; -#X connect 2 2 3 1; -#X connect 3 0 7 0; -#X connect 4 0 5 1; -#X connect 5 0 3 0; -#X connect 6 0 5 0; -#X connect 7 0 9 0; -#X connect 7 1 8 0; -#X connect 8 0 17 0; -#X connect 8 1 10 0; -#X connect 9 0 17 0; -#X connect 10 0 11 0; -#X connect 11 0 17 0; -#X connect 12 0 5 0; -#X connect 17 0 0 1; -#X connect 17 1 23 0; -#X connect 19 0 20 0; -#X connect 20 0 0 0; -#X connect 23 0 18 0; -#X connect 24 0 6 0; -#X connect 24 1 12 0; -#X connect 25 0 4 0; -#X restore 366 209 pd random-walk; -#X obj 366 234 * 600; -#X obj 366 259 - 300; -#X obj 367 109 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; -#N canvas 657 108 689 551 random-walk 0; -#X obj 167 125 f; -#X obj 74 197 random 2; -#X obj 167 150 t b b f; -#X obj 195 351 +; -#X obj 140 276 + 1; -#X obj 122 332 *; -#X msg 64 305 -1; -#X obj 278 85 moses 0; -#X obj 324 115 moses 100; -#X obj 278 115 * -1; -#X obj 384 143 * -1; -#X obj 384 168 + 200; -#X msg 97 305 1; -#X text 80 223 sign; -#X text 145 221 magnitude; -#X text 228 340 add prev value; -#X text 227 355 to random increment; -#X obj 304 202 t f f; -#X obj 362 284 outlet; -#X obj 167 24 inlet; -#X obj 163 66 b; -#X text 97 461 Pure Data/2.control.examples/22.random-walk.pd, f 74; -#X text 140 439 open the browser and look for:; -#X obj 349 243 * 0.01; -#X obj 74 276 sel; -#X obj 140 198 random 2; -#X connect 0 0 2 0; -#X connect 1 0 24 0; -#X connect 2 0 1 0; -#X connect 2 1 25 0; -#X connect 2 2 3 1; -#X connect 3 0 7 0; -#X connect 4 0 5 1; -#X connect 5 0 3 0; -#X connect 6 0 5 0; -#X connect 7 0 9 0; -#X connect 7 1 8 0; -#X connect 8 0 17 0; -#X connect 8 1 10 0; -#X connect 9 0 17 0; -#X connect 10 0 11 0; -#X connect 11 0 17 0; -#X connect 12 0 5 0; -#X connect 17 0 0 1; -#X connect 17 1 23 0; -#X connect 19 0 20 0; -#X connect 20 0 0 0; -#X connect 23 0 18 0; -#X connect 24 0 6 0; -#X connect 24 1 12 0; -#X connect 25 0 4 0; -#X restore 410 233 pd random-walk; -#X obj 410 258 * 600; -#X obj 410 283 - 300; -#X obj 360 183 t b b; -#X obj 367 134 metro 50; -#X obj 366 284 pack; -#X obj 363 317 s \$0-attractpt; -#X floatatom 433 109 5 0 0 0 - - - 0; -#X msg 663 295 all bang; -#X obj 545 96 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; -#X obj 545 121 metro 10; -#X obj 545 256 boids2d; -#X obj 546 335 clone struct-boid 16 \$0; -#X msg 568 188 reset; -#X obj 614 224 r \$0-boids-params; -#X obj 605 289 print; -#X msg 561 161 dump; -#X msg 626 125 attractpt \$1 \$2; -#X obj 626 101 r \$0-attractpt; -#X obj 666 271 r \$0-init-boids; -#X obj 712 375 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; -#X obj 712 400 s \$0-init; -#X text 359 75 ATTRACTION POINT; -#X text 579 68 Update boids; -#X text 359 359 BOUNDING BOX; -#X floatatom 577 91 5 0 0 0 - - - 0; -#X obj 617 406 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; -#X obj 615 435 s \$0-indices; -#X text 239 24 A 2d boids example using data structures; -#X msg 633 196 mode 2; -#X obj 628 169 loadbang; -#X connect 2 0 6 0; -#X connect 3 0 6 1; -#X connect 4 0 6 2; -#X connect 5 0 6 3; -#X connect 9 0 10 0; -#X connect 10 0 11 0; -#X connect 11 0 18 0; -#X connect 12 0 17 0; -#X connect 13 0 14 0; -#X connect 14 0 15 0; -#X connect 15 0 18 1; -#X connect 16 0 9 0; -#X connect 16 1 13 0; -#X connect 17 0 16 0; -#X connect 18 0 19 0; -#X connect 20 0 17 1; -#X connect 21 0 25 1; -#X connect 22 0 23 0; -#X connect 23 0 24 0; -#X connect 24 0 25 0; -#X connect 24 1 28 0; -#X connect 26 0 24 0; -#X connect 27 0 24 0; -#X connect 29 0 24 0; -#X connect 30 0 24 0; -#X connect 31 0 30 0; -#X connect 32 0 21 0; -#X connect 33 0 34 0; -#X connect 38 0 23 1; -#X connect 39 0 40 0; -#X connect 42 0 24 0; -#X connect 43 0 42 0; diff --git a/examples/boids3d-gem.pd b/examples/boids3d-gem.pd deleted file mode 100644 index eb9ca8e..0000000 --- a/examples/boids3d-gem.pd +++ /dev/null @@ -1,278 +0,0 @@ -#N canvas 854 293 711 590 12; -#X declare -lib Gem; -#X msg 100 40 destroy; -#N canvas 803 136 629 324 gemwin 0; -#X obj 209 190 gemwin; -#X obj 67 194 outlet; -#X obj 67 10 inlet; -#X obj 67 41 route create; -#X msg 67 70 set destroy; -#X msg 157 70 set create; -#X msg 350 115 destroy \, reset; -#X obj 157 18 loadbang; -#X msg 238 71 color 1 1 1; -#X obj 496 28 gemhead; -#X obj 496 50 world_light; -#X msg 212 146 create \, 1 \, frame 30 \, color 0 0 0.5 \, lighting 1; -#X connect 2 0 3 0; -#X connect 3 0 4 0; -#X connect 3 0 11 0; -#X connect 3 1 5 0; -#X connect 3 1 6 0; -#X connect 4 0 1 0; -#X connect 5 0 1 0; -#X connect 6 0 0 0; -#X connect 7 0 5 0; -#X connect 8 0 0 0; -#X connect 9 0 10 0; -#X connect 11 0 0 0; -#X restore 100 60 pd gemwin; -#N canvas 850 212 692 479 orbit 0; -#X obj 63 290 translateXYZ; -#X obj 69 109 color 1 0.5 0 0.5; -#X obj 72 136 t a b; -#X obj 99 260 unpack f f f; -#X obj 402 108 color 1 0.5 0 0.5; -#X obj 416 337 loadbang; -#X obj 59 339 sphere 0.1; -#X obj 402 80 gemhead 58; -#X msg 416 364 draw line; -#X obj 396 302 translateXYZ; -#X obj 436 274 unpack f f f; -#X obj 400 215 translate -4 0 0 1; -#X obj 462 189 * -8; -#X obj 435 244 r \$0-orbit-translation; -#N canvas 0 0 782 606 orbit-translation 0; -#X obj 66 169 expr $f1 * (3.141593/180.); -#X msg 69 217 1.5 \$1; -#X obj 127 268 t f f; -#X obj 124 296 cos; -#X obj 158 294 sin; -#X obj 77 319 * 1; -#X obj 67 267 t f f; -#X obj 108 319 * 0; -#X obj 66 141 f; -#X obj 94 142 + 1; -#X obj 125 142 mod 360; -#X obj 64 241 unpack; -#X obj 66 193 t f f; -#X obj 252 381 pack f f f; -#X obj 192 318 * 2; -#X obj 191 292 sin; -#X obj 58 76 spigot 1; -#X obj 251 45 route float bang; -#X obj 488 130 spigot; -#X obj 542 130 spigot; -#X obj 548 76 t f f; -#X obj 517 35 gemmouse 1 1; -#A saved init; -#X obj 494 170 * 8; -#X obj 494 193 - 4; -#X obj 540 235 - 4; -#X text 566 184 invert y; -#X obj 540 212 * 8; -#X msg 540 153 1 \$1; -#X obj 540 177 -; -#X obj 647 232 spigot; -#X obj 647 257 t b f; -#X obj 556 104 t f f; -#X obj 651 184 * 8; -#X obj 652 206 - 4; -#X obj 250 471 s \$0-orbit-translation; -#X obj 265 14 inlet; -#X obj 55 10 inlet; -#X floatatom 77 344 5 0 0 0 - - - 0; -#X obj 300 82 random 360; -#X text 239 112 random position; -#X text 70 107 move in orbit; -#X text 497 11 mouse interaction; -#X text 591 321 middle click to enable Z motion (up/down), f 19; -#X connect 0 0 12 0; -#X connect 1 0 11 0; -#X connect 2 0 3 0; -#X connect 2 1 4 0; -#X connect 3 0 5 1; -#X connect 4 0 7 1; -#X connect 5 0 13 0; -#X connect 5 0 37 0; -#X connect 6 0 5 0; -#X connect 6 1 7 0; -#X connect 7 0 13 1; -#X connect 8 0 9 0; -#X connect 8 0 0 0; -#X connect 9 0 10 0; -#X connect 10 0 8 1; -#X connect 11 0 6 0; -#X connect 11 1 2 0; -#X connect 12 0 1 0; -#X connect 12 1 15 0; -#X connect 13 0 34 0; -#X connect 14 0 13 2; -#X connect 15 0 14 0; -#X connect 16 0 8 0; -#X connect 17 0 16 1; -#X connect 17 1 38 0; -#X connect 18 0 22 0; -#X connect 19 0 27 0; -#X connect 20 0 18 1; -#X connect 20 1 19 1; -#X connect 21 0 18 0; -#X connect 21 1 31 0; -#X connect 21 2 20 0; -#X connect 21 3 29 1; -#X connect 22 0 23 0; -#X connect 23 0 13 0; -#X connect 24 0 13 1; -#X connect 26 0 24 0; -#X connect 27 0 28 0; -#X connect 28 0 26 0; -#X connect 29 0 30 0; -#X connect 30 0 13 0; -#X connect 30 1 13 2; -#X connect 31 0 19 0; -#X connect 31 1 32 0; -#X connect 32 0 33 0; -#X connect 33 0 29 0; -#X connect 35 0 17 0; -#X connect 36 0 16 0; -#X connect 38 0 8 0; -#X restore 102 166 pd orbit-translation; -#X obj 103 229 r \$0-orbit-translation; -#X text 76 49 a circle; -#X obj 68 82 gemhead; -#X text 423 51 a bounding box; -#X obj 236 18 inlet; -#X obj 462 162 * 0.5; -#X obj 498 378 * 4; -#X obj 397 399 cube 4; -#X obj 504 341 r \$0-bounding-box; -#X obj 463 135 r \$0-bounding-box; -#X obj 46 28 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; -#X obj 383 29 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; -#X connect 0 0 6 0; -#X connect 1 0 2 0; -#X connect 2 0 0 0; -#X connect 2 1 14 0; -#X connect 3 0 0 1; -#X connect 3 1 0 2; -#X connect 3 2 0 3; -#X connect 4 0 11 0; -#X connect 5 0 8 0; -#X connect 7 0 4 0; -#X connect 8 0 22 0; -#X connect 9 0 22 0; -#X connect 10 0 9 1; -#X connect 10 1 9 2; -#X connect 10 2 9 3; -#X connect 11 0 9 0; -#X connect 12 0 11 1; -#X connect 13 0 10 0; -#X connect 15 0 3 0; -#X connect 17 0 1 0; -#X connect 19 0 14 1; -#X connect 20 0 12 0; -#X connect 21 0 22 1; -#X connect 23 0 21 0; -#X connect 24 0 20 0; -#X connect 25 0 17 0; -#X connect 26 0 7 0; -#X restore 347 236 pd orbit; -#X obj 35 210 tgl 20 1 empty empty start\ flocking\ animation 0 -10 0 12 #fcfcfc #000000 #000000 1 1; -#X text 23 18 create/destroy the GEM window; -#X obj 349 24 declare -lib Gem; -#X obj 92 128 help/boids-params \$0; -#X obj 590 26 loadbang; -#X obj 590 51 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; -#X obj 590 76 s \$0-reset; -#X msg 132 348 reset; -#X obj 142 400 r \$0-boids-params; -#X msg 137 373 dump; -#X obj 103 459 print dump; -#X text 25 102 Change parameters to see their effect:; -#X floatatom 93 222 5 0 0 0 - - - 0; -#X obj 35 248 metro 25; -#X text 134 222 animation speed; -#X floatatom 395 312 5 0 2 0 - \$0-bounding-box-set \$0-bounding-box 0; -#X msg 74 319 attractpt \$1 \$2 \$3; -#X floatatom 364 383 5 0 0 0 left \$0-flyrect0 - 0; -#X floatatom 406 367 5 0 0 0 top \$0-flyrect1 - 0; -#X floatatom 459 389 5 0 0 0 right \$0-flyrect2 - 0; -#X floatatom 508 407 5 0 0 0 bottom \$0-flyrect3 - 0; -#N canvas 0 0 632 412 3D-bounding-box 0; -#X obj 58 181 s \$0-boids-params; -#X obj 365 210 list prepend \$0; -#X obj 349 25 r \$0-reset; -#X obj 29 27 inlet; -#X obj 74 29 inlet; -#X obj 119 29 inlet; -#X obj 170 29 inlet; -#X obj 41 76 pack f f f f f f; -#X obj 219 30 inlet; -#X obj 270 30 inlet; -#X msg 58 156 flyrect \$1 \$2 \$3 \$4 \$5 \$6; -#X obj 434 64 abs; -#X obj 372 102 t f f; -#X obj 372 127 * -1; -#X obj 372 152 pack; -#X msg 372 176 \$1 \$2 \$2 \$1 \$2 \$1; -#X obj 447 36 r \$0-bounding-box; -#X msg 349 50 1; -#X msg 365 235 \; \$1-flyrect0 \$2 \; \$1-flyrect1 \$3 \; \$1-flyrect2 \$4 \; \$1-flyrect3 \$5 \; \$1-flyrect4 \$6 \; \$1-flyrect5 \$7 \; \$1-bounding-box-set set \$3; -#X connect 1 0 18 0; -#X connect 2 0 17 0; -#X connect 3 0 7 0; -#X connect 4 0 7 1; -#X connect 5 0 7 2; -#X connect 6 0 7 3; -#X connect 7 0 10 0; -#X connect 8 0 7 4; -#X connect 9 0 7 5; -#X connect 10 0 0 0; -#X connect 11 0 12 0; -#X connect 12 0 13 0; -#X connect 12 1 14 1; -#X connect 13 0 14 0; -#X connect 14 0 15 0; -#X connect 15 0 1 0; -#X connect 16 0 11 0; -#X connect 17 0 12 0; -#X restore 381 462 pd 3D-bounding-box; -#X f 23; -#X floatatom 587 406 5 0 0 0 front \$0-flyrect4 - 0; -#X floatatom 589 430 5 0 0 0 back \$0-flyrect5 - 0; -#X obj 35 433 boids3d 16; -#X obj 347 172 tgl 20 1 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 1 1; -#X obj 357 200 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; -#X obj 76 290 r \$0-orbit-translation; -#X text 413 223 or click+drag for XY; -#X text 412 236 and middle-click to move Z; -#X text 339 133 ATTRACTION POINT, f 17; -#X text 381 199 random in orbit; -#X text 350 285 BOUNDING BOX; -#X text 371 172 move in an orbit; -#X text 437 313 (shift + drag 0..2); -#X obj 35 489 clone -x gemboid 16 \$0 1; -#X msg 238 342 mode 2; -#X connect 0 0 1 0; -#X connect 1 0 0 0; -#X connect 3 0 16 0; -#X connect 7 0 8 0; -#X connect 8 0 9 0; -#X connect 10 0 27 0; -#X connect 11 0 27 0; -#X connect 12 0 27 0; -#X connect 15 0 16 1; -#X connect 16 0 27 0; -#X connect 19 0 27 0; -#X connect 20 0 24 0; -#X connect 21 0 24 1; -#X connect 22 0 24 2; -#X connect 23 0 24 3; -#X connect 25 0 24 4; -#X connect 26 0 24 5; -#X connect 27 0 38 0; -#X connect 27 1 13 0; -#X connect 28 0 2 0; -#X connect 29 0 2 0; -#X connect 30 0 19 0; -#X connect 39 0 27 0; diff --git a/examples/gemboid.pd b/examples/gemboid.pd deleted file mode 100644 index 31a7e6b..0000000 --- a/examples/gemboid.pd +++ /dev/null @@ -1,87 +0,0 @@ -#N canvas 92 179 719 539 12; -#X obj 61 64 gemhead; -#X obj 61 241 translateXYZ; -#X obj 152 41 inlet; -#N canvas 0 22 474 324 rand_color 0; -#X obj 158 105 random 1000; -#X obj 158 146 * 0.001; -#X obj 224 140 random 1000; -#X obj 224 181 * 0.001; -#X obj 307 141 random 1000; -#X obj 307 182 * 0.001; -#X obj 189 44 t b b b; -#X obj 141 285 outlet; -#X obj 185 19 r \$1-reset; -#X obj 137 8 inlet; -#X obj 139 189 *; -#X obj 143 230 pack f f f; -#X msg 143 255 \$2 \$3 \$1 0; -#X connect 0 0 1 0; -#X connect 1 0 10 1; -#X connect 2 0 3 0; -#X connect 3 0 11 1; -#X connect 4 0 5 0; -#X connect 5 0 11 2; -#X connect 6 0 0 0; -#X connect 6 1 2 0; -#X connect 6 2 4 0; -#X connect 8 0 6 0; -#X connect 9 0 10 0; -#X connect 10 0 11 0; -#X connect 11 0 12 0; -#X connect 12 0 7 0; -#X restore 195 121 pd rand_color; -#X obj 72 433 circle 0.05; -#X text 34 14 helper abstraction for boids examples with Gem; -#X obj 152 202 unpack f f f; -#X obj 284 179 loadbang; -#X obj 284 204 f \$2; -#X obj 203 245 ==; -#X obj 73 371 spigot 1; -#X obj 60 266 t a a; -#X obj 216 332 spigot; -#X obj 254 244 == 1; -#X obj 152 164 list split 3; -#X obj 394 94 list split 3; -#X obj 432 124 unpack f f f; -#X obj 382 391 rotateXYZ; -#X text 426 36 with mode == 2; -#X obj 391 486 sphere3d 0.1 6; -#X obj 453 411 loadbang; -#X obj 61 125 color 1 0.5 0 0; -#X obj 438 463 r \$1-size; -#X msg 453 436 setCartesian 0 0 0 0 2; -#X text 356 120 speed; -#X text 397 145 yaw = azimuth; -#X text 449 369 pitch = elevation; -#X obj 152 103 t a a; -#X obj 228 467 outlet; -#X connect 0 0 21 0; -#X connect 1 0 11 0; -#X connect 2 0 27 0; -#X connect 3 0 21 1; -#X connect 6 0 1 1; -#X connect 6 1 1 2; -#X connect 6 2 1 3; -#X connect 7 0 8 0; -#X connect 8 0 13 0; -#X connect 9 0 10 1; -#X connect 10 0 4 0; -#X connect 11 0 10 0; -#X connect 11 1 12 0; -#X connect 12 0 17 0; -#X connect 13 0 9 0; -#X connect 13 0 12 1; -#X connect 14 0 6 0; -#X connect 14 1 15 0; -#X connect 15 1 16 0; -#X connect 16 0 3 0; -#X connect 16 1 17 1; -#X connect 16 2 17 3; -#X connect 17 0 19 0; -#X connect 20 0 23 0; -#X connect 21 0 1 0; -#X connect 22 0 19 1; -#X connect 23 0 19 0; -#X connect 27 0 14 0; -#X connect 27 1 28 0; diff --git a/examples/point.pd b/examples/point.pd deleted file mode 100644 index bef68c4..0000000 --- a/examples/point.pd +++ /dev/null @@ -1,83 +0,0 @@ -#N canvas 825 51 664 704 12; -#X obj 61 13 inlet; -#X obj 137 327 unpack; -#X obj 264 320 cos; -#X obj 296 320 sin; -#X obj 275 215 t f f; -#X obj 127 363 t f f; -#X obj 151 422 *; -#X obj 185 421 *; -#X obj 176 365 t f f; -#X obj 263 423 *; -#X obj 297 422 *; -#X obj 237 363 t f f; -#X obj 288 363 t f f; -#X obj 151 447 -; -#X obj 263 448 +; -#X obj 263 527 +; -#X obj 375 528 +; -#X obj 446 329 unpack; -#X obj 136 156 abs; -#X obj 134 206 * -1; -#X obj 137 117 unpack; -#X obj 436 118 list split 2; -#X obj 113 80 list split 2; -#X obj 263 552 pack; -#X msg 96 537 append \$1 \$2; -#X obj 64 580 list store; -#X obj 58 44 t b a a, f 42; -#X obj 64 605 t a b; -#X obj 64 630 outlet; -#X listbox 152 497 20 0 0 0 - - - 0; -#X listbox 263 473 20 0 0 0 - - - 0; -#X obj 134 231 pack f f f; -#X obj 135 181 t f f f; -#X msg 130 264 \$1 0 \, 0 \$3 \, \$2 0, f 11; -#X obj 195 203 * -3; -#X connect 0 0 26 0; -#X connect 1 0 5 0; -#X connect 1 1 8 0; -#X connect 2 0 11 0; -#X connect 3 0 12 0; -#X connect 4 0 2 0; -#X connect 4 1 3 0; -#X connect 5 0 6 0; -#X connect 5 1 9 0; -#X connect 6 0 13 0; -#X connect 7 0 13 1; -#X connect 8 0 7 0; -#X connect 8 1 10 0; -#X connect 9 0 14 0; -#X connect 10 0 14 1; -#X connect 11 0 6 1; -#X connect 11 1 10 1; -#X connect 12 0 7 1; -#X connect 12 1 9 1; -#X connect 13 0 15 0; -#X connect 13 0 29 0; -#X connect 14 0 16 0; -#X connect 14 0 30 0; -#X connect 15 0 23 0; -#X connect 16 0 23 1; -#X connect 17 0 15 1; -#X connect 17 1 16 1; -#X connect 18 0 32 0; -#X connect 19 0 31 0; -#X connect 20 0 18 0; -#X connect 20 1 4 0; -#X connect 21 0 17 0; -#X connect 22 1 20 0; -#X connect 23 0 24 0; -#X connect 24 0 25 0; -#X connect 25 0 27 0; -#X connect 26 0 25 0; -#X connect 26 1 22 0; -#X connect 26 2 21 0; -#X connect 27 0 28 0; -#X connect 27 1 25 1; -#X connect 31 0 33 0; -#X connect 32 0 19 0; -#X connect 32 1 31 1; -#X connect 32 2 34 0; -#X connect 33 0 1 0; -#X connect 34 0 31 2; diff --git a/examples/struct-boid.pd b/examples/struct-boid.pd deleted file mode 100644 index ae05b5d..0000000 --- a/examples/struct-boid.pd +++ /dev/null @@ -1,50 +0,0 @@ -#N canvas 576 120 648 513 12; -#X msg 430 259 traverse pd-\$1-data \, bang, f 21; -#X obj 429 315 pointer; -#X obj 430 219 f \$2; -#X obj 48 39 inlet; -#X obj 238 265 point; -#X obj 305 238 s \$0-color; -#X obj 324 277 r \$0-color; -#X obj 242 330 list prepend; -#X msg 324 302 list \$1 \$1 0; -#X obj 59 313 point; -#X obj 237 158 t b b b, f 8; -#X obj 307 207 random 998; -#X obj 52 403 set \$2-template x0 y0 x1 y1 x2 y2, f 16; -#X msg 234 213 0 0 6 0; -#X obj 42 87 list split 2; -#X obj 77 209 list; -#X obj 78 115 list split 2; -#X obj 99 144 unpack f f f; -#X msg 63 257 \$1 \$2 6 \$3; -#X obj 140 168 / 180; -#X obj 134 192 * 3.14156; -#X obj 135 212 * 2; -#X obj 240 120 r \$2-init-boids; -#X obj 240 404 append \$2-template k1 k2 k3 x0 y0 x1 y1 x2 y2, f 25; -#X connect 0 0 1 0; -#X connect 1 0 23 9; -#X connect 2 0 0 0; -#X connect 3 0 14 0; -#X connect 4 0 7 0; -#X connect 6 0 8 0; -#X connect 7 0 23 0; -#X connect 8 0 7 1; -#X connect 9 0 12 0; -#X connect 10 0 13 0; -#X connect 10 1 11 0; -#X connect 10 2 2 0; -#X connect 11 0 5 0; -#X connect 13 0 4 0; -#X connect 14 0 15 0; -#X connect 14 1 16 0; -#X connect 15 0 18 0; -#X connect 16 1 17 0; -#X connect 17 1 19 0; -#X connect 18 0 9 0; -#X connect 19 0 20 0; -#X connect 20 0 21 0; -#X connect 21 0 15 1; -#X connect 22 0 10 0; -#X connect 23 0 12 6; diff --git a/help/boids-params.pd b/help/boids-params.pd deleted file mode 100644 index 43d152c..0000000 --- a/help/boids-params.pd +++ /dev/null @@ -1,288 +0,0 @@ -#N canvas 74 74 1255 607 12; -#X text 487 26 Boids Parameters; -#N canvas 112 25 779 393 glue 0; -#X obj 48 57 r \$1-number; -#X obj 48 107 s \$1-boids-params; -#X obj 48 82 list prepend number; -#X obj 219 57 r \$1-neighbors; -#X obj 219 107 s \$1-boids-params; -#X obj 219 82 list prepend neighbors; -#X obj 387 57 r \$1-inertia; -#X obj 387 107 s \$1-boids-params; -#X obj 387 82 list prepend inertia; -#X obj 558 57 r \$1-speed; -#X obj 558 107 s \$1-boids-params; -#X obj 558 82 list prepend speed; -#X obj 47 135 r \$1-maxspeed; -#X obj 47 185 s \$1-boids-params; -#X obj 47 160 list prepend maxspeed; -#X obj 218 135 r \$1-minspeed; -#X obj 218 185 s \$1-boids-params; -#X obj 218 160 list prepend minspeed; -#X obj 388 140 r \$1-accel; -#X obj 388 190 s \$1-boids-params; -#X obj 388 165 list prepend accel; -#X obj 559 140 r \$1-match; -#X obj 559 190 s \$1-boids-params; -#X obj 559 165 list prepend match; -#X obj 46 218 r \$1-avoid; -#X obj 46 268 s \$1-boids-params; -#X obj 46 243 list prepend avoid; -#X obj 217 218 r \$1-repel; -#X obj 217 268 s \$1-boids-params; -#X obj 217 243 list prepend repel; -#X obj 385 218 r \$1-edgedist; -#X obj 385 268 s \$1-boids-params; -#X obj 385 243 list prepend edgedist; -#X obj 556 218 r \$1-prefdist; -#X obj 556 268 s \$1-boids-params; -#X obj 556 243 list prepend prefdist; -#X obj 45 296 r \$1-center; -#X obj 45 346 s \$1-boids-params; -#X obj 45 321 list prepend center; -#X obj 216 296 r \$1-attract; -#X obj 216 346 s \$1-boids-params; -#X obj 216 321 list prepend attract; -#X text 55 22 prepend the parameter name to the parameter values and send them to the global receiver, f 88; -#N canvas 192 66 1405 689 flyrect-dimensions 0; -#X obj 352 423 * -1; -#X obj 352 448 pack; -#X obj 55 109 r \$1-dimensions; -#X msg 353 243 symbol flyrect; -#X obj 353 268 text search \$1-parameters; -#X obj 353 293 sel -1; -#X msg 353 318 1; -#X obj 392 317 text get \$1-parameters; -#X obj 352 374 abs; -#X obj 124 523 list store, f 16; -#X obj 124 442 until; -#X obj 124 469 list; -#X msg 124 494 append \$1 \$2; -#X obj 78 417 t b f; -#X obj 124 549 t a b; -#X obj 124 574 list prepend flyrect; -#X obj 83 639 s \$1-boids-params; -#X obj 55 166 t f f b; -#X obj 392 343 list split 1; -#X obj 432 368 list split 1; -#X obj 55 606 list prepend dimensions; -#X text 176 548 -bound \, +bound \, -bound \, +bound \, etc; -#X text 32 60 bounds is interpreted as a pair -bound \, +bound per dimension to build the flying rectangle (or cube \, etc) \, so they are interlinked with dimensions, f 77; -#X text 184 16 Special treatment for dimensions and bounds (flyrect); -#X listbox 106 138 20 0 0 0 - - - 0; -#X listbox 354 479 20 0 0 0 - - - 0; -#X obj 134 268 text search \$1-parameters; -#X obj 134 293 sel -1; -#X obj 173 317 text get \$1-parameters; -#X obj 173 343 list split 1; -#X msg 134 243 symbol dimensions; -#X msg 134 318 2; -#X obj 571 244 list split 1; -#X obj 339 119 r \$1-bounds; -#X obj 353 350 t f; -#X obj 353 215 sel 0; -#X obj 353 190 f 0; -#X obj 352 398 t f f f; -#X obj 398 452 s \$1-bounds-set; -#X obj 55 138 max 1; -#X obj 137 391 s \$1-dimensions; -#X obj 337 143 t b f; -#X msg 407 427 set \$1; -#X floatatom 399 182 5 0 0 0 - - - 0; -#X floatatom 508 406 5 0 0 0 - - - 0; -#X obj 571 219 r \$1-flyrect-set; -#X obj 571 269 abs; -#X obj 571 294 s \$1-bounds-set; -#X connect 0 0 1 0; -#X connect 1 0 11 1; -#X connect 1 0 25 0; -#X connect 2 0 39 0; -#X connect 3 0 4 0; -#X connect 4 0 5 0; -#X connect 5 0 6 0; -#X connect 5 1 7 0; -#X connect 6 0 34 0; -#X connect 7 0 18 0; -#X connect 8 0 37 0; -#X connect 9 0 14 0; -#X connect 10 0 11 0; -#X connect 11 0 12 0; -#X connect 12 0 9 0; -#X connect 13 0 9 0; -#X connect 13 1 10 0; -#X connect 14 0 15 0; -#X connect 14 1 9 1; -#X connect 15 0 16 0; -#X connect 17 0 20 0; -#X connect 17 1 13 0; -#X connect 17 2 36 0; -#X connect 18 1 19 0; -#X connect 19 0 34 0; -#X connect 19 0 44 0; -#X connect 20 0 16 0; -#X connect 26 0 27 0; -#X connect 27 0 31 0; -#X connect 27 1 28 0; -#X connect 28 0 29 0; -#X connect 29 1 40 0; -#X connect 30 0 26 0; -#X connect 31 0 40 0; -#X connect 32 0 46 0; -#X connect 33 0 41 0; -#X connect 34 0 8 0; -#X connect 35 0 3 0; -#X connect 35 1 34 0; -#X connect 36 0 35 0; -#X connect 37 0 0 0; -#X connect 37 1 1 1; -#X connect 37 2 42 0; -#X connect 39 0 17 0; -#X connect 39 0 24 0; -#X connect 41 0 30 0; -#X connect 41 1 36 1; -#X connect 41 1 43 0; -#X connect 42 0 38 0; -#X connect 45 0 32 0; -#X connect 46 0 47 0; -#X restore 476 327 pd flyrect-dimensions; -#X connect 0 0 2 0; -#X connect 2 0 1 0; -#X connect 3 0 5 0; -#X connect 5 0 4 0; -#X connect 6 0 8 0; -#X connect 8 0 7 0; -#X connect 9 0 11 0; -#X connect 11 0 10 0; -#X connect 12 0 14 0; -#X connect 14 0 13 0; -#X connect 15 0 17 0; -#X connect 17 0 16 0; -#X connect 18 0 20 0; -#X connect 20 0 19 0; -#X connect 21 0 23 0; -#X connect 23 0 22 0; -#X connect 24 0 26 0; -#X connect 26 0 25 0; -#X connect 27 0 29 0; -#X connect 29 0 28 0; -#X connect 30 0 32 0; -#X connect 32 0 31 0; -#X connect 33 0 35 0; -#X connect 35 0 34 0; -#X connect 36 0 38 0; -#X connect 38 0 37 0; -#X connect 39 0 41 0; -#X connect 41 0 40 0; -#X restore 841 95 pd glue; -#X obj 104 451 r \$1-boids-params; -#X obj 105 479 outlet; -#N canvas 0 0 577 425 defaults 0; -#X obj 108 113 list prepend \$1; -#X obj 112 82 r \$1-defaults; -#X msg 103 139 \; \$1-dimensions-set 2 \; \$1-number-set 16 \; \$1-neighbors-set 4 \; \$1-maxspeed-set 1.5 \; \$1-minspeed-set 1.2 \; \$1-center-set 1.2 \; \$1-attract-set 1.25 \; \$1-match-set 0.3 \; \$1-avoid-set 3.5 \; \$1-repel-set 3.5 \; \$1-edgedist-set 3 \; \$1-speed-set 3 \; \$1-inertia-set 4.5 \; \$1-accel-set 2.5 \; \$1-prefdist-set 1.5 \; \$1-bounds-set 1 \;, f 36; -#X text 62 27 keep a list of default parameter values reflecting the internal initial state of the object; -#X connect 0 0 2 0; -#X connect 1 0 0 0; -#X restore 841 128 pd defaults; -#N canvas 133 208 1066 594 storage 0; -#X obj 646 299 savestate; -#X obj 68 187 r \$1-boids-params; -#X obj 65 239 list split 1; -#X obj 73 339 text search \$1-parameters; -#X obj 135 446 text set \$1-parameters 0 1; -#X obj 73 368 sel -1; -#X obj 139 392 t b f; -#X obj 731 337 text sequence \$1-parameters; -#X msg 732 309 line 0 \, auto; -#X obj 66 214 t a a; -#X obj 71 408 list; -#X obj 72 445 t a b; -#X msg 100 481 1e+10; -#X obj 66 506 text set \$1-parameters; -#X obj 137 421 list; -#X obj 535 208 text sequence \$1-parameters; -#X msg 536 180 line 0 \, auto; -#X obj 538 150 r \$1-output; -#X obj 532 355 t a a; -#X obj 589 420 list split 1; -#X obj 532 389 list split 1; -#X obj 571 485 s; -#X obj 589 445 makefilename \$1-%s-set; -#X text 533 96 this updates the number boxes with the stored parameters in the text (and subsequently outputs the parameters); -#X text 636 257 this saves the parameter text when saving the main patch (outputs it on load); -#X text 28 288 if the param is already in the text \, update it. Otherwise \, we create a new line for that parameter, f 51; -#X text 30 87 store the parameters on the text on a dictionary: a single line per parameter \, with the prepended parameter name and the values in the subsequent fields; -#X text 537 44 retrieval; -#X text 31 36 storage; -#X connect 0 0 18 0; -#X connect 0 1 8 0; -#X connect 1 0 9 0; -#X connect 2 0 3 0; -#X connect 2 1 14 1; -#X connect 3 0 5 0; -#X connect 5 0 10 0; -#X connect 5 1 6 0; -#X connect 6 0 14 0; -#X connect 6 1 4 1; -#X connect 7 0 0 0; -#X connect 8 0 7 0; -#X connect 9 0 2 0; -#X connect 9 1 10 1; -#X connect 10 0 11 0; -#X connect 11 0 13 0; -#X connect 11 1 12 0; -#X connect 12 0 13 1; -#X connect 14 0 4 0; -#X connect 15 0 18 0; -#X connect 16 0 15 0; -#X connect 17 0 16 0; -#X connect 18 0 20 0; -#X connect 18 1 19 0; -#X connect 19 0 22 0; -#X connect 20 1 21 0; -#X connect 22 0 21 1; -#X restore 841 64 pd storage; -#X text 399 178 FLOCK PARAMETERS -----------------------------; -#X text 787 179 NEIGHBORS -----------------------------; -#X text 404 347 BOID MOVEMENT -----------------------------; -#X text 786 397 WALL BEHAVIOR -----------------------------; -#X obj 184 134 nbx 5 18 -1e+37 1e+37 0 0 \$1-number \$1-number-set number 0 -10 0 12 #fcfcfc #000000 #000000 0 256; -#X obj 184 174 nbx 5 18 -1e+37 1e+37 0 0 \$1-center \$1-center-set center 0 -10 0 12 #fcfcfc #000000 #000000 0 256; -#X obj 109 174 nbx 5 18 -1e+37 1e+37 0 0 \$1-attract \$1-attract-set attract 0 -10 0 12 #fcfcfc #000000 #000000 0 256; -#X obj 259 213 nbx 5 18 -1e+37 1e+37 0 0 \$1-prefdist \$1-prefdist-set prefdist 0 -10 0 12 #fcfcfc #000000 #000000 0 256; -#X obj 259 134 nbx 5 18 -1e+37 1e+37 0 0 \$1-neighbors \$1-neighbors-set neighbors 0 -10 0 12 #fcfcfc #000000 #000000 0 256; -#X obj 109 213 nbx 5 18 -1e+37 1e+37 0 0 \$1-match \$1-match-set match 0 -10 0 12 #fcfcfc #000000 #000000 0 256; -#X obj 184 213 nbx 5 18 -1e+37 1e+37 0 0 \$1-avoid \$1-avoid-set avoid 0 -10 0 12 #fcfcfc #000000 #000000 0 256; -#X obj 259 252 nbx 5 18 -1e+37 1e+37 0 0 \$1-maxspeed \$1-maxspeed-set maxspeed 0 -10 0 12 #fcfcfc #000000 #000000 0 256; -#X obj 109 252 nbx 5 18 -1e+37 1e+37 0 0 \$1-speed \$1-speed-set speed 0 -10 0 12 #fcfcfc #000000 #000000 0 256; -#X obj 109 291 nbx 5 18 -1e+37 1e+37 0 0 \$1-inertia \$1-inertia-set inertia 0 -10 0 12 #fcfcfc #000000 #000000 0 256; -#X obj 184 291 nbx 5 18 -1e+37 1e+37 0 0 \$1-accel \$1-accel-set accel 0 -10 0 12 #fcfcfc #000000 #000000 0 256; -#X obj 184 252 nbx 5 18 -1e+37 1e+37 0 0 \$1-minspeed \$1-minspeed-set minspeed 0 -10 0 12 #fcfcfc #000000 #000000 0 256; -#X obj 184 330 nbx 5 18 -1e+37 1e+37 0 0 \$1-repel \$1-repel-set repel 0 -10 0 12 #fcfcfc #000000 #000000 0 256; -#X obj 109 330 nbx 5 18 -1e+37 1e+37 0 0 \$1-edgedist \$1-edgedist-set edgedist 0 -10 0 12 #fcfcfc #000000 #000000 0 256; -#X text 393 60 Here are all parameters you can send to the boids external. You can also get the defaults by sending a "dump" message before changing them; -#X obj 259 291 bng 20 250 50 0 \$1-defaults \$1-defaults defaults 0 -10 0 12 #fcfcfc #000000 #000000; -#X obj 259 330 bng 20 250 50 0 \$1-output \$1-output output 0 -10 0 12 #fcfcfc #000000 #000000; -#X obj 109 134 nbx 5 18 -1e+37 1e+37 0 0 \$1-dimensions \$1-dimensions-set dimensions 0 -10 0 12 #fcfcfc #000000 #000000 0 256; -#X obj 260 174 nbx 5 18 -1e+37 1e+37 0 0 \$1-bounds \$1-bounds-set bounds 0 -10 0 12 #fcfcfc #000000 #000000 0 256; -#X text 395 215 number: number of boids; -#X text 393 294 center: strength of centering instinct; -#X text 395 252 attractpt: strength of attraction to 'attractpt'; -#X text 404 389 inertia: willingness to change speed and direction; -#X text 403 431 speed: overall speed; -#X text 404 473 min/max speed: speed range; -#X text 406 515 accel: speed of acceleration; -#X text 799 219 neighbors: number of neighbors each boid consults when flocking; -#X text 793 266 match: strength of neighbor speed matching instinct; -#X text 789 308 avoid: strength of neighbor avoidance instinct; -#X text 796 350 prefdist: preferred distance from neighbors; -#X text 794 438 edgedist: distance of vision for avoiding wall edges; -#X text 791 481 repel: strength of wall avoidance instinct; -#X text 789 522 bounds: size of the equally space bounding box as in: -bound +bound \, one pair per dimension, f 45; -#X text 397 132 dimensions: number of dimensions: 1 \, 2 \, 3 \, ...; -#X obj 983 67 text define \$1-parameters; -#X obj 103 387 loadbang; -#X obj 103 412 s \$1-output; -#X connect 2 0 3 0; -#X connect 45 0 46 0; -#X coords 0 -1 1 1 230 270 1 100 100; From 4e31f700335aaf0bca77d2742cf04f91cfee74a1 Mon Sep 17 00:00:00 2001 From: fdch Date: Wed, 13 May 2026 17:24:53 +0200 Subject: [PATCH 18/19] cleanup helpfiles and abstractions --- .gitignore | 1 - Makefile | 2 +- boids/boids-params.pd | 288 ++++++++++++++++++++++++++++++++++++++ boids/gemboid.pd | 87 ++++++++++++ boids/point.pd | 83 +++++++++++ boids/struct-boid.pd | 50 +++++++ examples/boids-gem.pd | 40 +++--- examples/boids-gemlist.pd | 54 +++---- examples/boids-struct.pd | 38 ++--- help/boids-help.pd | 259 ++++++++++++++++------------------ help/boids2d-help.pd | 205 ++++++++++++--------------- help/boids3d-help.pd | 235 ++++++++++++++----------------- 12 files changed, 893 insertions(+), 449 deletions(-) create mode 100644 boids/boids-params.pd create mode 100644 boids/gemboid.pd create mode 100644 boids/point.pd create mode 100644 boids/struct-boid.pd diff --git a/.gitignore b/.gitignore index c167498..f5dd675 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ *.pd_linux *.o -boids/ compile_commands.json .cache/ diff --git a/Makefile b/Makefile index db3167d..016ab52 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ class.sources = src/boids.c common.sources = src/boid_params.c src/vec.c # all extra files to be included in binary distribution of the library -datafiles = boids-meta.pd help/boids2d-help.pd help/boids3d-help.pd README.txt LICENSE.txt +datafiles = boids-meta.pd help/boids2d-help.pd help/boids3d-help.pd README.txt LICENSE.txt $(wildcard boids/*.pd) datadirs = examples boids diff --git a/boids/boids-params.pd b/boids/boids-params.pd new file mode 100644 index 0000000..43d152c --- /dev/null +++ b/boids/boids-params.pd @@ -0,0 +1,288 @@ +#N canvas 74 74 1255 607 12; +#X text 487 26 Boids Parameters; +#N canvas 112 25 779 393 glue 0; +#X obj 48 57 r \$1-number; +#X obj 48 107 s \$1-boids-params; +#X obj 48 82 list prepend number; +#X obj 219 57 r \$1-neighbors; +#X obj 219 107 s \$1-boids-params; +#X obj 219 82 list prepend neighbors; +#X obj 387 57 r \$1-inertia; +#X obj 387 107 s \$1-boids-params; +#X obj 387 82 list prepend inertia; +#X obj 558 57 r \$1-speed; +#X obj 558 107 s \$1-boids-params; +#X obj 558 82 list prepend speed; +#X obj 47 135 r \$1-maxspeed; +#X obj 47 185 s \$1-boids-params; +#X obj 47 160 list prepend maxspeed; +#X obj 218 135 r \$1-minspeed; +#X obj 218 185 s \$1-boids-params; +#X obj 218 160 list prepend minspeed; +#X obj 388 140 r \$1-accel; +#X obj 388 190 s \$1-boids-params; +#X obj 388 165 list prepend accel; +#X obj 559 140 r \$1-match; +#X obj 559 190 s \$1-boids-params; +#X obj 559 165 list prepend match; +#X obj 46 218 r \$1-avoid; +#X obj 46 268 s \$1-boids-params; +#X obj 46 243 list prepend avoid; +#X obj 217 218 r \$1-repel; +#X obj 217 268 s \$1-boids-params; +#X obj 217 243 list prepend repel; +#X obj 385 218 r \$1-edgedist; +#X obj 385 268 s \$1-boids-params; +#X obj 385 243 list prepend edgedist; +#X obj 556 218 r \$1-prefdist; +#X obj 556 268 s \$1-boids-params; +#X obj 556 243 list prepend prefdist; +#X obj 45 296 r \$1-center; +#X obj 45 346 s \$1-boids-params; +#X obj 45 321 list prepend center; +#X obj 216 296 r \$1-attract; +#X obj 216 346 s \$1-boids-params; +#X obj 216 321 list prepend attract; +#X text 55 22 prepend the parameter name to the parameter values and send them to the global receiver, f 88; +#N canvas 192 66 1405 689 flyrect-dimensions 0; +#X obj 352 423 * -1; +#X obj 352 448 pack; +#X obj 55 109 r \$1-dimensions; +#X msg 353 243 symbol flyrect; +#X obj 353 268 text search \$1-parameters; +#X obj 353 293 sel -1; +#X msg 353 318 1; +#X obj 392 317 text get \$1-parameters; +#X obj 352 374 abs; +#X obj 124 523 list store, f 16; +#X obj 124 442 until; +#X obj 124 469 list; +#X msg 124 494 append \$1 \$2; +#X obj 78 417 t b f; +#X obj 124 549 t a b; +#X obj 124 574 list prepend flyrect; +#X obj 83 639 s \$1-boids-params; +#X obj 55 166 t f f b; +#X obj 392 343 list split 1; +#X obj 432 368 list split 1; +#X obj 55 606 list prepend dimensions; +#X text 176 548 -bound \, +bound \, -bound \, +bound \, etc; +#X text 32 60 bounds is interpreted as a pair -bound \, +bound per dimension to build the flying rectangle (or cube \, etc) \, so they are interlinked with dimensions, f 77; +#X text 184 16 Special treatment for dimensions and bounds (flyrect); +#X listbox 106 138 20 0 0 0 - - - 0; +#X listbox 354 479 20 0 0 0 - - - 0; +#X obj 134 268 text search \$1-parameters; +#X obj 134 293 sel -1; +#X obj 173 317 text get \$1-parameters; +#X obj 173 343 list split 1; +#X msg 134 243 symbol dimensions; +#X msg 134 318 2; +#X obj 571 244 list split 1; +#X obj 339 119 r \$1-bounds; +#X obj 353 350 t f; +#X obj 353 215 sel 0; +#X obj 353 190 f 0; +#X obj 352 398 t f f f; +#X obj 398 452 s \$1-bounds-set; +#X obj 55 138 max 1; +#X obj 137 391 s \$1-dimensions; +#X obj 337 143 t b f; +#X msg 407 427 set \$1; +#X floatatom 399 182 5 0 0 0 - - - 0; +#X floatatom 508 406 5 0 0 0 - - - 0; +#X obj 571 219 r \$1-flyrect-set; +#X obj 571 269 abs; +#X obj 571 294 s \$1-bounds-set; +#X connect 0 0 1 0; +#X connect 1 0 11 1; +#X connect 1 0 25 0; +#X connect 2 0 39 0; +#X connect 3 0 4 0; +#X connect 4 0 5 0; +#X connect 5 0 6 0; +#X connect 5 1 7 0; +#X connect 6 0 34 0; +#X connect 7 0 18 0; +#X connect 8 0 37 0; +#X connect 9 0 14 0; +#X connect 10 0 11 0; +#X connect 11 0 12 0; +#X connect 12 0 9 0; +#X connect 13 0 9 0; +#X connect 13 1 10 0; +#X connect 14 0 15 0; +#X connect 14 1 9 1; +#X connect 15 0 16 0; +#X connect 17 0 20 0; +#X connect 17 1 13 0; +#X connect 17 2 36 0; +#X connect 18 1 19 0; +#X connect 19 0 34 0; +#X connect 19 0 44 0; +#X connect 20 0 16 0; +#X connect 26 0 27 0; +#X connect 27 0 31 0; +#X connect 27 1 28 0; +#X connect 28 0 29 0; +#X connect 29 1 40 0; +#X connect 30 0 26 0; +#X connect 31 0 40 0; +#X connect 32 0 46 0; +#X connect 33 0 41 0; +#X connect 34 0 8 0; +#X connect 35 0 3 0; +#X connect 35 1 34 0; +#X connect 36 0 35 0; +#X connect 37 0 0 0; +#X connect 37 1 1 1; +#X connect 37 2 42 0; +#X connect 39 0 17 0; +#X connect 39 0 24 0; +#X connect 41 0 30 0; +#X connect 41 1 36 1; +#X connect 41 1 43 0; +#X connect 42 0 38 0; +#X connect 45 0 32 0; +#X connect 46 0 47 0; +#X restore 476 327 pd flyrect-dimensions; +#X connect 0 0 2 0; +#X connect 2 0 1 0; +#X connect 3 0 5 0; +#X connect 5 0 4 0; +#X connect 6 0 8 0; +#X connect 8 0 7 0; +#X connect 9 0 11 0; +#X connect 11 0 10 0; +#X connect 12 0 14 0; +#X connect 14 0 13 0; +#X connect 15 0 17 0; +#X connect 17 0 16 0; +#X connect 18 0 20 0; +#X connect 20 0 19 0; +#X connect 21 0 23 0; +#X connect 23 0 22 0; +#X connect 24 0 26 0; +#X connect 26 0 25 0; +#X connect 27 0 29 0; +#X connect 29 0 28 0; +#X connect 30 0 32 0; +#X connect 32 0 31 0; +#X connect 33 0 35 0; +#X connect 35 0 34 0; +#X connect 36 0 38 0; +#X connect 38 0 37 0; +#X connect 39 0 41 0; +#X connect 41 0 40 0; +#X restore 841 95 pd glue; +#X obj 104 451 r \$1-boids-params; +#X obj 105 479 outlet; +#N canvas 0 0 577 425 defaults 0; +#X obj 108 113 list prepend \$1; +#X obj 112 82 r \$1-defaults; +#X msg 103 139 \; \$1-dimensions-set 2 \; \$1-number-set 16 \; \$1-neighbors-set 4 \; \$1-maxspeed-set 1.5 \; \$1-minspeed-set 1.2 \; \$1-center-set 1.2 \; \$1-attract-set 1.25 \; \$1-match-set 0.3 \; \$1-avoid-set 3.5 \; \$1-repel-set 3.5 \; \$1-edgedist-set 3 \; \$1-speed-set 3 \; \$1-inertia-set 4.5 \; \$1-accel-set 2.5 \; \$1-prefdist-set 1.5 \; \$1-bounds-set 1 \;, f 36; +#X text 62 27 keep a list of default parameter values reflecting the internal initial state of the object; +#X connect 0 0 2 0; +#X connect 1 0 0 0; +#X restore 841 128 pd defaults; +#N canvas 133 208 1066 594 storage 0; +#X obj 646 299 savestate; +#X obj 68 187 r \$1-boids-params; +#X obj 65 239 list split 1; +#X obj 73 339 text search \$1-parameters; +#X obj 135 446 text set \$1-parameters 0 1; +#X obj 73 368 sel -1; +#X obj 139 392 t b f; +#X obj 731 337 text sequence \$1-parameters; +#X msg 732 309 line 0 \, auto; +#X obj 66 214 t a a; +#X obj 71 408 list; +#X obj 72 445 t a b; +#X msg 100 481 1e+10; +#X obj 66 506 text set \$1-parameters; +#X obj 137 421 list; +#X obj 535 208 text sequence \$1-parameters; +#X msg 536 180 line 0 \, auto; +#X obj 538 150 r \$1-output; +#X obj 532 355 t a a; +#X obj 589 420 list split 1; +#X obj 532 389 list split 1; +#X obj 571 485 s; +#X obj 589 445 makefilename \$1-%s-set; +#X text 533 96 this updates the number boxes with the stored parameters in the text (and subsequently outputs the parameters); +#X text 636 257 this saves the parameter text when saving the main patch (outputs it on load); +#X text 28 288 if the param is already in the text \, update it. Otherwise \, we create a new line for that parameter, f 51; +#X text 30 87 store the parameters on the text on a dictionary: a single line per parameter \, with the prepended parameter name and the values in the subsequent fields; +#X text 537 44 retrieval; +#X text 31 36 storage; +#X connect 0 0 18 0; +#X connect 0 1 8 0; +#X connect 1 0 9 0; +#X connect 2 0 3 0; +#X connect 2 1 14 1; +#X connect 3 0 5 0; +#X connect 5 0 10 0; +#X connect 5 1 6 0; +#X connect 6 0 14 0; +#X connect 6 1 4 1; +#X connect 7 0 0 0; +#X connect 8 0 7 0; +#X connect 9 0 2 0; +#X connect 9 1 10 1; +#X connect 10 0 11 0; +#X connect 11 0 13 0; +#X connect 11 1 12 0; +#X connect 12 0 13 1; +#X connect 14 0 4 0; +#X connect 15 0 18 0; +#X connect 16 0 15 0; +#X connect 17 0 16 0; +#X connect 18 0 20 0; +#X connect 18 1 19 0; +#X connect 19 0 22 0; +#X connect 20 1 21 0; +#X connect 22 0 21 1; +#X restore 841 64 pd storage; +#X text 399 178 FLOCK PARAMETERS -----------------------------; +#X text 787 179 NEIGHBORS -----------------------------; +#X text 404 347 BOID MOVEMENT -----------------------------; +#X text 786 397 WALL BEHAVIOR -----------------------------; +#X obj 184 134 nbx 5 18 -1e+37 1e+37 0 0 \$1-number \$1-number-set number 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 184 174 nbx 5 18 -1e+37 1e+37 0 0 \$1-center \$1-center-set center 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 109 174 nbx 5 18 -1e+37 1e+37 0 0 \$1-attract \$1-attract-set attract 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 259 213 nbx 5 18 -1e+37 1e+37 0 0 \$1-prefdist \$1-prefdist-set prefdist 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 259 134 nbx 5 18 -1e+37 1e+37 0 0 \$1-neighbors \$1-neighbors-set neighbors 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 109 213 nbx 5 18 -1e+37 1e+37 0 0 \$1-match \$1-match-set match 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 184 213 nbx 5 18 -1e+37 1e+37 0 0 \$1-avoid \$1-avoid-set avoid 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 259 252 nbx 5 18 -1e+37 1e+37 0 0 \$1-maxspeed \$1-maxspeed-set maxspeed 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 109 252 nbx 5 18 -1e+37 1e+37 0 0 \$1-speed \$1-speed-set speed 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 109 291 nbx 5 18 -1e+37 1e+37 0 0 \$1-inertia \$1-inertia-set inertia 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 184 291 nbx 5 18 -1e+37 1e+37 0 0 \$1-accel \$1-accel-set accel 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 184 252 nbx 5 18 -1e+37 1e+37 0 0 \$1-minspeed \$1-minspeed-set minspeed 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 184 330 nbx 5 18 -1e+37 1e+37 0 0 \$1-repel \$1-repel-set repel 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 109 330 nbx 5 18 -1e+37 1e+37 0 0 \$1-edgedist \$1-edgedist-set edgedist 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X text 393 60 Here are all parameters you can send to the boids external. You can also get the defaults by sending a "dump" message before changing them; +#X obj 259 291 bng 20 250 50 0 \$1-defaults \$1-defaults defaults 0 -10 0 12 #fcfcfc #000000 #000000; +#X obj 259 330 bng 20 250 50 0 \$1-output \$1-output output 0 -10 0 12 #fcfcfc #000000 #000000; +#X obj 109 134 nbx 5 18 -1e+37 1e+37 0 0 \$1-dimensions \$1-dimensions-set dimensions 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 260 174 nbx 5 18 -1e+37 1e+37 0 0 \$1-bounds \$1-bounds-set bounds 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X text 395 215 number: number of boids; +#X text 393 294 center: strength of centering instinct; +#X text 395 252 attractpt: strength of attraction to 'attractpt'; +#X text 404 389 inertia: willingness to change speed and direction; +#X text 403 431 speed: overall speed; +#X text 404 473 min/max speed: speed range; +#X text 406 515 accel: speed of acceleration; +#X text 799 219 neighbors: number of neighbors each boid consults when flocking; +#X text 793 266 match: strength of neighbor speed matching instinct; +#X text 789 308 avoid: strength of neighbor avoidance instinct; +#X text 796 350 prefdist: preferred distance from neighbors; +#X text 794 438 edgedist: distance of vision for avoiding wall edges; +#X text 791 481 repel: strength of wall avoidance instinct; +#X text 789 522 bounds: size of the equally space bounding box as in: -bound +bound \, one pair per dimension, f 45; +#X text 397 132 dimensions: number of dimensions: 1 \, 2 \, 3 \, ...; +#X obj 983 67 text define \$1-parameters; +#X obj 103 387 loadbang; +#X obj 103 412 s \$1-output; +#X connect 2 0 3 0; +#X connect 45 0 46 0; +#X coords 0 -1 1 1 230 270 1 100 100; diff --git a/boids/gemboid.pd b/boids/gemboid.pd new file mode 100644 index 0000000..31a7e6b --- /dev/null +++ b/boids/gemboid.pd @@ -0,0 +1,87 @@ +#N canvas 92 179 719 539 12; +#X obj 61 64 gemhead; +#X obj 61 241 translateXYZ; +#X obj 152 41 inlet; +#N canvas 0 22 474 324 rand_color 0; +#X obj 158 105 random 1000; +#X obj 158 146 * 0.001; +#X obj 224 140 random 1000; +#X obj 224 181 * 0.001; +#X obj 307 141 random 1000; +#X obj 307 182 * 0.001; +#X obj 189 44 t b b b; +#X obj 141 285 outlet; +#X obj 185 19 r \$1-reset; +#X obj 137 8 inlet; +#X obj 139 189 *; +#X obj 143 230 pack f f f; +#X msg 143 255 \$2 \$3 \$1 0; +#X connect 0 0 1 0; +#X connect 1 0 10 1; +#X connect 2 0 3 0; +#X connect 3 0 11 1; +#X connect 4 0 5 0; +#X connect 5 0 11 2; +#X connect 6 0 0 0; +#X connect 6 1 2 0; +#X connect 6 2 4 0; +#X connect 8 0 6 0; +#X connect 9 0 10 0; +#X connect 10 0 11 0; +#X connect 11 0 12 0; +#X connect 12 0 7 0; +#X restore 195 121 pd rand_color; +#X obj 72 433 circle 0.05; +#X text 34 14 helper abstraction for boids examples with Gem; +#X obj 152 202 unpack f f f; +#X obj 284 179 loadbang; +#X obj 284 204 f \$2; +#X obj 203 245 ==; +#X obj 73 371 spigot 1; +#X obj 60 266 t a a; +#X obj 216 332 spigot; +#X obj 254 244 == 1; +#X obj 152 164 list split 3; +#X obj 394 94 list split 3; +#X obj 432 124 unpack f f f; +#X obj 382 391 rotateXYZ; +#X text 426 36 with mode == 2; +#X obj 391 486 sphere3d 0.1 6; +#X obj 453 411 loadbang; +#X obj 61 125 color 1 0.5 0 0; +#X obj 438 463 r \$1-size; +#X msg 453 436 setCartesian 0 0 0 0 2; +#X text 356 120 speed; +#X text 397 145 yaw = azimuth; +#X text 449 369 pitch = elevation; +#X obj 152 103 t a a; +#X obj 228 467 outlet; +#X connect 0 0 21 0; +#X connect 1 0 11 0; +#X connect 2 0 27 0; +#X connect 3 0 21 1; +#X connect 6 0 1 1; +#X connect 6 1 1 2; +#X connect 6 2 1 3; +#X connect 7 0 8 0; +#X connect 8 0 13 0; +#X connect 9 0 10 1; +#X connect 10 0 4 0; +#X connect 11 0 10 0; +#X connect 11 1 12 0; +#X connect 12 0 17 0; +#X connect 13 0 9 0; +#X connect 13 0 12 1; +#X connect 14 0 6 0; +#X connect 14 1 15 0; +#X connect 15 1 16 0; +#X connect 16 0 3 0; +#X connect 16 1 17 1; +#X connect 16 2 17 3; +#X connect 17 0 19 0; +#X connect 20 0 23 0; +#X connect 21 0 1 0; +#X connect 22 0 19 1; +#X connect 23 0 19 0; +#X connect 27 0 14 0; +#X connect 27 1 28 0; diff --git a/boids/point.pd b/boids/point.pd new file mode 100644 index 0000000..bef68c4 --- /dev/null +++ b/boids/point.pd @@ -0,0 +1,83 @@ +#N canvas 825 51 664 704 12; +#X obj 61 13 inlet; +#X obj 137 327 unpack; +#X obj 264 320 cos; +#X obj 296 320 sin; +#X obj 275 215 t f f; +#X obj 127 363 t f f; +#X obj 151 422 *; +#X obj 185 421 *; +#X obj 176 365 t f f; +#X obj 263 423 *; +#X obj 297 422 *; +#X obj 237 363 t f f; +#X obj 288 363 t f f; +#X obj 151 447 -; +#X obj 263 448 +; +#X obj 263 527 +; +#X obj 375 528 +; +#X obj 446 329 unpack; +#X obj 136 156 abs; +#X obj 134 206 * -1; +#X obj 137 117 unpack; +#X obj 436 118 list split 2; +#X obj 113 80 list split 2; +#X obj 263 552 pack; +#X msg 96 537 append \$1 \$2; +#X obj 64 580 list store; +#X obj 58 44 t b a a, f 42; +#X obj 64 605 t a b; +#X obj 64 630 outlet; +#X listbox 152 497 20 0 0 0 - - - 0; +#X listbox 263 473 20 0 0 0 - - - 0; +#X obj 134 231 pack f f f; +#X obj 135 181 t f f f; +#X msg 130 264 \$1 0 \, 0 \$3 \, \$2 0, f 11; +#X obj 195 203 * -3; +#X connect 0 0 26 0; +#X connect 1 0 5 0; +#X connect 1 1 8 0; +#X connect 2 0 11 0; +#X connect 3 0 12 0; +#X connect 4 0 2 0; +#X connect 4 1 3 0; +#X connect 5 0 6 0; +#X connect 5 1 9 0; +#X connect 6 0 13 0; +#X connect 7 0 13 1; +#X connect 8 0 7 0; +#X connect 8 1 10 0; +#X connect 9 0 14 0; +#X connect 10 0 14 1; +#X connect 11 0 6 1; +#X connect 11 1 10 1; +#X connect 12 0 7 1; +#X connect 12 1 9 1; +#X connect 13 0 15 0; +#X connect 13 0 29 0; +#X connect 14 0 16 0; +#X connect 14 0 30 0; +#X connect 15 0 23 0; +#X connect 16 0 23 1; +#X connect 17 0 15 1; +#X connect 17 1 16 1; +#X connect 18 0 32 0; +#X connect 19 0 31 0; +#X connect 20 0 18 0; +#X connect 20 1 4 0; +#X connect 21 0 17 0; +#X connect 22 1 20 0; +#X connect 23 0 24 0; +#X connect 24 0 25 0; +#X connect 25 0 27 0; +#X connect 26 0 25 0; +#X connect 26 1 22 0; +#X connect 26 2 21 0; +#X connect 27 0 28 0; +#X connect 27 1 25 1; +#X connect 31 0 33 0; +#X connect 32 0 19 0; +#X connect 32 1 31 1; +#X connect 32 2 34 0; +#X connect 33 0 1 0; +#X connect 34 0 31 2; diff --git a/boids/struct-boid.pd b/boids/struct-boid.pd new file mode 100644 index 0000000..ae05b5d --- /dev/null +++ b/boids/struct-boid.pd @@ -0,0 +1,50 @@ +#N canvas 576 120 648 513 12; +#X msg 430 259 traverse pd-\$1-data \, bang, f 21; +#X obj 429 315 pointer; +#X obj 430 219 f \$2; +#X obj 48 39 inlet; +#X obj 238 265 point; +#X obj 305 238 s \$0-color; +#X obj 324 277 r \$0-color; +#X obj 242 330 list prepend; +#X msg 324 302 list \$1 \$1 0; +#X obj 59 313 point; +#X obj 237 158 t b b b, f 8; +#X obj 307 207 random 998; +#X obj 52 403 set \$2-template x0 y0 x1 y1 x2 y2, f 16; +#X msg 234 213 0 0 6 0; +#X obj 42 87 list split 2; +#X obj 77 209 list; +#X obj 78 115 list split 2; +#X obj 99 144 unpack f f f; +#X msg 63 257 \$1 \$2 6 \$3; +#X obj 140 168 / 180; +#X obj 134 192 * 3.14156; +#X obj 135 212 * 2; +#X obj 240 120 r \$2-init-boids; +#X obj 240 404 append \$2-template k1 k2 k3 x0 y0 x1 y1 x2 y2, f 25; +#X connect 0 0 1 0; +#X connect 1 0 23 9; +#X connect 2 0 0 0; +#X connect 3 0 14 0; +#X connect 4 0 7 0; +#X connect 6 0 8 0; +#X connect 7 0 23 0; +#X connect 8 0 7 1; +#X connect 9 0 12 0; +#X connect 10 0 13 0; +#X connect 10 1 11 0; +#X connect 10 2 2 0; +#X connect 11 0 5 0; +#X connect 13 0 4 0; +#X connect 14 0 15 0; +#X connect 14 1 16 0; +#X connect 15 0 18 0; +#X connect 16 1 17 0; +#X connect 17 1 19 0; +#X connect 18 0 9 0; +#X connect 19 0 20 0; +#X connect 20 0 21 0; +#X connect 21 0 15 1; +#X connect 22 0 10 0; +#X connect 23 0 12 6; diff --git a/examples/boids-gem.pd b/examples/boids-gem.pd index 0a1b3ad..1eeaae5 100644 --- a/examples/boids-gem.pd +++ b/examples/boids-gem.pd @@ -1,5 +1,5 @@ #N canvas 741 52 738 578 12; -#X declare -lib Gem; +#X declare -lib Gem -lib boids -path boids; #X msg 100 40 create; #N canvas 803 136 629 324 gemwin 0; #X obj 209 190 gemwin; @@ -170,7 +170,6 @@ #X restore 347 236 pd orbit; #X obj 35 210 tgl 20 1 empty empty start\ flocking\ animation 0 -10 0 12 #fcfcfc #000000 #000000 1 1; #X text 23 18 create/destroy the GEM window; -#X obj 349 24 declare -lib Gem; #X obj 345 288 boids-params \$0; #A saved flyrect -2 2 -2 2; #A saved dimensions 3; @@ -400,25 +399,26 @@ #X text 371 172 move around (like a pray); #X msg 225 305 mode 2; #X obj 35 433 boids; +#X obj 300 20 declare -lib Gem -lib boids -path boids; #X connect 0 0 1 0; #X connect 1 0 0 0; -#X connect 3 0 16 0; +#X connect 3 0 15 0; +#X connect 6 0 7 0; #X connect 7 0 8 0; -#X connect 8 0 9 0; -#X connect 10 0 35 0; -#X connect 11 0 26 0; -#X connect 12 0 35 0; -#X connect 15 0 16 1; -#X connect 16 0 35 0; -#X connect 18 0 35 0; -#X connect 19 0 2 0; -#X connect 20 0 18 0; -#X connect 24 0 32 0; +#X connect 9 0 34 0; +#X connect 10 0 25 0; +#X connect 11 0 34 0; +#X connect 14 0 15 1; +#X connect 15 0 34 0; +#X connect 17 0 34 0; +#X connect 18 0 2 0; +#X connect 19 0 17 0; +#X connect 23 0 31 0; +#X connect 24 0 33 0; #X connect 25 0 34 0; -#X connect 26 0 35 0; -#X connect 27 0 29 0; -#X connect 29 0 28 0; -#X connect 30 0 31 0; -#X connect 34 0 35 0; -#X connect 35 0 24 0; -#X connect 35 1 13 0; +#X connect 26 0 28 0; +#X connect 28 0 27 0; +#X connect 29 0 30 0; +#X connect 33 0 34 0; +#X connect 34 0 23 0; +#X connect 34 1 12 0; diff --git a/examples/boids-gemlist.pd b/examples/boids-gemlist.pd index 66e8bb1..e5cd757 100644 --- a/examples/boids-gemlist.pd +++ b/examples/boids-gemlist.pd @@ -1,5 +1,5 @@ #N canvas 1018 93 597 774 10; -#X declare -path boids -lib Gem; +#X declare -path boids -lib Gem -lib boids; #X msg 432 52 create; #N canvas 1028 103 629 324 gemwin 0; #X obj 170 199 gemwin; @@ -152,7 +152,6 @@ #X obj 47 368 trigger bang anything bang; #X obj 200 449 unpack 0 0 0; #X obj 47 459 color; -#X obj 265 6 declare -path boids -lib Gem; #X obj 47 342 boids 100; #X obj 125 508 list split 1; #X obj 75 565 unpack f f f; @@ -186,43 +185,44 @@ #X msg 182 239 mode 2; #X obj 194 570 list split 3; #X obj 130 622 unpack f f f; +#X obj 265 6 declare -path boids -lib Gem -lib boids; #X connect 0 0 1 0; #X connect 1 0 0 0; +#X connect 4 0 22 0; #X connect 4 0 23 0; -#X connect 4 0 24 0; -#X connect 5 0 28 1; +#X connect 5 0 27 1; #X connect 6 0 12 0; -#X connect 7 0 30 0; +#X connect 7 0 29 0; #X connect 8 0 7 0; #X connect 9 0 10 0; #X connect 10 0 16 0; -#X connect 12 0 18 0; +#X connect 12 0 17 0; #X connect 12 1 9 1; #X connect 12 2 13 1; -#X connect 12 2 28 0; +#X connect 12 2 27 0; #X connect 13 0 15 0; #X connect 13 0 16 1; #X connect 14 0 9 0; -#X connect 14 1 19 0; +#X connect 14 1 18 0; #X connect 14 2 13 0; #X connect 15 0 8 1; #X connect 16 0 8 0; -#X connect 18 0 14 0; -#X connect 19 1 21 0; -#X connect 20 0 7 1; -#X connect 20 1 7 2; -#X connect 20 2 7 3; -#X connect 21 0 20 0; -#X connect 21 1 33 0; -#X connect 22 0 18 0; -#X connect 23 0 22 0; -#X connect 23 1 11 0; -#X connect 26 0 27 0; -#X connect 27 0 18 0; -#X connect 28 0 4 0; -#X connect 30 0 29 0; -#X connect 31 0 32 0; -#X connect 32 0 18 0; -#X connect 33 1 34 0; -#X connect 34 1 30 1; -#X connect 34 2 30 3; +#X connect 17 0 14 0; +#X connect 18 1 20 0; +#X connect 19 0 7 1; +#X connect 19 1 7 2; +#X connect 19 2 7 3; +#X connect 20 0 19 0; +#X connect 20 1 32 0; +#X connect 21 0 17 0; +#X connect 22 0 21 0; +#X connect 22 1 11 0; +#X connect 25 0 26 0; +#X connect 26 0 17 0; +#X connect 27 0 4 0; +#X connect 29 0 28 0; +#X connect 30 0 31 0; +#X connect 31 0 17 0; +#X connect 32 1 33 0; +#X connect 33 1 29 1; +#X connect 33 2 29 3; diff --git a/examples/boids-struct.pd b/examples/boids-struct.pd index 3486b90..7a0f129 100644 --- a/examples/boids-struct.pd +++ b/examples/boids-struct.pd @@ -1,24 +1,25 @@ #N canvas 986 25 614 803 12; +#X declare -lib boids -path boids; #N struct \$0-template float k1 float k2 float k3 float x0 float y0 float x1 float y1 float x2 float y2; #N struct \$0-attractpoint float x float y; #N canvas 0 25 554 469 \$0-data 0; -#X scalar \$0-template 559 559 0 65.0746 -56.696 69.5656 -38.2615 54.9121 -50.3145 \;; -#X scalar \$0-template 662 662 0 33.1008 -167.948 52.0493 -168.924 37.4763 -156.774 \;; -#X scalar \$0-template 653 653 0 -21.2323 -123.544 -18.132 -142.263 -9.38101 -125.427 \;; -#X scalar \$0-template 354 354 0 -73.2501 -110.582 -91.9465 -113.814 -75.0502 -122.446 \;; -#X scalar \$0-template 292 292 0 -51.1678 -110.237 -44.863 -128.132 -39.1696 -110.033 \;; -#X scalar \$0-template 591 591 0 -38.161 -124.099 -32.7755 -142.292 -26.1679 -124.506 \;; -#X scalar \$0-template 620 620 0 -42.069 -70.8646 -58.9269 -62.1576 -50.6647 -79.2379 \;; -#X scalar \$0-template 278 278 0 -7.71273 -73.7757 -19.6283 -59.0102 -18.9551 -77.9719 \;; -#X scalar \$0-template 687 687 0 -5.51123 -150.007 11.1193 -140.873 -7.66542 -138.202 \;; -#X scalar \$0-template 767 767 0 160.597 -182.205 149.207 -197.38 167.424 -192.074 \;; -#X scalar \$0-template 867 867 0 -47.1116 -146.392 -54.0828 -164.038 -37.9179 -154.104 \;; -#X scalar \$0-template 476 476 0 92.4542 -13.669 92.6008 5.3041 81.0997 -9.78638 \;; -#X scalar \$0-template 40 40 0 92.258 -129.968 105.908 -143.147 102.895 -124.414 \;; -#X scalar \$0-template 41 41 0 -45.82 -185.435 -28.9757 -194.168 -37.2112 -177.075 \;; -#X scalar \$0-template 501 501 0 -14.1743 -157.58 -8.5463 -175.7 -2.17688 -157.827 \;; -#X scalar \$0-template 839 839 0 123.069 12.6053 105.359 5.7973 123.612 0.61761 \;; -#X scalar \$0-attractpoint -12 -138 \;; +#X scalar \$0-template 742 742 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 927 927 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 726 726 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 918 918 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 628 628 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 565 565 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 485 485 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 304 304 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 55 55 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 300 300 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 157 157 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 737 737 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 433 433 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 271 271 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 987 987 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 916 916 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-attractpoint 0 0 \;; #X coords -300 -300 300 300 300 300 2 100 100; #X restore 24 69 pd \$0-data; #N canvas 125 78 524 337 \$0-template 0; @@ -76,7 +77,7 @@ #X text 48 411 ATTRACTION POINT; #X text 354 430 Update boids; #X floatatom 357 467 5 0 0 0 - - - 0; -#X text 155 26 A 2d boids example using data structures; +#X text 33 18 A 2d boids example using data structures; #X obj 408 545 loadbang; #X obj 325 632 boids 16; #X obj 470 606 list trim; @@ -257,6 +258,7 @@ #X text 79 443 random walk; #X obj 486 518 r \$0-attractpt; #X text 80 518 manual input (turn random off first), f 18; +#X obj 360 21 declare -lib boids -path boids; #X connect 3 0 4 0; #X connect 4 0 18 0; #X connect 6 0 18 0; diff --git a/help/boids-help.pd b/help/boids-help.pd index 5451985..43ac55b 100644 --- a/help/boids-help.pd +++ b/help/boids-help.pd @@ -1,20 +1,17 @@ -#N canvas 587 25 836 757 12; -#X floatatom 520 123 5 0 0 0 left \$0-flyrect0 - 0; -#X floatatom 562 107 5 0 0 0 top \$0-flyrect1 - 0; -#X floatatom 615 129 5 0 0 0 right \$0-flyrect2 - 0; -#X floatatom 664 147 5 0 0 0 bottom \$0-flyrect3 - 0; -#X floatatom 465 338 5 0 0 0 - - - 0; -#X floatatom 509 336 5 0 0 0 - - - 0; +#N canvas 506 25 822 888 12; +#X declare -path boids; +#X floatatom 492 656 5 0 0 0 - - - 0; +#X floatatom 536 654 5 0 0 0 - - - 0; #X msg 80 386 mode \$1; #X text 145 424 reset boids randomly inside flyrect; -#X text 394 639 (c) 1995-98 Eric L. Singer (eric@ericsinger.com); +#X text 34 827 (c) 1995-98 Eric L. Singer (eric@ericsinger.com); #X text 25 73 Based on Simon Fraser's implementation of Craig Reynolds' Boids algorithm. Boids is free for non-commercial use; #X text 25 109 Boids is a bird flight and animal flock simulator. It is based on the same algorithm which was used in Jurassic Park for the herding dinosaurs.; -#X text 387 571 For more information about the Boids algorithm \, see Craig Reynolds' Web site at http://www.red3d.com/cwr/boids/; -#X text 397 617 arguments: number of boids \, output mode; +#X text 27 759 For more information about the Boids algorithm \, see Craig Reynolds' Web site at http://www.red3d.com/cwr/boids/; +#X text 37 805 arguments: number of boids \, output mode; #X obj 78 536 print dump; #X obj 19 10 cnv 15 800 48 empty empty boids 15 20 2 24 #dce0c8 #404040 0; -#X text 395 662 float/2d/3d adaptation 08/2005 by a. sier / jasch; +#X text 35 850 float/2d/3d adaptation 08/2005 by a. sier / jasch; #N canvas 88 105 494 344 META 0; #X text 13 182 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 13 160 AUTHOR Eric L. Singer; @@ -25,13 +22,13 @@ #X text 13 138 OUTLET_1 list; #X text 13 28 LICENSE GPL v2; #X restore 760 21 pd META; -#X obj 494 438 s \$0-boids-params; +#X obj 518 751 s \$0-boids-params; #X text 225 654 ..., f 4; #X floatatom 24 677 5 0 0 0 - - - 0; #X floatatom 62 695 5 0 0 0 - - - 0; #X floatatom 127 675 5 0 0 0 - - - 0; #X floatatom 164 694 5 0 0 0 - - - 0; -#X obj 79 360 hradio 18 1 0 3 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0; +#X obj 79 360 hradio 18 1 0 4 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0; #X msg 53 316 dump; #X msg 99 422 reset; #X obj 32 228 bng 18 250 50 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000; @@ -56,13 +53,9 @@ #X text 39 267 (0) new position only; #X obj 186 17 inlet; #X text 298 14 this patch shows the different output modes of the boids external.; -#X msg 393 100 mode \$1; -#X obj 393 167 s \$0-boids-params; -#X obj 392 74 hradio 18 1 0 3 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0; #X text 391 45 output mode:; -#X text 468 100 (1) new and old positions; -#X text 468 78 (0) new position only; -#X text 470 122 (2) new and old with delta positions; +#X text 426 99 (1) new and old positions; +#X text 426 77 (0) new position only; #X obj 47 203 unpack f f f; #X floatatom 129 228 5 0 0 0 - - - 0; #X obj 198 262 unpack f f f f f f; @@ -73,144 +66,136 @@ #X floatatom 587 361 5 0 0 0 - - - 0; #X obj 343 229 unpack f f f f f f f f f, f 33; #X obj 189 141 route 3 6 9; +#X text 428 121 (2) new and old with speed \, azim \, elev; +#X text 428 145 (3) position and direction vectors; +#X text 138 424 (3) position and direction vectors; #X connect 10 0 11 1; -#X connect 11 0 36 0; +#X connect 11 0 32 0; #X connect 12 0 11 0; #X connect 12 1 10 0; #X connect 18 0 12 0; -#X connect 20 0 21 0; -#X connect 22 0 20 0; -#X connect 27 0 13 0; -#X connect 27 1 14 0; -#X connect 27 2 28 0; -#X connect 29 0 0 0; -#X connect 29 1 1 0; -#X connect 29 2 2 0; -#X connect 29 3 3 0; -#X connect 29 4 30 0; -#X connect 29 5 31 0; -#X connect 35 0 4 0; -#X connect 35 1 5 0; -#X connect 35 2 6 0; -#X connect 35 3 7 0; -#X connect 35 4 8 0; -#X connect 35 5 9 0; -#X connect 35 6 32 0; -#X connect 35 7 33 0; -#X connect 35 8 34 0; -#X connect 36 0 27 0; -#X connect 36 1 29 0; -#X connect 36 2 35 0; +#X connect 23 0 13 0; +#X connect 23 1 14 0; +#X connect 23 2 24 0; +#X connect 25 0 0 0; +#X connect 25 1 1 0; +#X connect 25 2 2 0; +#X connect 25 3 3 0; +#X connect 25 4 26 0; +#X connect 25 5 27 0; +#X connect 31 0 4 0; +#X connect 31 1 5 0; +#X connect 31 2 6 0; +#X connect 31 3 7 0; +#X connect 31 4 8 0; +#X connect 31 5 9 0; +#X connect 31 6 28 0; +#X connect 31 7 29 0; +#X connect 31 8 30 0; +#X connect 32 0 23 0; +#X connect 32 1 25 0; +#X connect 32 2 31 0; #X restore 251 605 pd output-mode; #X floatatom 279 690 5 0 0 0 - - - 0; #X floatatom 317 708 5 0 0 0 - - - 0; #X obj 32 572 route 0 1 2 3 4 10 15, f 27; -#X text 136 361 see [pd-output-mode]; -#X obj 272 262 boids-params \$0; -#X obj 109 453 r \$0-boids-params; -#X obj 507 358 t b f; +#X text 164 363 see [pd-output-mode]; +#X obj 110 447 r \$0-boids-params; +#X obj 534 676 t b f; #X text 98 308 Use the 'dump' message to output a list of the current parameter settings., f 42; -#X text 51 254 The flight parameters can be changed with messages -->, f 28; -#X text 461 253 ATTRACTION POINT; -#X text 473 75 BOUNDING BOX; -#X text 460 274 Usually \, the attraction point is what can be "moved" to cause the entire flock to follow it, f 39; +#X text 131 261 The flight parameters can be changed with messages -->, f 55; +#X text 488 571 ATTRACTION POINT; +#X text 487 592 Usually \, the attraction point is what can be "moved" to cause the entire flock to follow it, f 39; #X text 98 492 optional arguments: integer number of boids (default is 16); #X text 165 508 next optional argument is mode (default is 0); #X obj 32 175 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; -#X obj 567 503 bng 18 250 50 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000; -#X text 592 502 bang to reset to defaults; -#X obj 565 528 s \$0-reset; -#X obj 565 478 loadbang; #X obj 24 651 unpack f f f; #X obj 127 650 unpack f f f; #X obj 279 664 unpack f f f; #X floatatom 102 703 5 0 0 0 - - - 0; #X floatatom 209 701 5 0 0 0 - - - 0; #X floatatom 373 692 5 0 0 0 - - - 0; -#X msg 494 408 attractpt \$1 \$2 \$3; -#X text 605 342 point to which boids are attracted (x/y/z), f 21; -#X floatatom 561 338 5 0 0 0 - - - 0; -#X obj 559 360 t b f; -#X obj 495 382 pack f f f; -#N canvas 0 0 561 332 3D-bounding-box 0; -#X obj 58 181 s \$0-boids-params; -#X obj 350 78 list prepend \$0; -#X text 459 54 defaults; -#X obj 349 25 r \$0-reset; -#X obj 29 27 inlet; -#X obj 74 29 inlet; -#X obj 119 29 inlet; -#X obj 170 29 inlet; -#X obj 41 76 pack f f f f f f; -#X obj 219 30 inlet; -#X obj 270 30 inlet; -#X msg 58 156 flyrect \$1 \$2 \$3 \$4 \$5 \$6; -#X msg 350 103 \; \$1-flyrect0 \$2 \; \$1-flyrect1 \$3 \; \$1-flyrect2 \$4 \; \$1-flyrect3 \$5 \; \$1-flyrect4 \$6 \; \$1-flyrect5 \$7; -#X msg 350 53 -1 1 1 -1 1 -1; -#X connect 1 0 12 0; -#X connect 3 0 13 0; -#X connect 4 0 8 0; -#X connect 5 0 8 1; -#X connect 6 0 8 2; -#X connect 7 0 8 3; -#X connect 8 0 11 0; -#X connect 9 0 8 4; -#X connect 10 0 8 5; -#X connect 11 0 0 0; -#X connect 13 0 1 0; -#X restore 537 202 pd 3D-bounding-box; -#X f 23; -#X floatatom 740 132 5 0 0 0 front \$0-flyrect4 - 0; -#X floatatom 745 170 5 0 0 0 back \$0-flyrect5 - 0; -#X text 602 76 3D bounding cube (walls) in which to fly, f 23; +#X msg 521 726 attractpt \$1 \$2 \$3; +#X text 632 660 point to which boids are attracted (x/y/z), f 21; +#X floatatom 588 656 5 0 0 0 - - - 0; +#X obj 586 678 t b f; +#X obj 522 700 pack f f f; #X text 101 174 Each time Boids receives a bang \, it calculates and outputs the new positions of the boids. The output consists of the X \, Y \, Z coordiantes for each boid., f 49; #X obj 32 493 boids; -#X floatatom 287 371 5 0 0 0 - - - 0; -#X msg 287 395 dimensions \$1; #X obj 32 200 metro 40; #X obj 264 549 list length; #X floatatom 264 574 5 0 0 0 - - - 0; -#X connect 0 0 58 0; -#X connect 1 0 58 1; -#X connect 2 0 58 2; -#X connect 3 0 58 3; -#X connect 4 0 57 0; -#X connect 5 0 34 0; -#X connect 6 0 63 0; -#X connect 23 0 6 0; -#X connect 24 0 63 0; -#X connect 25 0 63 0; -#X connect 26 0 63 0; -#X connect 30 0 47 0; -#X connect 30 1 48 0; -#X connect 30 5 49 0; -#X connect 30 6 27 0; -#X connect 30 6 67 0; -#X connect 33 0 63 0; -#X connect 34 0 57 0; -#X connect 34 1 57 1; -#X connect 42 0 66 0; -#X connect 43 0 45 0; -#X connect 46 0 43 0; -#X connect 47 0 19 0; -#X connect 47 1 20 0; -#X connect 47 2 50 0; -#X connect 48 0 21 0; -#X connect 48 1 22 0; -#X connect 48 2 51 0; -#X connect 49 0 28 0; -#X connect 49 1 29 0; -#X connect 49 2 52 0; -#X connect 53 0 17 0; -#X connect 55 0 56 0; -#X connect 56 0 57 0; -#X connect 56 1 57 2; -#X connect 57 0 53 0; -#X connect 59 0 58 4; -#X connect 60 0 58 5; -#X connect 63 0 30 0; -#X connect 63 1 13 0; -#X connect 64 0 65 0; -#X connect 65 0 63 0; -#X connect 66 0 26 0; -#X connect 67 0 68 0; +#X obj 533 121 boids-params \$0; +#A saved flyrect -1 1 -1 1; +#A saved dimensions 2; +#A saved number 16; +#A saved neighbors 4; +#A saved maxspeed 1.5; +#A saved minspeed 1.2; +#A saved center 1.2; +#A saved attract 1.25; +#A saved match 0.3; +#A saved avoid 3.5; +#A saved repel 3.5; +#A saved edgedist 3; +#A saved speed 3; +#A saved inertia 4.5; +#A saved accel 2.5; +#A saved prefdist 1.5; +#X obj 551 79 declare -path boids; +#X obj 565 841 boids2d; +#X obj 641 841 boids3d; +#X text 493 807 Aliases for previous versions:; +#N canvas 0 0 596 342 multidimensionality 0; +#X obj 37 137 boids; +#X msg 97 71 dimensions 5; +#X obj 34 24 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; +#X listbox 35 192 45 0 0 0 - - - 0; +#X text 316 129 NOTE: output mode 2 will not work; +#X obj 37 162 route 0 3; +#X listbox 55 227 45 0 0 0 - - - 0; +#X msg 117 99 attractpt 0.1 0.2 0.3 0.4 0.4; +#X text 171 28 Multidimensionality can be used; +#X connect 0 0 5 0; +#X connect 1 0 0 0; +#X connect 2 0 0 0; +#X connect 5 0 3 0; +#X connect 5 1 6 0; +#X connect 7 0 0 0; +#X restore 544 431 pd multidimensionality; +#X obj 109 468 list trim; +#X connect 0 0 47 0; +#X connect 1 0 29 0; +#X connect 2 0 49 0; +#X connect 19 0 2 0; +#X connect 20 0 49 0; +#X connect 21 0 49 0; +#X connect 22 0 49 0; +#X connect 26 0 37 0; +#X connect 26 1 38 0; +#X connect 26 5 39 0; +#X connect 26 6 23 0; +#X connect 26 6 51 0; +#X connect 28 0 59 0; +#X connect 29 0 47 0; +#X connect 29 1 47 1; +#X connect 36 0 50 0; +#X connect 37 0 15 0; +#X connect 37 1 16 0; +#X connect 37 2 40 0; +#X connect 38 0 17 0; +#X connect 38 1 18 0; +#X connect 38 2 41 0; +#X connect 39 0 24 0; +#X connect 39 1 25 0; +#X connect 39 2 42 0; +#X connect 43 0 13 0; +#X connect 45 0 46 0; +#X connect 46 0 47 0; +#X connect 46 1 47 2; +#X connect 47 0 43 0; +#X connect 49 0 26 0; +#X connect 49 1 9 0; +#X connect 50 0 22 0; +#X connect 51 0 52 0; +#X connect 59 0 49 0; diff --git a/help/boids2d-help.pd b/help/boids2d-help.pd index e888657..1a40112 100644 --- a/help/boids2d-help.pd +++ b/help/boids2d-help.pd @@ -1,22 +1,19 @@ -#N canvas 587 25 836 713 12; -#X floatatom 501 143 5 0 0 0 left \$0-flyrect0 - 0; -#X floatatom 562 107 5 0 0 0 top \$0-flyrect1 - 0; -#X floatatom 650 137 5 0 0 0 right \$0-flyrect2 - 0; -#X floatatom 711 176 5 0 0 0 bottom \$0-flyrect3 - 0; -#X floatatom 533 326 5 0 0 0 - - - 0; -#X floatatom 577 324 5 0 0 0 - - - 0; +#N canvas 587 25 829 908 12; +#X declare -lib boids -path boids; +#X floatatom 506 694 5 0 0 0 - - - 0; +#X floatatom 550 692 5 0 0 0 - - - 0; #X msg 80 386 mode \$1; #X text 145 424 reset boids randomly inside flyrect; -#X text 389 641 (c) 1995-98 Eric L. Singer (eric@ericsinger.com); +#X text 40 814 (c) 1995-98 Eric L. Singer (eric@ericsinger.com); #X text 25 73 Based on Simon Fraser's implementation of Craig Reynolds' Boids algorithm. Boids is free for non-commercial use; #X text 25 109 Boids is a bird flight and animal flock simulator. It is based on the same algorithm which was used in Jurassic Park for the herding dinosaurs.; -#X text 387 571 For more information about the Boids algorithm \, see Craig Reynolds' Web site at http://www.red3d.com/cwr/boids/; -#X text 392 619 arguments: number of boids \, output mode; +#X text 38 744 For more information about the Boids algorithm \, see Craig Reynolds' Web site at http://www.red3d.com/cwr/boids/; +#X text 43 792 arguments: number of boids \, output mode; #X obj 78 536 print dump; #X obj 19 10 cnv 15 800 48 empty empty boids2d 15 20 2 24 #dce0c8 #404040 0; -#X text 390 664 float/2d/3d adaptation 08/2005 by a. sier / jasch; -#X msg 562 396 attractpt \$1 \$2; -#X text 632 328 point to which boids are attracted (x/y), f 21; +#X text 41 837 float/2d/3d adaptation 08/2005 by a. sier / jasch; +#X msg 535 764 attractpt \$1 \$2; +#X text 605 696 point to which boids are attracted (x/y), f 21; #N canvas 88 105 494 344 META 0; #X text 13 182 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 13 160 AUTHOR Eric L. Singer; @@ -27,7 +24,7 @@ #X text 13 138 OUTLET_1 list; #X text 13 28 LICENSE GPL v2; #X restore 760 21 pd META; -#X obj 562 426 s \$0-boids-params; +#X obj 535 794 s \$0-boids-params; #X text 156 633 ..., f 4; #X obj 32 635 unpack; #X floatatom 32 661 5 0 0 0 - - - 0; @@ -35,7 +32,7 @@ #X obj 109 636 unpack; #X floatatom 109 661 5 0 0 0 - - - 0; #X floatatom 146 680 5 0 0 0 - - - 0; -#X obj 79 360 hradio 18 1 0 3 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0; +#X obj 79 360 hradio 18 1 0 4 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0; #X msg 53 316 dump; #X msg 99 422 reset; #X obj 32 228 bng 18 250 50 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000; @@ -49,129 +46,113 @@ #X floatatom 373 279 5 0 0 0 - - - 0; #X floatatom 405 260 5 0 0 0 - - - 0; #X floatatom 431 283 5 0 0 0 - - - 0; -#X obj 343 229 unpack f f f f f f, f 25; -#X floatatom 471 265 5 0 0 0 - - - 0; -#X floatatom 497 288 5 0 0 0 - - - 0; +#X floatatom 516 281 5 0 0 0 - - - 0; +#X floatatom 557 281 5 0 0 0 - - - 0; #X obj 233 84 list length; -#X obj 189 141 route 2 4 6; #X obj 183 112 list prepend; #X obj 186 66 t a a; #X obj 109 205 unpack; #X floatatom 109 230 5 0 0 0 - - - 0; #X floatatom 146 249 5 0 0 0 - - - 0; -#X text 363 307 (2) new and old with delta positions; #X text 217 339 (1) new and old positions; #X text 39 267 (0) new position only; #X obj 186 17 inlet; #X text 298 14 this patch shows the different output modes of the boids external.; -#X msg 393 100 mode \$1; -#X obj 393 167 s \$0-boids-params; -#X obj 392 74 hradio 18 1 0 3 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0; #X text 391 45 output mode:; -#X text 468 100 (1) new and old positions; -#X text 468 78 (0) new position only; -#X text 470 122 (2) new and old with delta positions; +#X text 411 100 (1) new and old positions; +#X text 411 78 (0) new position only; +#X text 413 122 (2) new and old with speed \, azim \, elev (0); +#X text 412 142 (3) position and direction vectors; +#X text 221 359 (3) position and direction vectors; +#X obj 189 141 route 2 4 7; +#X obj 343 229 unpack f f f f f f f, f 25; +#X floatatom 603 281 5 0 0 0 - - - 0; +#X text 363 307 (2) new and old with speed \, azim \, elev (0); #X connect 0 0 1 0; #X connect 0 1 2 0; #X connect 0 2 3 0; #X connect 0 3 4 0; -#X connect 9 0 5 0; -#X connect 9 1 6 0; -#X connect 9 2 7 0; -#X connect 9 3 8 0; -#X connect 9 4 10 0; -#X connect 9 5 11 0; -#X connect 12 0 14 1; -#X connect 13 0 16 0; -#X connect 13 1 0 0; -#X connect 13 2 9 0; -#X connect 14 0 13 0; -#X connect 15 0 14 0; -#X connect 15 1 12 0; -#X connect 16 0 17 0; -#X connect 16 1 18 0; -#X connect 22 0 15 0; -#X connect 24 0 25 0; -#X connect 26 0 24 0; +#X connect 11 0 12 1; +#X connect 12 0 27 0; +#X connect 13 0 12 0; +#X connect 13 1 11 0; +#X connect 14 0 15 0; +#X connect 14 1 16 0; +#X connect 19 0 13 0; +#X connect 27 0 14 0; +#X connect 27 1 0 0; +#X connect 27 2 28 0; +#X connect 28 0 5 0; +#X connect 28 1 6 0; +#X connect 28 2 7 0; +#X connect 28 3 8 0; +#X connect 28 4 9 0; +#X connect 28 5 10 0; +#X connect 28 6 29 0; #X restore 226 607 pd output-mode; #X obj 193 635 unpack; #X floatatom 193 661 5 0 0 0 - - - 0; #X floatatom 231 679 5 0 0 0 - - - 0; #X obj 32 572 route 0 1 2 3 4 10 15, f 27; -#X text 136 361 see [pd-output-mode]; -#X obj 272 262 boids-params \$0; +#X text 160 356 see [pd-output-mode]; #X obj 109 453 r \$0-boids-params; -#X obj 563 370 pack; -#X obj 575 346 t b f; +#X obj 536 738 pack; +#X obj 548 714 t b f; #X text 98 308 Use the 'dump' message to output a list of the current parameter settings., f 42; #X text 101 174 Each time Boids receives a bang \, it calculates and outputs the new positions of the boids. The output consists of the X \, Y coordiantes for each boid., f 49; #X text 51 254 The flight parameters can be changed with messages -->, f 28; -#N canvas 0 0 450 300 2D-bounding-box 0; -#X msg 58 156 flyrect \$1 \$2 \$3 \$4; -#X obj 58 181 s \$0-boids-params; -#X msg 262 41 -1 1 1 -1; -#X msg 262 91 \; \$1-flyrect0 \$2 \; \$1-flyrect1 \$3 \; \$1-flyrect2 \$4 \; \$1-flyrect3 \$5; -#X obj 262 66 list prepend \$0; -#X text 336 44 defaults; -#X obj 261 13 r \$0-reset; -#X obj 29 27 inlet; -#X obj 74 29 inlet; -#X obj 119 29 inlet; -#X obj 170 29 inlet; -#X obj 41 76 pack f f f f; -#X connect 0 0 1 0; -#X connect 2 0 4 0; -#X connect 4 0 3 0; -#X connect 6 0 2 0; -#X connect 7 0 11 0; -#X connect 8 0 11 1; -#X connect 9 0 11 2; -#X connect 10 0 11 3; -#X connect 11 0 0 0; -#X restore 537 202 pd 2D-bounding-box; -#X f 23; -#X text 613 78 2D bounding box (walls) in which to fly, f 23; -#X text 465 245 ATTRACTION POINT; -#X text 473 75 BOUNDING BOX; -#X text 464 266 Usually \, the attraction point is what can be "moved" to cause the entire flock to follow it, f 39; +#X text 503 603 ATTRACTION POINT; +#X text 502 624 Usually \, the attraction point is what can be "moved" to cause the entire flock to follow it, f 39; #X obj 32 493 boids2d; #X text 98 492 optional arguments: integer number of boids (default is 16); #X text 165 508 next optional argument is mode (default is 0); #X obj 32 175 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; #X obj 32 200 metro 10; -#X obj 567 503 bng 18 250 50 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000; -#X text 592 502 bang to reset to defaults; -#X obj 565 528 s \$0-reset; -#X obj 565 478 loadbang; -#X connect 0 0 44 0; -#X connect 1 0 44 1; -#X connect 2 0 44 2; -#X connect 3 0 44 3; -#X connect 4 0 39 0; -#X connect 5 0 40 0; -#X connect 6 0 49 0; -#X connect 16 0 19 0; -#X connect 21 0 22 0; -#X connect 21 1 23 0; -#X connect 24 0 25 0; -#X connect 24 1 26 0; -#X connect 27 0 6 0; -#X connect 28 0 49 0; -#X connect 29 0 49 0; -#X connect 30 0 49 0; -#X connect 32 0 33 0; -#X connect 32 1 34 0; -#X connect 35 0 21 0; -#X connect 35 1 24 0; -#X connect 35 5 32 0; -#X connect 35 6 31 0; -#X connect 38 0 49 0; -#X connect 39 0 16 0; -#X connect 40 0 39 0; -#X connect 40 1 39 1; -#X connect 49 0 35 0; -#X connect 49 1 13 0; -#X connect 52 0 53 0; -#X connect 53 0 30 0; -#X connect 54 0 56 0; -#X connect 57 0 54 0; +#X obj 527 166 boids-params \$0; +#A saved flyrect -1 1 -1 1; +#A saved dimensions 2; +#A saved number 16; +#A saved neighbors 4; +#A saved maxspeed 1.5; +#A saved minspeed 1.2; +#A saved center 1.2; +#A saved attract 1.25; +#A saved match 0.3; +#A saved avoid 3.5; +#A saved repel 3.5; +#A saved edgedist 3; +#A saved speed 3; +#A saved inertia 4.5; +#A saved accel 2.5; +#A saved prefdist 1.5; +#X obj 547 69 declare -lib boids -path boids; +#X text 571 142 see helpfile for this:; +#X text 295 15 NOTE: this object is a 2-d only alias for [boids]. You can drop-in and replace it with [boids] from now on.; +#X obj 110 475 list trim; +#X connect 0 0 34 0; +#X connect 1 0 35 0; +#X connect 2 0 41 0; +#X connect 12 0 15 0; +#X connect 17 0 18 0; +#X connect 17 1 19 0; +#X connect 20 0 21 0; +#X connect 20 1 22 0; +#X connect 23 0 2 0; +#X connect 24 0 41 0; +#X connect 25 0 41 0; +#X connect 26 0 41 0; +#X connect 28 0 29 0; +#X connect 28 1 30 0; +#X connect 31 0 17 0; +#X connect 31 1 20 0; +#X connect 31 5 28 0; +#X connect 31 6 27 0; +#X connect 33 0 50 0; +#X connect 34 0 12 0; +#X connect 35 0 34 0; +#X connect 35 1 34 1; +#X connect 41 0 31 0; +#X connect 41 1 9 0; +#X connect 44 0 45 0; +#X connect 45 0 26 0; +#X connect 50 0 41 0; diff --git a/help/boids3d-help.pd b/help/boids3d-help.pd index cde1de1..c1acf88 100644 --- a/help/boids3d-help.pd +++ b/help/boids3d-help.pd @@ -1,20 +1,17 @@ -#N canvas 587 25 836 757 12; -#X floatatom 520 123 5 0 0 0 left \$0-flyrect0 - 0; -#X floatatom 562 107 5 0 0 0 top \$0-flyrect1 - 0; -#X floatatom 615 129 5 0 0 0 right \$0-flyrect2 - 0; -#X floatatom 664 147 5 0 0 0 bottom \$0-flyrect3 - 0; -#X floatatom 465 338 5 0 0 0 - - - 0; -#X floatatom 509 336 5 0 0 0 - - - 0; +#N canvas 587 25 816 913 12; +#X declare -lib boids -path boids; +#X floatatom 481 677 5 0 0 0 - - - 0; +#X floatatom 525 675 5 0 0 0 - - - 0; #X msg 80 386 mode \$1; #X text 145 424 reset boids randomly inside flyrect; -#X text 394 639 (c) 1995-98 Eric L. Singer (eric@ericsinger.com); +#X text 36 840 (c) 1995-98 Eric L. Singer (eric@ericsinger.com); #X text 25 73 Based on Simon Fraser's implementation of Craig Reynolds' Boids algorithm. Boids is free for non-commercial use; #X text 25 109 Boids is a bird flight and animal flock simulator. It is based on the same algorithm which was used in Jurassic Park for the herding dinosaurs.; -#X text 387 571 For more information about the Boids algorithm \, see Craig Reynolds' Web site at http://www.red3d.com/cwr/boids/; -#X text 397 617 arguments: number of boids \, output mode; +#X text 29 772 For more information about the Boids algorithm \, see Craig Reynolds' Web site at http://www.red3d.com/cwr/boids/; +#X text 39 818 arguments: number of boids \, output mode; #X obj 78 536 print dump; #X obj 19 10 cnv 15 800 48 empty empty boids3d 15 20 2 24 #dce0c8 #404040 0; -#X text 395 662 float/2d/3d adaptation 08/2005 by a. sier / jasch; +#X text 37 863 float/2d/3d adaptation 08/2005 by a. sier / jasch; #N canvas 88 105 494 344 META 0; #X text 13 182 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; #X text 13 160 AUTHOR Eric L. Singer; @@ -25,17 +22,17 @@ #X text 13 138 OUTLET_1 list; #X text 13 28 LICENSE GPL v2; #X restore 760 21 pd META; -#X obj 494 438 s \$0-boids-params; +#X obj 510 777 s \$0-boids-params; #X text 225 654 ..., f 4; #X floatatom 24 677 5 0 0 0 - - - 0; #X floatatom 62 695 5 0 0 0 - - - 0; #X floatatom 127 675 5 0 0 0 - - - 0; #X floatatom 164 694 5 0 0 0 - - - 0; -#X obj 79 360 hradio 18 1 0 3 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0; +#X obj 79 360 hradio 18 1 0 4 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0; #X msg 53 316 dump; #X msg 99 422 reset; #X obj 32 228 bng 18 250 50 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000; -#N canvas 72 225 794 467 output-mode 0; +#N canvas 55 187 794 467 output-mode 0; #X floatatom 156 318 5 0 0 0 - - - 0; #X floatatom 186 344 5 0 0 0 - - - 0; #X floatatom 219 367 5 0 0 0 - - - 0; @@ -51,18 +48,12 @@ #X obj 186 66 t a a; #X floatatom 49 228 5 0 0 0 - - - 0; #X floatatom 86 247 5 0 0 0 - - - 0; -#X text 371 400 (2) new and old with delta positions; #X text 141 407 (1) new and old positions; #X text 39 267 (0) new position only; #X obj 186 17 inlet; #X text 298 14 this patch shows the different output modes of the boids external.; -#X msg 393 100 mode \$1; -#X obj 393 167 s \$0-boids-params; -#X obj 392 74 hradio 18 1 0 3 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0; -#X text 391 45 output mode:; -#X text 468 100 (1) new and old positions; -#X text 468 78 (0) new position only; -#X text 470 122 (2) new and old with delta positions; +#X text 389 99 (1) new and old positions; +#X text 389 77 (0) new position only; #X obj 47 203 unpack f f f; #X floatatom 129 228 5 0 0 0 - - - 0; #X obj 198 262 unpack f f f f f f; @@ -73,55 +64,51 @@ #X floatatom 587 361 5 0 0 0 - - - 0; #X obj 343 229 unpack f f f f f f f f f, f 33; #X obj 189 141 route 3 6 9; +#X text 391 121 (2) new and old with speed \, azi \, elev; +#X text 391 141 (3) position and direction vectors; +#X text 140 433 (3) position and direction vectors; +#X text 371 400 (2) new and old with speed \, azi \, elev; #X connect 10 0 11 1; -#X connect 11 0 36 0; +#X connect 11 0 30 0; #X connect 12 0 11 0; #X connect 12 1 10 0; -#X connect 18 0 12 0; -#X connect 20 0 21 0; -#X connect 22 0 20 0; -#X connect 27 0 13 0; -#X connect 27 1 14 0; -#X connect 27 2 28 0; -#X connect 29 0 0 0; -#X connect 29 1 1 0; -#X connect 29 2 2 0; -#X connect 29 3 3 0; -#X connect 29 4 30 0; -#X connect 29 5 31 0; -#X connect 35 0 4 0; -#X connect 35 1 5 0; -#X connect 35 2 6 0; -#X connect 35 3 7 0; -#X connect 35 4 8 0; -#X connect 35 5 9 0; -#X connect 35 6 32 0; -#X connect 35 7 33 0; -#X connect 35 8 34 0; -#X connect 36 0 27 0; -#X connect 36 1 29 0; -#X connect 36 2 35 0; +#X connect 17 0 12 0; +#X connect 21 0 13 0; +#X connect 21 1 14 0; +#X connect 21 2 22 0; +#X connect 23 0 0 0; +#X connect 23 1 1 0; +#X connect 23 2 2 0; +#X connect 23 3 3 0; +#X connect 23 4 24 0; +#X connect 23 5 25 0; +#X connect 29 0 4 0; +#X connect 29 1 5 0; +#X connect 29 2 6 0; +#X connect 29 3 7 0; +#X connect 29 4 8 0; +#X connect 29 5 9 0; +#X connect 29 6 26 0; +#X connect 29 7 27 0; +#X connect 29 8 28 0; +#X connect 30 0 21 0; +#X connect 30 1 23 0; +#X connect 30 2 29 0; #X restore 251 605 pd output-mode; #X floatatom 279 690 5 0 0 0 - - - 0; #X floatatom 317 708 5 0 0 0 - - - 0; #X obj 32 572 route 0 1 2 3 4 10 15, f 27; -#X text 136 361 see [pd-output-mode]; -#X obj 272 262 boids-params \$0; +#X text 161 362 see [pd-output-mode]; #X obj 109 453 r \$0-boids-params; -#X obj 507 358 t b f; +#X obj 523 697 t b f; #X text 98 308 Use the 'dump' message to output a list of the current parameter settings., f 42; #X text 51 254 The flight parameters can be changed with messages -->, f 28; -#X text 461 253 ATTRACTION POINT; -#X text 473 75 BOUNDING BOX; -#X text 460 274 Usually \, the attraction point is what can be "moved" to cause the entire flock to follow it, f 39; +#X text 477 592 ATTRACTION POINT; +#X text 476 613 Usually \, the attraction point is what can be "moved" to cause the entire flock to follow it, f 39; #X text 98 492 optional arguments: integer number of boids (default is 16); #X text 165 508 next optional argument is mode (default is 0); #X obj 32 175 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; #X obj 32 200 metro 10; -#X obj 567 503 bng 18 250 50 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000; -#X text 592 502 bang to reset to defaults; -#X obj 565 528 s \$0-reset; -#X obj 565 478 loadbang; #X obj 32 493 boids3d; #X obj 24 651 unpack f f f; #X obj 127 650 unpack f f f; @@ -129,80 +116,62 @@ #X floatatom 102 703 5 0 0 0 - - - 0; #X floatatom 209 701 5 0 0 0 - - - 0; #X floatatom 373 692 5 0 0 0 - - - 0; -#X msg 494 408 attractpt \$1 \$2 \$3; -#X text 605 342 point to which boids are attracted (x/y/z), f 21; -#X floatatom 561 338 5 0 0 0 - - - 0; -#X obj 559 360 t b f; -#X obj 495 382 pack f f f; -#N canvas 0 0 561 332 3D-bounding-box 0; -#X obj 58 181 s \$0-boids-params; -#X obj 350 78 list prepend \$0; -#X text 459 54 defaults; -#X obj 349 25 r \$0-reset; -#X obj 29 27 inlet; -#X obj 74 29 inlet; -#X obj 119 29 inlet; -#X obj 170 29 inlet; -#X obj 41 76 pack f f f f f f; -#X obj 219 30 inlet; -#X obj 270 30 inlet; -#X msg 58 156 flyrect \$1 \$2 \$3 \$4 \$5 \$6; -#X msg 350 103 \; \$1-flyrect0 \$2 \; \$1-flyrect1 \$3 \; \$1-flyrect2 \$4 \; \$1-flyrect3 \$5 \; \$1-flyrect4 \$6 \; \$1-flyrect5 \$7; -#X msg 350 53 -1 1 1 -1 1 -1; -#X connect 1 0 12 0; -#X connect 3 0 13 0; -#X connect 4 0 8 0; -#X connect 5 0 8 1; -#X connect 6 0 8 2; -#X connect 7 0 8 3; -#X connect 8 0 11 0; -#X connect 9 0 8 4; -#X connect 10 0 8 5; -#X connect 11 0 0 0; -#X connect 13 0 1 0; -#X restore 537 202 pd 3D-bounding-box; -#X f 23; -#X floatatom 740 132 5 0 0 0 front \$0-flyrect4 - 0; -#X floatatom 745 170 5 0 0 0 back \$0-flyrect5 - 0; -#X text 602 76 3D bounding cube (walls) in which to fly, f 23; +#X msg 510 747 attractpt \$1 \$2 \$3; +#X text 621 681 point to which boids are attracted (x/y/z), f 21; +#X floatatom 577 677 5 0 0 0 - - - 0; +#X obj 575 699 t b f; +#X obj 511 721 pack f f f; #X text 101 174 Each time Boids receives a bang \, it calculates and outputs the new positions of the boids. The output consists of the X \, Y \, Z coordiantes for each boid., f 49; -#X connect 0 0 60 0; -#X connect 1 0 60 1; -#X connect 2 0 60 2; -#X connect 3 0 60 3; -#X connect 4 0 59 0; -#X connect 5 0 34 0; -#X connect 6 0 48 0; -#X connect 23 0 6 0; -#X connect 24 0 48 0; -#X connect 25 0 48 0; -#X connect 26 0 48 0; -#X connect 30 0 49 0; -#X connect 30 1 50 0; -#X connect 30 5 51 0; -#X connect 30 6 27 0; -#X connect 33 0 48 0; -#X connect 34 0 59 0; -#X connect 34 1 59 1; -#X connect 42 0 43 0; -#X connect 43 0 26 0; -#X connect 44 0 46 0; -#X connect 47 0 44 0; -#X connect 48 0 30 0; -#X connect 48 1 13 0; -#X connect 49 0 19 0; -#X connect 49 1 20 0; -#X connect 49 2 52 0; -#X connect 50 0 21 0; -#X connect 50 1 22 0; -#X connect 50 2 53 0; -#X connect 51 0 28 0; -#X connect 51 1 29 0; -#X connect 51 2 54 0; -#X connect 55 0 17 0; -#X connect 57 0 58 0; -#X connect 58 0 59 0; -#X connect 58 1 59 2; -#X connect 59 0 55 0; -#X connect 61 0 60 4; -#X connect 62 0 60 5; +#X obj 499 139 boids-params \$0; +#A saved flyrect -1 1 -1 1; +#A saved dimensions 2; +#A saved number 16; +#A saved neighbors 4; +#A saved maxspeed 1.5; +#A saved minspeed 1.2; +#A saved center 1.2; +#A saved attract 1.25; +#A saved match 0.3; +#A saved avoid 3.5; +#A saved repel 3.5; +#A saved edgedist 3; +#A saved speed 3; +#A saved inertia 4.5; +#A saved accel 2.5; +#A saved prefdist 1.5; +#X obj 501 80 declare -lib boids -path boids; +#X obj 110 474 list trim; +#X text 313 7 NOTE: this object is a 3d-only version of [boids] and won't take the "dimensions" message. You can drop-in and replace it with [boids] from now on.; +#X connect 0 0 49 0; +#X connect 1 0 29 0; +#X connect 2 0 38 0; +#X connect 19 0 2 0; +#X connect 20 0 38 0; +#X connect 21 0 38 0; +#X connect 22 0 38 0; +#X connect 26 0 39 0; +#X connect 26 1 40 0; +#X connect 26 5 41 0; +#X connect 26 6 23 0; +#X connect 28 0 53 0; +#X connect 29 0 49 0; +#X connect 29 1 49 1; +#X connect 36 0 37 0; +#X connect 37 0 22 0; +#X connect 38 0 26 0; +#X connect 38 1 9 0; +#X connect 39 0 15 0; +#X connect 39 1 16 0; +#X connect 39 2 42 0; +#X connect 40 0 17 0; +#X connect 40 1 18 0; +#X connect 40 2 43 0; +#X connect 41 0 24 0; +#X connect 41 1 25 0; +#X connect 41 2 44 0; +#X connect 45 0 13 0; +#X connect 47 0 48 0; +#X connect 48 0 49 0; +#X connect 48 1 49 2; +#X connect 49 0 45 0; +#X connect 53 0 38 0; From e8c257e2551b9816f6d9eba4638df04b33501d54 Mon Sep 17 00:00:00 2001 From: fdch Date: Wed, 13 May 2026 17:27:54 +0200 Subject: [PATCH 19/19] cleanup lib --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 016ab52..6dfd6e4 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ class.sources = src/boids.c common.sources = src/boid_params.c src/vec.c # all extra files to be included in binary distribution of the library -datafiles = boids-meta.pd help/boids2d-help.pd help/boids3d-help.pd README.txt LICENSE.txt $(wildcard boids/*.pd) +datafiles = boids-meta.pd README.txt LICENSE.txt $(wildcard boids/*.pd) $(wildcard help/*.pd) datadirs = examples boids