PageRenderTime 42ms CodeModel.GetById 19ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 0ms

/examples/advanced/touchTail/TailGesture.java

http://mt4j.googlecode.com/
Java | 292 lines | 221 code | 45 blank | 26 comment | 18 complexity | 3a542657b800af9e9d9db3992bc41c89 MD5 | raw file
  1package advanced.touchTail;
  2
  3import java.awt.Polygon;
  4
  5import org.mt4j.util.MTColor;
  6import org.mt4j.util.math.ToolsMath;
  7import org.mt4j.util.math.Vector3D;
  8
  9import processing.core.PApplet;
 10
 11/**
 12 * The Class TailGesture.
 13 * 
 14 * Yellowtail by Golan Levin (www.flong.com)
 15 * Yellowtail (1998-2000) is an interactive software system for the gestural creation 
 16 * and performance of real-time abstract animation. Yellowtail repeats a user's strokes end-over-end, 
 17 * enabling simultaneous specification of a line's shape and quality of movement. 
 18 * Each line repeats according to its own period, 
 19 * producing an ever-changing and responsive display of lively, worm-like textures.
 20 */
 21public class TailGesture {
 22
 23//	private float  damp = 5.0f; //ORIGINAL
 24	private float  damp = 5.0f;
 25	private float  dampInv = 1.0f / damp;
 26	private float  damp1 = damp - 1;
 27
 28	private int w;
 29	private int h;
 30	private int capacity;
 31
 32	private float INIT_TH = 14; //ORIGINAL
 33//	private float INIT_TH = 24; 
 34	private float   thickness = INIT_TH;
 35
 36	Vector3D path[];
 37	int crosses[];
 38	Polygon polygons[];
 39	int nPoints;
 40	int nPolys;
 41
 42	float jumpDx;
 43	float jumpDy;
 44	boolean exists;
 45	private MTColor color;
 46
 47	public TailGesture(int mw, int mh) {
 48		w = mw;
 49		h = mh;
 50		capacity = 600;
 51		path = new Vector3D[capacity];
 52		polygons = new Polygon[capacity];
 53		crosses  = new int[capacity];
 54		for (int i=0;i<capacity;i++) {
 55			polygons[i] = new Polygon();
 56			polygons[i].npoints = 4;
 57			path[i] = new Vector3D();
 58			crosses[i] = 0;
 59		}
 60		nPoints = 0;
 61		nPolys = 0;
 62
 63		exists = false;
 64		jumpDx = 0;
 65		jumpDy = 0;
 66		
 67//		this.color = new MTColor(Tools3D.getRandom(50, 255), Tools3D.getRandom(50, 255), Tools3D.getRandom(50, 255), 255);
 68		this.color = new MTColor(ToolsMath.getRandom(0, 255), ToolsMath.getRandom(0, 255), ToolsMath.getRandom(0, 255), 255);
 69	}
 70
 71	public void clear() {
 72		nPoints = 0;
 73		exists = false;
 74		thickness = INIT_TH;
 75	}
 76
 77	public void clearPolys() {
 78		nPolys = 0;
 79	}
 80
 81	public void addPoint(float x, float y) {
 82		if (nPoints >= capacity) {
 83			// there are all sorts of possible solutions here,
 84			// but for abject simplicity, I don't do anything.
 85		} 
 86		else {
 87			float v = distToLast(x, y);
 88			float p = getPressureFromVelocity(v);
 89			path[nPoints++].setXYZ(x,y,p);
 90
 91			if (nPoints > 1) {
 92				exists = true;
 93				jumpDx = path[nPoints-1].x - path[0].x;
 94				jumpDy = path[nPoints-1].y - path[0].y;
 95			}
 96		}
 97
 98	}
 99
100	private float getPressureFromVelocity(float v) {
101		final float scale = 18;
102		final float minP = 0.02f;
103		final float oldP = (nPoints > 0) ? path[nPoints-1].z : 0;
104		return ((minP + PApplet.max(0, 1.0f - v/scale)) + (damp1*oldP))*dampInv;
105	}
106
107	private void setPressures() {
108		// pressures vary from 0...1
109		float pressure;
110		Vector3D tmp;
111		float t = 0;
112		float u = 1.0f / (nPoints - 1)*PApplet.TWO_PI;
113		for (int i = 0; i < nPoints; i++) {
114			pressure = PApplet.sqrt((1.0f - PApplet.cos(t)) * 0.5f);
115			path[i].z = pressure;
116			t += u;
117		}
118	}
119
120	public float distToLast(float ix, float iy) {
121		if (nPoints > 0) {
122			Vector3D v = path[nPoints-1];
123			float dx = v.x - ix;
124			float dy = v.y - iy;
125			return PApplet.mag(dx, dy);
126		} 
127		else {
128			return 30;
129		}
130	}
131
132	public  void compile() {
133		// compute the polygons from the path of Vector3D's
134		if (exists) {
135			clearPolys();
136
137			Vector3D p0, p1, p2;
138			float radius0, radius1;
139			float ax, bx, cx, dx;
140			float ay, by, cy, dy;
141			int   axi, bxi, cxi, dxi, axip, axid;
142			int   ayi, byi, cyi, dyi, ayip, ayid;
143			float p1x, p1y;
144			float dx01, dy01, hp01, si01, co01;
145			float dx02, dy02, hp02, si02, co02;
146			float dx13, dy13, hp13, si13, co13;
147			float taper = 1.0f;
148
149			int  nPathPoints = nPoints - 1;
150			int  lastPolyIndex = nPathPoints - 1;
151			float npm1finv =  1.0f / PApplet.max(1, nPathPoints - 1);
152
153			// handle the first point
154			p0 = path[0];
155			p1 = path[1];
156			radius0 = p0.z * thickness;
157			dx01 = p1.x - p0.x;
158			dy01 = p1.y - p0.y;
159			hp01 = PApplet.sqrt(dx01*dx01 + dy01*dy01);
160			if (hp01 == 0) {
161				hp02 = 0.0001f;
162			}
163			co01 = radius0 * dx01 / hp01;
164			si01 = radius0 * dy01 / hp01;
165			ax = p0.x - si01; 
166			ay = p0.y + co01;
167			bx = p0.x + si01; 
168			by = p0.y - co01;
169
170			int xpts[];
171			int ypts[];
172
173			int LC = 20;
174			int RC = w-LC;
175			int TC = 20;
176			int BC = h-TC;
177			float mint = 0.618f;
178			float tapow = 0.4f;
179
180			// handle the middle points
181			int i = 1;
182			Polygon apoly;
183			for (i = 1; i < nPathPoints; i++) {
184				taper = PApplet.pow((lastPolyIndex-i) * npm1finv, tapow);
185
186				p0 = path[i-1];
187				p1 = path[i  ];
188				p2 = path[i+1];
189				p1x = p1.x;
190				p1y = p1.y;
191				radius1 = Math.max(mint, taper * p1.z * thickness);
192
193				// assumes all segments are roughly the same length...
194				dx02 = p2.x - p0.x;
195				dy02 = p2.y - p0.y;
196				hp02 = (float) Math.sqrt(dx02*dx02 + dy02*dy02);
197				if (hp02 != 0) {
198					hp02 = radius1/hp02;
199				}
200				co02 = dx02 * hp02;
201				si02 = dy02 * hp02;
202
203				// translate the integer coordinates to the viewing rectangle
204				axi = axip = (int)ax;
205				ayi = ayip = (int)ay;
206				axi=(axi<0)?(w-((-axi)%w)):axi%w;
207				axid = axi-axip;
208				ayi=(ayi<0)?(h-((-ayi)%h)):ayi%h;
209				ayid = ayi-ayip;
210
211				// set the vertices of the polygon
212				apoly = polygons[nPolys++];
213				xpts = apoly.xpoints;
214				ypts = apoly.ypoints;
215				xpts[0] = axi = axid + axip;
216				xpts[1] = bxi = axid + (int) bx;
217				xpts[2] = cxi = axid + (int)(cx = p1x + si02);
218				xpts[3] = dxi = axid + (int)(dx = p1x - si02);
219				ypts[0] = ayi = ayid + ayip;
220				ypts[1] = byi = ayid + (int) by;
221				ypts[2] = cyi = ayid + (int)(cy = p1y - co02);
222				ypts[3] = dyi = ayid + (int)(dy = p1y + co02);
223
224				// keep a record of where we cross the edge of the screen
225				crosses[i] = 0;
226				if ((axi<=LC)||(bxi<=LC)||(cxi<=LC)||(dxi<=LC)) { 
227					crosses[i]|=1; 
228				}
229				if ((axi>=RC)||(bxi>=RC)||(cxi>=RC)||(dxi>=RC)) { 
230					crosses[i]|=2; 
231				}
232				if ((ayi<=TC)||(byi<=TC)||(cyi<=TC)||(dyi<=TC)) { 
233					crosses[i]|=4; 
234				}
235				if ((ayi>=BC)||(byi>=BC)||(cyi>=BC)||(dyi>=BC)) { 
236					crosses[i]|=8; 
237				}
238
239				//swap data for next time
240				ax = dx; 
241				ay = dy;
242				bx = cx; 
243				by = cy;
244			}
245
246			// handle the last point
247			p2 = path[nPathPoints];
248			apoly = polygons[nPolys++];
249			xpts = apoly.xpoints;
250			ypts = apoly.ypoints;
251
252			xpts[0] = (int)ax;
253			xpts[1] = (int)bx;
254			xpts[2] = (int)(p2.x);
255			xpts[3] = (int)(p2.x);
256
257			ypts[0] = (int)ay;
258			ypts[1] = (int)by;
259			ypts[2] = (int)(p2.y);
260			ypts[3] = (int)(p2.y);
261		}
262	}
263
264	public void smooth() {
265		// average neighboring points
266		final float weight = 18;
267		final float scale  = 1.0f / (weight + 2);
268		int nPointsMinusTwo = nPoints - 2;
269		Vector3D lower, upper, center;
270
271		for (int i = 1; i < nPointsMinusTwo; i++) {
272			lower = path[i-1];
273			center = path[i];
274			upper = path[i+1];
275
276			center.x = (lower.x + weight*center.x + upper.x)*scale;
277			center.y = (lower.y + weight*center.y + upper.y)*scale;
278		}
279	}
280
281	public MTColor getColor() {
282		return color;
283	}
284
285	public void setColor(MTColor color) {
286		this.color = color;
287	}
288	
289	
290
291}
292