annotate mesh.mm @ 15:d5758530a039 tip

oF0.84 Retina, and iPhone support
author Robert Tubb <rt300@eecs.qmul.ac.uk>
date Tue, 12 May 2015 15:48:52 +0100
parents 4ba81a12b008
children
rev   line source
rt300@0 1 /*
rt300@0 2 * mesh.cpp
rt300@0 3 * springstructure
rt300@0 4 *
rt300@0 5 * Created by Robert Tubb on 07/06/2011.
rt300@0 6 * Copyright 2011 __MyCompanyName__. All rights reserved.
rt300@0 7 *
rt300@0 8 */
rt300@0 9
rt300@0 10 #include "mesh.h"
rt300@0 11 #include "testApp.h"
rt300@0 12 #include "lump.h"
rt300@0 13 #include <math.h>
rt300@0 14
rt300@0 15 extern GlobalForces globalForces;
rt300@3 16 extern ScanPath scanPath; // now global
rt300@0 17
rt300@0 18 //--------------------------------------------------------------
rt300@0 19 Mesh::Mesh(){
rt300@0 20 // construct an empty structure
rt300@10 21 setReasonableDefaults();
rt300@10 22
rt300@10 23 cout << "constructed mesh base" << endl;
rt300@10 24 }
rt300@10 25
rt300@10 26
rt300@10 27 Mesh::~Mesh(){
rt300@10 28 cout << "destroying mesh" << endl;
rt300@10 29
rt300@10 30
rt300@10 31 }
rt300@10 32 //--------------------------------------------------------------
rt300@10 33 void Mesh::setReasonableDefaults(){
rt300@10 34 numSprings = 0;
rt300@0 35 numLumps = 0;
rt300@10 36
rt300@0 37 syrup = false;
rt300@0 38 GRAB_RANGE = 0.040;
rt300@0 39 propagationSpeed = 0.5; // this will be changed by adjusting k/m
rt300@10 40
rt300@0 41
rt300@0 42 m = 123.0;
rt300@0 43 k = 0.1;
rt300@0 44 f = 0.999;
rt300@10 45
rt300@0 46 prevLump = -1;
rt300@0 47
rt300@0 48 // some reasonable defaults
rt300@0 49 setSpringConstant(0.8);
rt300@0 50 setMass(1);
rt300@0 51 setFriction(0.999991);
rt300@0 52 }
rt300@9 53 //--------------------------------------------------------------
rt300@9 54 //--------------------------------------------------------------
rt300@9 55 Mesh::Mesh(Json::Value& jmesh){
rt300@10 56 setReasonableDefaults(); // sensible?
rt300@9 57
rt300@9 58 meshType = (MeshType)jmesh.get("meshType",0).asInt();
rt300@9 59 dim1 = jmesh.get("dim1",0).asInt();
rt300@9 60 dim2 = jmesh.get("dim1",0).asInt();
rt300@9 61
rt300@9 62 // need to know how many springs and lumps
rt300@9 63 numLumps = jmesh.get("numLumps",0).asInt();
rt300@9 64 numSprings = jmesh.get("numSprings",0).asInt();
rt300@9 65
rt300@9 66 // make them
rt300@9 67 makeComponents(numLumps, numSprings);
rt300@13 68 setLumpPositionsFromJson(jmesh["lumpPositions"], jmesh["lumpRestPositions"]);
rt300@9 69 makeConnectionsFromJson(jmesh["connections"]);
rt300@9 70 makeScanPathFromJson(jmesh["scanPath"]);
rt300@9 71 constrainFromJson(jmesh["constrainedLumps"]);
rt300@9 72
rt300@9 73 // now set saved properties
rt300@9 74 setSpringConstant(jmesh["springConstant"].asDouble());
rt300@9 75 setMass(jmesh["mass"].asDouble());
rt300@9 76 setFriction(jmesh["friction" ].asDouble());
rt300@9 77 // rest length?
rt300@9 78 zeroRestLength();
rt300@9 79 }
rt300@9 80
rt300@9 81 //--------------------------------------------------------------
rt300@13 82 void Mesh::setLumpPositionsFromJson(Json::Value lumpPositions, Json::Value lumpRestPositions){
rt300@9 83 int N = lumpPositions.size();
rt300@9 84
rt300@9 85 for(int i=0;i<N;i++){
rt300@9 86 lumps[i].position.x = lumpPositions[i]["x"].asFloat();
rt300@9 87 lumps[i].position.y = lumpPositions[i]["y"].asFloat();
rt300@9 88
rt300@13 89 lumps[i].zeroRefPos.x = lumpRestPositions[i]["x"].asFloat();
rt300@13 90 lumps[i].zeroRefPos.y = lumpRestPositions[i]["y"].asFloat();
rt300@9 91 }
rt300@9 92 }
rt300@9 93 //--------------------------------------------------------------
rt300@9 94 void Mesh::makeConnectionsFromJson(Json::Value connections){
rt300@9 95
rt300@9 96 // format: pairs of lump indexes, and a connecting spring
rt300@9 97 for (int i=0;i<connections.size();i++){
rt300@13 98 connect(i, connections[i]["s"].asInt(),connections[i]["e"].asInt()); // will the springs be in the right order? they need to be!
rt300@9 99
rt300@9 100 }
rt300@9 101 }
rt300@9 102
rt300@9 103 //--------------------------------------------------------------
rt300@9 104 void Mesh::makeScanPathFromJson(Json::Value jscanPath){
rt300@9 105
rt300@9 106 for(int i=0;i<jscanPath.size();i++){
rt300@9 107 scanPath.addElement(&lumps[jscanPath[i]["lumpNo"].asInt()], &springs[jscanPath[i]["springNo"].asInt()]);
rt300@9 108 }
rt300@9 109 }
rt300@9 110 //--------------------------------------------------------------
rt300@9 111 void Mesh::constrainFromJson(Json::Value constrainedLumps){
rt300@9 112
rt300@9 113 for(int i=0;i<constrainedLumps.size();i++){
rt300@9 114
rt300@9 115 lumps[constrainedLumps[i].asInt()].constrain(); // TODO ignores XY thing
rt300@9 116
rt300@9 117 }
rt300@9 118 }
rt300@9 119
rt300@9 120 //--------------------------------------------------------------
rt300@9 121 Json::Value Mesh::convertToJsonForSaving(){
rt300@9 122
rt300@9 123 // needs to be good to put back into
rt300@9 124 /*
rt300@9 125 void setLumpPositionsFromJson(Json::Value lumpPositions);
rt300@9 126 void makeConnectionsFromJson(Json::Value connections);
rt300@9 127 void makeScanPathFromJson(Json::Value scanPathElements);
rt300@9 128 void constrainFromJson(Json::Value constrainedLumps);
rt300@9 129 */
rt300@9 130
rt300@9 131 Json::Value jmesh;
rt300@9 132
rt300@9 133 jmesh["meshType"] = meshType;
rt300@9 134 jmesh["dim1"] = dim1; // these don't exist...
rt300@9 135 jmesh["dim2"] = dim2;
rt300@9 136 // need to know how many springs and lumps
rt300@9 137 jmesh["numLumps"] = numLumps;
rt300@9 138 jmesh["numSprings"] = numSprings;
rt300@9 139 jmesh["springConstant"] = k;
rt300@9 140 jmesh["mass"] = m;
rt300@9 141 jmesh["friction" ] = f;
rt300@9 142 for(int i=0;i<lumps.size();i++){
rt300@9 143 jmesh["lumpPositions"][i]["x"] = lumps[i].position.x;
rt300@9 144 jmesh["lumpPositions"][i]["y"] = lumps[i].position.y;
rt300@13 145 // just use rest pos ... too much data!
rt300@13 146 jmesh["lumpRestPositions"][i]["x"] = lumps[i].zeroRefPos.x;
rt300@13 147 jmesh["lumpRestPositions"][i]["y"] = lumps[i].zeroRefPos.y;
rt300@9 148 }
rt300@9 149
rt300@9 150 jmesh["connections"] = saveConnectionsAsJson();
rt300@9 151 jmesh["scanPath"] = scanPath.convertToJsonForSaving();
rt300@9 152
rt300@9 153 // save all indexes of constrained lumps
rt300@9 154 int j = 0;
rt300@9 155 for(int i=0;i<lumps.size();i++){
rt300@9 156 if(lumps[i].constrained){
rt300@9 157
rt300@9 158 jmesh["constrainedLumps"][j] = i;
rt300@9 159 j++;
rt300@9 160 }
rt300@9 161 }
rt300@9 162
rt300@9 163
rt300@9 164 return jmesh;
rt300@9 165
rt300@9 166 }
rt300@9 167 //--------------------------------------------------------------
rt300@9 168 Json::Value Mesh::saveConnectionsAsJson(){
rt300@9 169 Json::Value connections;
rt300@9 170 // loop all springs
rt300@9 171
rt300@9 172 for(int i = 0; i<springs.size(); i++){
rt300@13 173 connections[i]["s"]= springs[i].getStartLumpIndex();
rt300@13 174 connections[i]["e"]= springs[i].getEndLumpIndex();
rt300@9 175 }
rt300@9 176 return connections;
rt300@9 177
rt300@9 178
rt300@9 179 }
rt300@9 180 //--------------------------------------------------------------
rt300@9 181 //--------------------------------------------------------------
rt300@0 182 ///////////
rt300@0 183 // interface (called from testApp)
rt300@0 184 ///////////
rt300@0 185 void Mesh::update(){
rt300@0 186 // update all the springs and masses sequentially
rt300@0 187 // INTERP HACK - this bit of code is to debug pops and clicks
rt300@0 188 /*
rt300@0 189 static int updown = 0;
rt300@0 190 updown++;
rt300@0 191 if(updown > 24){
rt300@4 192 for(int i=0;i<lumps.size();i++){
rt300@0 193 lumps[i].position.y = 0.4;
rt300@0 194 }
rt300@0 195
rt300@0 196 }else{
rt300@0 197
rt300@4 198 for(int i=0;i<lumps.size();i++){
rt300@0 199 lumps[i].position.y = 0.6;
rt300@0 200 }
rt300@0 201
rt300@0 202 }
rt300@0 203 if(updown > 48) updown = 0;
rt300@0 204 // update the ends of the springs to reflect lump movement
rt300@0 205
rt300@0 206 for(int i=0;i<numSprings;i++){
rt300@0 207 springs[i].updateEndPoints();
rt300@0 208 }
rt300@0 209
rt300@0 210 return;
rt300@0 211
rt300@0 212 */
rt300@0 213
rt300@0 214 globalForces.update();
rt300@0 215 // calculate all the forces in the springs
rt300@4 216 for(int i=0;i<springs.size();i++){
rt300@0 217 springs[i].calculateForce();
rt300@0 218 }
rt300@0 219
rt300@0 220 // accelerate the lumps
rt300@4 221 for(int i=0;i<lumps.size();i++){
rt300@0 222 lumps[i].applyForce();
rt300@0 223 }
rt300@0 224
rt300@0 225 // move filters into apply force? not really, they're not forces.
rt300@0 226 // apply homing filter
rt300@4 227 for(int i=0;i<lumps.size();i++){
rt300@0 228 lumps[i].homingFilter(globalForces.homingAmt);
rt300@0 229 }
rt300@0 230 // apply averaging filter
rt300@0 231 //
rt300@0 232 averagingFilter(globalForces.avFilterAmt);
rt300@0 233
rt300@0 234 // update the ends of the springs to reflect lump movement
rt300@0 235 for(int i=0;i<numSprings;i++){
rt300@0 236 springs[i].updateEndPoints();
rt300@0 237 }
rt300@0 238
rt300@0 239 // scan the updated mesh
rt300@3 240 scanPath.updateWavetables();
rt300@0 241 }
rt300@0 242 //--------------------------------------------------------------
rt300@0 243 void Mesh::averagingFilter(double amt){
rt300@0 244 // we need a temporary store for average position, can't update in place with central diffs
rt300@4 245 vector<TwoVector> avLumpPos = vector<TwoVector>(lumps.size());
rt300@0 246
rt300@4 247
rt300@4 248 for(int i=0;i<lumps.size();i++){
rt300@0 249 avLumpPos[i] = lumps[i].averageOfConnected();
rt300@0 250 }
rt300@4 251 // now we can set pos. needs to be separate loop because we don't want to average *moved* lumps
rt300@4 252 for(int i=0;i<lumps.size();i++){
rt300@0 253 // mix in the average with the 'real'
rt300@0 254
rt300@0 255 lumps[i].position.x = (1 - amt)*lumps[i].position.x + amt*avLumpPos[i].x;
rt300@0 256 lumps[i].position.y = (1 - amt)*lumps[i].position.y + amt*avLumpPos[i].y;
rt300@0 257
rt300@0 258 }
rt300@0 259
rt300@0 260 }
rt300@0 261 //--------------------------------------------------------------
rt300@0 262 void Mesh::draw(){
rt300@0 263 // draw all the components belonging to mesh
rt300@0 264
rt300@0 265 int i;
rt300@0 266 for(i=0;i<numSprings;i++){
rt300@0 267 springs[i].draw();
rt300@0 268 }
rt300@0 269
rt300@4 270 for(i=0;i<lumps.size();i++){
rt300@0 271 lumps[i].draw();
rt300@0 272 }
rt300@0 273
rt300@8 274
rt300@0 275
rt300@0 276
rt300@0 277 }
rt300@0 278 //--------------------------------------------------------------
rt300@0 279 TwoVector Mesh::calculateCentre(){
rt300@0 280 // calculates average of all lump positions
rt300@0 281
rt300@0 282 double x = 0, y = 0;
rt300@4 283 for(int i = 0; i < lumps.size(); i++){
rt300@0 284 x += lumps[i].position.x;
rt300@0 285 y += lumps[i].position.y;
rt300@0 286
rt300@0 287 }
rt300@4 288 x = x/lumps.size();
rt300@4 289 y = y/lumps.size();
rt300@0 290
rt300@0 291 //cout << "centre : " << x << "," << y << endl;
rt300@0 292
rt300@0 293 centre.setCoord(x,y);
rt300@0 294
rt300@0 295 return centre;
rt300@0 296 }
rt300@0 297 //--------------------------------------------------------------
rt300@0 298 void Mesh::resetAll(){
rt300@0 299 // it's this simple
rt300@0 300 resetPositions();
rt300@0 301 resetVelocities();
rt300@0 302 unconstrain();
rt300@0 303 clearScanPath();
rt300@0 304 makeDefaultScanPath();
rt300@0 305 constrain(0.0,0.0,CONSTRAIN_EDGES);
rt300@0 306 constrain(0.0,0.0,CONSTRAIN_CORNERS);
rt300@0 307
rt300@0 308 // unless we want to reset velocities...?
rt300@0 309 }
rt300@0 310 //--------------------------------------------------------------
rt300@0 311 void Mesh::resetPositions(){
rt300@0 312 // it's this simple
rt300@0 313 setLumpPositions();
rt300@0 314 // unless we want to reset velocities...?
rt300@0 315 }
rt300@0 316 //--------------------------------------------------------------
rt300@0 317 void Mesh::resetVelocities(){
rt300@4 318 for(int i = 0; i < lumps.size(); i++){
rt300@0 319 lumps[i].setVelocity(0.0,0.0);
rt300@0 320
rt300@0 321 }
rt300@0 322 }
rt300@0 323 void Mesh::toggleHome(bool on){
rt300@0 324 static double prev;
rt300@0 325
rt300@0 326 if(!home && on){
rt300@0 327 home = on;
rt300@0 328 prev = globalForces.homingAmt;
rt300@0 329 globalForces.homingAmt = 0.3;
rt300@0 330
rt300@0 331
rt300@0 332 }else if (home && !on){
rt300@0 333 home = on; // ie false
rt300@0 334 globalForces.homingAmt = prev;
rt300@0 335 }
rt300@0 336 }
rt300@0 337 //--------------------------------------------------------------
rt300@0 338 void Mesh::resetEverything(){
rt300@0 339
rt300@0 340 }
rt300@0 341
rt300@0 342 //--------------
rt300@0 343 void Mesh::toggleSyrup(){
rt300@0 344 if(syrup){
rt300@0 345 toggleSyrup(false);
rt300@0 346 }else{
rt300@0 347 toggleSyrup(true);
rt300@0 348 }
rt300@0 349 }
rt300@0 350 //--------------
rt300@0 351 void Mesh::toggleSyrup(bool on){
rt300@0 352 if (!on){
rt300@0 353 syrup = false;
rt300@4 354 for(int i=0;i<lumps.size();i++) lumps[i].setFriction(0.998);
rt300@0 355 }else{
rt300@0 356 syrup = true;
rt300@4 357 for(int i=0;i<lumps.size();i++) lumps[i].setFriction(0.90);
rt300@0 358 }
rt300@0 359 }
rt300@0 360 //----------------------------------------------------------------
rt300@0 361 void Mesh::toggleGravity(){
rt300@0 362 globalForces.gravityOn = !globalForces.gravityOn;
rt300@0 363 }
rt300@0 364 //----------------------------------------------------------------
rt300@0 365 void Mesh::toggleGravity(bool on){
rt300@0 366 if (!on){
rt300@0 367 globalForces.gravityOn = true;
rt300@0 368 }else{
rt300@0 369 globalForces.gravityOn = false;
rt300@0 370 }
rt300@0 371 }
rt300@0 372
rt300@0 373 //----------------------------------------------------------------
rt300@0 374 void Mesh::toggleSpringForces(){
rt300@0 375
rt300@0 376 Spring::forcesOn = !Spring::forcesOn;
rt300@0 377
rt300@0 378 }
rt300@0 379 //----------------------------------------------------------------
rt300@0 380 void Mesh::toggleSpringForces(bool on){
rt300@0 381 if (!on){
rt300@0 382 Spring::forcesOn = false;
rt300@0 383
rt300@0 384 }else{
rt300@0 385 Spring::forcesOn = true;
rt300@0 386
rt300@0 387 }
rt300@0 388 }
rt300@0 389
rt300@0 390 //--------------------------------------------------------------
rt300@0 391 void Mesh::unconstrain(){
rt300@0 392
rt300@4 393 for(int i = 0; i<lumps.size(); i++){
rt300@0 394
rt300@0 395 lumps[i].unconstrain();
rt300@0 396
rt300@0 397 }
rt300@0 398 }
rt300@0 399 //--------------------------------------------------------------
rt300@0 400 void Mesh::unconstrain(double ax, double ay, constrainMode aMode){
rt300@0 401 int i = 0;
rt300@0 402 TwoVector diff;
rt300@0 403 // check if lump is within grab range
rt300@0 404 switch (aMode) {
rt300@0 405 case CONSTRAIN_GRAB_REGION:
rt300@4 406 for(i = 0; i<lumps.size(); i++){
rt300@0 407
rt300@0 408 diff.setCoord(lumps[i].position.x - ax, lumps[i].position.y - ay);
rt300@0 409
rt300@0 410 if (diff.norm() < GRAB_RANGE){
rt300@0 411 lumps[i].unconstrain();
rt300@0 412 }
rt300@0 413 }
rt300@0 414 break;
rt300@0 415 case CONSTRAIN_EDGES:
rt300@0 416 // hmm
rt300@0 417 break;
rt300@0 418
rt300@0 419 default:
rt300@0 420 break;
rt300@0 421 }
rt300@0 422 }
rt300@0 423 //--------------------------------------------------------------
rt300@0 424 void Mesh::setRestLength(){
rt300@0 425 for(int i = 0; i<numSprings; i++){
rt300@0 426 springs[i].setRestLength();
rt300@0 427 }
rt300@0 428
rt300@0 429 }
rt300@0 430 //--------------------------------------------------------------
rt300@0 431 void Mesh::setZeroAudioLine(){
rt300@0 432 // set zero rest pos to where they are now
rt300@4 433 for(int i = 0; i<lumps.size(); i++){
rt300@0 434
rt300@0 435 lumps[i].setZeroRefPos();
rt300@0 436
rt300@0 437 }
rt300@0 438 }
rt300@0 439 //--------------------------------------------------------------
rt300@0 440 void Mesh::setPropagationSpeed(double aSpeed){
rt300@0 441
rt300@0 442 propagationSpeed = aSpeed;
rt300@4 443 for(int i = 0; i < lumps.size(); i++){
rt300@0 444 lumps[i].setInvMass(propagationSpeed*propagationSpeed); // inverse mass is c^2
rt300@0 445 }
rt300@0 446 }
rt300@0 447 //--------------------------------------------------------------
rt300@0 448 void Mesh::increasePropagationSpeed(){
rt300@0 449
rt300@0 450 propagationSpeed = propagationSpeed + 0.01;
rt300@4 451 for(int i = 0; i < lumps.size(); i++){
rt300@0 452 lumps[i].setInvMass(propagationSpeed*propagationSpeed); // inverse mass is c^2
rt300@0 453 }
rt300@0 454 cout << "prop speed = " << propagationSpeed << endl;
rt300@0 455 }
rt300@0 456 //--------------------------------------------------------------
rt300@0 457 void Mesh::decreasePropagationSpeed(){
rt300@0 458
rt300@0 459 propagationSpeed = propagationSpeed - 0.01;
rt300@4 460 for(int i = 0; i < lumps.size(); i++){
rt300@0 461 lumps[i].setInvMass(propagationSpeed*propagationSpeed); // inverse mass is c^2
rt300@0 462 }
rt300@0 463 cout << "prop speed = " << propagationSpeed << endl;
rt300@0 464 }
rt300@0 465 //--------------------------------------------------------------
rt300@0 466 void Mesh::setSpringConstant(double aK){
rt300@0 467 k = aK;
rt300@0 468 if(sqrt(k/m) > 0.9){
rt300@0 469 k = m * 0.9;
rt300@0 470 }
rt300@0 471 cout << "k/m = " << k/m << endl;
rt300@9 472 for(int i = 0; i < springs.size(); i++){
rt300@0 473 springs[i].setSpringConstant(k); // inverse mass is c^2
rt300@0 474 }
rt300@0 475 }
rt300@0 476 //--------------------------------------------------------------
rt300@0 477 void Mesh::setMass(double aM){
rt300@0 478
rt300@0 479 m = aM;
rt300@0 480
rt300@0 481 if(sqrt(k/m) > 0.9){
rt300@0 482 m = k/0.9;
rt300@0 483 }
rt300@15 484 //cout << "k/m = " << k/m << endl;
rt300@0 485 double im = 1/aM;
rt300@4 486 for(int i = 0; i < lumps.size(); i++){
rt300@0 487 lumps[i].setInvMass(im);
rt300@0 488 }
rt300@0 489 }
rt300@0 490 //--------------------------------------------------------------
rt300@0 491 void Mesh::setFriction(double newF){
rt300@0 492 f = newF;
rt300@4 493 for(int i = 0; i < lumps.size(); i++){
rt300@0 494 lumps[i].setFriction(f);
rt300@0 495 }
rt300@0 496 }
rt300@0 497 //--------------------------------------------------------------
rt300@0 498 void Mesh::setMassAsym(double aAsym){
rt300@0 499 // use m as bass and add asym linearly across mesh. might be wierd for some meshes!
rt300@0 500 double newm,incr;
rt300@0 501 newm = m;
rt300@4 502 incr = aAsym*m/(lumps.size()-1);
rt300@4 503 for(int i = 0; i < lumps.size(); i++){
rt300@0 504 lumps[i].setInvMass(1/newm);
rt300@0 505 newm += incr;
rt300@0 506 }
rt300@0 507 }
rt300@0 508 //--------------------------------------------------------------
rt300@0 509 void Mesh::setSpringConstantAsym(double aAsym){
rt300@0 510 // from 0 to 1
rt300@0 511 if (aAsym > 1.0){
rt300@0 512 aAsym = 1.0;
rt300@0 513 }
rt300@0 514 if (aAsym < 0.0){
rt300@0 515 aAsym = 0.0;
rt300@0 516 }
rt300@0 517 double newk, incr;
rt300@0 518 newk = k;
rt300@0 519 incr = (1-aAsym)*k/(numSprings-1);
rt300@0 520 for(int i = 0; i < numSprings; i++){
rt300@0 521 springs[i].setSpringConstant(newk);
rt300@0 522 newk -= incr;
rt300@0 523 }
rt300@0 524 }
rt300@0 525
rt300@0 526 //--------------------------------------------------------------
rt300@0 527 void Mesh::setFrictionAsym(double aAsym){
rt300@0 528 // multiplying it doesn't make sense!
rt300@0 529 double newF,incr;
rt300@0 530 newF = f;
rt300@4 531 incr = aAsym*f/(lumps.size()-1);
rt300@4 532 for(int i = 0; i < lumps.size(); i++){
rt300@0 533 lumps[i].setFriction(newF);
rt300@0 534 newF += incr;
rt300@0 535 }
rt300@0 536 }
rt300@0 537 //--------------------------------------------------------------
rt300@0 538 void Mesh::checkHover(double ax, double ay){
rt300@0 539 TwoVector diff;
rt300@0 540 bool found = false;
rt300@0 541 // check if lump is within grab range
rt300@4 542 for(int i = 0; i<lumps.size(); i++){
rt300@0 543 diff.setCoord(lumps[i].position.x - ax, lumps[i].position.y - ay);
rt300@0 544 //cout << "diff " << diff.x << "," << diff.y << endl;
rt300@0 545 if (diff.norm() < GRAB_RANGE){
rt300@0 546 if(!found) {
rt300@0 547 lumps[i].highlight();
rt300@0 548 found = true;
rt300@0 549 }
rt300@0 550 }else{
rt300@0 551 lumps[i].unhighlight();
rt300@0 552 }
rt300@0 553 }
rt300@0 554
rt300@0 555 }
rt300@0 556
rt300@0 557 //--------------------------------------------------------------
rt300@0 558 void Mesh::grab(double ax, double ay, int touchID){
rt300@0 559 // attempt to grab a lump ax and ay should be already normalised
rt300@0 560
rt300@0 561 TwoVector diff;
rt300@0 562
rt300@0 563 // find closest
rt300@0 564 int nearest = getNearestLump(ax,ay);
rt300@10 565 //if(nearest = -1) return; // there are no lumps!
rt300@0 566 diff.setCoord(lumps[nearest].position.x - ax, lumps[nearest].position.y - ay);
rt300@0 567 //cout << "diff " << diff.x << "," << diff.y << endl;
rt300@10 568 cout << GRAB_RANGE << endl;
rt300@0 569 if (diff.norm() < GRAB_RANGE){
rt300@10 570
rt300@0 571 cout << "grabbing lump " << nearest << endl;
rt300@10 572
rt300@0 573 // move this lump to mouse pos
rt300@0 574
rt300@0 575 lumps[nearest].grab(touchID);
rt300@0 576 }
rt300@0 577
rt300@0 578
rt300@0 579 }
rt300@0 580 //--------------------------------------------------------------
rt300@0 581 void Mesh::unGrab(int touchID){
rt300@0 582
rt300@4 583 for(int i=0; i<lumps.size();i++){
rt300@0 584 if(lumps[i].grabID == touchID){ // only release the lumps that were grabbed by this finger
rt300@0 585 lumps[i].unGrab();
rt300@0 586 lumps[i].unhighlight();
rt300@0 587 }
rt300@0 588 }
rt300@0 589 }
rt300@0 590
rt300@0 591 //--------------------------------------------------------------
rt300@0 592 void Mesh::drag(double ax, double ay, int touchID){
rt300@0 593 // maybe set up specific id's for grabbed lumps
rt300@4 594 for(int i=0; i<lumps.size();i++){
rt300@0 595 if(lumps[i].grabID == touchID){// only move the lumps that were grabbed by this finger
rt300@0 596
rt300@0 597 lumps[i].drag(ax,ay,touchID);
rt300@0 598 }
rt300@0 599 }
rt300@0 600 }
rt300@0 601 //--------------------------------------------------------------
rt300@0 602 /* also could:
rt300@0 603 add random velocities
rt300@0 604 etc
rt300@0 605 */
rt300@0 606 //////////////////////
rt300@0 607 // protected utils
rt300@0 608 ////////////////////////
rt300@0 609 //---------------------------------------------------------------
rt300@0 610 void Mesh::connect(int aspringnum,int alumpnum){
rt300@0 611 //cout << "connecting spring " << aspringnum << " to lump " << alumpnum << endl;
rt300@0 612 // should we check valid indexes?
rt300@0 613 lumps[alumpnum].attachSpring(&springs[aspringnum]);
rt300@0 614 springs[aspringnum].attachLump(&lumps[alumpnum]);
rt300@0 615
rt300@0 616 }
rt300@0 617 //---------------------------------------------------------------
rt300@0 618 void Mesh::connect(int aspringnum,int alumpnum,int alumpnum2){
rt300@0 619 // better version - just connects 2 lumps with a spring
rt300@0 620 // should we check valid indexes?
rt300@0 621 lumps[alumpnum].attachSpring(&springs[aspringnum]);
rt300@0 622 springs[aspringnum].attachLump(&lumps[alumpnum]);
rt300@0 623 lumps[alumpnum2].attachSpring(&springs[aspringnum]);
rt300@0 624 springs[aspringnum].attachLump(&lumps[alumpnum2]);
rt300@0 625
rt300@0 626 }
rt300@0 627
rt300@0 628 void Mesh::zeroRestLength(){
rt300@0 629 // sets springs rest length to zero - collapses structure
rt300@3 630 for(vector<Spring>::iterator spriter = springs.begin(); spriter < springs.end(); spriter++){
rt300@3 631 (*spriter).setRestLength(0.0);
rt300@0 632 }
rt300@3 633
rt300@0 634 }
rt300@0 635 //--------------------------------------------------------------
rt300@0 636 int Mesh::getNearestLump(double ax, double ay){
rt300@0 637 // not used yet
rt300@0 638 int nearestLumpIndex = -1;
rt300@0 639 TwoVector diff;
rt300@0 640 double distance = 1.0;
rt300@0 641 double minDistance = 1.0;
rt300@0 642
rt300@4 643 for(int i = 0; i<lumps.size(); i++){
rt300@0 644 diff.setCoord(lumps[i].position.x - ax, lumps[i].position.y - ay);
rt300@0 645 distance = diff.norm();
rt300@0 646 if(distance < minDistance && !lumps[i].constrained){ // don't grab if constrained ??
rt300@0 647 minDistance = distance;
rt300@0 648 nearestLumpIndex = i;
rt300@0 649 }
rt300@0 650 }
rt300@13 651 //cout << "nearest lump : " << nearestLumpIndex << endl;
rt300@0 652
rt300@0 653 return nearestLumpIndex;
rt300@0 654 }
rt300@0 655 //--------------------------------------------------------------
rt300@0 656 void Mesh::clearScanPath(){
rt300@0 657 // in between having clicked and drawn we can't play anything
rt300@3 658 scanPath.clear();
rt300@0 659 prevLump = -1;
rt300@0 660 }
rt300@0 661 //--------------------------------------------------------------
rt300@0 662 void Mesh::disconnectDraw(){
rt300@0 663 prevLump = -1;
rt300@0 664 }
rt300@0 665 //--------------------------------------------------------------
rt300@0 666 int Mesh::inscribeScanPath(double ax, double ay){
rt300@0 667 bool foundPath = false;
rt300@0 668 int targetLump, intermediateLump;
rt300@0 669 int count = 0;
rt300@0 670 TwoVector halfWay;
rt300@0 671 // is this ridiculously complicated for no reason?
rt300@0 672
rt300@0 673 targetLump = getNearestLump(ax,ay); // target is the one closest to touch point, prev is last point already on our path
rt300@0 674
rt300@4 675 while(!foundPath && count < 10000){
rt300@0 676 count++;
rt300@3 677 if(prevLump == -1){ // (scanPath.howManyElements() == 0){ //
rt300@0 678 //first lump
rt300@0 679 foundPath = true;
rt300@0 680 prevLump = targetLump;
rt300@0 681 //cout << "first lump" << endl;
rt300@4 682 lumps[targetLump].isScanPathStart = true;
rt300@0 683 return targetLump;
rt300@0 684 }
rt300@0 685 // check if this lump connected to last lump by a spring
rt300@0 686 Spring * connectedToPrev = lumps[targetLump].checkConnectedTo(&lumps[prevLump]);
rt300@0 687
rt300@0 688 // if not connectedToLast will be null
rt300@0 689 if (!connectedToPrev){
rt300@0 690 //cout << "setting half way" << endl;
rt300@0 691 // set coords to 1/2 way and recurse
rt300@0 692 double halfdiffx = ((ax-lumps[prevLump].position.x)*0.5);
rt300@0 693 double halfdiffy = ((ay - lumps[prevLump].position.y)*0.5);
rt300@0 694 if (halfdiffx < 0.0001 && halfdiffy < 0.0001){
rt300@0 695 // not found nuffun
rt300@0 696 //cout << "not found a path, quitting" << endl;
rt300@0 697 return -1;
rt300@0 698 }
rt300@0 699 halfWay.setCoord( ax - halfdiffx , ay - halfdiffy);
rt300@0 700
rt300@0 701
rt300@0 702 intermediateLump = inscribeScanPath(halfWay.x,halfWay.y);
rt300@0 703 if(intermediateLump == -1){
rt300@0 704 //cout << "finding intermediate didn't work" << endl;
rt300@0 705 return -1;
rt300@0 706 }
rt300@0 707 // now check that the found intermediate targetLump is connected to the original targetlump
rt300@0 708 Spring * connectedToNext = lumps[targetLump].checkConnectedTo(&lumps[prevLump]);
rt300@0 709 if(!connectedToNext){
rt300@0 710 // set prevLump to the interm and try again
rt300@0 711 prevLump = intermediateLump;
rt300@0 712 targetLump = inscribeScanPath(ax,ay);
rt300@0 713 if(targetLump == -1){
rt300@0 714 //cout << "joining up next one didn't work" << endl;
rt300@0 715 return -1;
rt300@0 716 }
rt300@0 717 }
rt300@0 718 }else{
rt300@0 719 //cout << "CONNECTED! adding an element" << endl;
rt300@0 720
rt300@0 721 // hurrah, add the spring and lump to the scanpath in the right order...
rt300@0 722 // get pointer to lump and spring
rt300@0 723
rt300@3 724 scanPath.addElement(&lumps[targetLump], connectedToPrev);
rt300@4 725
rt300@4 726 // indicate end
rt300@4 727 lumps[prevLump].isScanPathEnd = false;
rt300@4 728 lumps[targetLump].isScanPathEnd = true;
rt300@0 729 // and set prev lump to that one
rt300@0 730 prevLump = targetLump;
rt300@0 731 foundPath = true;
rt300@0 732 return targetLump; //
rt300@0 733 }
rt300@0 734
rt300@0 735 }
rt300@0 736
rt300@0 737 cout << "reached end of inscribe func" << endl;
rt300@0 738
rt300@0 739 return -1;
rt300@0 740 }
rt300@0 741
rt300@8 742 // ---------------------------------------------------------------------------------------
rt300@8 743
rt300@8 744
rt300@8 745
rt300@0 746 void Mesh::hit(double dax, double day,int velocity, GlobalForces::excitationTypes aEType, GlobalForces::excitationShapes aEShape){
rt300@0 747 // set filter to something low
rt300@0 748 globalForces.homingAmt = 0.0;
rt300@0 749
rt300@0 750 double radius = 0.1, distance; // size of lump
rt300@0 751 double impactStrength = globalForces.excitationStrength*velocity/1000; // velocity as in note loudness
rt300@0 752 double amt = 0.0;
rt300@0 753 TwoVector diff;
rt300@0 754 // get all the lumps and smack em
rt300@12 755 int xamt = globalForces.exciteShapeX; // harmonic number of sine
rt300@0 756 int yamt = globalForces.exciteShapeY;
rt300@0 757
rt300@0 758 switch(aEShape){
rt300@0 759
rt300@0 760 case GlobalForces::SINE:
rt300@0 761
rt300@0 762 // applies a sine wave to all lumps, x and y
rt300@4 763 for(int i = 0; i < lumps.size(); i++){
rt300@0 764 if(!lumps[i].constrained){
rt300@0 765 lumps[i].position.y = lumps[i].zeroRefPos.y + impactStrength*sin(PI* (2*(xamt-1) + 1) * lumps[i].position.x);
rt300@0 766 lumps[i].position.x = lumps[i].zeroRefPos.x + impactStrength*sin(PI* (2*(yamt-1) + 1) * lumps[i].position.y);
rt300@0 767 }
rt300@0 768 }
rt300@0 769
rt300@0 770 break;
rt300@0 771 case GlobalForces::GAUSS:
rt300@0 772 // temporarily not a gauss...
rt300@4 773 for(int i = 0; i < lumps.size(); i++){
rt300@0 774 diff.setCoord(lumps[i].position.x - dax, lumps[i].position.y - day);
rt300@0 775 distance = diff.norm();
rt300@0 776 if(distance < radius){
rt300@0 777 amt = impactStrength*(1 + cos(PI*distance/radius)); // a 2d hamming.
rt300@0 778 lumps[i].position.y += amt;
rt300@0 779
rt300@0 780 }
rt300@0 781 }
rt300@0 782 break;
rt300@0 783 case GlobalForces::NOISE:
rt300@0 784 // 2D noise
rt300@4 785 for(int i = 0; i < lumps.size(); i++){
rt300@0 786 lumps[i].position.x += impactStrength*rand();
rt300@0 787 lumps[i].position.y += impactStrength*rand();
rt300@0 788
rt300@0 789 }
rt300@0 790 break;
rt300@0 791 default:
rt300@0 792 break;
rt300@0 793 }
rt300@0 794
rt300@0 795
rt300@0 796 }
rt300@0 797
rt300@0 798 void Mesh::spatialHarmonic(int aharm, int aharm2){
rt300@0 799 double magdr,theta;
rt300@0 800 TwoVector r, nr, centre, rhat, displacement;
rt300@0 801 centre.setCoord(0.5, 0.5);
rt300@0 802 // applies a sine wave to all lumps, x and y
rt300@0 803 if(radial){
rt300@0 804 // distance from centre is tweaked
rt300@4 805 for(int i = 0; i < lumps.size(); i++){
rt300@0 806 if(!lumps[i].constrained ){ //&& lumps[i].isInScanPath
rt300@0 807
rt300@0 808 // lots of sins and tans - might be simplifiable?
rt300@0 809 r = lumps[i].position - centre;
rt300@0 810 rhat = r.unitDir();
rt300@0 811 theta = atan2(r.y,r.x);
rt300@0 812 magdr = sin(aharm*theta);
rt300@0 813
rt300@0 814 // new r for lump:
rt300@0 815 displacement = rhat * 0.1*globalForces.touchStrength*magdr;
rt300@0 816 lumps[i].position = lumps[i].position + displacement;
rt300@0 817
rt300@0 818 }
rt300@0 819 }
rt300@0 820 }else{
rt300@4 821 for(int i = 0; i < lumps.size(); i++){
rt300@0 822 if(!lumps[i].constrained){
rt300@1 823 lumps[i].position.y = lumps[i].zeroRefPos.y + globalForces.touchStrength/256.0*sin(PI* (2*(aharm-1) + 1) * lumps[i].position.x);
rt300@1 824 lumps[i].position.x = lumps[i].zeroRefPos.x + globalForces.touchStrength/256.0*sin(PI* (2*(aharm2-1) + 1) * lumps[i].position.y);
rt300@0 825 }
rt300@0 826 }
rt300@0 827 }
rt300@0 828 }
rt300@0 829
rt300@0 830 void Mesh::damp(){
rt300@0 831 // set friction and filters to something high
rt300@0 832 //globalForces.avFilterAmt = 0.0;
rt300@0 833 globalForces.homingAmt = 0.3;
rt300@0 834 }
rt300@0 835 void Mesh::forceField(double dax,double day,double strength){
rt300@0 836
rt300@0 837 //
rt300@0 838 }
rt300@0 839 //--------------------------------------------------------------
rt300@0 840 double Mesh::getNextSample(){
rt300@0 841
rt300@0 842 return 0.0;
rt300@0 843
rt300@0 844 }
rt300@0 845
rt300@0 846 //--------------------------------------------------------------
rt300@0 847 // VIRTUAL
rt300@0 848 //--------------------------------------------------------------
rt300@0 849 void Mesh::makeDefaultScanPath(){
rt300@9 850 // make
rt300@0 851 cout << "!!!!Mesh base class makeDefaultScanPath\n";
rt300@0 852 }
rt300@0 853
rt300@0 854 //--------------------------------------------------------------
rt300@0 855 void Mesh::setLumpPositions(){
rt300@0 856 // places lumps in the right positions
rt300@0 857 cout << "!!!!Mesh base class setLumpPositions\n";
rt300@0 858 }
rt300@0 859 //--------------------------------------------------------------
rt300@0 860 void Mesh::makeConnections(){
rt300@0 861 // connects the lmps and springs. the spring needs to know which lumps are at each end
rt300@0 862 // and lumps need to know which springs attached
rt300@0 863 // calls connect method that does this
rt300@0 864 cout << "!!!!Mesh base class make connections\n";
rt300@0 865 }
rt300@0 866 //--------------------------------------------------------------
rt300@9 867 void Mesh::makeComponents(int numLumps, int numSprings){
rt300@9 868 // does not need to know what shape we're in to set up the right number of lumps and springs
rt300@0 869 cout << "!!!!Mesh base class makeComponents\n";
rt300@9 870
rt300@9 871 //lumps = new Lump[numLumps];
rt300@9 872 lumps = vector<Lump>(numLumps);
rt300@9 873 cout << "made " << numLumps << " lumps\n";
rt300@9 874
rt300@9 875 // one by one
rt300@9 876 springs = vector<Spring>(numSprings);
rt300@9 877
rt300@9 878 cout << "made " << numSprings << " springs\n";
rt300@9 879
rt300@9 880 // tell them what index they are (for connections)
rt300@9 881 for(int i = 0; i<lumps.size(); i++){
rt300@9 882 lumps[i].myIndexInMesh = i;
rt300@9 883 }
rt300@9 884 for(int i = 0; i<springs.size(); i++){
rt300@9 885 springs[i].myIndexInMesh = i;
rt300@9 886 }
rt300@9 887
rt300@9 888
rt300@0 889 }
rt300@0 890 //--------------------------------------------------------------
rt300@0 891 void Mesh::constrain(double ax, double ay, constrainMode aMode){
rt300@0 892 cout << "!!!!Mesh base class constrain\n";
rt300@0 893 }
rt300@0 894 //--------------------------------------------------------------
rt300@0 895 /****************************************/
rt300@9 896 // SquareMesh */
rt300@0 897 /****************************************/
rt300@0 898 //--------------------------------------------------------------
rt300@9 899 SquareMesh::SquareMesh(): Mesh() {
rt300@9 900 // the default is called from derived classes
rt300@9 901 radial = false;
rt300@9 902 cout << "default constructor SQUARE mesh\n";
rt300@9 903 }
rt300@9 904 //---------------------------------------------------------------
rt300@9 905 SquareMesh::SquareMesh(int height, int width): Mesh() {
rt300@9 906 // this one called when no derived class
rt300@9 907 meshType = SQUARE_MESH;
rt300@0 908 makeComponents(height, width);
rt300@0 909
rt300@0 910 setLumpPositions();
rt300@0 911
rt300@0 912 makeConnections();
rt300@0 913
rt300@0 914 makeDefaultScanPath();
rt300@0 915
rt300@0 916 constrain(0,0,CONSTRAIN_EDGES_XY);
rt300@0 917
rt300@0 918 zeroRestLength();
rt300@0 919
rt300@0 920 radial = false;
rt300@0 921
rt300@0 922 cout << "constructing SQUARE mesh\n";
rt300@0 923 }
rt300@9 924 SquareMesh::~SquareMesh(){
rt300@0 925
rt300@9 926 cout << "destructing SQUARE mesh\n";
rt300@0 927 }
rt300@0 928
rt300@0 929 //--------------------------------------------------------------
rt300@0 930 // make componets for square
rt300@9 931 void SquareMesh::makeComponents(int aheight, int awidth){
rt300@1 932
rt300@9 933
rt300@0 934 height = aheight;
rt300@0 935 width = awidth;
rt300@0 936 numLumps = height * width;
rt300@9 937 // horz // vert // criss cross
rt300@0 938 numSprings = (width-1)*height + (height-1)*width + 2*(height-1)*(width-1);
rt300@0 939
rt300@9 940 Mesh::makeComponents(numLumps, numSprings); // kinda wierd but works.
rt300@3 941
rt300@0 942 }
rt300@0 943
rt300@0 944 //--------------------------------------------------------------
rt300@9 945 void SquareMesh::setLumpPositions(){
rt300@9 946 // numbering works line by line like text, analogue tv's etc
rt300@0 947 double vspacing = 1.0/(height-1);
rt300@0 948 double hspacing = 1.0/(width-1);
rt300@0 949 int i =0;
rt300@0 950 // set positions
rt300@0 951 for(int row = 0; row < height; row++){ // go down column
rt300@0 952 for(int col = 0;col < width; col++){ // go along row
rt300@4 953 if(i >= lumps.size()){
rt300@1 954 cout << " setLumpPosisions index error!\n";
rt300@1 955 }
rt300@0 956 lumps[i].setPosition(hspacing*col,vspacing*row);
rt300@0 957
rt300@0 958 i++;
rt300@0 959 }
rt300@0 960 }
rt300@9 961
rt300@9 962 }
rt300@9 963 //--------------------------------------------------------------
rt300@9 964 void SquareMesh::makeConnections(){
rt300@9 965
rt300@9 966 // could be cleverer in terms of numbering?
rt300@9 967 int lumpnum = 0;
rt300@9 968 int springnum = 0;
rt300@9 969 // attach horizontal
rt300@9 970 for ( int i=0;i<height;i++){
rt300@9 971 for(int j=0;j<width-1;j++){
rt300@9 972 connect(springnum,lumpnum);
rt300@9 973 lumpnum++;
rt300@9 974 if(springnum >= numSprings){
rt300@9 975 cout << " makeConnections index error!\n";
rt300@9 976 }
rt300@9 977 if(lumpnum >= lumps.size()){
rt300@9 978 cout << " makeConnections index error!\n";
rt300@9 979 }
rt300@9 980 connect(springnum,lumpnum);
rt300@9 981 springnum++;
rt300@9 982
rt300@9 983 }
rt300@9 984 lumpnum++;
rt300@9 985 }
rt300@9 986 cout << "lumps attach horz: " << lumpnum-1 << ", spring " << springnum-1 << "\n";
rt300@9 987 // attach vertical
rt300@9 988 lumpnum = 0;
rt300@9 989 for ( int i=0;i<width;i++){
rt300@9 990 for(int j=0;j<height-1;j++){
rt300@9 991 connect(springnum,lumpnum);
rt300@9 992 lumpnum+=width;
rt300@9 993 if(springnum >= numSprings){
rt300@9 994 cout << " makeConnections index error!\n";
rt300@9 995 }
rt300@9 996 if(lumpnum >= lumps.size()){
rt300@9 997 cout << " makeConnections index error!\n";
rt300@9 998 }
rt300@9 999 connect(springnum,lumpnum);
rt300@9 1000 springnum++;
rt300@9 1001
rt300@9 1002 }
rt300@9 1003 lumpnum -= (width*(height-1)) - 1;
rt300@9 1004 }
rt300@1 1005
rt300@0 1006 }
rt300@9 1007
rt300@9 1008 //--------------------------------------------------------------
rt300@9 1009 void SquareMesh::constrain(double ax, double ay, constrainMode aMode){
rt300@9 1010
rt300@9 1011 TwoVector diff;
rt300@9 1012 int i = 0;
rt300@9 1013
rt300@9 1014 // check if lump is within grab range
rt300@9 1015 switch (aMode) {
rt300@9 1016 case CONSTRAIN_GRAB_REGION:
rt300@9 1017 for(i = 0; i<lumps.size(); i++){
rt300@9 1018
rt300@9 1019 diff.setCoord(lumps[i].position.x - ax, lumps[i].position.y - ay);
rt300@9 1020
rt300@9 1021 if (diff.norm() < GRAB_RANGE){
rt300@9 1022 if(i >= lumps.size()){
rt300@9 1023 cout << "constrain index error\n";
rt300@9 1024 }
rt300@9 1025 lumps[i].constrain();
rt300@9 1026 }
rt300@9 1027 }
rt300@9 1028 break;
rt300@9 1029 case CONSTRAIN_EDGES:
rt300@9 1030 i = 0;
rt300@9 1031 for(int row = 0; row < height; row++){ // go down column
rt300@9 1032 for(int col = 0;col < width; col++){ // go along row
rt300@9 1033 if(row == 0 || row == height-1 || col == 0 || col == width-1){
rt300@9 1034 if(i >= lumps.size()){
rt300@9 1035 cout << "constrain index error\n";
rt300@9 1036 }
rt300@9 1037 lumps[i].constrain();
rt300@9 1038 }
rt300@9 1039 i++;
rt300@9 1040 }
rt300@9 1041 }
rt300@9 1042 break;
rt300@9 1043 case CONSTRAIN_EDGES_XY:
rt300@9 1044 i = 0;
rt300@9 1045 for(int row = 0; row < height; row++){ // go down column
rt300@9 1046 for(int col = 0;col < width; col++){ // go along row
rt300@9 1047 if(row == 0 || row == height-1){
rt300@9 1048 if(i >= lumps.size()){
rt300@9 1049 cout << "constrain index error\n";
rt300@9 1050 }
rt300@9 1051 lumps[i].constrain(Lump::CONSTRAIN_Y);
rt300@9 1052 }else if( col == 0 || col == width-1){
rt300@9 1053 if(i >= lumps.size()){
rt300@9 1054 cout << "constrain index error\n";
rt300@9 1055 }
rt300@9 1056 lumps[i].constrain(Lump::CONSTRAIN_X);
rt300@9 1057 }
rt300@9 1058 i++;
rt300@9 1059 }
rt300@9 1060 }
rt300@9 1061 break;
rt300@9 1062 case CONSTRAIN_CORNERS:
rt300@9 1063 i = 0;
rt300@9 1064 for(int row = 0; row < height; row++){ // go down column
rt300@9 1065 for(int col = 0;col < width; col++){ // go along row
rt300@9 1066 if( (row == 0 && col == 0)
rt300@9 1067 || (row == height-1 && col == 0)
rt300@9 1068 || (row == 0 && col == width-1)
rt300@9 1069 || (row == height-1 && col == width-1)){
rt300@9 1070 if(i >= lumps.size()){
rt300@9 1071 cout << "constrain index error\n";
rt300@9 1072 }
rt300@9 1073 lumps[i].constrain();
rt300@9 1074 }
rt300@9 1075 i++;
rt300@9 1076 }
rt300@9 1077 }
rt300@9 1078 break;
rt300@9 1079
rt300@9 1080 default:
rt300@9 1081 break;
rt300@9 1082 }
rt300@9 1083
rt300@9 1084 }
rt300@9 1085
rt300@9 1086 //--------------------------------------------------------------
rt300@9 1087 void SquareMesh::makeDefaultScanPath(){
rt300@9 1088 if (height < 10 || width < 10) return; // not much point
rt300@9 1089
rt300@9 1090 int vmarg = 5;
rt300@9 1091 int hmarg = 5;
rt300@9 1092
rt300@9 1093 int lumpno = vmarg * width + hmarg; // top left corner
rt300@9 1094 int springno = vmarg * (width - 1) + hmarg;
rt300@9 1095 // do top horz
rt300@9 1096 for(int i = 0; i < width - 2*hmarg; i++){
rt300@9 1097 if(lumpno >= lumps.size()) cout << "makeDefaultScanPath index error\n";
rt300@9 1098 if(springno >= numSprings) cout << "makeDefaultScanPath index error\n";
rt300@9 1099 scanPath.addElement(&lumps[lumpno], &springs[springno]);
rt300@9 1100 lumpno++;
rt300@9 1101 springno++;
rt300@9 1102 }
rt300@9 1103
rt300@9 1104 // do right vert, lumpno starts the same
rt300@9 1105 // all horz spr // left marg rows // top margin
rt300@9 1106 springno = height*(width-1) + ((height-1) * (width - hmarg)) + vmarg;
rt300@9 1107
rt300@9 1108 for(int i = 0; i < height - (2 * vmarg); i++){
rt300@9 1109 if(lumpno >= lumps.size()) cout << "makeDefaultScanPath index error\n";
rt300@9 1110 if(springno >= numSprings) cout << "makeDefaultScanPath index error\n";
rt300@9 1111 scanPath.addElement(&lumps[lumpno], &springs[springno]);
rt300@9 1112 springno++; // jump to next row
rt300@9 1113 lumpno += width; // ditto
rt300@9 1114 }
rt300@9 1115
rt300@9 1116
rt300@9 1117 // do bottom horz right to left
rt300@9 1118 springno = (height - vmarg) * (width - 1) + (width - hmarg - 1);
rt300@9 1119 for(int i = 0; i < width - 2*hmarg; i++){
rt300@9 1120 if(lumpno >= lumps.size()) cout << "makeDefaultScanPath index error\n";
rt300@9 1121 if(springno >= numSprings) cout << "makeDefaultScanPath index error\n";
rt300@9 1122 scanPath.addElement(&lumps[lumpno], &springs[springno]);
rt300@9 1123 springno--; // jump to next row
rt300@9 1124 lumpno--; // ditto
rt300@9 1125 }
rt300@9 1126
rt300@9 1127 // all horz spr // left marg rows // top margin
rt300@9 1128 springno = height*(width-1) + ((height-1) * hmarg) + height - vmarg - 1;
rt300@9 1129 for(int i = 0; i < height - 2 * vmarg; i++){
rt300@9 1130 if(lumpno >= lumps.size()) cout << "makeDefaultScanPath index error\n";
rt300@9 1131 if(springno >= numSprings) cout << "makeDefaultScanPath index error\n";
rt300@9 1132 scanPath.addElement(&lumps[lumpno], &springs[springno]);
rt300@9 1133 springno--; // jump to next row
rt300@9 1134 lumpno -= width; // ditto
rt300@9 1135 }
rt300@9 1136
rt300@9 1137 }
rt300@9 1138 //--------------------------------------------------------------
rt300@9 1139
rt300@9 1140 /****************************************/
rt300@9 1141 // SquareCrossMesh */
rt300@9 1142 /****************************************/
rt300@9 1143 //--------------------------------------------------------------
rt300@9 1144 SquareCrossMesh::SquareCrossMesh(int height, int width){
rt300@9 1145
rt300@9 1146 meshType = SQUARE_CROSS_MESH;
rt300@9 1147 makeComponents(height, width);
rt300@9 1148
rt300@9 1149 setLumpPositions();
rt300@9 1150
rt300@9 1151 makeConnections();
rt300@9 1152
rt300@9 1153 makeDefaultScanPath();
rt300@9 1154
rt300@9 1155 constrain(0,0,CONSTRAIN_EDGES);
rt300@9 1156
rt300@9 1157 zeroRestLength();
rt300@9 1158
rt300@9 1159 radial = false;
rt300@9 1160
rt300@9 1161 cout << "constructing SQUARECROSS mesh\n";
rt300@9 1162 }
rt300@9 1163 SquareCrossMesh::~SquareCrossMesh(){
rt300@9 1164
rt300@9 1165 cout << "destructing SQUARECROSS mesh\n";
rt300@9 1166 }
rt300@9 1167
rt300@0 1168 //--------------------------------------------------------------
rt300@0 1169 void SquareCrossMesh::makeConnections(){
rt300@0 1170
rt300@0 1171 // could be cleverer in terms of numbering?
rt300@0 1172 int lumpnum = 0;
rt300@0 1173 int springnum = 0;
rt300@0 1174 // attach horizontal
rt300@0 1175 for ( int i=0;i<height;i++){
rt300@0 1176 for(int j=0;j<width-1;j++){
rt300@0 1177 connect(springnum,lumpnum);
rt300@0 1178 lumpnum++;
rt300@1 1179 if(springnum >= numSprings){
rt300@1 1180 cout << " makeConnections index error!\n";
rt300@1 1181 }
rt300@4 1182 if(lumpnum >= lumps.size()){
rt300@1 1183 cout << " makeConnections index error!\n";
rt300@1 1184 }
rt300@0 1185 connect(springnum,lumpnum);
rt300@0 1186 springnum++;
rt300@0 1187
rt300@0 1188 }
rt300@0 1189 lumpnum++;
rt300@0 1190 }
rt300@1 1191 cout << "lumps attach horz: " << lumpnum-1 << ", spring " << springnum-1 << "\n";
rt300@0 1192 // attach vertical
rt300@0 1193 lumpnum = 0;
rt300@0 1194 for ( int i=0;i<width;i++){
rt300@0 1195 for(int j=0;j<height-1;j++){
rt300@0 1196 connect(springnum,lumpnum);
rt300@0 1197 lumpnum+=width;
rt300@1 1198 if(springnum >= numSprings){
rt300@1 1199 cout << " makeConnections index error!\n";
rt300@1 1200 }
rt300@4 1201 if(lumpnum >= lumps.size()){
rt300@1 1202 cout << " makeConnections index error!\n";
rt300@1 1203 }
rt300@0 1204 connect(springnum,lumpnum);
rt300@0 1205 springnum++;
rt300@0 1206
rt300@0 1207 }
rt300@0 1208 lumpnum -= (width*(height-1)) - 1;
rt300@0 1209 }
rt300@0 1210 // attach diagonal
rt300@0 1211 lumpnum = 0;
rt300@0 1212 for ( int i=0;i<width-1;i++){
rt300@0 1213 for(int j=0;j<height-1;j++){
rt300@0 1214 connect(springnum,lumpnum);
rt300@0 1215 lumpnum+=(width);
rt300@1 1216 if(springnum >= numSprings){
rt300@1 1217 cout << " makeConnections index error!\n";
rt300@1 1218 }
rt300@4 1219 if(lumpnum >= lumps.size()){
rt300@1 1220 cout << " makeConnections index error!\n";
rt300@1 1221 }
rt300@0 1222 connect(springnum,lumpnum+1);
rt300@0 1223 springnum++;
rt300@0 1224
rt300@0 1225 }
rt300@0 1226 lumpnum -= (width*(height-1)) - 1;
rt300@0 1227 }
rt300@0 1228 // attach other diagonal
rt300@0 1229 lumpnum = 1;
rt300@0 1230 for ( int i=0;i<width-1;i++){
rt300@0 1231 for(int j=0;j<height-1;j++){
rt300@0 1232 connect(springnum,lumpnum);
rt300@0 1233 lumpnum+=(width);
rt300@1 1234 if(springnum >= numSprings){
rt300@1 1235 cout << " makeConnections index error!\n";
rt300@1 1236 }
rt300@4 1237 if(lumpnum >= lumps.size()){
rt300@1 1238 cout << " makeConnections index error!\n";
rt300@1 1239 }
rt300@0 1240 connect(springnum,lumpnum-1);
rt300@0 1241 springnum++;
rt300@0 1242
rt300@0 1243 }
rt300@0 1244 lumpnum -= (width*(height-1)) - 1;
rt300@0 1245 }
rt300@0 1246 }
rt300@0 1247
rt300@0 1248 //--------------------------------------------------------------
rt300@9 1249
rt300@0 1250 //--------------------------------------------------------------
rt300@0 1251
rt300@0 1252
rt300@0 1253 /****************************************/
rt300@0 1254 // SpiderMesh */
rt300@0 1255 /****************************************/
rt300@0 1256 SpiderMesh::SpiderMesh(int aNumSpokes,int aNumRings) : Mesh(){
rt300@8 1257 meshType = SPIDER_MESH;
rt300@8 1258
rt300@0 1259 numSpokes = aNumSpokes;
rt300@0 1260 numRings = aNumRings;
rt300@0 1261
rt300@0 1262 radial = true;
rt300@0 1263
rt300@0 1264 makeComponents(numSpokes, numRings);
rt300@0 1265
rt300@0 1266 setLumpPositions();
rt300@0 1267
rt300@0 1268 makeConnections();
rt300@0 1269
rt300@0 1270 makeDefaultScanPath();
rt300@0 1271
rt300@0 1272 constrain(0.0,0.0,CONSTRAIN_EDGES);
rt300@0 1273 constrain(0.0,0.0,CONSTRAIN_CORNERS);
rt300@0 1274
rt300@0 1275 cout << "constructed SPIDER mesh\n";
rt300@0 1276
rt300@0 1277
rt300@0 1278
rt300@0 1279 }
rt300@0 1280 //--------------------------------------------------------------
rt300@0 1281 void SpiderMesh::makeComponents(int aDimension1, int aDimension2){
rt300@0 1282 // make componets creates the correct number of lumps and springs according to dimensions and mesh type
rt300@0 1283 cout << "!!!spider makeComponents\n";
rt300@0 1284 numLumps = numSpokes * numRings + 1; // +1 cos one in the middle
rt300@0 1285 numSprings = 2 * numSpokes * numRings;
rt300@0 1286
rt300@4 1287 //lumps = new Lump[numLumps];
rt300@4 1288 lumps = vector<Lump>(numLumps);
rt300@4 1289 cout << "made " << numLumps << " lumps\n";
rt300@3 1290 springs = vector<Spring>(numSprings);
rt300@3 1291
rt300@0 1292 cout << "made " << numSprings << " springs\n";
rt300@0 1293
rt300@0 1294
rt300@0 1295 }
rt300@0 1296 //--------------------------------------------------------------
rt300@0 1297 void SpiderMesh::setLumpPositions(){
rt300@0 1298 cout << "!spider setLumpPositions\n";
rt300@0 1299 // here we're assuming that zero spoke is to right
rt300@0 1300 // work out sines / cosines for each spoke
rt300@0 1301 int l = 1;
rt300@0 1302 double hyplen,xpos,ypos;
rt300@0 1303
rt300@0 1304 double * cosines = new double[numSpokes];
rt300@0 1305 double * sines = new double[numSpokes];
rt300@0 1306 double angle = 2 * PI / numSpokes;
rt300@0 1307
rt300@0 1308 double ringSpacing = 1.0/(2*numRings);
rt300@0 1309
rt300@0 1310 for(int spoke = 0; spoke < numSpokes; spoke++){
rt300@0 1311 cosines[spoke] = cos(angle*spoke);
rt300@0 1312 sines[spoke] = sin(angle*spoke);
rt300@0 1313 }
rt300@0 1314
rt300@0 1315 lumps[0].setPosition(0.5,0.5);
rt300@0 1316
rt300@0 1317 for(int ring = 0; ring < numRings; ring++){
rt300@0 1318 for(int spoke = 0; spoke < numSpokes; spoke++){
rt300@0 1319 hyplen = ringSpacing * (ring+1);
rt300@0 1320 xpos = hyplen * cosines[spoke] + 0.5;
rt300@0 1321 ypos = hyplen*sines[spoke] + 0.5;
rt300@0 1322 lumps[l].setPosition(xpos,ypos);
rt300@0 1323 l++;
rt300@0 1324
rt300@0 1325 }
rt300@0 1326 }
rt300@0 1327 delete [] cosines;
rt300@0 1328 delete [] sines;
rt300@0 1329
rt300@0 1330 }
rt300@0 1331 //--------------------------------------------------------------
rt300@0 1332 void SpiderMesh::makeConnections(){
rt300@0 1333 // TODO needs to be rewritten to automatically
rt300@0 1334 // add in lumps and springs AS we're connecting
rt300@0 1335 //using std vector
rt300@0 1336 // this is dumb
rt300@0 1337 cout << "!!!spider make connections\n";
rt300@0 1338
rt300@0 1339 // UNLIKE a spider we're going to make rings first, to make indexing the scan path easier...
rt300@0 1340
rt300@0 1341 for(int ring = 0; ring < numRings; ring++){
rt300@0 1342 for(int spoke = 0; spoke < numSpokes-1; spoke++){
rt300@0 1343 // spring , lump
rt300@0 1344 connect(numSpokes*ring + spoke, ring*numSpokes + spoke + 1);
rt300@0 1345 connect(numSpokes*ring + spoke, ring*numSpokes + spoke + 2);
rt300@0 1346 }
rt300@0 1347 // remember the last one on the ring goes back to first
rt300@0 1348 // spring , lump
rt300@0 1349 connect(numSpokes*ring + numSpokes - 1 , ring*numSpokes + numSpokes);
rt300@0 1350 connect(numSpokes*ring + numSpokes - 1, ring*numSpokes + 1);
rt300@0 1351 }
rt300@0 1352 // at which point we have used numSpokes*numRings springs
rt300@0 1353 int used = numSpokes*numRings;
rt300@0 1354 // first ring is different cos it connects to central point
rt300@0 1355 for(int spoke = 0; spoke < numSpokes; spoke++){
rt300@0 1356 connect(used,0); // inner radial on center
rt300@0 1357 connect(used,spoke+1); // outer radial
rt300@0 1358 springs[used].setRestLength(0.0); // need tension on spokes
rt300@0 1359 used++;
rt300@0 1360 }
rt300@0 1361 // now do the rest of the radial spokes
rt300@0 1362 for(int ring = 0; ring < numRings-1; ring++){
rt300@0 1363 for(int spoke = 0; spoke < numSpokes; spoke++){
rt300@0 1364 connect(used,ring*numSpokes+1+spoke); //
rt300@0 1365 connect(used,(ring+1)*numSpokes+1+spoke); // going to next ring out
rt300@0 1366 springs[used].setRestLength(0.0);
rt300@0 1367 used++;
rt300@0 1368 }
rt300@0 1369 }
rt300@0 1370 }
rt300@0 1371
rt300@0 1372 //--------------------------------------------------------------
rt300@0 1373 void SpiderMesh::constrain(double ax, double ay, constrainMode aMode){
rt300@0 1374 cout << "!!spider constrain\n";
rt300@0 1375
rt300@0 1376 TwoVector diff;
rt300@0 1377 int i = 0;
rt300@0 1378
rt300@0 1379 // check if lump is within grab range
rt300@0 1380 switch (aMode) {
rt300@0 1381 case CONSTRAIN_GRAB_REGION:
rt300@4 1382 for(i = 0; i<lumps.size(); i++){
rt300@0 1383
rt300@0 1384 diff.setCoord(lumps[i].position.x - ax, lumps[i].position.y - ay);
rt300@0 1385
rt300@0 1386 if (diff.norm() < GRAB_RANGE){
rt300@0 1387 lumps[i].constrain();
rt300@0 1388 }
rt300@0 1389 }
rt300@0 1390 break;
rt300@0 1391 case CONSTRAIN_EDGES:
rt300@0 1392 {
rt300@0 1393 // constrain outer ring
rt300@0 1394 int startLump = numSpokes*(numRings-1) + 1;
rt300@0 1395 for(int l = startLump; l < startLump + numSpokes; l++){
rt300@0 1396 lumps[l].constrain();
rt300@0 1397 }
rt300@0 1398
rt300@0 1399 break;
rt300@0 1400 }
rt300@0 1401 case CONSTRAIN_CORNERS:
rt300@0 1402 // er... constrain the centre
rt300@0 1403 lumps[0].constrain();
rt300@0 1404
rt300@0 1405 break;
rt300@0 1406
rt300@0 1407 default:
rt300@0 1408 break;
rt300@0 1409 }
rt300@0 1410 }
rt300@0 1411
rt300@0 1412 //--------------------------------------------------------------
rt300@0 1413
rt300@0 1414 void SpiderMesh::makeDefaultScanPath(){
rt300@0 1415
rt300@0 1416 cout << "!!spider makeDefaultScanPath\n";
rt300@0 1417
rt300@5 1418 /*
rt300@5 1419 // add a all inner rings to the path
rt300@5 1420
rt300@5 1421
rt300@0 1422 int ringNo = ceil(numRings/2.0);
rt300@0 1423 int springno = 0, lumpno = 0;
rt300@0 1424 for(int i = 0; i < numSpokes; i++){
rt300@0 1425 lumpno = numSpokes*ringNo + 1 + i;
rt300@0 1426 springno = numSpokes*ringNo + i;
rt300@3 1427 scanPath.addElement(&lumps[lumpno], &springs[springno]);
rt300@0 1428 }
rt300@0 1429 cout << "!!spider scan path created on ring " << ringNo << "\n";
rt300@5 1430 */
rt300@5 1431
rt300@0 1432 // add a spoke to the path
rt300@5 1433
rt300@0 1434 int springno = 0, lumpno = 0;
rt300@0 1435
rt300@0 1436 int springsinrings = numSpokes*numRings;
rt300@0 1437 for(int i = 0; i < numRings-1; i++){
rt300@0 1438 lumpno = numSpokes*i; // zero, numspokes etc
rt300@5 1439 springno = springsinrings + numSpokes*i -1; // starts from total rings, increments by numspokes etc
rt300@5 1440 scanPath.addElement(&lumps[lumpno], &springs[springno]);
rt300@5 1441 }
rt300@5 1442
rt300@5 1443 for(int i = 0; i < numRings-1; i++){
rt300@5 1444 lumpno = numSpokes*i + 1; // zero, numspokes etc
rt300@0 1445 springno = springsinrings + numSpokes*i; // starts from total rings, increments by numspokes etc
rt300@3 1446 scanPath.addElement(&lumps[lumpno], &springs[springno]);
rt300@5 1447 }
rt300@5 1448 /*
rt300@5 1449 for(int i = numRings-2; i >= 0 ; i--){
rt300@5 1450 lumpno = numSpokes*i; // zero, numspokes etc
rt300@5 1451 springno = springsinrings + numSpokes*i; // starts from total rings, increments by numspokes etc
rt300@5 1452 scanPath.addElement(&lumps[lumpno], &springs[springno]);
rt300@5 1453 }
rt300@5 1454 */
rt300@5 1455
rt300@0 1456 }
rt300@0 1457
rt300@0 1458
rt300@0 1459 //--------------------------------------------------------------
rt300@0 1460 /****************************************/
rt300@0 1461 // Holed Spider Mesh */
rt300@0 1462 /****************************************/
rt300@0 1463 //--------------------------------------------------------------
rt300@0 1464 HoledSpiderMesh::HoledSpiderMesh(int aNumSpokes,int aNumRings) : Mesh(){
rt300@8 1465 meshType = HOLED_SPIDER_MESH;
rt300@0 1466 numSpokes = aNumSpokes;
rt300@0 1467 numRings = aNumRings;
rt300@0 1468 radial = true;
rt300@0 1469
rt300@0 1470 makeComponents(numSpokes, numRings);
rt300@0 1471
rt300@0 1472 setLumpPositions();
rt300@0 1473
rt300@0 1474 makeConnections();
rt300@0 1475
rt300@0 1476 makeDefaultScanPath();
rt300@0 1477
rt300@0 1478 constrain(0.0,0.0,CONSTRAIN_EDGES);
rt300@0 1479 constrain(0.0,0.0,CONSTRAIN_CORNERS);
rt300@0 1480
rt300@0 1481 cout << "constructed SPIDER mesh\n";
rt300@0 1482 }
rt300@0 1483
rt300@0 1484 void HoledSpiderMesh::makeComponents(int aDimension1, int aDimension2){
rt300@0 1485 // make componets creates the correct number of lumps and springs according to dimensions and mesh type
rt300@0 1486 cout << "HOLED spider makeComponents\n";
rt300@0 1487 numLumps = numSpokes * numRings;
rt300@0 1488 numSprings = numSpokes * numRings + numSpokes * (numRings - 1);
rt300@0 1489
rt300@4 1490 lumps = vector<Lump>(numLumps);
rt300@4 1491 cout << "made " << numLumps << " lumps\n";
rt300@3 1492 springs = vector<Spring>(numSprings);
rt300@0 1493 cout << "made " << numSprings << " springs\n";
rt300@0 1494
rt300@0 1495
rt300@0 1496 }
rt300@0 1497 //--------------------------------------------------------------
rt300@0 1498 void HoledSpiderMesh::setLumpPositions(){
rt300@0 1499 cout << "HOLED spider setLumpPositions\n";
rt300@0 1500 // here we're assuming that zero spoke is to right
rt300@0 1501 // work out sines / cosines for each spoke
rt300@0 1502 int l = 0;
rt300@0 1503 double hyplen,xpos,ypos;
rt300@0 1504
rt300@0 1505 double * cosines = new double[numSpokes];
rt300@0 1506 double * sines = new double[numSpokes];
rt300@0 1507 double angle = 2 * PI / numSpokes;
rt300@0 1508
rt300@0 1509 double ringSpacing = 1.0/(2*numRings);
rt300@0 1510
rt300@0 1511 for(int spoke = 0; spoke < numSpokes; spoke++){
rt300@0 1512 cosines[spoke] = cos(angle*spoke);
rt300@0 1513 sines[spoke] = sin(angle*spoke);
rt300@0 1514 }
rt300@0 1515
rt300@0 1516 for(int ring = 0; ring < numRings; ring++){
rt300@0 1517 for(int spoke = 0; spoke < numSpokes; spoke++){
rt300@0 1518 hyplen = ringSpacing * (ring+1);
rt300@0 1519 xpos = hyplen * cosines[spoke] + 0.5;
rt300@0 1520 ypos = hyplen*sines[spoke] + 0.5;
rt300@0 1521 lumps[l].setPosition(xpos,ypos);
rt300@0 1522 l++;
rt300@0 1523
rt300@0 1524 }
rt300@0 1525 }
rt300@0 1526 delete [] cosines;
rt300@0 1527 delete [] sines;
rt300@0 1528
rt300@0 1529 }
rt300@0 1530 //--------------------------------------------------------------
rt300@0 1531 void HoledSpiderMesh::makeConnections(){
rt300@0 1532 // TODO needs to be rewritten to automatically
rt300@0 1533 // add in lumps and springs AS we're connecting
rt300@0 1534 //using std vector
rt300@0 1535 // this is dumb
rt300@0 1536 cout << "HOLED spider make connections\n";
rt300@0 1537
rt300@0 1538 // UNLIKE a spider we're going to make rings first, to make indexing the scan path easier...
rt300@0 1539
rt300@0 1540 for(int ring = 0; ring < numRings; ring++){
rt300@0 1541 for(int spoke = 0; spoke < numSpokes-1; spoke++){
rt300@0 1542 // spring , lump
rt300@0 1543 connect(numSpokes*ring + spoke, ring*numSpokes + spoke + 0);
rt300@0 1544 connect(numSpokes*ring + spoke, ring*numSpokes + spoke + 1);
rt300@0 1545 }
rt300@0 1546 // remember the last one on the ring goes back to first
rt300@0 1547 // spring , lump
rt300@0 1548 connect(numSpokes*ring + numSpokes - 1 , ring*numSpokes + numSpokes - 1);
rt300@0 1549 connect(numSpokes*ring + numSpokes - 1, ring*numSpokes);
rt300@0 1550 }
rt300@0 1551 // at which point we have used numSpokes*numRings springs
rt300@0 1552 int used = numSpokes*numRings;
rt300@0 1553 // now do the rest of the radial spokes
rt300@0 1554 for(int ring = 0; ring < numRings-1; ring++){
rt300@0 1555 for(int spoke = 0; spoke < numSpokes; spoke++){
rt300@0 1556 connect(used,ring*numSpokes+spoke); //
rt300@0 1557 connect(used,(ring+1)*numSpokes+spoke); // going to next ring out
rt300@0 1558 springs[used].setRestLength(0.0);
rt300@0 1559 used++;
rt300@0 1560 }
rt300@0 1561 }
rt300@0 1562 }
rt300@0 1563
rt300@0 1564 //--------------------------------------------------------------
rt300@0 1565 void HoledSpiderMesh::constrain(double ax, double ay, constrainMode aMode){
rt300@0 1566 cout << "HOLED spider constrain\n";
rt300@0 1567
rt300@0 1568 TwoVector diff;
rt300@0 1569 int i = 0;
rt300@0 1570 int startLump = 0;
rt300@0 1571 // check if lump is within grab range
rt300@0 1572 switch (aMode) {
rt300@0 1573 case CONSTRAIN_GRAB_REGION:
rt300@4 1574 for(i = 0; i<lumps.size(); i++){
rt300@0 1575
rt300@0 1576 diff.setCoord(lumps[i].position.x - ax, lumps[i].position.y - ay);
rt300@0 1577
rt300@0 1578 if (diff.norm() < GRAB_RANGE){
rt300@0 1579 lumps[i].constrain();
rt300@0 1580 }
rt300@0 1581 }
rt300@0 1582 break;
rt300@0 1583 case CONSTRAIN_EDGES:
rt300@0 1584 {
rt300@0 1585 // constrain outer ring
rt300@0 1586 startLump = numSpokes*(numRings-1);
rt300@0 1587 for(int l = startLump; l < startLump + numSpokes; l++){
rt300@0 1588 lumps[l].constrain();
rt300@0 1589 }
rt300@0 1590
rt300@0 1591 break;
rt300@0 1592 }
rt300@0 1593 case CONSTRAIN_CORNERS:
rt300@0 1594 // constrain inner ring
rt300@0 1595
rt300@0 1596 for(int l = startLump; l < startLump + numSpokes; l++){
rt300@0 1597 lumps[l].constrain();
rt300@0 1598 }
rt300@0 1599
rt300@0 1600 break;
rt300@0 1601
rt300@0 1602 default:
rt300@0 1603 break;
rt300@0 1604 }
rt300@0 1605 }
rt300@0 1606 //--------------------------------------------------------------
rt300@0 1607
rt300@0 1608 void HoledSpiderMesh::makeDefaultScanPath(){
rt300@0 1609
rt300@0 1610 cout << "HOLED spider makeDefaultScanPath\n";
rt300@0 1611
rt300@0 1612 // add a ring to the path
rt300@0 1613 int ringNo = floor(numRings/2.0);
rt300@0 1614 int springno = 0, lumpno = 0;
rt300@0 1615 for(int i = 0; i < numSpokes; i++){
rt300@0 1616 lumpno = numSpokes*ringNo + i;
rt300@0 1617 springno = numSpokes*ringNo + i;
rt300@0 1618
rt300@3 1619 scanPath.addElement(&lumps[lumpno], &springs[springno]);
rt300@0 1620 }
rt300@0 1621 cout << "HOLED spider scan path created on ring " << ringNo << "\n";
rt300@0 1622
rt300@0 1623 // add a spoke to the path
rt300@0 1624 /*
rt300@0 1625 int springno = 0, lumpno = 0;
rt300@0 1626
rt300@0 1627 int springsinrings = numSpokes*numRings;
rt300@0 1628 for(int i = 0; i < numRings-1; i++){
rt300@0 1629 lumpno = numSpokes*i; // zero, numspokes etc
rt300@0 1630 springno = springsinrings + numSpokes*i; // starts from total rings, increments by numspokes etc
rt300@3 1631 scanPath.addElement(&lumps[lumpno], &springs[springno]);
rt300@0 1632 }
rt300@0 1633 */
rt300@0 1634 }
rt300@0 1635
rt300@0 1636 //--------------------------------------------------------------
rt300@0 1637 /****************************************/
rt300@0 1638 // Holed Spider Cross Mesh */
rt300@0 1639 /****************************************/
rt300@0 1640 //--------------------------------------------------------------
rt300@0 1641 SpiderCrossMesh::SpiderCrossMesh(int aNumSpokes,int aNumRings) : Mesh(){
rt300@8 1642 meshType = SPIDER_CROSS_MESH;
rt300@0 1643 numSpokes = aNumSpokes;
rt300@0 1644 numRings = aNumRings;
rt300@0 1645 radial = true;
rt300@0 1646
rt300@0 1647 makeComponents(numSpokes, numRings);
rt300@0 1648
rt300@0 1649 setLumpPositions();
rt300@0 1650
rt300@0 1651 makeConnections();
rt300@0 1652
rt300@0 1653 makeDefaultScanPath();
rt300@0 1654
rt300@0 1655 constrain(0.0,0.0,CONSTRAIN_EDGES);
rt300@0 1656 constrain(0.0,0.0,CONSTRAIN_CORNERS);
rt300@0 1657
rt300@0 1658 cout << "constructed SpiderCrossMesh mesh\n";
rt300@0 1659 }
rt300@0 1660
rt300@0 1661 void SpiderCrossMesh::makeComponents(int aDimension1, int aDimension2){
rt300@0 1662 // make componets creates the correct number of lumps and springs according to dimensions and mesh type
rt300@0 1663 cout << "SpiderCrossMesh spider makeComponents\n";
rt300@0 1664 numLumps = numSpokes * numRings;
rt300@0 1665 // rings // spokes & diags
rt300@0 1666 numSprings = numSpokes * numRings + 3 * numSpokes * (numRings - 1);
rt300@0 1667
rt300@9 1668 Mesh::makeComponents(numLumps, numSprings);
rt300@0 1669
rt300@0 1670
rt300@0 1671 }
rt300@0 1672 //--------------------------------------------------------------
rt300@0 1673 void SpiderCrossMesh::setLumpPositions(){
rt300@0 1674 cout << "SpiderCrossMesh spider setLumpPositions\n";
rt300@0 1675 // here we're assuming that zero spoke is to right
rt300@0 1676 // work out sines / cosines for each spoke
rt300@0 1677 int l = 0;
rt300@0 1678 double hyplen,xpos,ypos;
rt300@0 1679
rt300@0 1680 double * cosines = new double[numSpokes];
rt300@0 1681 double * sines = new double[numSpokes];
rt300@0 1682 double angle = 2 * PI / numSpokes;
rt300@0 1683
rt300@0 1684 double ringSpacing = 1.0/(2*numRings);
rt300@0 1685
rt300@0 1686 for(int spoke = 0; spoke < numSpokes; spoke++){
rt300@0 1687 cosines[spoke] = cos(angle*spoke);
rt300@0 1688 sines[spoke] = sin(angle*spoke);
rt300@0 1689 }
rt300@0 1690
rt300@0 1691 for(int ring = 0; ring < numRings; ring++){
rt300@0 1692 for(int spoke = 0; spoke < numSpokes; spoke++){
rt300@0 1693 hyplen = ringSpacing * (ring+1);
rt300@0 1694 xpos = hyplen * cosines[spoke] + 0.5;
rt300@0 1695 ypos = hyplen*sines[spoke] + 0.5;
rt300@0 1696 lumps[l].setPosition(xpos,ypos);
rt300@0 1697 l++;
rt300@0 1698
rt300@0 1699 }
rt300@0 1700 }
rt300@0 1701 delete [] cosines;
rt300@0 1702 delete [] sines;
rt300@0 1703
rt300@0 1704 }
rt300@0 1705 //--------------------------------------------------------------
rt300@0 1706 void SpiderCrossMesh::makeConnections(){
rt300@0 1707
rt300@0 1708 cout << "SpiderCrossMesh spider make connections\n";
rt300@0 1709
rt300@0 1710 // UNLIKE a spider we're going to make rings first, to make indexing the scan path easier...
rt300@0 1711
rt300@0 1712 for(int ring = 0; ring < numRings; ring++){
rt300@0 1713 for(int spoke = 0; spoke < numSpokes-1; spoke++){
rt300@0 1714 // spring , lump
rt300@0 1715 connect(numSpokes*ring + spoke, ring*numSpokes + spoke + 0);
rt300@0 1716 connect(numSpokes*ring + spoke, ring*numSpokes + spoke + 1);
rt300@0 1717 }
rt300@0 1718 // remember the last one on the ring goes back to first
rt300@0 1719 // spring , lump
rt300@0 1720 connect(numSpokes*ring + numSpokes - 1 , ring*numSpokes + numSpokes - 1);
rt300@0 1721 connect(numSpokes*ring + numSpokes - 1, ring*numSpokes);
rt300@0 1722 }
rt300@0 1723 // at which point we have used numSpokes*numRings springs
rt300@0 1724 int used = numSpokes*numRings;
rt300@0 1725
rt300@0 1726 // now do radial spokes
rt300@0 1727 for(int ring = 0; ring < numRings-1; ring++){
rt300@0 1728 for(int spoke = 0; spoke < numSpokes; spoke++){
rt300@0 1729 connect(used,ring*numSpokes+spoke); //
rt300@0 1730 connect(used,(ring+1)*numSpokes+spoke); // going to next ring out
rt300@0 1731 springs[used].setRestLength(0.0);
rt300@0 1732 used++;
rt300@0 1733 }
rt300@0 1734 }
rt300@0 1735 // now do diag /
rt300@0 1736 for(int ring = 0; ring < numRings-1; ring++){
rt300@0 1737 for(int spoke = 0; spoke < numSpokes-1; spoke++){
rt300@0 1738 connect(used,ring*numSpokes+spoke,(ring+1)*numSpokes+spoke+1); //
rt300@0 1739 springs[used].setRestLength(0.0);
rt300@0 1740 used++;
rt300@0 1741 }
rt300@0 1742 connect(used,ring*numSpokes+numSpokes-1,(ring+1)*numSpokes); // wrap to first
rt300@0 1743 springs[used].setRestLength(0.0);
rt300@0 1744 used++;
rt300@0 1745 }
rt300@0 1746
rt300@0 1747 // now do \ diag
rt300@0 1748 for(int ring = 0; ring < numRings-1; ring++){
rt300@0 1749 connect(used,ring*numSpokes,(ring+1)*numSpokes+numSpokes-1); // wrap first to last
rt300@0 1750 springs[used].setRestLength(0.0);
rt300@0 1751 used++;
rt300@0 1752 for(int spoke = 1; spoke < numSpokes; spoke++){
rt300@0 1753 connect(used,ring*numSpokes+spoke,(ring+1)*numSpokes+spoke-1); //
rt300@0 1754 springs[used].setRestLength(0.0);
rt300@0 1755 used++;
rt300@0 1756 }
rt300@0 1757
rt300@0 1758 }
rt300@0 1759 cout << "used: " << used << " numSprings: " << numSprings << endl;
rt300@0 1760
rt300@0 1761 }
rt300@0 1762
rt300@0 1763 //--------------------------------------------------------------
rt300@0 1764 void SpiderCrossMesh::constrain(double ax, double ay, constrainMode aMode){
rt300@0 1765 cout << "SpiderCrossMesh spider constrain\n";
rt300@0 1766
rt300@0 1767 TwoVector diff;
rt300@0 1768 int i = 0;
rt300@0 1769 int startLump = 0;
rt300@0 1770 // check if lump is within grab range
rt300@0 1771 switch (aMode) {
rt300@0 1772 case CONSTRAIN_GRAB_REGION:
rt300@4 1773 for(i = 0; i<lumps.size(); i++){
rt300@0 1774
rt300@0 1775 diff.setCoord(lumps[i].position.x - ax, lumps[i].position.y - ay);
rt300@0 1776
rt300@0 1777 if (diff.norm() < GRAB_RANGE){
rt300@0 1778 lumps[i].constrain();
rt300@0 1779 }
rt300@0 1780 }
rt300@0 1781 break;
rt300@0 1782 case CONSTRAIN_EDGES:
rt300@0 1783 {
rt300@0 1784 // constrain outer ring
rt300@0 1785 startLump = numSpokes*(numRings-1);
rt300@0 1786 for(int l = startLump; l < startLump + numSpokes; l++){
rt300@0 1787 lumps[l].constrain();
rt300@0 1788 }
rt300@0 1789
rt300@0 1790 break;
rt300@0 1791 }
rt300@0 1792 case CONSTRAIN_CORNERS:
rt300@0 1793 // constrain inner ring
rt300@0 1794
rt300@0 1795 for(int l = startLump; l < startLump + numSpokes; l++){
rt300@0 1796 lumps[l].constrain();
rt300@0 1797 }
rt300@0 1798
rt300@0 1799 break;
rt300@0 1800
rt300@0 1801 default:
rt300@0 1802 break;
rt300@0 1803 }
rt300@0 1804 }
rt300@0 1805 //--------------------------------------------------------------
rt300@0 1806
rt300@0 1807 void SpiderCrossMesh::makeDefaultScanPath(){
rt300@0 1808
rt300@0 1809 cout << "SpiderCrossMesh spider makeDefaultScanPath\n";
rt300@0 1810
rt300@0 1811 // add a ring to the path
rt300@0 1812 int ringNo = floor(numRings/2.0);
rt300@0 1813 int springno = 0, lumpno = 0;
rt300@0 1814 for(int i = 0; i < numSpokes; i++){
rt300@0 1815 lumpno = numSpokes*ringNo + i;
rt300@0 1816 springno = numSpokes*ringNo + i;
rt300@3 1817 scanPath.addElement(&lumps[lumpno], &springs[springno]);
rt300@0 1818 }
rt300@0 1819 cout << "SpiderCrossMesh spider scan path created on ring " << ringNo << "\n";
rt300@0 1820
rt300@0 1821 // add a spoke to the path
rt300@0 1822 /*
rt300@0 1823 int springno = 0, lumpno = 0;
rt300@0 1824
rt300@0 1825 int springsinrings = numSpokes*numRings;
rt300@0 1826 for(int i = 0; i < numRings-1; i++){
rt300@0 1827 lumpno = numSpokes*i; // zero, numspokes etc
rt300@0 1828 springno = springsinrings + numSpokes*i; // starts from total rings, increments by numspokes etc
rt300@3 1829 scanPath.addElement(&lumps[lumpno], &springs[springno]);
rt300@0 1830 }
rt300@0 1831 */
rt300@0 1832 }
rt300@0 1833
rt300@0 1834 /****************************************/
rt300@0 1835 // Line Mesh */
rt300@0 1836 /****************************************/
rt300@0 1837
rt300@0 1838 LineMesh::LineMesh(int aNumSegments) : Mesh(){
rt300@8 1839 meshType = LINE_MESH;
rt300@0 1840 numSegments = aNumSegments;
rt300@0 1841 radial = false;
rt300@0 1842
rt300@0 1843 makeComponents(aNumSegments, 0);
rt300@0 1844
rt300@0 1845 setLumpPositions();
rt300@0 1846
rt300@0 1847 makeConnections();
rt300@0 1848
rt300@0 1849 makeDefaultScanPath();
rt300@0 1850
rt300@6 1851
rt300@0 1852
rt300@0 1853 setPropagationSpeed(0.6);
rt300@0 1854
rt300@6 1855 for(int i = 0; i < lumps.size(); i++){
rt300@6 1856 lumps[i].constrain(Lump::CONSTRAIN_X);
rt300@6 1857 }
rt300@6 1858
rt300@6 1859 constrain(0.0,0.0,CONSTRAIN_EDGES);
rt300@0 1860 cout << "constructed LINE mesh\n";
rt300@0 1861
rt300@0 1862 }
rt300@0 1863 //--------------------------------------------------------------
rt300@0 1864 void LineMesh::makeComponents(int aDimension1, int aDimension2){
rt300@0 1865 // make componets creates the correct number of lumps and springs according to dimensions and mesh type
rt300@0 1866 cout << "Line class makeComponents\n";
rt300@0 1867 //
rt300@0 1868 numLumps = numSegments+1;
rt300@0 1869 numSprings = numSegments;
rt300@9 1870 Mesh::makeComponents(numLumps, numSprings);
rt300@0 1871
rt300@0 1872 }
rt300@0 1873 //--------------------------------------------------------------
rt300@0 1874 void LineMesh::setLumpPositions(){
rt300@0 1875 cout << "LineMesh class setLumpPositions\n";
rt300@0 1876 //
rt300@0 1877 double hspacing = (1.0 - 0.05)/numSegments;
rt300@4 1878 for(int i = 0; i < lumps.size(); i++){
rt300@0 1879 lumps[i].setPosition(0.025+hspacing*i, 0.5);
rt300@0 1880 }
rt300@0 1881 }
rt300@0 1882 //--------------------------------------------------------------
rt300@0 1883 void LineMesh::makeConnections(){
rt300@0 1884 // connects the lmps and springs. the spring needs to know which lumps are at each end
rt300@0 1885 // and lumps need to know which springs attached
rt300@0 1886 // calls connect method that does this
rt300@0 1887 cout << "LineMesh class make connections\n";
rt300@0 1888 for(int i = 0; i < numSegments; i++){
rt300@0 1889 connect(i,i);
rt300@0 1890 connect(i,i+1);
rt300@0 1891 }
rt300@6 1892
rt300@0 1893 }
rt300@0 1894
rt300@0 1895 //--------------------------------------------------------------
rt300@0 1896 void LineMesh::constrain(double ax, double ay, constrainMode aMode){
rt300@0 1897 cout << "LineMesh class constrain\n";
rt300@0 1898 if (aMode == CONSTRAIN_EDGES || aMode == CONSTRAIN_CORNERS){
rt300@0 1899 lumps[0].constrain();
rt300@4 1900 lumps[lumps.size()-1].constrain();
rt300@0 1901 }else if (aMode == CONSTRAIN_GRAB_REGION){
rt300@0 1902 TwoVector diff;
rt300@4 1903 for(int i = 0; i<lumps.size(); i++){
rt300@0 1904
rt300@0 1905 diff.setCoord(lumps[i].position.x - ax, lumps[i].position.y - ay);
rt300@0 1906
rt300@0 1907 if (diff.norm() < GRAB_RANGE){
rt300@0 1908 lumps[i].constrain();
rt300@0 1909 }
rt300@0 1910 }
rt300@0 1911 }
rt300@0 1912 }
rt300@0 1913 //--------------------------------------------------------------
rt300@0 1914 //--------------------------------------------------------------
rt300@0 1915 void LineMesh::makeDefaultScanPath(){
rt300@0 1916
rt300@0 1917 cout << "LineMesh class makeDefaultScanPath\n";
rt300@14 1918 for(int i = 1; i < numSegments-1; i++){
rt300@3 1919 scanPath.addElement(&lumps[i], &springs[i]);
rt300@0 1920 }
rt300@0 1921 }
rt300@0 1922 //--------------------------------------------------------------
rt300@0 1923 /****************************************/
rt300@0 1924 // GROUNDED LINE Mesh */
rt300@0 1925 /****************************************/
rt300@0 1926
rt300@0 1927 GroundedLineMesh::GroundedLineMesh(int aNumSegments) : Mesh(){
rt300@8 1928 meshType = GROUNDED_LINE_MESH;
rt300@0 1929 numSegments = aNumSegments;
rt300@0 1930 radial = false;
rt300@0 1931 makeComponents(aNumSegments, 0);
rt300@0 1932
rt300@0 1933 setLumpPositions();
rt300@0 1934
rt300@0 1935 makeConnections();
rt300@0 1936
rt300@0 1937 makeDefaultScanPath();
rt300@0 1938
rt300@0 1939 constrain(0.0,0.0,CONSTRAIN_ALL_X);
rt300@0 1940
rt300@0 1941 setPropagationSpeed(0.6);
rt300@0 1942
rt300@0 1943 cout << "constructed GROUNDED LINE mesh\n";
rt300@0 1944
rt300@0 1945 }
rt300@0 1946 //--------------------------------------------------------------
rt300@0 1947 void GroundedLineMesh::makeComponents(int aDimension1, int aDimension2){
rt300@0 1948 // make componets creates the correct number of lumps and springs according to dimensions and mesh type
rt300@0 1949
rt300@0 1950 // THIS IS CRAP should be able to just create new ones and attach them...?
rt300@0 1951 cout << "Line class makeComponents\n";
rt300@0 1952 //
rt300@0 1953 numLumps = (numSegments+1)*2;
rt300@0 1954 numSprings = numSegments*2;
rt300@9 1955 Mesh::makeComponents(numLumps, numSprings);
rt300@0 1956
rt300@0 1957 }
rt300@0 1958 //--------------------------------------------------------------
rt300@0 1959 void GroundedLineMesh::setLumpPositions(){
rt300@0 1960 cout << "LineMesh class setLumpPositions\n";
rt300@0 1961 //
rt300@0 1962
rt300@0 1963 double hspacing = (1.0 - 0.05)/numSegments;
rt300@0 1964 for(int i = 0; i < (numSegments+1); i++){
rt300@0 1965 // moving ones
rt300@0 1966 lumps[i].setPosition(0.025+hspacing*i, 0.5);
rt300@0 1967 //grounded ones
rt300@0 1968 lumps[i + numSegments+1].setPosition(0.025+hspacing*i,0.5*cos(i*hspacing*PI) + 0.5 );
rt300@0 1969 }
rt300@0 1970
rt300@0 1971
rt300@0 1972
rt300@0 1973 }
rt300@0 1974 //--------------------------------------------------------------
rt300@0 1975 void GroundedLineMesh::makeConnections(){
rt300@0 1976 // connects the lmps and springs. the spring needs to know which lumps are at each end
rt300@0 1977 // and lumps need to know which springs attached
rt300@0 1978 // calls connect method that does this
rt300@0 1979 cout << "LineMesh class make connections\n";
rt300@0 1980 for(int i = 0; i < numSegments; i++){
rt300@0 1981 connect(i,i,i+1);
rt300@0 1982 connect(i + numSegments,i , i + numSegments+1);
rt300@0 1983
rt300@0 1984 }
rt300@0 1985
rt300@0 1986 setRestLength();
rt300@0 1987 }
rt300@0 1988
rt300@0 1989 //--------------------------------------------------------------
rt300@0 1990 void GroundedLineMesh::constrain(double ax, double ay, constrainMode aMode){
rt300@0 1991 cout << "LineMesh class constrain\n";
rt300@0 1992 if (aMode == CONSTRAIN_EDGES || aMode == CONSTRAIN_CORNERS){
rt300@0 1993 lumps[0].constrain();
rt300@4 1994 lumps[lumps.size()-1].constrain();
rt300@0 1995
rt300@4 1996 for(int i = numSegments; i < lumps.size(); i++){
rt300@0 1997 lumps[i].constrain();
rt300@0 1998 }
rt300@0 1999 }
rt300@0 2000
rt300@0 2001 if (aMode == CONSTRAIN_GRAB_REGION){
rt300@0 2002 TwoVector diff;
rt300@4 2003 for(int i = 0; i<lumps.size(); i++){
rt300@0 2004
rt300@0 2005 diff.setCoord(lumps[i].position.x - ax, lumps[i].position.y - ay);
rt300@0 2006
rt300@0 2007 if (diff.norm() < GRAB_RANGE){
rt300@0 2008 lumps[i].constrain();
rt300@0 2009 }
rt300@0 2010 }
rt300@0 2011 }
rt300@0 2012 if (aMode == CONSTRAIN_ALL_X){
rt300@0 2013
rt300@0 2014
rt300@0 2015 for(int i = 0; i<numSegments; i++){
rt300@0 2016
rt300@0 2017 lumps[i].constrain(Lump::CONSTRAIN_X);
rt300@0 2018 }
rt300@4 2019 for(int i = numSegments; i < lumps.size(); i++){
rt300@0 2020 lumps[i].constrain();
rt300@0 2021 }
rt300@0 2022 lumps[0].constrain();
rt300@4 2023 lumps[lumps.size()-1].constrain();
rt300@0 2024 }
rt300@0 2025
rt300@0 2026 }
rt300@0 2027 //--------------------------------------------------------------
rt300@0 2028 //--------------------------------------------------------------
rt300@0 2029 void GroundedLineMesh::makeDefaultScanPath(){
rt300@0 2030
rt300@0 2031 cout << "LineMesh class makeDefaultScanPath\n";
rt300@0 2032 for(int i = 0; i < numSegments; i++){
rt300@3 2033 scanPath.addElement(&lumps[i], &springs[i]);
rt300@0 2034 }
rt300@0 2035 }
rt300@0 2036 //--------------------------------------------------------------
rt300@0 2037
rt300@0 2038 /****************************************/
rt300@0 2039 // DROPLET Mesh */
rt300@0 2040 /****************************************/
rt300@0 2041 // more of a balloon really - filled with compressible gas
rt300@0 2042 DropletMesh::DropletMesh(int aNumSegments) : Mesh(){
rt300@8 2043 meshType = DROPLET_MESH;
rt300@0 2044 restArea = 1.0;
rt300@0 2045 radial = true;
rt300@0 2046 numSegments = aNumSegments;
rt300@0 2047
rt300@0 2048 makeComponents(aNumSegments, 0);
rt300@0 2049
rt300@0 2050 setLumpPositions();
rt300@0 2051
rt300@0 2052 makeConnections();
rt300@0 2053
rt300@0 2054 makeDefaultScanPath();
rt300@0 2055
rt300@0 2056 //constrain(0.0,0.0,CONSTRAIN_EDGES);
rt300@0 2057
rt300@0 2058 setPropagationSpeed(0.8);
rt300@0 2059
rt300@0 2060 zeroRestLength();
rt300@0 2061 globalForces.pressureAmt = 0.4;
rt300@0 2062
rt300@0 2063 cout << "constructed DropletMesh mesh\n";
rt300@0 2064
rt300@0 2065 }
rt300@0 2066 //--------------------------------------------------------------
rt300@0 2067 void DropletMesh::makeComponents(int aDimension1, int aDimension2){
rt300@0 2068 // make componets creates the correct number of lumps and springs according to dimensions and mesh type
rt300@0 2069 cout << "Line class makeComponents\n";
rt300@0 2070 //
rt300@0 2071 numLumps = numSegments;
rt300@0 2072 numSprings = numSegments;
rt300@9 2073 Mesh::makeComponents(numLumps, numSprings);
rt300@0 2074 }
rt300@0 2075 //--------------------------------------------------------------
rt300@0 2076 void DropletMesh::setLumpPositions(){
rt300@0 2077 cout << "DropletMesh class setLumpPositions\n";
rt300@0 2078 // make a circle centred around 0.5,0.5 radius 0.4
rt300@0 2079 int l = 0;
rt300@0 2080 double hyplen,xpos,ypos;
rt300@0 2081
rt300@0 2082 double * cosines = new double[numSegments];
rt300@0 2083 double * sines = new double[numSegments];
rt300@0 2084 double angle = 2 * PI / numSegments;
rt300@0 2085
rt300@0 2086 for(int spoke = 0; spoke < numSegments; spoke++){
rt300@0 2087 cosines[spoke] = cos(angle*spoke);
rt300@0 2088 sines[spoke] = sin(angle*spoke);
rt300@0 2089 }
rt300@0 2090
rt300@0 2091 hyplen = 0.2; // aka radius
rt300@0 2092
rt300@0 2093 //
rt300@0 2094 //lumps[0].setPosition(0.5,0.5);
rt300@0 2095
rt300@0 2096 for(int spoke = 0; spoke < numSegments; spoke++){
rt300@0 2097
rt300@0 2098 xpos = hyplen * cosines[spoke] + 0.5;
rt300@0 2099 ypos = hyplen*sines[spoke] + 0.5;
rt300@0 2100 lumps[l].setPosition(xpos,ypos);
rt300@0 2101 l++;
rt300@0 2102
rt300@0 2103 }
rt300@0 2104 calculateCentre();
rt300@0 2105 restArea = calculateArea() * 3; // this is like the amount of air in there originally, inflate a bit !
rt300@0 2106
rt300@0 2107 delete [] cosines;
rt300@0 2108 delete [] sines;
rt300@0 2109 }
rt300@0 2110 //--------------------------------------------------------------
rt300@0 2111 void DropletMesh::makeConnections(){
rt300@0 2112 // connects the lmps and springs. the spring needs to know which lumps are at each end
rt300@0 2113 // and lumps need to know which springs attached
rt300@0 2114 // calls connect method that does this
rt300@0 2115 cout << "DropletMesh class make connections\n";
rt300@0 2116 for(int i = 0; i < numSegments-1; i++){
rt300@0 2117 connect(i,i,i+1);
rt300@0 2118 }
rt300@0 2119 // finally connect end spring to start lump
rt300@0 2120 connect(numSegments-1,numSegments-1);
rt300@0 2121 connect(numSegments-1,0);
rt300@0 2122 }
rt300@0 2123
rt300@0 2124 //--------------------------------------------------------------
rt300@0 2125 void DropletMesh::constrain(double ax, double ay, constrainMode aMode){
rt300@0 2126 cout << "DropletMesh class constrain\n";
rt300@0 2127 if (aMode == CONSTRAIN_EDGES || aMode == CONSTRAIN_CORNERS){
rt300@0 2128 lumps[0].constrain();
rt300@4 2129 lumps[lumps.size()-1].constrain();
rt300@0 2130 } else if (aMode == CONSTRAIN_GRAB_REGION){
rt300@0 2131 TwoVector diff;
rt300@4 2132 for(int i = 0; i<lumps.size(); i++){
rt300@0 2133
rt300@0 2134 diff.setCoord(lumps[i].position.x - ax, lumps[i].position.y - ay);
rt300@0 2135
rt300@0 2136 if (diff.norm() < GRAB_RANGE){
rt300@0 2137 lumps[i].constrain();
rt300@0 2138 }
rt300@0 2139 }
rt300@0 2140 }
rt300@0 2141 }
rt300@0 2142 //--------------------------------------------------------------
rt300@0 2143 //--------------------------------------------------------------
rt300@0 2144 void DropletMesh::makeDefaultScanPath(){
rt300@0 2145
rt300@0 2146 cout << "DropletMesh class makeDefaultScanPath\n";
rt300@0 2147 for(int i = 0; i < numSegments; i++){
rt300@3 2148 scanPath.addElement(&lumps[i], &springs[i]);
rt300@0 2149 }
rt300@0 2150 cout << "DropletMesh class makeDefaultScanPath\n";
rt300@0 2151 }
rt300@0 2152 //--------------------------------------------------------------
rt300@0 2153 double DropletMesh::calculateArea(){
rt300@0 2154
rt300@0 2155 // how do we calculate area?? answer: average all radii !
rt300@0 2156
rt300@0 2157 // calc average radius magnitude
rt300@0 2158 double radiusMag = 0.0, avRadiusMag = 0.0;
rt300@4 2159 for(int i = 0; i < lumps.size(); i++){
rt300@0 2160 TwoVector radius;
rt300@0 2161 radius.setCoord(centre.x - lumps[i].position.x, centre.y - lumps[i].position.y );
rt300@0 2162 radiusMag = radius.norm();
rt300@0 2163 avRadiusMag += radiusMag;
rt300@0 2164 }
rt300@4 2165 avRadiusMag /= lumps.size();
rt300@0 2166
rt300@0 2167 // calc area
rt300@0 2168 double area = 2 * PI * avRadiusMag*avRadiusMag;
rt300@0 2169
rt300@0 2170 return area;
rt300@0 2171
rt300@0 2172 }
rt300@0 2173
rt300@0 2174 double DropletMesh::calculatePressure(){
rt300@0 2175 // work out pressure on the springs.
rt300@0 2176 // this will be proportional to the difference in the rest area to the current area
rt300@0 2177 //this will exert a force proportional to length
rt300@0 2178
rt300@0 2179 double da = restArea - calculateArea();
rt300@0 2180 // if current area is smaller this will create positive pressure
rt300@0 2181
rt300@0 2182 globalForces.setPressure(da);
rt300@0 2183 return globalForces.pressure;
rt300@0 2184
rt300@0 2185 }
rt300@0 2186 //--------------------------------------------------------------
rt300@0 2187 void DropletMesh::update(){
rt300@0 2188
rt300@0 2189 calculateCentre();
rt300@0 2190 calculatePressure();
rt300@0 2191 Mesh::update(); // schweet
rt300@0 2192
rt300@0 2193 }
rt300@0 2194 //--------------------------------------------------------------
rt300@0 2195
rt300@0 2196 /****************************************/
rt300@0 2197 // TriangleMesh */
rt300@0 2198 /****************************************/
rt300@0 2199 //--------------------------------------------------------------
rt300@0 2200 TriangleMesh::TriangleMesh(int height, int width): Mesh() {
rt300@8 2201 meshType = TRIANGLE_MESH;
rt300@0 2202 radial = false;
rt300@0 2203 makeComponents(height, width);
rt300@0 2204
rt300@0 2205 setLumpPositions();
rt300@0 2206
rt300@0 2207 makeConnections();
rt300@0 2208
rt300@0 2209 makeDefaultScanPath();
rt300@0 2210
rt300@0 2211 constrain(0,0,CONSTRAIN_EDGES);
rt300@0 2212
rt300@0 2213 zeroRestLength();
rt300@1 2214
rt300@0 2215
rt300@0 2216 cout << "constructing TRIANGLE mesh\n";
rt300@0 2217 }
rt300@0 2218 //--------------------------------------------------------------
rt300@0 2219 // make componets for tri
rt300@0 2220 void TriangleMesh::makeComponents(int aheight, int awidth){
rt300@0 2221 height = aheight;
rt300@0 2222 width = awidth;
rt300@0 2223 numLumps = height * width;
rt300@0 2224 /* horz --- \ diag / diag */
rt300@0 2225 numSprings = (width-1) * (height-1) + width * (height - 1) + (width-1) * (height - 1);
rt300@0 2226
rt300@9 2227 Mesh::makeComponents(numLumps, numSprings);
rt300@0 2228 }
rt300@0 2229
rt300@0 2230 //--------------------------------------------------------------
rt300@0 2231 void TriangleMesh::setLumpPositions(){
rt300@0 2232 double vspacing = 1.0/(height-1);
rt300@0 2233 double hspacing = 1.0/(width - 0.5);
rt300@0 2234 int i =0;
rt300@0 2235 // set positions
rt300@0 2236 for(int row = 0; row < height; row++){ // go down column
rt300@0 2237 for(int col = 0;col < width; col++){ // go along row
rt300@0 2238 // if even row start from wall
rt300@0 2239 if(row%2){ // odd
rt300@0 2240 lumps[i].setPosition(hspacing*col + 0.5*hspacing,vspacing*row);
rt300@0 2241 }else{ // even
rt300@0 2242 lumps[i].setPosition(hspacing*col,vspacing*row);
rt300@0 2243 }
rt300@0 2244 i++;
rt300@0 2245 }
rt300@0 2246 }
rt300@0 2247 }
rt300@0 2248 //--------------------------------------------------------------
rt300@0 2249 void TriangleMesh::makeConnections(){
rt300@0 2250
rt300@0 2251 // could be cleverer in terms of numbering?
rt300@0 2252 int lumpnum = 0;
rt300@0 2253 int springnum = 0;
rt300@0 2254
rt300@0 2255 // attach horizontal a
rt300@0 2256 for ( int row=1;row< height;row++){
rt300@0 2257 for(int col=0;col<width-1;col++){
rt300@0 2258 connect(springnum,lumpnum,lumpnum+1);
rt300@0 2259 lumpnum++;
rt300@0 2260 springnum++;
rt300@0 2261 }
rt300@0 2262 lumpnum++;
rt300@0 2263 }
rt300@0 2264
rt300@0 2265 /* now do /\/\/\/\/\/\/\ */
rt300@0 2266 lumpnum = 0;
rt300@0 2267 for ( int row=0;row<height-1;row++){
rt300@0 2268
rt300@0 2269 if(row%2 == 0){
rt300@0 2270 // even ie 0
rt300@0 2271 /* start with \ diag */
rt300@0 2272 for(int col=0;col<width-1;col++){
rt300@0 2273 /* \ */
rt300@0 2274 connect(springnum++, lumpnum, lumpnum+ width);
rt300@0 2275 lumpnum++;
rt300@0 2276 /* / */
rt300@0 2277 connect(springnum++, lumpnum, lumpnum+(width-1));
rt300@0 2278
rt300@0 2279 }
rt300@0 2280 connect(springnum++, lumpnum, lumpnum+width);
rt300@0 2281 lumpnum++;
rt300@0 2282
rt300@0 2283 }else{ // odd
rt300@0 2284 for(int col=0;col<width-1;col++){
rt300@0 2285 /* / */
rt300@0 2286 connect(springnum++, lumpnum, lumpnum+ width);
rt300@0 2287 /* \ */
rt300@0 2288 connect(springnum++, lumpnum, lumpnum+(width+1));
rt300@0 2289 lumpnum++;
rt300@0 2290 }
rt300@0 2291 // last r to l
rt300@0 2292 /* / */
rt300@0 2293 connect(springnum++, lumpnum, lumpnum+(width));
rt300@0 2294 lumpnum++;
rt300@0 2295
rt300@0 2296 }
rt300@0 2297 }
rt300@0 2298
rt300@0 2299 }
rt300@0 2300
rt300@0 2301
rt300@0 2302
rt300@0 2303 //--------------------------------------------------------------
rt300@0 2304 void TriangleMesh::constrain(double ax, double ay, constrainMode aMode){
rt300@0 2305 // exactly the same as square
rt300@0 2306 TwoVector diff;
rt300@0 2307 int i = 0;
rt300@0 2308
rt300@0 2309 // check if lump is within grab range
rt300@0 2310 switch (aMode) {
rt300@0 2311 case CONSTRAIN_GRAB_REGION:
rt300@4 2312 for(i = 0; i<lumps.size(); i++){
rt300@0 2313
rt300@0 2314 diff.setCoord(lumps[i].position.x - ax, lumps[i].position.y - ay);
rt300@0 2315
rt300@0 2316 if (diff.norm() < GRAB_RANGE){
rt300@0 2317 lumps[i].constrain();
rt300@0 2318 }
rt300@0 2319 }
rt300@0 2320 break;
rt300@0 2321 case CONSTRAIN_EDGES:
rt300@0 2322 i = 0;
rt300@0 2323 for(int row = 0; row < height; row++){ // go down column
rt300@0 2324 for(int col = 0;col < width; col++){ // go along row
rt300@0 2325 if(row == 0 || row == height-1 || col == 0 || col == width-1){
rt300@0 2326 lumps[i].constrain();
rt300@0 2327 }
rt300@0 2328 i++;
rt300@0 2329 }
rt300@0 2330 }
rt300@0 2331 break;
rt300@0 2332 case CONSTRAIN_CORNERS:
rt300@0 2333 i = 0;
rt300@0 2334 for(int row = 0; row < height; row++){ // go down column
rt300@0 2335 for(int col = 0;col < width; col++){ // go along row
rt300@0 2336 if( (row == 0 && col == 0)
rt300@0 2337 || (row == height-1 && col == 0)
rt300@0 2338 || (row == 0 && col == width-1)
rt300@0 2339 || (row == height-1 && col == width-1)){
rt300@0 2340 lumps[i].constrain();
rt300@0 2341 }
rt300@0 2342 i++;
rt300@0 2343 }
rt300@0 2344 }
rt300@0 2345 break;
rt300@0 2346
rt300@0 2347 default:
rt300@0 2348 break;
rt300@0 2349 }
rt300@0 2350
rt300@0 2351 }
rt300@0 2352 //--------------------------------------------------------------
rt300@0 2353 //--------------------------------------------------------------
rt300@0 2354 void TriangleMesh::makeDefaultScanPath(){
rt300@0 2355
rt300@0 2356 int vmarg = 4;
rt300@0 2357 int hmarg = 4;
rt300@0 2358
rt300@0 2359 int lumpno = vmarg * width + hmarg; // top left corner
rt300@0 2360 int springno = vmarg * (width - 1) + hmarg;
rt300@0 2361 // do top horz
rt300@0 2362 for(int i = 0; i < width - 2*hmarg; i++){
rt300@3 2363 scanPath.addElement(&lumps[lumpno], &springs[springno]);
rt300@0 2364 lumpno++;
rt300@0 2365 springno++;
rt300@0 2366 }
rt300@0 2367
rt300@0 2368
rt300@0 2369 }
rt300@0 2370