rt300@0
|
1 /*
|
rt300@0
|
2 * lump.cpp
|
rt300@0
|
3 * simplespring
|
rt300@0
|
4 *
|
rt300@0
|
5 * Created by Robert Tubb on 01/06/2011.
|
rt300@0
|
6 * Copyright 2011 __MyCompanyName__. All rights reserved.
|
rt300@0
|
7 *
|
rt300@0
|
8 */
|
rt300@0
|
9 #include "lump.h"
|
rt300@0
|
10 #include "testApp.h"
|
rt300@0
|
11 #include <iostream>
|
rt300@0
|
12 #include "globalForces.h"
|
rt300@0
|
13 #include "globalUI.h"
|
rt300@0
|
14 extern GlobalForces globalForces;
|
rt300@0
|
15 extern GlobalUI globalUI;
|
rt300@0
|
16 //int Lump::numLumps = 0;
|
rt300@0
|
17 //--------------------------------------------------------------
|
rt300@0
|
18 // default constr
|
rt300@4
|
19 Lump::Lump(){
|
rt300@0
|
20 //cout << "constructing a default lump" << endl;
|
rt300@8
|
21 // myIndexInMesh = index; HOW TO GET THIS??
|
rt300@0
|
22 mass = 10.0;
|
rt300@0
|
23 inverseMass = 1.0/mass; // not needed - used csquared for force
|
rt300@0
|
24 friction = 0.996;
|
rt300@0
|
25 position.x = 0.5;
|
rt300@0
|
26 position.y = 0.5;
|
rt300@0
|
27 velocity.x = 0.0;
|
rt300@0
|
28 velocity.y = 0.0;
|
rt300@0
|
29 accel.x = 0.0;
|
rt300@0
|
30 accel.y = 0.0;
|
rt300@0
|
31 numAttachedSprings = 0;
|
rt300@0
|
32 grabbed = false;
|
rt300@0
|
33 highlighted = false;
|
rt300@0
|
34 constrained = false;
|
rt300@0
|
35 totalForceMag = 0.0;
|
rt300@8
|
36 //size = 3; //sqrt(mass/3.0);
|
rt300@0
|
37 isInScanPath = false;
|
rt300@4
|
38 isScanPathStart = false;
|
rt300@4
|
39 isScanPathEnd = false;
|
rt300@4
|
40
|
rt300@0
|
41 previousPosition.setCoord(0.5,0.5);
|
rt300@0
|
42 zeroRefPos.setCoord(0.0,0.0);
|
rt300@0
|
43 constrainMode = NOT_CONSTRAINED;
|
rt300@5
|
44 radialDisplacement = 0.0;
|
rt300@0
|
45 grabID = -1;
|
rt300@0
|
46
|
rt300@0
|
47 }
|
rt300@0
|
48 //--------------------------------------------------------------
|
rt300@0
|
49 // arg constructor
|
rt300@4
|
50 Lump::Lump(double aMass,double aFriction, double positionX, double positionY){
|
rt300@0
|
51 // set members
|
rt300@0
|
52
|
rt300@0
|
53 }
|
rt300@0
|
54
|
rt300@0
|
55 //--------------------------------------------------------------
|
rt300@0
|
56 Lump::~Lump(){
|
rt300@4
|
57
|
rt300@0
|
58 }
|
rt300@0
|
59 //--------------------------------------------------------------
|
rt300@0
|
60 void Lump::attachSpring(Spring* aSpring){
|
rt300@0
|
61
|
rt300@4
|
62
|
rt300@4
|
63 attachedSprings.push_back(aSpring);
|
rt300@4
|
64 numAttachedSprings++;
|
rt300@4
|
65
|
rt300@0
|
66 }
|
rt300@0
|
67 //--------------------------------------------------------------
|
rt300@0
|
68 Spring * Lump::checkConnectedTo(Lump * otherLump){
|
rt300@0
|
69 // loop thru all attached springs looking at other end
|
rt300@4
|
70 for(int i = 0; i<attachedSprings.size(); i++){
|
rt300@0
|
71 if(attachedSprings[i]->getLumpOnOtherEnd(this) == otherLump){
|
rt300@0
|
72 return attachedSprings[i];
|
rt300@0
|
73 }
|
rt300@0
|
74 }
|
rt300@0
|
75 return NULL;
|
rt300@0
|
76 }
|
rt300@0
|
77 //--------------------------------------------------------------
|
rt300@0
|
78 void Lump::constrain(){
|
rt300@0
|
79 // TODO1 different constrain modes
|
rt300@0
|
80 constrained = true;
|
rt300@0
|
81 constrainMode = CONSTRAIN_XY;
|
rt300@0
|
82 setZeroRefPos();
|
rt300@0
|
83 //cout << "constraining lump "<< endl;
|
rt300@0
|
84
|
rt300@0
|
85 }
|
rt300@6
|
86
|
rt300@0
|
87 //--------------------------------------------------------------
|
rt300@0
|
88 void Lump::constrain(ConstrainMode aconstrainMode){
|
rt300@6
|
89 if(aconstrainMode == CONSTRAIN_XY){
|
rt300@6
|
90 constrained = true;
|
rt300@6
|
91 }
|
rt300@0
|
92 constrainMode = aconstrainMode;
|
rt300@0
|
93 setZeroRefPos();
|
rt300@0
|
94 //cout << "constraining lump "<< endl;
|
rt300@0
|
95
|
rt300@0
|
96 }
|
rt300@0
|
97 void Lump::setInvMass(double aInvMass){
|
rt300@0
|
98 // use csquared
|
rt300@0
|
99 inverseMass = aInvMass;
|
rt300@0
|
100 }
|
rt300@0
|
101 //--------------------------------------------------------------
|
rt300@0
|
102
|
rt300@0
|
103 void Lump::draw(){
|
rt300@0
|
104 /*
|
rt300@0
|
105
|
rt300@0
|
106
|
rt300@0
|
107 */
|
rt300@0
|
108
|
rt300@0
|
109 if(grabbed){
|
rt300@0
|
110
|
rt300@0
|
111 int xpos = position.x * ofGetHeight() + globalUI.borderSize;
|
rt300@0
|
112 int ypos = position.y * ofGetHeight();
|
rt300@0
|
113 // draw a circle round it
|
rt300@0
|
114 ofSetColor(255, 0, 0);
|
rt300@0
|
115 ofNoFill();
|
rt300@0
|
116 ofCircle(xpos, ypos, 35.0);
|
rt300@0
|
117 ofFill();
|
rt300@0
|
118 }else if(isInScanPath){
|
rt300@12
|
119 /*
|
rt300@0
|
120 ofSetColor(0, 200, 20);
|
rt300@0
|
121 int xpos = position.x * ofGetHeight() + globalUI.borderSize;
|
rt300@0
|
122 int ypos = position.y * ofGetHeight();
|
rt300@0
|
123 ofEllipse(xpos,ypos, 6, 6);
|
rt300@4
|
124 if(isScanPathEnd){
|
rt300@4
|
125 ofSetColor(255, 255, 0);
|
rt300@4
|
126 ofNoFill();
|
rt300@4
|
127 ofCircle(xpos, ypos, 6.0);
|
rt300@4
|
128 ofFill();
|
rt300@4
|
129 }
|
rt300@4
|
130 if(isScanPathStart){
|
rt300@4
|
131 ofSetColor(0, 255, 255);
|
rt300@4
|
132 ofNoFill();
|
rt300@4
|
133 ofCircle(xpos, ypos, 7.0);
|
rt300@4
|
134 ofFill();
|
rt300@4
|
135 }
|
rt300@0
|
136 // code to display restpos and displacement
|
rt300@12
|
137
|
rt300@0
|
138 ofSetColor(0, 0, 0);
|
rt300@0
|
139 int rxpos = zeroRefPos.x * ofGetHeight() + 128;
|
rt300@0
|
140 int rypos = zeroRefPos.y * ofGetHeight();
|
rt300@0
|
141 ofEllipse(rxpos,rypos, 6, 6);
|
rt300@0
|
142
|
rt300@0
|
143 ofSetColor(100, 100, 100);
|
rt300@0
|
144
|
rt300@0
|
145 ofLine(rxpos,rypos,xpos,ypos);
|
rt300@0
|
146 */
|
rt300@0
|
147
|
rt300@0
|
148 }else if(highlighted){
|
rt300@0
|
149 ofSetColor(200, 0, 0);
|
rt300@0
|
150 int xpos = position.x * ofGetHeight() + globalUI.borderSize;
|
rt300@0
|
151 int ypos = position.y * ofGetHeight();
|
rt300@0
|
152 ofEllipse(xpos,ypos, 2, 2);
|
rt300@0
|
153 }else if (constrained){
|
rt300@4
|
154 ofSetColor(200,5,5);
|
rt300@4
|
155 int xpos = position.x * ofGetHeight() + globalUI.borderSize;
|
rt300@4
|
156 int ypos = position.y * ofGetHeight();
|
rt300@4
|
157 ofEllipse(xpos,ypos, 2, 2);
|
rt300@0
|
158 }else{
|
rt300@0
|
159 // dont draw 'normal ' lumps
|
rt300@0
|
160 return;
|
rt300@0
|
161 //ofSetColor(23, 23, 200);
|
rt300@0
|
162 }
|
rt300@0
|
163 }
|
rt300@0
|
164
|
rt300@0
|
165 //--------------------------------------------------------------
|
rt300@0
|
166
|
rt300@0
|
167 TwoVector Lump::applyForce(){
|
rt300@0
|
168
|
rt300@0
|
169
|
rt300@0
|
170 if(grabbed || constrainMode == CONSTRAIN_XY){
|
rt300@0
|
171
|
rt300@0
|
172 // don't bother
|
rt300@0
|
173 return position;
|
rt300@0
|
174 }
|
rt300@0
|
175 // called LOTS so optimise
|
rt300@0
|
176 // use spring force to calc accel - vel - pos
|
rt300@0
|
177
|
rt300@0
|
178 TwoVector springForce(0.0,0.0);
|
rt300@0
|
179 TwoVector totalForce(0.0,0.0);
|
rt300@0
|
180
|
rt300@0
|
181 // sum up force from each attached spring
|
rt300@4
|
182 for(int i = 0;i<attachedSprings.size(); i++){
|
rt300@0
|
183
|
rt300@0
|
184 springForce = (attachedSprings[i])->getForce(this);
|
rt300@0
|
185
|
rt300@0
|
186 //cout << "spring number " << i << " force x " << springForce.x << endl;
|
rt300@0
|
187 totalForce.x += springForce.x;
|
rt300@0
|
188 totalForce.y += springForce.y;
|
rt300@0
|
189 }
|
rt300@0
|
190
|
rt300@0
|
191 // get the global forces, gravity and so on
|
rt300@0
|
192 totalForce.x += globalForces.getAllForceAt(position.x,position.y).x;
|
rt300@0
|
193 totalForce.y += globalForces.getAllForceAt(position.x,position.y).y;
|
rt300@0
|
194
|
rt300@0
|
195 if (constrainMode != CONSTRAIN_X){
|
rt300@0
|
196 accel.x = totalForce.x*inverseMass;
|
rt300@0
|
197 }else{
|
rt300@0
|
198 accel.x = 0.0;
|
rt300@0
|
199 }
|
rt300@0
|
200 if(constrainMode != CONSTRAIN_Y){
|
rt300@0
|
201 accel.y = totalForce.y*inverseMass;
|
rt300@0
|
202 }else{
|
rt300@0
|
203 accel.y = 0.0;
|
rt300@0
|
204 }
|
rt300@0
|
205
|
rt300@0
|
206 // DIFFERENCE EQUATIONS HERE. This is the bit that controls the movement!
|
rt300@0
|
207
|
rt300@0
|
208 // Heun
|
rt300@0
|
209
|
rt300@0
|
210 double pvx = velocity.x*friction + accel.x*2/3;
|
rt300@0
|
211 double pvy = velocity.y*friction + accel.y*2/3;
|
rt300@0
|
212
|
rt300@0
|
213
|
rt300@0
|
214 velocity.x = 0.75*pvx + 0.25*velocity.x;
|
rt300@0
|
215 velocity.y = 0.75*pvy + 0.25*velocity.y;
|
rt300@0
|
216
|
rt300@0
|
217 double px = position.x + velocity.x*2/3;
|
rt300@0
|
218 double py = position.y + velocity.y*2/3;
|
rt300@0
|
219
|
rt300@0
|
220
|
rt300@0
|
221 position.x = 0.75*px + 0.25*position.x;
|
rt300@0
|
222 position.y = 0.75*py + 0.25*position.y;
|
rt300@0
|
223
|
rt300@0
|
224
|
rt300@0
|
225 // Newton's 2nd law
|
rt300@0
|
226 /*
|
rt300@0
|
227 velocity.x += accel.x;
|
rt300@0
|
228 velocity.x *= friction;
|
rt300@0
|
229 position.x += velocity.x;
|
rt300@0
|
230
|
rt300@0
|
231 velocity.y += accel.y;
|
rt300@0
|
232 velocity.y *= friction;
|
rt300@0
|
233 position.y += velocity.y;
|
rt300@0
|
234 */
|
rt300@0
|
235
|
rt300@0
|
236
|
rt300@0
|
237 // WALLS
|
rt300@0
|
238 if (position.x < 0.0){
|
rt300@0
|
239 position.x = -position.x;
|
rt300@0
|
240 velocity.x = -velocity.x * globalForces.wallBounce;
|
rt300@0
|
241
|
rt300@0
|
242 } else if (position.x > 1.0){
|
rt300@0
|
243 position.x = 2.0 - position.x;
|
rt300@0
|
244 velocity.x = -velocity.x * globalForces.wallBounce;
|
rt300@0
|
245
|
rt300@0
|
246 }
|
rt300@0
|
247 if (position.y < 0.0){
|
rt300@0
|
248 position.y = -position.y;
|
rt300@0
|
249 velocity.y = -velocity.y * globalForces.wallBounce;
|
rt300@0
|
250
|
rt300@0
|
251 } else if (position.y > 1.0){
|
rt300@0
|
252 position.y = 2.0 - position.y;
|
rt300@0
|
253 velocity.y = -velocity.y * globalForces.wallBounce;
|
rt300@0
|
254
|
rt300@5
|
255 }
|
rt300@5
|
256 radialDisplacement = position.distanceTo(zeroRefPos);
|
rt300@0
|
257 return position;
|
rt300@0
|
258
|
rt300@0
|
259 }
|
rt300@0
|
260 //---------------------------------------------
|
rt300@0
|
261 void Lump::homingFilter(double amt){
|
rt300@0
|
262 // includes a little bit of the zero pos in the position, so sound will exponentially decay
|
rt300@0
|
263
|
rt300@0
|
264 if (constrained || grabbed) return;
|
rt300@0
|
265
|
rt300@0
|
266 position.x = (1 - amt)*position.x + amt*zeroRefPos.x;
|
rt300@0
|
267 position.y = (1 - amt)*position.y + amt*zeroRefPos.y;
|
rt300@0
|
268
|
rt300@0
|
269 }
|
rt300@0
|
270 //---------------------------------------------
|
rt300@0
|
271 void Lump::averagingFilter(double amt){
|
rt300@0
|
272 // NOT USED AVERAGING FILTER NOW IN MESH
|
rt300@0
|
273 // amt is between 0 and 1
|
rt300@0
|
274 if (constrained || grabbed) return;
|
rt300@0
|
275 double avx = 0.0, avy = 0.0;
|
rt300@0
|
276 // average the position of all the attached lumps
|
rt300@4
|
277 for(int i = 0;i<attachedSprings.size(); i++){
|
rt300@0
|
278
|
rt300@0
|
279 Lump* otherLump = attachedSprings[i]->getLumpOnOtherEnd(this);
|
rt300@0
|
280 avx += otherLump->position.x;
|
rt300@0
|
281 avy += otherLump->position.y;
|
rt300@0
|
282 }
|
rt300@4
|
283 avx /= attachedSprings.size();
|
rt300@4
|
284 avy /= attachedSprings.size();
|
rt300@0
|
285
|
rt300@0
|
286 // mix in the average with the 'real'
|
rt300@0
|
287 position.x = (1 - amt)*position.x + amt*avx;
|
rt300@0
|
288 position.y = (1 - amt)*position.y + amt*avy;
|
rt300@0
|
289
|
rt300@0
|
290 }
|
rt300@0
|
291 //---------------------------------------------
|
rt300@0
|
292 TwoVector Lump::averageOfConnected(){
|
rt300@0
|
293 TwoVector av;
|
rt300@0
|
294 if (constrained || grabbed) return position; // don't want constrained ones moving
|
rt300@0
|
295 //TODO what if edges unconstrained? this is why filtered unconstrained just ends up as a line...
|
rt300@0
|
296
|
rt300@0
|
297 // average the position of all the attached lumps
|
rt300@4
|
298 for(int i = 0;i<attachedSprings.size(); i++){
|
rt300@0
|
299
|
rt300@0
|
300 Lump* otherLump = attachedSprings[i]->getLumpOnOtherEnd(this);
|
rt300@0
|
301 av.x += otherLump->position.x;
|
rt300@0
|
302 av.y += otherLump->position.y;
|
rt300@0
|
303 }
|
rt300@4
|
304 av.x /= attachedSprings.size();
|
rt300@4
|
305 av.y /= attachedSprings.size();
|
rt300@0
|
306
|
rt300@0
|
307 return av;
|
rt300@0
|
308
|
rt300@0
|
309 }
|
rt300@0
|
310 //--------------------------------------------------------------
|
rt300@0
|
311 void Lump::setPosition(double ax, double ay){
|
rt300@0
|
312 // set INITIAL position
|
rt300@0
|
313 // Called from mesh set up. not used for updates
|
rt300@0
|
314
|
rt300@0
|
315 position.x = ax;
|
rt300@0
|
316 position.y = ay;
|
rt300@0
|
317 zeroRefPos.x = ax;
|
rt300@0
|
318 zeroRefPos.y = ay;
|
rt300@0
|
319 }
|
rt300@0
|
320 //--------------------------------------------------------------
|
rt300@0
|
321 void Lump::setVelocity(double ax, double ay){
|
rt300@0
|
322
|
rt300@0
|
323 velocity.x = ax;
|
rt300@0
|
324 velocity.y = ay;
|
rt300@0
|
325
|
rt300@0
|
326 }
|
rt300@0
|
327 //--------------------------------------------------------------
|
rt300@0
|
328
|
rt300@0
|
329 void Lump::setFriction(double aF){
|
rt300@0
|
330 friction = aF;
|
rt300@0
|
331 }
|
rt300@0
|
332 //--------------------------------------------------------------
|
rt300@0
|
333
|
rt300@0
|
334 void Lump::setZeroRefPos(){
|
rt300@0
|
335 // sets the reference point from which displacement is measured for scan amplitudes
|
rt300@0
|
336 zeroRefPos = position;
|
rt300@0
|
337 }
|
rt300@0
|
338 //--------------------------------------------------------------
|
rt300@0
|
339 double Lump::getTotalForceMag(){
|
rt300@0
|
340 return totalForceMag;
|
rt300@0
|
341 }
|
rt300@0
|
342 //--------------------------------------------------------------
|
rt300@0
|
343 double Lump::scanDisplacement(){
|
rt300@0
|
344 // returns the absolute distance from 'home'
|
rt300@0
|
345 return position.distanceTo(zeroRefPos);
|
rt300@0
|
346 }
|
rt300@0
|
347 //--------------------------------------------------------------
|
rt300@0
|
348 double Lump::scanLumpSpeed(){
|
rt300@0
|
349 // returns the absolute magnitude of the lumps velocity
|
rt300@0
|
350 return velocity.norm();
|
rt300@0
|
351 }
|
rt300@0
|
352 //--------------------------------------------------------------
|
rt300@0
|
353 double Lump::scanYPos(){
|
rt300@0
|
354 // returns the y displ
|
rt300@0
|
355 return position.y - zeroRefPos.y;
|
rt300@0
|
356 }
|
rt300@0
|
357 //--------------------------------------------------------------
|
rt300@0
|
358 double Lump::scanXPos(){
|
rt300@0
|
359 // returns the x displ
|
rt300@0
|
360 return position.x - zeroRefPos.x;
|
rt300@0
|
361 }
|
rt300@0
|
362 // -------------------
|
rt300@0
|
363 double Lump::scanRadialDisplacement(){
|
rt300@0
|
364 // returns the distance from circle zero line
|
rt300@0
|
365 // need to know where the centre point of the circle is and default radius
|
rt300@0
|
366
|
rt300@0
|
367 //return position.y - 0.5;
|
rt300@5
|
368 return radialDisplacement;
|
rt300@0
|
369
|
rt300@0
|
370 }
|
rt300@0
|
371 //--------------------------------------------------------------
|
rt300@0
|
372 void Lump::addToScanPath(){
|
rt300@0
|
373 isInScanPath = true;
|
rt300@0
|
374 setZeroRefPos();
|
rt300@0
|
375 }
|
rt300@0
|
376 //--------------------------------------------------------------
|
rt300@0
|
377 void Lump::removeFromScanPath(){
|
rt300@0
|
378 isInScanPath = false;
|
rt300@0
|
379
|
rt300@0
|
380 }
|
rt300@0
|
381 //--------------------------------------------------------------
|
rt300@0
|
382 void Lump::grab(int aGrabID){
|
rt300@0
|
383 // hover hilight doesn't work on touchscreens if(highlighted) grabbed = true;
|
rt300@0
|
384 grabbed = true;
|
rt300@0
|
385 grabID = aGrabID;
|
rt300@0
|
386 velocity.x = 0.0;
|
rt300@0
|
387 velocity.y = 0.0;
|
rt300@0
|
388 }
|
rt300@0
|
389 //--------------------------------------------------------------
|
rt300@0
|
390 void Lump::drag(double ax, double ay, int aGrabID){
|
rt300@0
|
391 if(aGrabID == grabID){
|
rt300@0
|
392 //cout << "dragging lump ID: " << grabID << endl;
|
rt300@0
|
393 position.x = ax;
|
rt300@0
|
394 position.y = ay;
|
rt300@0
|
395 velocity.x = previousPosition.x - position.x;
|
rt300@0
|
396 velocity.y = previousPosition.y - position.y;
|
rt300@0
|
397 previousPosition = position; // sets velocity too
|
rt300@0
|
398 }
|
rt300@0
|
399 }
|
rt300@0
|
400 //--------------------------------------------------------------
|
rt300@0
|
401 void Lump::unGrab(){
|
rt300@0
|
402 cout << "ungrabbed something\n";
|
rt300@0
|
403 grabbed = false;
|
rt300@0
|
404 grabID = -1;
|
rt300@0
|
405 velocity.x = 0.0;
|
rt300@0
|
406 velocity.y = 0.0;
|
rt300@0
|
407 }
|
rt300@0
|
408 //--------------------------------------------------------------
|
rt300@0
|
409 void Lump::unconstrain(){
|
rt300@0
|
410 constrained = false;
|
rt300@0
|
411 constrainMode = NOT_CONSTRAINED;
|
rt300@0
|
412 }
|
rt300@0
|
413
|
rt300@0
|
414
|
rt300@0
|
415 //--------------------------------------------------------------
|
rt300@0
|
416
|
rt300@0
|
417 bool Lump::isGrabbed(){
|
rt300@0
|
418 return grabbed;
|
rt300@0
|
419 }
|
rt300@0
|
420
|
rt300@0
|
421 //--------------------------------------------------------------
|
rt300@0
|
422
|
rt300@0
|
423 void Lump::highlight(){
|
rt300@0
|
424 highlighted = true;
|
rt300@0
|
425 }
|
rt300@0
|
426
|
rt300@0
|
427 //--------------------------------------------------------------
|
rt300@0
|
428
|
rt300@0
|
429 void Lump::unhighlight(){
|
rt300@0
|
430 highlighted = false;
|
rt300@0
|
431 }
|
rt300@0
|
432 //--------------------------------------------------------------
|