//***************************************************************************** // TITLE: uniform cubic B-spline // DESCRIPTION: To show that interative refine & smoothing makes a uniform cubic B-spline // AUTHOR: Sungbae Kim // DATE CREATED: Sep. 3. 2007 // EDITS: //***************************************************************************** boolean showText = true; // toggled by key to show/hide help text boolean printIt=false; // temporarily set when a key is pressed and used to print some debugging values int mousepoint; //! n is the total number of points. int n=4; int p=0; // index to the point being dragged // Those are predefined colors of Professor Jarek. color red, yellow, green, cyan, blue, magenta, dred, dyellow, dgreen, dcyan, dblue, dmagenta, white, black, orange, grey, metal; // declares colors Vector orgpolyloop = new Vector(); Vector oldpolyloop = new Vector(); Vector polyloop = new Vector(); Vector smoothingVector = new Vector(); int op = 0; // 1 : refine, 0 : smoothing boolean smoothing = false; boolean refine = false; boolean reset = false; int smoothingtimes = 0; int refinetimes = 0; boolean vertexchanged = false; class vertex { pt P; boolean isNew; vertex() { P = new pt(); isNew = false; } vertex(vertex V) { P = new pt(); P.setTo(V.P); isNew = V.isNew; }; } void resetPolyloop() { orgpolyloop.clear(); oldpolyloop.clear(); polyloop.clear(); smoothingVector.clear(); for (int i=0; i i*2 + 1 ) polyloop.add( i*2+1, newV ); else polyloop.add(newV); } } void smoothingPolyloop() { oldpolyloop.clear(); smoothingVector.clear(); for ( int i = 0; i < polyloop.size(); i++ ) { vertex v0 = (vertex)polyloop.get(i%polyloop.size()); vec L = new vec(); if ( v0.isNew == false ) { vertex v_minus1 = (vertex)polyloop.get((i+polyloop.size()-1)%polyloop.size()); vertex v_plus1 = (vertex)polyloop.get((i+1)%polyloop.size()); L.setTo((v_minus1.P.x + v_plus1.P.x)/2, (v_minus1.P.y + v_plus1.P.y)/2); L.add(-v0.P.x, -v0.P.y); L.scaleBy(0.25); } else { vertex v_minus2 = (vertex)polyloop.get((i+polyloop.size()-2)%polyloop.size()); vertex v_plus2 = (vertex)polyloop.get((i+2)%polyloop.size()); L.setTo(v0.P.x, v0.P.y); L.add(-(v_minus2.P.x + v_plus2.P.x)/2, -(v_minus2.P.y+v_plus2.P.y)/2); L.scaleBy(0.125); } smoothingVector.add(L); oldpolyloop.add(new vertex(v0)); } for ( int i = 0; i < polyloop.size(); i++ ) { vertex v = (vertex)polyloop.get(i); vec L = (vec)smoothingVector.get(i); v.P.translateBy(L); } } /** @brief This function is called only ONCE when the program is being initialized.\n The purpose of this function is to make an initialized environment of program.\n @param none. @return none. */ void setup() { size(600, 600); smooth(); colorMode(HSB,121); strokeJoin(ROUND); strokeCap(ROUND); // set up window and drawing modes red = color(0, 120, 120); yellow = color(20, 120, 120); green = color(40, 120, 120); cyan = color(60, 120, 120); blue = color(80, 120, 120); magenta = color(100, 120, 120); dred = color(0, 120, 60); dyellow = color(20, 120, 60); dgreen = color(40, 120, 60); dcyan = color(60, 120, 60); dblue = color(80, 120, 60); dmagenta = color(100, 120, 60); white = color(0, 0, 120); black = color(0, 120,0); grey = color(0, 120,60); orange = color(10, 100, 120); metal = color(70, 60, 100); PFont font = loadFont("Courier-14.vlw"); textFont(font, 14); // load font resetPolyloop(); } /** @brief This function is called every pre-defined framerate.\n The framerate can be defined in setup() function and default value is 1/60 sec.\n @param none. @return none. */ void draw() { // rendering loop to refresh the window if (mousePressed) { if ( mousepoint>=0 && orgpolyloop.size() > 0 ) { vertex v = (vertex)orgpolyloop.get(mousepoint); v.P.setToMouse(); setCurrentPolyloop(); } else if ( vertexchanged ) { setCurrentPolyloop(); vertexchanged = false; } } if ( refine == true ) { if ( refinetimes == 0 && smoothingtimes == 0) initPolyloop(); refinePolyloop(); op = 1; refine = false; refinetimes++; } else if ( smoothing == true ) { if ( refinetimes == 0 && smoothingtimes == 0) initPolyloop(); smoothingPolyloop(); op = 0; smoothing = false; smoothingtimes++; } else if ( reset == true ) { op = 0; resetPolyloop(); reset = false; smoothingtimes = 0; refinetimes = 0; } background(121); // sets background strokeWeight(1); // sets weight of stroke if (showText) {fill(dblue); pushMatrix(); translate(20,20); fill(dblue); text("* Press 'f' to refine or smoothing", 0, 0); translate(0, 20); text(" now - refine " + refinetimes + " times, smoothing " + smoothingtimes + " times",0,0); translate(0,20); text("* Press 'e' to reset",0,0); translate(0,20); popMatrix(); noFill();}; strokeWeight(1); // polygon if ( smoothingtimes >= 0 ) { stroke(green); fill(green); for ( int i = 0; i < orgpolyloop.size(); i++ ) { vertex v = (vertex)orgpolyloop.get(i); vertex w = (vertex)orgpolyloop.get((i+1)%orgpolyloop.size()); if ( refinetimes == 0 && smoothingtimes == 0 ) { v.P.showSegmentTo(w.P); v.P.show(2); } else if ( smoothingtimes > 0 ) { v.P.showDashTo(w.P, 2); v.P.show(2); } } } stroke(green); //noFill(); //beginShape(); /* for ( int i = 0; i < oldpolyloop.size(); i++ ) { vertex v = (vertex) oldpolyloop.get(i); vertex w = (vertex) oldpolyloop.get((i+1)%oldpolyloop.size()); vertex x = (vertex) oldpolyloop.get((i+2)%oldpolyloop.size()); vec L = (vec) smoothingVector.get(i); pt Q = new pt(v.P); Q.translateBy(2, L); v.P.showDashTo(w.P, 2); v.P.showDashTo(x.P, 2); v.P.showDashTo(Q, 2); } */ stroke(blue); for ( int i = 0; i < polyloop.size(); i++ ) { vertex v = (vertex) polyloop.get(i); vertex w = (vertex) polyloop.get((i+1)%polyloop.size()); v.P.showSegmentTo(w.P); } if ( op == 1) { noStroke(); for ( int i = 0; i < polyloop.size(); i++ ) { vertex v = (vertex) polyloop.elementAt(i); if ( v.isNew ) fill(red); else fill(green); v.P.show(1); } } }; /** @brief This function is called when the user press any key in keyboard.\n \n When user press any key in keyboard, this function will check which key has been pressed.\n We modified Professor Jarek's code in this function.\n We added a logic to check key '0', '1' and '3' to show different results and we also added a logic 'm' to display different mode of program. @param none. @return none. */ void keyPressed() { if (key=='h') showText = !showText; if (key=='?') printIt = true; // sets the debugging mode for one pass if ( key == 'f') { if ( op == 1 ) // refine { refine = false; smoothing = true; } else { refine = true; smoothing = false; } } else if ( key == 'e' ) { reset = true; } } /** @brief This function is called when the mouse is being clicked.\n \n When user clicks mouse button on certain point, this function will make users to be able to drag it.\n The actual idea of doing this is kind of make the point stick to current position of the cursor.\n I used Professor Jarek's code in this function. @param none. @return none. */ void mousePressed() { vertexchanged = false; mousepoint=-1; float d=10; for (int i=0; i< orgpolyloop.size(); i++) { vertex v = (vertex)orgpolyloop.get(i); if ( v.P.disToMouse()= 0 ) return; pt P = new pt(); P.setTo(mouseX, mouseY); P.write(); for ( int i = 0; i < orgpolyloop.size(); i++ ) { vertex v = (vertex)orgpolyloop.get(i); vertex w = (vertex)orgpolyloop.get((i+1)%orgpolyloop.size()); if ( isOnLine(v.P, w.P, P) ) { vertexchanged = true; println ("on"); vertex x = new vertex(); x.P.setTo(P); if (i+1 >= orgpolyloop.size()) orgpolyloop.add(x); else orgpolyloop.add(i+1, x); return; } } }