// LinePlay 2. // A program to animate hand drawn lines using movable anchor points. import processing.opengl.*; import traer.physics.*; float SPRING_CONSTANT = 1.0; float DAMP_CONSTANT = 0.0; float TIME_STEP = 0.1; float GLOBAL_DAMP_CONSTANT = 10.0; int MAX_ANCHOR_HISTORY = 1000; int MAX_NUM_POINTS = 10000; int NUM_FIT_POINTS = 50; float ANCHOR_ATTACH_RADIUS = 20.0; Chronometer chrono; ParticleSystem physics; Anchors anchors; ArrayList curveList; MultiBezier newCurve; MultiBezier selectedCurve; int selectedCurveIndex; boolean drawingCurve = false; boolean selectedAnchor = false; boolean selectedPoint = false; boolean showingInformation = false; boolean showControlPoints = false; boolean showAnchorPoints = true; float currentWeight; PFont font; String str1 = "This program allows to animate freehand line drawings by attaching the lines to anchor points. By moving the anchor " + "points in different ways, the attached lines will follow the motions\n\n"; String str2 = "By clicking with the mouse, new lines can be added to the drawing. Clicking while pressing the key will " + "add new anchor points. The anchor points can be moved around by dragging and clicking on them. The motions of the " + "anchor points are recorded in a loop, and these loops are repeated continously.\n\n"; String str3 = "The lines are attached to the anchor points by passing the drawing through the anchors.\n\n"; String str4 = " clears the drawing.\n"; String str5 = " shows/hides the curves control points.\n"; String str6 = " starts a new line, or selects a pre-existing point.\n"; String str7 = " + adds a new anchor point or selects a pre-existing one and moves it around.\n"; String str8 = " and arrow keys increase/decrease the weight of the line.\n"; String str9 = " shows/hides the anchor points.\n"; void setup() { size(800, 600); ellipseMode(CENTER); smooth(); physics = new ParticleSystem(0, GLOBAL_DAMP_CONSTANT); anchors = new Anchors(); chrono = new Chronometer(); curveList = new ArrayList(); newCurve = null; drawingCurve = false; selectedCurve = null; selectedCurveIndex = -1; currentWeight = 1.0; font = loadFont("BrowalliaNew-24.vlw"); textFont(font); noFill(); } void draw() { background(0); physics.tick(TIME_STEP); strokeWeight(1); anchors.update(); if (showAnchorPoints) anchors.render(); noFill(); MultiBezier bCurve; for (int i = 0; i < curveList.size(); i++) { bCurve = (MultiBezier)curveList.get(i); bCurve.update(); bCurve.render(showControlPoints); } if (showingInformation) { noStroke(); fill(255, 50); rect(5, 5, width - 5, 0.75 * height); fill(255); text(str1 + str2 + str3 + str4 + str5 + str6 + str7 + str8 + str9, 10, 30, width - 10, 0.75 * height); text("Press any key to put this information away.", 10, height - 30); } else { fill(255); text("Click the mouse to start drawing.", 10, height - 50); text("Mouse click + Control key to add anchor points. Press for more information.", 10, height - 30); } noStroke(); fill(255); rect(width - 10 * currentWeight, height - 35, 10 * currentWeight, 10); chrono.update(); chrono.printfps(); } void mouseReleased() { if (showingInformation) { showingInformation = false; return; } if (selectedAnchor) { selectedAnchor = false; anchors.unselectedAnchor(); } if (selectedPoint) { selectedPoint = false; selectedCurve.unselectedPoint(); } if (drawingCurve) { newCurve.closeCurve(); newCurve.setupAnchors(anchors); newCurve = null; drawingCurve = false; } } void keyPressed() { if (showingInformation) { showingInformation = false; return; } if (key == CODED) { if ((keyCode == UP) && (currentWeight < 15)) currentWeight++; else if ((keyCode == DOWN) && (1 < currentWeight)) currentWeight--; } else { if (key == BACKSPACE) { curveList.clear(); anchors.clear(); MultiBezier newCurve; drawingCurve = false; selectedAnchor = false; selectedPoint = false; } else if (key == 'i') { showingInformation = !showingInformation; } else if (key == 'h') { showAnchorPoints = !showAnchorPoints; } else if (key == ' ') { showControlPoints = !showControlPoints; } } } void mouseDragged() { if (showingInformation) { showingInformation = false; return; } if (drawingCurve) { newCurve.addPoint(mouseX, mouseY, anchors); } else { if (selectedAnchor) anchors.setSelectedAnchor(mouseX, mouseY); if (selectedPoint) selectedCurve.setSelectedPoint(mouseX, mouseY); } } void mousePressed() { if (showingInformation) { showingInformation = false; return; } if (keyPressed && (key == CODED && keyCode == CONTROL)) selectedAnchor = anchors.selectAnchor(mouseX, mouseY, 10); else selectedAnchor = false; if (!selectedAnchor) { selectedPoint = false; selectedCurve = null; selectedCurveIndex = -1; MultiBezier bCurve; for (int i = 0; i < curveList.size(); i++) { bCurve = (MultiBezier)curveList.get(i); boolean res = bCurve.selectPoint(mouseX, mouseY, 10); if (res) { selectedPoint = true; selectedCurve = bCurve; selectedCurveIndex = i; break; } } if (!selectedPoint) { if (keyPressed && (key == CODED && keyCode == CONTROL)) { selectedAnchor = anchors.addAnchor(mouseX, mouseY); } else { newCurve = new MultiBezier(currentWeight); newCurve.addPoint(mouseX, mouseY, anchors); drawingCurve = true; curveList.add(newCurve); } } } }