//***************************************************************************** // CURVE TWEENING, Jarek Rossignac, 2008 //***************************************************************************** int _deg=3; float [] _w = new float[5]; // weights for retrofitting boolean symmetryEnds=true; POLY C = new POLY(); // control, retrofit, and subdivided polyloops boolean [] used = new boolean [10]; float Carea=0, Clength=0, Sarea=0, Slength=0; //float nrv=30; // number of vertices on resampled curve U pt closest = new pt(0,0); // tracks closest point on control polyloop float taper (float v, int i, int n) { // returns v scaled down smothly when i approaches 0 or n if (i3*n/4) return (1-sq(cos(PI*(i-n/2)/n*2)))*v; else return v; } boolean ccl; //************************************************************************************************************************ POLY P(POLY Q) {POLY P = new POLY(); P.setTo(Q); return P;} // **************************************** POLY CLASS ************************************* START !!!!!!!! class POLY { // class of polyloops (open loop polygon) int vn = 6, cap=20000; // number of control vertices and the cap on vn pt[] P = new pt [cap]; // control points int[] m = new int[3]; // marks: vertex indices splitting poly in 4 for morphing and dollies int p = 0; // id of currently point selected (with mouse for dragging, etc.) POLY () {for (int i=0; i_rec) return; push(k); ringAdvance(k+1); push(k); ringAdvance(k+1); } void ringAdvance() { push(0); push(1); push(2); push(3); push(4); push(5); push(5); push(4); push(5); push(5); push(3); push(4); push(5); push(5); push(4); push(5); push(5); push(2); push(3); push(4); push(5); push(5); push(4); push(5); push(5); push(3); push(4); push(5); push(5); push(4); push(5); push(5); push(1); push(2); push(3); push(4); push(5); push(5); push(4); push(5); push(5); push(3); push(4); push(5); push(5); push(4); push(5); push(5); push(2); push(3); push(4); push(5); push(5); push(4); push(5); push(5); push(3); push(4); push(5); push(5); push(4); push(5); push(5); push(0); push(1); push(2); push(3); push(4); push(5); push(5); push(4); push(5); push(5); push(3); push(4); push(5); push(5); push(4); push(5); push(5); push(2); push(3); push(4); push(5); push(5); push(4); push(5); push(5); push(3); push(4); push(5); push(5); push(4); push(5); push(5); push(1); push(2); push(3); push(4); push(5); push(5); push(4); push(5); push(5); push(3); push(4); push(5); push(5); push(4); push(5); push(5); push(2); push(3); push(4); push(5); push(5); push(4); push(5); push(5); push(3); push(4); push(5); push(5); push(4); push(5); push(5); } void ringAdvanceX() { push(0); push(1); push(2); push(3); push(4); push(4); push(3); push(4); push(4); push(2); push(3); push(4); push(4); push(3); push(4); push(4); push(1); push(2); push(3); push(4); push(4); push(3); push(4); push(4); push(2); push(3); push(4); push(4); push(3); push(4); push(4); push(0); push(1); push(2); push(3); push(4); push(4); push(3); push(4); push(4); push(2); push(3); push(4); push(4); push(3); push(4); push(4); push(1); push(2); push(3); push(4); push(4); push(3); push(4); push(4); push(2); push(3); push(4); push(4); push(3); push(4); push(4); } void subdivideGlobal() { pt[] Q = new pt [vn]; for (int i=0; ie) {int t=b; b=e; e=t; Q.resample(e-b+1); int j=e-b; for (int i=b; i<=e; i++) P[i].translateTowards(taper(s,i-b,e-b),Q.P[j--]); } else {Q.resample(e-b+1); int j=0; for (int i=b; i<=e; i++) P[i].translateTowards(taper(s,i-b,e-b),Q.P[j++]); }; for (int i=1; i<100; i++) smoothen(b,e); }; // COMPATIBLE ***************************************************************************************************************************** POLY compatibleO(POLY Q) { if(vn==0) return this; POLY R= P(this); // print("C: vn="+vn); writeMarks(); print("R: vn="+R.vn); R.writeMarks(); if(Q.m[0]>R.m[0]) R.resample(Q.m[0]+1,0,R.m[0]); if(Q.m[1]-Q.m[0]>R.m[1]-R.m[0]) R.resample(Q.m[1]-Q.m[0]+1,R.m[0],R.m[1]); if(Q.m[2]-Q.m[1]>R.m[2]-R.m[1]) R.resample(Q.m[2]-Q.m[1]+1,R.m[1],R.m[2]); if(Q.vn-Q.m[2]>R.vn-R.m[2]) R.resample(Q.vn-Q.m[2]+1,R.m[2],R.vn-1); return R; } POLY compatible(POLY Q) { if(vn==0) return this; POLY R= P(this); // print("C: vn="+vn); writeMarks(); print("R: vn="+R.vn); R.writeMarks(); R.resample(max(Q.m[0],R.m[0])+1,0,R.m[0]); R.resample(max(Q.m[1]-Q.m[0],R.m[1]-R.m[0])+1,R.m[0],R.m[1]); R.resample(max(Q.m[2]-Q.m[1],R.m[2]-R.m[1])+1,R.m[1],R.m[2]); R.resample(max(Q.vn-Q.m[2],R.vn-R.m[2])+1,R.m[2],R.vn-1); return R; } // REGULARIZE ********************************************************************************* POLY regularized() { if(vn==0) return this; POLY Q= P(this); for (int i=0; i<_filters; i++) Q.smoothen(); for (int i=0; i<_subdivisions; i++) Q.refine(_gs); Q.resample(_samples); if (threeSegments) Q.resetMarks(); else Q.resetEndMarks(); return Q; } void prep() { for (int i=0; i<_filters; i++) smoothen(); for (int i=0; i<_subdivisions; i++) refine(_gs); resample(_samples); if (threeSegments) resetMarks(); else resetEndMarks(); } // RESAMPLE ************************************************************************************ void resample(int nrv) { if(vn==0) println("resample vn="+vn+", nrv="+nrv); if(vn==0) return; float L = length(); pt R[] = new pt[nrv+1]; // temporary array for new samples pt Q = new pt(0,0); float d = L / (nrv-1); // desired distance between new samples float rd=d; // remaining distance to next sample float cl=0; // length of remaining portion of current edge int nk=1; // index of the next vertex on the original curve int n=0; // number of already added points Q.setTo(P[0]); // Set Q as first vertex R[n++]=P(Q); // add Q as first sample and increment counter n while (n