//Ploygon drawign and curve editor for Project 1 of CS 4451 //Code and design by Devin G Hunt (www.lcc.gatech.edu/~dhunt) //Click on the circular points to move control points. //Click on the rectangular midpoint to make new control points //All code in this program is original with design and functionality //concepts taken from Prof. Jarek Rossignacs processing example. //setup globals; //Array and there counters! int cap = 1024; //max array size Vert[] control; //the control points Vert[] bspline; //the points of the b spline, used for parametric Vert[] fpoint; //the points of the four points, used for parametric int bcount; //Size of the bpline array int fcount; //Size of the fourpoint int count; //number of vertices int selectedVertex; //index of vertex that is under the mouses control int snapIndex; //the index of the vertex being moved int recursionSize = 4; //length to recurse to //colors! color blue = color(100, 100, 210); color red = color(210, 100, 100); color black = color(0, 0, 0); color darkgrey = color(100, 100, 100); color lightgrey = color(150, 150, 150); color yellow = color(196, 181, 5); color white = color(255, 255, 255); color green = color(100, 210, 100); color lightbrown = color(220, 218, 211); //flags used to turn curves on and off boolean bViewSpline; //Turn on/off B-Spline boolean bViewFourpoint; //Turn on/off Four Point Curve boolean bViewPara; //Turn on/off Parametric Animation boolean bViewConst; //Turn on/off Const Animation boolean bViewPoly; //Turn on/off Polygon boolean bPause; //Pauses the whole application //animation stuff! int oldTime; int newTime; //t1 and t2 are used to calcualte the passage of time int timePassed; //a tally varible used to make finite intervals int paraSplineIndex; //the location of the current parametric animation of the bspline int paraFourPointIndex; //the location of the current parametric animation of the four point int constSplineIndex; //the location of the next vertex in the constant animations int constFourPointIndex; //the location of the next vertex in the constant animations Vert constbLocation; //the current location of the b spline ellipse being drawn for constant speed animation Vert constfLocation; //the current location of the four point ellipse being drawn for constant speed animation //some (static) variables for animation int interval = 40; //the interval of time used in parametric static int DOT_SIZE = 12; //the size of the "cars" of the curves float pointVelocity; //the speed at which points move along the curve int totalFrames = 20; //the number of frames in the full cicle animation float MAXIMUM_DISPLACEMENT_FROM_CURVE = 3.0; //the farthest a dot can be off a curve! //the setup for the program void setup(){ //set the window size size(500, 500); //arrays control = new Vert[cap]; bspline = new Vert[cap]; fpoint = new Vert[cap]; //setup the indexing system count=4; bcount = 0; fcount = 0; selectedVertex=0; oldTime=0; newTime=0; paraSplineIndex = 0; paraFourPointIndex = 0; constSplineIndex = 0; constFourPointIndex = 0; //set up booleans bViewSpline = true; bViewFourpoint = true; bViewConst = true; bViewPara = true; bViewPoly = true; //the index used to determin which vertex is following the mouse snapIndex = 0; //set up a default polygon control[1] = new Vert(100, 100); control[2] = new Vert(400, 100); control[3] = new Vert(400, 400); control[4] = new Vert(100, 400); //xControl[5] = 200; yControl[5] = 300; //xControl[6] = 300; yControl[6] = 200; //set up the position points for the constant speed animation constbLocation = new Vert(130, 130); constfLocation = new Vert(400, 100); //um, make the strokes fancy strokeJoin(ROUND); strokeCap(ROUND); } //the main draw loop //curves are built in two steps, first the vertices of the curves are computed and placed in an array (bspline and fpoint).\ //using a for loop they are then drawn void draw(){ if(!bPause){ background(lightbrown); if(snapIndex>0){ control[snapIndex].x = mouseX; control[snapIndex].y = mouseY; } Vert mid; control[0] = control[count]; //loop is back around //draw all those cool curves Vert[] c; int apIndex = 0; if(bViewSpline){ //this part of the wrapper that builds the proper array to pass into the recursiv c = control; for(int i = 0; i<=3; i++){ if(apIndex >= count){ apIndex = 0; } c[count + i] = control[apIndex]; apIndex++; } //build curve, the part of the wrapper that sends the peices to the recusive algorith dbs bcount = 0; //reset bcount for(int i=0; i<=count; i++){ dbs(c[i], c[i+1], c[i+2], c[i+3], recursionSize); } //draw curve for the track, stroke(darkgrey); strokeWeight(12); beginShape(LINE_STRIP); for(int i=0; i= count){ apIndex = 0; } c[count + i] = control[apIndex]; apIndex++; } //compute the array, the part of the wrapper that sends the peices to the recusive algorith dbs fcount = 0; //resest fcount for(int i=0; i<=count; i++){ fourpoint(c[i], c[i+1], c[i+2], c[i+3], c[i+4], c[i+5], recursionSize); } //draw curve stroke(lightgrey); strokeWeight(12); beginShape(LINE_STRIP); for(int i=0; i= interval){ paraSplineIndex++; //move the parametric positions foward one paraFourPointIndex++; //move the parametric positions foward one timePassed = 0; //reset the interval } //activate all the animation drawers if(bViewPara){ drawParametric(); } if(bViewConst){ drawConstantSplineSpeed(); drawConstantFourPointSpeed(); } } } //animates a point that moves around the curves at a parametric speed void drawParametric(){ if(paraSplineIndex > bcount-(recursionSize*recursionSize)-1){ //make sure you draw in a smooth loop paraSplineIndex = 0; } if(paraFourPointIndex > bcount-(recursionSize*recursionSize)-1){//make sure you draw in a smooth loop paraFourPointIndex = 0; } stroke(black); fill(white); strokeWeight(1); ellipse(bspline[paraSplineIndex].x, bspline[paraSplineIndex].y, DOT_SIZE, DOT_SIZE); ellipse(fpoint[paraFourPointIndex].x, fpoint[paraFourPointIndex].y, DOT_SIZE, DOT_SIZE); } //animates the constant speed along the curves //del is the change in time void drawConstantSplineSpeed(){ float step = curveLength(bspline) / totalFrames; //the normal step size is the starting amount of how much one has left to go boolean eDrawn = false; //this is set true when the point is drawn on the screen float currentNorm; while(!eDrawn){ currentNorm = norm(constbLocation, bspline[constSplineIndex]); //make sure the point isn't to far off! if(currentNorm > step){ constbLocation.x += (step/currentNorm) * (bspline[constSplineIndex].x - constbLocation.x); constbLocation.y += (step/currentNorm) * (bspline[constSplineIndex].y - constbLocation.y); //ready to draw! eDrawn = true; } else { //ok, so it was to long, get the next point of the curve and go! step -= currentNorm; //get the new step size constbLocation.x = bspline[constSplineIndex].x; //set the new location of the point constbLocation.y = bspline[constSplineIndex].y; //set the new location of the point constSplineIndex++; //and increment the index if(constSplineIndex >= bcount-(recursionSize*recursionSize)-1) { //if the const index is to big, reset constSplineIndex = 0; } } } stroke(black); fill(green); strokeWeight(1); ellipse(constbLocation.x, constbLocation.y, DOT_SIZE, DOT_SIZE); } //animates the constant speed along the curves //del is the change in time void drawConstantFourPointSpeed(){ float step = curveLength(fpoint) / totalFrames; //the normal step size is the starting amount of how much one has left to go boolean eDrawn = false; //this is set true when the point is drawn on the screen float currentNorm; while(!eDrawn){ currentNorm = norm(constfLocation, fpoint[constFourPointIndex]); //make sure the point isn't to far off! /*if(currentNorm > MAXIMUM_DISPLACEMENT_FROM_CURVE){ constfLocation.x = fpoint[constFourPointIndex].x; //set the new location of the point constfLocation.y = fpoint[constFourPointIndex].y; //set the new location of the point //ready to draw! eDrawn = true; } else */ if(currentNorm > step){ constfLocation.x += (step/currentNorm) * (fpoint[constFourPointIndex].x - constfLocation.x); constfLocation.y += (step/currentNorm) * (fpoint[constFourPointIndex].y - constfLocation.y); //ready to draw! eDrawn = true; } else { //ok, so it was to long, get the next point of the curve and go! step -= currentNorm; //get the new step size constfLocation.x = fpoint[constFourPointIndex].x; //set the new location of the point constfLocation.y = fpoint[constFourPointIndex].y; //set the new location of the point constFourPointIndex++; //and increment the index if(constFourPointIndex >= fcount-(recursionSize*recursionSize)-1) { //if the const index is to big, reset constFourPointIndex = 0; } } } stroke(black); fill(green); strokeWeight(1); ellipse(constfLocation.x, constfLocation.y, DOT_SIZE, DOT_SIZE); } //draws a span of a cubic bspline as defined by 4 points void dbs(Vert A, Vert B, Vert C, Vert D, int recursiveLevel){ if(recursiveLevel>0){ Vert mid1; //Midpoint 1 Vert mid2; //Midpoint 2 Vert mid3; //Midpoint 3 Vert spot1; //Tweak Spot 1 Vert spot2; //Tweak Spot 2 Vert bprime; //New Curve point for B Vert cprime; //New Curve point for B mid1 = midpoint(A, B); mid2 = midpoint(B, C); mid3 = midpoint(C, D); //the midpoints spot1 = midpoint(mid1, mid2); spot2 = midpoint(mid2, mid3); //the spots used to figure the tweaks bprime = new Vert(B.x + (spot1.x - B.x) /2, B.y + (spot1.y - B.y) /2); cprime = new Vert(C.x + (spot2.x - C.x) /2, C.y + (spot2.y - C.y) /2); //Make the new curve points by moving it "inward" by 2 dbs(mid1, bprime, mid2, cprime, recursiveLevel-1); //recurse! dbs(bprime, mid2, cprime, mid3, recursiveLevel-1); //recurse! } else { bspline[bcount] = new Vert(B.x, B.y); //Add it to the B-Spline array! bcount++; } } //draws a span of a cubic bspline as defined by 4 points void fourpoint(Vert A, Vert B, Vert C, Vert D, Vert E, Vert F, int recursiveLevel){ if(recursiveLevel>0){ Vert mid1; Vert mid2; Vert mid3; Vert mid4; Vert mid5; Vert ref1; Vert ref2; Vert ref3; Vert spot1; Vert spot2; Vert spot3; mid1 = midpoint(A, D); //midpoint 1 mid2 = midpoint(B, E); //midpoint 2 mid3 = midpoint(C, F); //midpoint 3 ref1 = midpoint(B, C); ref2 = midpoint(C, D); ref3 = midpoint(D, E); spot1 = new Vert(ref1.x + (ref1.x - mid1.x) / 8, ref1.y + (ref1.y - mid1.y) / 8); //new curve point! spot2 = new Vert(ref2.x + (ref2.x - mid2.x) / 8, ref2.y + (ref2.y - mid2.y) / 8); //new curve point! spot3 = new Vert(ref3.x + (ref3.x - mid3.x) / 8, ref3.y + (ref3.y - mid3.y) / 8); //new curve point! fourpoint(B, spot1, C, spot2, D, spot3, recursiveLevel - 1); //recurse! fourpoint(spot1, C, spot2, D, spot3, E, recursiveLevel - 1); //recurse! } else { fpoint[fcount] = new Vert(C.x, C.y); //add it to the fourpoint array fcount++; } } void mousePressed(){ int vert = closeVertex(); if(vert > 0){ snapIndex = vert; //snap the vertex to the mouse } } void mouseReleased(){ //delete any points outside the drawing area if((mouseX > 500 || mouseY > 500 || mouseX < 0 || mouseY < 0) && snapIndex > 0){ //shift out the vertex for(int i = snapIndex; i cIndex; i--){ control[i+1] = control[i]; } control[cIndex + 1] = new Vert(px, py); count++; return cIndex + 1; } else { return -1; } } Vert midpoint(Vert A, Vert B){ return new Vert((A.x + B.x) / 2, (A.y + B.y) / 2); } float curveLength(Vert[] curvy){ float total = 0; for(int i = 0; i