changeset 9:0e03760cf2d9

save preset stuff, not quite there
author Robert Tubb <rt300@eecs.qmul.ac.uk>
date Tue, 14 May 2013 18:05:08 +0100
parents 4ea605899aca
children df1d4beb6994
files globalForces.h globalForces.mm mesh.h mesh.mm scanpath.h scanpath.mm spring.h spring.mm testApp.h testApp.mm
diffstat 10 files changed, 580 insertions(+), 226 deletions(-) [+]
line wrap: on
line diff
--- a/globalForces.h	Tue May 14 10:34:32 2013 +0100
+++ b/globalForces.h	Tue May 14 18:05:08 2013 +0100
@@ -57,7 +57,8 @@
     void removeForceTouchPoint(int touchId);
     TwoVector getAllForceAt(double ax, double ay);
     
-    
+    Json::Value convertToJsonForSaving();
+    void setFromJson(Json::Value jgf);
 };
 
 
--- a/globalForces.mm	Tue May 14 10:34:32 2013 +0100
+++ b/globalForces.mm	Tue May 14 18:05:08 2013 +0100
@@ -119,4 +119,43 @@
     
     return force;
 }
-//-----------------------------------------------------------
\ No newline at end of file
+//-----------------------------------------------------------
+
+Json::Value GlobalForces::convertToJsonForSaving(){
+    
+    Json::Value jgf;
+    jgf["gravityOn"] = gravityOn;
+    jgf["forceTouchOn"] = forceTouchOn;
+    jgf["pressureOn"] = pressureOn;
+    jgf["pressureAmt"] = pressureAmt;
+    jgf["gravityAmt"] = gravityAmt;
+    jgf["touchStrength"] = touchStrength;
+    jgf["excitationStrength"] = excitationStrength;
+    jgf["homingAmt"] = homingAmt;
+    jgf["avFilterAmt"] = avFilterAmt;
+    jgf["exciteShapeX"] = exciteShapeX;
+    jgf["exciteShapeY"] = exciteShapeY;
+    jgf["speedLimit"] = speedLimit;
+    jgf["wallBounce"] = wallBounce;
+
+    return jgf;
+}
+//-----------------------------------------------------------
+
+void GlobalForces::setFromJson(Json::Value jgf){
+
+    gravityOn = jgf["gravityOn"].asBool();
+    forceTouchOn = jgf["forceTouchOn"].asBool();
+    pressureOn = jgf["pressureOn"].asBool();
+    pressureAmt = jgf["pressureAmt"].asDouble();
+    gravityAmt = jgf["gravityAmt"].asDouble();
+    touchStrength = jgf["touchStrength"].asDouble();
+    excitationStrength = jgf["excitationStrength"].asDouble();
+    homingAmt = jgf["homingAmt"].asDouble();
+    avFilterAmt = jgf["avFilterAmt"].asDouble();
+    exciteShapeX = jgf["exciteShapeX"].asInt();
+    exciteShapeY = jgf["exciteShapeY"].asInt();
+    speedLimit = jgf["speedLimit"].asDouble();
+    wallBounce = jgf["wallBounce"].asDouble();
+
+}
--- a/mesh.h	Tue May 14 10:34:32 2013 +0100
+++ b/mesh.h	Tue May 14 18:05:08 2013 +0100
@@ -44,11 +44,13 @@
 	enum constrainMode { CONSTRAIN_CORNERS, CONSTRAIN_EDGES,CONSTRAIN_EDGES_XY, CONSTRAIN_SINGLE_POINT, CONSTRAIN_SINGLE_POINT_X, CONSTRAIN_SINGLE_POINT_Y, CONSTRAIN_GRAB_REGION,CONSTRAIN_GRAB_REGION_X,CONSTRAIN_GRAB_REGION_Y, CONSTRAIN_ALL_X, CONSTRAIN_ALL_Y};
 	double GRAB_RANGE;
 	 
-	enum MeshType {SQUARE_CROSS_MESH, SPIDER_MESH, SPIDER_CROSS_MESH, DROPLET_MESH, LINE_MESH, TRIANGLE_MESH, GROUNDED_LINE_MESH, HOLED_SPIDER_MESH};
+	enum MeshType {SQUARE_MESH, SQUARE_CROSS_MESH, SPIDER_MESH, SPIDER_CROSS_MESH, DROPLET_MESH, LINE_MESH, TRIANGLE_MESH, GROUNDED_LINE_MESH, HOLED_SPIDER_MESH};
     MeshType meshType;
 
     // MEMBER FUNCTIONS
 	Mesh();
+    Mesh(Json::Value& savedMesh); // contructor using saved mesh
+    
 	virtual ~Mesh();
 
     void draw();
@@ -119,7 +121,7 @@
     
 // save stuff
     Json::Value convertToJsonForSaving();
-    
+    Json::Value saveConnectionsAsJson();
 protected:
 
     int prevLump;
@@ -130,7 +132,13 @@
 	virtual void setLumpPositions();
 	virtual void makeConnections();
 	virtual void makeDefaultScanPath();
-
+    
+    // alternatively get from saved:
+    
+	void setLumpPositionsFromJson(Json::Value lumpPositions);
+	void makeConnectionsFromJson(Json::Value connections);
+	void makeScanPathFromJson(Json::Value scanPathElements);
+    void constrainFromJson(Json::Value constrainedLumps);
     // UTILS    
     TwoVector calculateCentre();
 	void connect(int springnum,int lumpnum);
@@ -177,20 +185,30 @@
 	void makeDefaultScanPath(); // same
 };
 //---------------------------------------------------------
-// square grid with all diagonals connected
-class SquareCrossMesh : public Mesh{
+// square grid 
+class SquareMesh : public Mesh{
 public:
 	// square specific
 	int height;
 	int width;
-	
-	SquareCrossMesh(int height, int width);	
+	SquareMesh();
+	SquareMesh(int height, int width);
+    ~SquareMesh();
+	void constrain(double x, double y, constrainMode aMode);
+    void makeComponents(int adimension1, int adimension2);
+    void setLumpPositions();
+    void makeConnections();
+    void makeDefaultScanPath();
+};
+//---------------------------------------------------------
+// square grid with all diagonals connected i.e. we override makeConnections
+class SquareCrossMesh : public SquareMesh{
+public:
+    SquareCrossMesh(){};
+	SquareCrossMesh(int height, int width);
     ~SquareCrossMesh();
-	void constrain(double x, double y, constrainMode aMode);
-	 void makeComponents(int adimension1, int adimension2);
-	 void setLumpPositions();
 	 void makeConnections();
-	 void makeDefaultScanPath();
+
 };
 //---------------------------------------------------------
 // simple 1d line
--- a/mesh.mm	Tue May 14 10:34:32 2013 +0100
+++ b/mesh.mm	Tue May 14 18:05:08 2013 +0100
@@ -46,34 +46,137 @@
 
 
 }
+
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+Mesh::Mesh(Json::Value& jmesh){
+    //Mesh(); // sensible?
+    
+    cout << jmesh;
+    
+    meshType = (MeshType)jmesh.get("meshType",0).asInt();
+    dim1 = jmesh.get("dim1",0).asInt();
+    dim2 = jmesh.get("dim1",0).asInt();
+    
+    // need to know how many springs and lumps
+    numLumps = jmesh.get("numLumps",0).asInt();
+    numSprings = jmesh.get("numSprings",0).asInt();
+    
+    // make them
+    makeComponents(numLumps, numSprings);
+    setLumpPositionsFromJson(jmesh["lumpPositions"]);
+    makeConnectionsFromJson(jmesh["connections"]);
+    makeScanPathFromJson(jmesh["scanPath"]);
+    constrainFromJson(jmesh["constrainedLumps"]);
+
+    // now set saved properties 
+    setSpringConstant(jmesh["springConstant"].asDouble());
+    setMass(jmesh["mass"].asDouble());
+    setFriction(jmesh["friction" ].asDouble());
+    // rest length?
+    zeroRestLength();
+}
+
+//--------------------------------------------------------------
+void Mesh::setLumpPositionsFromJson(Json::Value lumpPositions){
+    int N = lumpPositions.size();
+    
+    for(int i=0;i<N;i++){
+        lumps[i].position.x = lumpPositions[i]["x"].asFloat();
+        lumps[i].position.y = lumpPositions[i]["y"].asFloat();
+        
+	}
+}
+//--------------------------------------------------------------
+void Mesh::makeConnectionsFromJson(Json::Value connections){
+    
+    // format: pairs of lump indexes, and a connecting spring
+    for (int i=0;i<connections.size();i++){
+        connect(i, connections[i]["startLump"].asInt(),connections[i]["endLump"].asInt()); // will the springs be in the right order? they need to be!
+        
+    }
+}
+
+//--------------------------------------------------------------
+void Mesh::makeScanPathFromJson(Json::Value jscanPath){
+    
+    for(int i=0;i<jscanPath.size();i++){
+        scanPath.addElement(&lumps[jscanPath[i]["lumpNo"].asInt()], &springs[jscanPath[i]["springNo"].asInt()]);
+    }
+}
+//--------------------------------------------------------------
+void Mesh::constrainFromJson(Json::Value constrainedLumps){
+
+    for(int i=0;i<constrainedLumps.size();i++){
+
+        lumps[constrainedLumps[i].asInt()].constrain(); // TODO ignores XY thing
+
+	}
+}
+
+//--------------------------------------------------------------
+Json::Value Mesh::convertToJsonForSaving(){
+    
+    // needs to be good to put back into
+    /*
+     void setLumpPositionsFromJson(Json::Value lumpPositions);
+     void makeConnectionsFromJson(Json::Value connections);
+     void makeScanPathFromJson(Json::Value scanPathElements);
+     void constrainFromJson(Json::Value constrainedLumps);
+    */
+    
+    Json::Value jmesh;
+    
+    jmesh["meshType"] = meshType;
+    jmesh["dim1"] = dim1; // these don't exist...
+    jmesh["dim2"] = dim2;
+    // need to know how many springs and lumps
+    jmesh["numLumps"] = numLumps;
+    jmesh["numSprings"] = numSprings;
+    jmesh["springConstant"] = k;
+    jmesh["mass"] = m;
+    jmesh["friction" ] = f;
+    for(int i=0;i<lumps.size();i++){
+        jmesh["lumpPositions"][i]["x"] = lumps[i].position.x;
+        jmesh["lumpPositions"][i]["y"] = lumps[i].position.y;
+
+	}
+
+    jmesh["connections"] = saveConnectionsAsJson();
+    jmesh["scanPath"] = scanPath.convertToJsonForSaving();
+
+    // save all indexes of constrained lumps
+    int j = 0;
+    for(int i=0;i<lumps.size();i++){
+		if(lumps[i].constrained){
+            
+            jmesh["constrainedLumps"][j] = i;
+            j++;
+        }
+	}
+  
+    
+    return jmesh;
+    
+}
+//--------------------------------------------------------------
+Json::Value Mesh::saveConnectionsAsJson(){
+    Json::Value connections;
+    // loop all springs
+    
+    for(int i = 0; i<springs.size(); i++){
+        connections[i]["startLump"]= springs[i].getStartLumpIndex();
+        connections[i]["endLump"]= springs[i].getEndLumpIndex();
+    }
+    return connections;
+    
+    
+}
+//--------------------------------------------------------------
+//--------------------------------------------------------------
 ///////////
 // interface (called from testApp)
 ///////////
-
-//--------------------------------------------------------------
-Json::Value Mesh::convertToJsonForSaving(){
-    Json::Value jmesh;
-    
-    jmesh["meshType"] = meshType;
-    jmesh["dim1"] = dim1;
-    jmesh["dim1"] = dim2;
-    int j = 0;
-    
-    for(int i=0;i<lumps.size();i++){
-		if(lumps[i].constrained){
-            j++;
-            jmesh["constrainedLumps"][j] = i;
-        }
-	}
-    
-    // get list of indexes for lumps and springs in scanpath
-    // iterate over scanpath elements
-
-    return jmesh;
-    
-}
-
-//--------------------------------------------------------------
 void Mesh::update(){
 	// update all the springs and masses sequentially
     // INTERP HACK - this bit of code is to debug pops and clicks
@@ -361,7 +464,7 @@
         k = m * 0.9;
     }
     cout << "k/m = " << k/m << endl;
-    for(int i = 0; i < numSprings; i++){
+    for(int i = 0; i < springs.size(); i++){
         springs[i].setSpringConstant(k); // inverse mass is c^2
     }      
 }
@@ -454,6 +557,7 @@
     
 	// find closest
     int nearest = getNearestLump(ax,ay);
+    if(nearest = -1) return; // there are no lumps!
     diff.setCoord(lumps[nearest].position.x - ax, lumps[nearest].position.y - ay);
     //cout << "diff " << diff.x << "," << diff.y << endl;
     if (diff.norm() < GRAB_RANGE){
@@ -735,7 +839,7 @@
 // VIRTUAL
 //--------------------------------------------------------------
 void Mesh::makeDefaultScanPath(){
-	// make componets creates the correct number of lumps and springs according to dimensions and mesh type
+	// make 
 	cout << "!!!!Mesh base class makeDefaultScanPath\n";
 }
 
@@ -752,22 +856,47 @@
 	cout << "!!!!Mesh base class make connections\n";
 }
 //--------------------------------------------------------------
-void Mesh::makeComponents(int aDimension1, int aDimension2){
+void Mesh::makeComponents(int numLumps, int numSprings){
+    // does not need to know what shape we're in to set up the right number of lumps and springs
 	cout << "!!!!Mesh base class makeComponents\n";
+    
+    //lumps = new Lump[numLumps];
+    lumps = vector<Lump>(numLumps);
+	cout << "made " << numLumps << " lumps\n";
+	
+    // one by one
+    springs = vector<Spring>(numSprings);
+    
+	cout << "made " << numSprings << " springs\n";
+    
+    // tell them what index they are (for connections)
+    for(int i = 0; i<lumps.size(); i++){
+        lumps[i].myIndexInMesh = i;
+    }
+    for(int i = 0; i<springs.size(); i++){
+        springs[i].myIndexInMesh = i;
+    }
+    
+    
 }
 //--------------------------------------------------------------
 void Mesh::constrain(double ax, double ay, constrainMode aMode){
 	cout << "!!!!Mesh base class constrain\n";
 }
 //--------------------------------------------------------------
-
-
 /****************************************/
-//		SquareCrossMesh					*/
+//		SquareMesh					*/
 /****************************************/
 //--------------------------------------------------------------
-SquareCrossMesh::SquareCrossMesh(int height, int width): Mesh() {
-	meshType = SQUARE_CROSS_MESH;
+SquareMesh::SquareMesh(): Mesh() {
+    // the default is called from derived classes
+    radial = false;
+	cout << "default constructor SQUARE mesh\n";
+}
+//---------------------------------------------------------------
+SquareMesh::SquareMesh(int height, int width): Mesh() {
+    // this one called when no derived class
+	meshType = SQUARE_MESH;
 	makeComponents(height, width);
 	
 	setLumpPositions();
@@ -784,34 +913,29 @@
 	
 	cout << "constructing SQUARE mesh\n";
 }
-SquareCrossMesh::~SquareCrossMesh(){
+SquareMesh::~SquareMesh(){
 	
-	cout << "destructing SQUARECROSS mesh\n";
+	cout << "destructing SQUARE mesh\n";
 }
 
 //--------------------------------------------------------------
 // make componets for square
-void SquareCrossMesh::makeComponents(int aheight, int awidth){
+void SquareMesh::makeComponents(int aheight, int awidth){
     
-
+    
 	height = aheight;
 	width = awidth;
 	numLumps = height * width;
-                // horz             // vert             // criss cross
+    // horz             // vert             // criss cross
 	numSprings = (width-1)*height + (height-1)*width + 2*(height-1)*(width-1);
 	
-	//lumps = new Lump[numLumps];
-    lumps = vector<Lump>(numLumps);
-	cout << "made " << numLumps << " lumps\n";
-	
-    // one by one
-    springs = vector<Spring>(numSprings);
+    Mesh::makeComponents(numLumps, numSprings); // kinda wierd but works.
     
-	cout << "made " << numSprings << " springs\n";
 }
 
 //--------------------------------------------------------------
-void SquareCrossMesh::setLumpPositions(){
+void SquareMesh::setLumpPositions(){
+    // numbering works line by line like text, analogue tv's etc
 	double vspacing = 1.0/(height-1);
 	double hspacing = 1.0/(width-1);
 	int i =0;
@@ -826,8 +950,213 @@
 			i++;
 		}
 	}
+    
+}
+//--------------------------------------------------------------
+void SquareMesh::makeConnections(){
+	
+	// could be cleverer in terms of numbering?
+	int lumpnum = 0;
+	int springnum = 0;
+	// attach horizontal
+	for ( int i=0;i<height;i++){
+		for(int j=0;j<width-1;j++){
+			connect(springnum,lumpnum);
+			lumpnum++;
+            if(springnum >= numSprings){
+                cout << " makeConnections index error!\n";
+            }
+            if(lumpnum >= lumps.size()){
+                cout << " makeConnections index error!\n";
+            }
+			connect(springnum,lumpnum);
+			springnum++;
+			
+		}
+		lumpnum++;
+	}
+    cout << "lumps attach horz: " << lumpnum-1 << ", spring " << springnum-1 << "\n";
+	// attach vertical
+	lumpnum = 0;
+	for ( int i=0;i<width;i++){
+		for(int j=0;j<height-1;j++){
+			connect(springnum,lumpnum);
+			lumpnum+=width;
+            if(springnum >= numSprings){
+                cout << " makeConnections index error!\n";
+            }
+            if(lumpnum >= lumps.size()){
+                cout << " makeConnections index error!\n";
+            }
+			connect(springnum,lumpnum);
+			springnum++;
+			
+		}
+		lumpnum -= (width*(height-1)) - 1;
+	}
 
 }
+
+//--------------------------------------------------------------
+void SquareMesh::constrain(double ax, double ay, constrainMode aMode){
+	
+	TwoVector diff;
+	int i = 0;
+	
+	// check if lump is within grab range
+	switch (aMode) {
+		case CONSTRAIN_GRAB_REGION:
+			for(i = 0; i<lumps.size(); i++){
+				
+				diff.setCoord(lumps[i].position.x - ax, lumps[i].position.y - ay);
+				
+				if (diff.norm() < GRAB_RANGE){
+                    if(i >= lumps.size()){
+                        cout << "constrain index error\n";
+                    }
+					lumps[i].constrain();
+				}
+			}
+			break;
+		case CONSTRAIN_EDGES:
+			i = 0;
+			for(int row = 0; row < height; row++){ // go down column
+				for(int col = 0;col < width; col++){ // go along row
+					if(row == 0 || row == height-1 || col == 0 || col == width-1){
+                        if(i >= lumps.size()){
+                            cout << "constrain index error\n";
+                        }
+						lumps[i].constrain();
+					}
+					i++;
+				}
+			}
+			break;
+		case CONSTRAIN_EDGES_XY:
+			i = 0;
+			for(int row = 0; row < height; row++){ // go down column
+				for(int col = 0;col < width; col++){ // go along row
+					if(row == 0 || row == height-1){
+                        if(i >= lumps.size()){
+                            cout << "constrain index error\n";
+                        }
+						lumps[i].constrain(Lump::CONSTRAIN_Y);
+					}else if( col == 0 || col == width-1){
+                        if(i >= lumps.size()){
+                            cout << "constrain index error\n";
+                        }
+                        lumps[i].constrain(Lump::CONSTRAIN_X);
+                    }
+					i++;
+				}
+			}
+			break;
+		case CONSTRAIN_CORNERS:
+			i = 0;
+			for(int row = 0; row < height; row++){ // go down column
+				for(int col = 0;col < width; col++){ // go along row
+					if(   (row == 0 && col == 0)
+					   || (row == height-1 && col == 0)
+					   || (row == 0 && col == width-1)
+					   || (row == height-1 && col == width-1)){
+                        if(i >= lumps.size()){
+                            cout << "constrain index error\n";
+                        }
+						lumps[i].constrain();
+					}
+					i++;
+				}
+			}
+			break;
+			
+		default:
+			break;
+	}
+	
+}
+
+//--------------------------------------------------------------
+void SquareMesh::makeDefaultScanPath(){
+    if (height < 10 || width < 10) return; // not much point
+    
+    int vmarg = 5;
+    int hmarg = 5;
+    
+    int lumpno = vmarg * width + hmarg; // top left corner
+    int springno = vmarg * (width - 1) + hmarg;
+    // do top horz
+    for(int i = 0; i < width - 2*hmarg; i++){
+        if(lumpno >= lumps.size()) cout << "makeDefaultScanPath index error\n";
+        if(springno >= numSprings) cout << "makeDefaultScanPath index error\n";
+        scanPath.addElement(&lumps[lumpno], &springs[springno]);
+        lumpno++;
+        springno++;
+    }
+    
+    // do right vert, lumpno starts the same
+    // all horz spr    // left marg rows      // top margin
+    springno  = height*(width-1) + ((height-1) * (width - hmarg)) + vmarg;
+    
+    for(int i = 0; i < height - (2 * vmarg); i++){
+        if(lumpno >= lumps.size()) cout << "makeDefaultScanPath index error\n";
+        if(springno >= numSprings) cout << "makeDefaultScanPath index error\n";
+        scanPath.addElement(&lumps[lumpno], &springs[springno]);
+        springno++; // jump to next row
+        lumpno += width;   // ditto
+    }
+    
+    
+    // do bottom horz right to left
+    springno = (height - vmarg) * (width - 1) + (width - hmarg - 1);
+    for(int i = 0; i < width - 2*hmarg; i++){
+        if(lumpno >= lumps.size()) cout << "makeDefaultScanPath index error\n";
+        if(springno >= numSprings) cout << "makeDefaultScanPath index error\n";
+        scanPath.addElement(&lumps[lumpno], &springs[springno]);
+        springno--; // jump to next row
+        lumpno--;   // ditto
+    }
+    
+    // all horz spr    // left marg rows    // top margin
+    springno  = height*(width-1) + ((height-1) * hmarg) +  height - vmarg - 1;
+    for(int i = 0; i < height - 2 * vmarg; i++){
+        if(lumpno >= lumps.size()) cout << "makeDefaultScanPath index error\n";
+        if(springno >= numSprings) cout << "makeDefaultScanPath index error\n";
+        scanPath.addElement(&lumps[lumpno], &springs[springno]);
+        springno--; // jump to next row
+        lumpno -= width;   // ditto
+    }
+    
+}
+//--------------------------------------------------------------
+
+/****************************************/
+//		SquareCrossMesh					*/
+/****************************************/
+//--------------------------------------------------------------
+SquareCrossMesh::SquareCrossMesh(int height, int width){
+    
+	meshType = SQUARE_CROSS_MESH;
+	makeComponents(height, width);
+	
+	setLumpPositions();
+	
+	makeConnections();
+	
+	makeDefaultScanPath();
+    
+    constrain(0,0,CONSTRAIN_EDGES);
+    
+    zeroRestLength();
+    
+    radial = false;
+	
+	cout << "constructing SQUARECROSS mesh\n";
+}
+SquareCrossMesh::~SquareCrossMesh(){
+	
+	cout << "destructing SQUARECROSS mesh\n";
+}
+
 //--------------------------------------------------------------
 void SquareCrossMesh::makeConnections(){
 	
@@ -909,135 +1238,7 @@
 }
 
 //--------------------------------------------------------------
-void SquareCrossMesh::constrain(double ax, double ay, constrainMode aMode){
-	
-	TwoVector diff;
-	int i = 0;
-	
-	// check if lump is within grab range
-	switch (aMode) {
-		case CONSTRAIN_GRAB_REGION:
-			for(i = 0; i<lumps.size(); i++){
-				
-				diff.setCoord(lumps[i].position.x - ax, lumps[i].position.y - ay);
-				
-				if (diff.norm() < GRAB_RANGE){
-                    if(i >= lumps.size()){
-                        cout << "constrain index error\n";
-                    }
-					lumps[i].constrain();
-				}
-			}
-			break;
-		case CONSTRAIN_EDGES:
-			i = 0;
-			for(int row = 0; row < height; row++){ // go down column
-				for(int col = 0;col < width; col++){ // go along row
-					if(row == 0 || row == height-1 || col == 0 || col == width-1){
-                        if(i >= lumps.size()){
-                            cout << "constrain index error\n";
-                        }
-						lumps[i].constrain();
-					}
-					i++;
-				}
-			}	
-			break;
-		case CONSTRAIN_EDGES_XY:
-			i = 0;
-			for(int row = 0; row < height; row++){ // go down column
-				for(int col = 0;col < width; col++){ // go along row
-					if(row == 0 || row == height-1){
-                        if(i >= lumps.size()){
-                            cout << "constrain index error\n";
-                        }
-						lumps[i].constrain(Lump::CONSTRAIN_Y);
-					}else if( col == 0 || col == width-1){
-                        if(i >= lumps.size()){
-                            cout << "constrain index error\n";
-                        }
-                        lumps[i].constrain(Lump::CONSTRAIN_X);
-                    }
-					i++;
-				}
-			}	
-			break;
-		case CONSTRAIN_CORNERS:
-			i = 0;
-			for(int row = 0; row < height; row++){ // go down column
-				for(int col = 0;col < width; col++){ // go along row
-					if(   (row == 0 && col == 0)
-					   || (row == height-1 && col == 0) 
-					   || (row == 0 && col == width-1) 
-					   || (row == height-1 && col == width-1)){
-                        if(i >= lumps.size()){
-                            cout << "constrain index error\n";
-                        }
-						lumps[i].constrain();
-					}
-					i++;
-				}
-			}
-			break;
-			
-		default:
-			break;
-	}
-	
-}
-//--------------------------------------------------------------
-//--------------------------------------------------------------
-void SquareCrossMesh::makeDefaultScanPath(){
-    if (height < 10 || width < 10) return; // not much point
-    
-    int vmarg = 5;
-    int hmarg = 5;
-    
-    int lumpno = vmarg * width + hmarg; // top left corner
-    int springno = vmarg * (width - 1) + hmarg;
-    // do top horz
-    for(int i = 0; i < width - 2*hmarg; i++){
-        if(lumpno >= lumps.size()) cout << "makeDefaultScanPath index error\n";
-          if(springno >= numSprings) cout << "makeDefaultScanPath index error\n";
-        scanPath.addElement(&lumps[lumpno], &springs[springno]);
-        lumpno++;
-        springno++;
-    }
-    
-    // do right vert, lumpno starts the same
-                // all horz spr    // left marg rows      // top margin
-    springno  = height*(width-1) + ((height-1) * (width - hmarg)) + vmarg;
-    
-    for(int i = 0; i < height - (2 * vmarg); i++){
-        if(lumpno >= lumps.size()) cout << "makeDefaultScanPath index error\n";
-        if(springno >= numSprings) cout << "makeDefaultScanPath index error\n";
-        scanPath.addElement(&lumps[lumpno], &springs[springno]);
-        springno++; // jump to next row
-        lumpno += width;   // ditto
-    }
-    
-    
-    // do bottom horz right to left
-    springno = (height - vmarg) * (width - 1) + (width - hmarg - 1);
-    for(int i = 0; i < width - 2*hmarg; i++){
-        if(lumpno >= lumps.size()) cout << "makeDefaultScanPath index error\n";
-        if(springno >= numSprings) cout << "makeDefaultScanPath index error\n";
-        scanPath.addElement(&lumps[lumpno], &springs[springno]);
-        springno--; // jump to next row
-        lumpno--;   // ditto
-    } 
-    
-                 // all horz spr    // left marg rows    // top margin   
-    springno  = height*(width-1) + ((height-1) * hmarg) +  height - vmarg - 1;
-    for(int i = 0; i < height - 2 * vmarg; i++){
-        if(lumpno >= lumps.size()) cout << "makeDefaultScanPath index error\n";
-        if(springno >= numSprings) cout << "makeDefaultScanPath index error\n";
-        scanPath.addElement(&lumps[lumpno], &springs[springno]);
-        springno--; // jump to next row
-        lumpno -= width;   // ditto
-    }
-    
-}
+
 //--------------------------------------------------------------
 
 
@@ -1278,7 +1479,6 @@
 	numLumps = numSpokes * numRings; 
 	numSprings = numSpokes * numRings + numSpokes * (numRings - 1);
 	
-	//lumps = new Lump[numLumps];
 	lumps = vector<Lump>(numLumps);
     cout << "made " << numLumps << " lumps\n";
 	springs = vector<Spring>(numSprings);
@@ -1457,10 +1657,7 @@
                 // rings                // spokes  & diags
 	numSprings = numSpokes * numRings + 3 * numSpokes * (numRings - 1);
 	
-	lumps = vector<Lump>(numLumps);
-	cout << "made " << numLumps << " lumps\n";
-	springs = vector<Spring>(numSprings);
-	cout << "made " << numSprings << " springs\n";	
+	Mesh::makeComponents(numLumps, numSprings);
 	
     
 }
@@ -1662,8 +1859,7 @@
     // 
     numLumps = numSegments+1;
     numSprings = numSegments;
-    lumps = vector<Lump>(numLumps);
-	springs = vector<Spring>(numSprings);
+    Mesh::makeComponents(numLumps, numSprings);
     
 }
 //--------------------------------------------------------------
@@ -1748,8 +1944,7 @@
     // 
     numLumps = (numSegments+1)*2;
     numSprings = numSegments*2;
-    lumps = vector<Lump>(numLumps);
-	springs = vector<Spring>(numSprings);
+    Mesh::makeComponents(numLumps, numSprings);
     
 }
 //--------------------------------------------------------------
@@ -1867,11 +2062,7 @@
     // 
     numLumps = numSegments;
     numSprings = numSegments;
-    lumps = vector<Lump>(numLumps);
-	//springs = new PressureSpring[numSprings];
-    
-    //TODO PressureSpring  shoudl BE a spring ?
-    springs = vector<Spring>(numSprings);
+    Mesh::makeComponents(numLumps, numSprings);
 }
 //--------------------------------------------------------------
 void DropletMesh::setLumpPositions(){
@@ -2025,10 +2216,7 @@
                 /* horz   ---            \ diag                  / diag              */
 	numSprings = (width-1) * (height-1) +  width * (height - 1) + (width-1) * (height - 1);
 	
-	lumps = vector<Lump>(numLumps);
-	cout << "made " << numLumps << " lumps\n";
-	springs = vector<Spring>(numSprings);
-	cout << "made " << numSprings << " springs\n";
+	Mesh::makeComponents(numLumps, numSprings);
 }
 
 //--------------------------------------------------------------
--- a/scanpath.h	Tue May 14 10:34:32 2013 +0100
+++ b/scanpath.h	Tue May 14 18:05:08 2013 +0100
@@ -33,9 +33,7 @@
     bool updateAccessing;
 
     bool bidirectional;
-	//Spring ** springPath;
-	// springpath - an array of pointers to the springs in the path
-	// lump path - ditto should be same number
+
     vector<Element> pathElements;
 
     double * wavetableNew;
--- a/scanpath.mm	Tue May 14 10:34:32 2013 +0100
+++ b/scanpath.mm	Tue May 14 18:05:08 2013 +0100
@@ -410,8 +410,13 @@
 
 Json::Value ScanPath::convertToJsonForSaving(){
     Json::Value jscanpath;
-    jscanpath["numElements"] = numElements;
-    // shiit. pointers mean nothing. the lups won't know which index they are.
+
+    for(int i=0;i<pathElements.size();i++){
+        //scanPath.addElement(&lumps[scanPathElements[i]["lumpNo"].asInt()], &springs[scanPathElements[i]["springNo"].asInt()]);
+        jscanpath[i]["lumpNo"] = pathElements[i].eLump->myIndexInMesh;
+        jscanpath[i]["springNo"] = pathElements[i].eSpring->myIndexInMesh;
+    }
+    
     return jscanpath;
 }
 
--- a/spring.h	Tue May 14 10:34:32 2013 +0100
+++ b/spring.h	Tue May 14 18:05:08 2013 +0100
@@ -43,7 +43,7 @@
 public:
     bool isInScanPath;
 	static bool forcesOn;
-	
+	int myIndexInMesh;
 	Spring();
 	Spring(double aStartx, double aStarty, double aEndx, double aEndy, double aK);
 	void updateEndPoints();
@@ -61,6 +61,10 @@
 	void addToScanPath();
     void removeFromScanPath();
     Lump * getLumpOnOtherEnd(Lump * alump);
+    Lump * getStartLump();
+    Lump * getEndLump();
+    int getStartLumpIndex();
+    int getEndLumpIndex();
 	//void checkStuff();
     
     // interface for scanner
--- a/spring.mm	Tue May 14 10:34:32 2013 +0100
+++ b/spring.mm	Tue May 14 18:05:08 2013 +0100
@@ -76,6 +76,19 @@
 
     return NULL;
 }
+
+Lump * Spring::getStartLump(){
+    return startLumpPtr;
+}
+Lump * Spring::getEndLump(){
+    return endLumpPtr;
+}
+int Spring::getStartLumpIndex(){
+    return startLumpPtr->myIndexInMesh;
+}
+int Spring::getEndLumpIndex(){
+    return endLumpPtr->myIndexInMesh;
+}
 //---------------------------------------------------------------
 void Spring::setRestLength(){
 
--- a/testApp.h	Tue May 14 10:34:32 2013 +0100
+++ b/testApp.h	Tue May 14 18:05:08 2013 +0100
@@ -101,7 +101,9 @@
 
     Json::Value convertToJsonForSaving();
     void savePreset();
-    void constructPresetFromJson(Json::Value presetJson);
+    void constructPresetFromJson(Json::Value& presetJson);
+    void  loadPreset();
+    Json::Value loadPresetFile();
     
     ofxOscReceiver	receiver;
     ofxOscSender sender;
--- a/testApp.mm	Tue May 14 10:34:32 2013 +0100
+++ b/testApp.mm	Tue May 14 18:05:08 2013 +0100
@@ -109,32 +109,104 @@
     
     
 }
+//--------------------------------------------------------------
 Json::Value testApp::convertToJsonForSaving(){
     Json::Value root;
     
     root["pitch"] = pitch; //
+
     
+    root["globalForces"] = globalForces.convertToJsonForSaving();
     
-    // pitch;
-    
-    // globalForces.convertToJsonForSaving();
-    // root["mesh"] = mesh.convertToJsonForSaving();
     root["mesh"] = theMesh->convertToJsonForSaving();
     
     return root;
 }
+//--------------------------------------------------------------
 void testApp::savePreset(){
-    convertToJsonForSaving();
+    Json::Value jpreset = convertToJsonForSaving();
     //save json to file
+    string fname = ofxiPhoneGetDocumentsDirectory() + "presetFile";
     
+    // write to file
+
+    ofFile logFile(fname,ofFile::WriteOnly);
+    logFile << jpreset;
+    logFile.close();
 }
-void testApp::constructPresetFromJson(Json::Value presetJson){
+//--------------------------------------------------------------
+Json::Value testApp::loadPresetFile(){
+    Json::Value jpreset;
+    //save json to file
+    string fname = ofxiPhoneGetDocumentsDirectory() + "presetFile";
+    
+    Json::Value root;
+    Json::Reader reader;
+    
+    /////////////
+    // read file
+    
+    ifstream theFile(fname.c_str());
+    stringstream fileText;
+    string line;
+    if(!theFile){
+        cout<<"No preset file found\n";
+        return root;
+    }else{
+        while(theFile){
+            theFile >> line;
+            // cout << line;  // lots!!!!
+            fileText << line;
+        }
+        theFile.close();
+    }
+    
+    cout << "size of preset JSON string:" << fileText.str().length() << "BYTES \n";
+    
+    bool parsingSuccessful = reader.parse( fileText.str(), root );
+    
+    if ( !parsingSuccessful )
+    {
+        // report to the user the failure and their locations in the document.
+        std::cout  << "Failed to parse preset JSON: \n" << reader.getFormattedErrorMessages();
+        return root; // will be null
+    }
+    
+    return root;
+}
+//--------------------------------------------------------------
+void testApp::constructPresetFromJson(Json::Value& presetJson){
     
     // construct mesh with right type and size
     // impose saved constraints
     // make saved scanpath
     // recall global settings
     pitch = presetJson["pitch"].asDouble();
+
+    globalForces.setFromJson(presetJson["globalForces"]);
+    
+    theMesh = new Mesh(presetJson["mesh"]);
+}
+void testApp::loadPreset(){
+    if(audioAccessFlag) return; // or rather wait !
+    meshConstructionFlag = TRUE;
+    
+    deleteMesh();
+    
+    Json::Value jp = loadPresetFile();
+    
+    constructPresetFromJson(jp);
+    
+    // check these stupid tyhings
+    numTouches = 0;
+    meshConstructionFlag = FALSE;
+    paused = false;
+    audioOn = true;
+    drawingOn = true;
+    ofSoundStreamStart();
+    
+    cout << "PRESET WAS LOADED\n";
+    
 }
 //--------------------------------------------------------------
 //--------------------------------------------------------------
@@ -217,11 +289,14 @@
     static int type = 0;
     int numTypes = 7;
     
-    // TODO: Just empty vectors
+
+
     
     if(type % numTypes == 0){
-        theMesh = new LineMesh(60);
+        theMesh = new SquareCrossMesh(6,6);
+        
     }else if (type % numTypes == 1){
+        
         // different for iphone
         if(ofGetWidth() == 480){ //PHONE
             theMesh = new SpiderCrossMesh(60,5);
@@ -231,7 +306,8 @@
             theMesh = new SpiderCrossMesh(100,9);
         }
     }else if(type % numTypes ==2){
-        theMesh = new LineMesh(2520);
+        
+        theMesh = new SquareCrossMesh(16,16);
         
     }else if(type % numTypes ==3){
         theMesh = new SquareCrossMesh(28,28);
@@ -1280,7 +1356,8 @@
     guiR->addToggle("PAUSE", false, dim, dim);
     guiR->addButton("RESET", false, dim, dim);
     guiR->addButton("NEW", false, dim, dim);
-    
+    guiR->addButton("SAVE", false, dim, dim);
+    guiR->addButton("LOAD", false, dim, dim);
     
     ofAddListener(guiR->newGUIEvent, this, &testApp::guiREvent);
     //guiR->loadSettings(ofxiPhoneGetDocumentsDirectory() + "guiSettings.xml");
@@ -1362,13 +1439,22 @@
         cout << ((ofxUIButton *)e.widget)->getValue();
         
         if( ((ofxUIButton *)e.widget)->getValue() == 0) {
-            cout << "new BUP";
+            
             deleteMesh();
             setupMesh();
         }else{
-            cout << "new BDOWN";
+            
         }
-        
+    }else if(e.widget->getName() == "SAVE"){
+        // save the preset somehow
+        if( ((ofxUIButton *)e.widget)->getValue() == 0) {
+            savePreset();
+        }
+    }else if(e.widget->getName() == "LOAD"){
+        // save the preset somehow
+        if( ((ofxUIButton *)e.widget)->getValue() == 0) {
+            loadPreset();
+        }
     }else if(e.widget->getName() == "PAUSE"){
         paused = !paused;
     }else if(e.widget->getName() == "TOUCH AMT"){