diff --git a/README.md b/README.md index 0abb6a8..06cbba7 100644 --- a/README.md +++ b/README.md @@ -5,14 +5,11 @@ Copyright (C) 2016 by Windell H. Oskay, www.evilmadscientist.com ![Snap! Screenshot](https://raw.github.com/evil-mad/stipplegen/master/examples/screenshots/7368233514_59f7d25603.jpg) - -This is a program, written in [Processing](https://www.processing.org), that can take an image file in .jpg, .png, or .gif format, and create from it either a vector stipple drawing or a TSP art vector drawing. +This is a program, written in [Processing](https://www.processing.org), that can take an image file in .jpg, .png, or .gif format, and create from it either a vector stipple drawing or a [TSP](https://en.wikipedia.org/wiki/Travelling_salesman_problem) art vector drawing. An implementation of Weighted Voronoi Stippling: http://mrl.nyu.edu/~ajsecord/stipples.html - - Full Documentation: http://wiki.evilmadscience.com/StippleGen Blog post about the release: http://www.evilmadscientist.com/go/stipple2 diff --git a/StippleGen/StippleGen2.pde b/StippleGen/StippleGen2.pde index a6250a1..f2ff3b2 100644 --- a/StippleGen/StippleGen2.pde +++ b/StippleGen/StippleGen2.pde @@ -8,7 +8,6 @@ Full Documentation: http://wiki.evilmadscience.com/StippleGen Blog post about the release: http://www.evilmadscientist.com/go/stipple2 - An implementation of Weighted Voronoi Stippling: http://mrl.nyu.edu/~ajsecord/stipples.html @@ -51,13 +50,10 @@ ******************************************************************************* - - Program is based on the Toxic Libs Library ( http://toxiclibs.org/ ) & example code: http://forum.processing.org/topic/toxiclib-voronoi-example-sketch - Additional inspiration: Stipple Cam from Jim Bumgardner http://joyofprocessing.com/blog/2011/11/stipple-cam/ @@ -67,17 +63,13 @@ MeshLibDemo.pde - Demo of Lee Byron's Mesh library, by Marius Watz - http://workshop.evolutionzone.com/ - Requires ControlP5 library and Toxic Libs library: http://www.sojamo.de/libraries/controlP5/ http://hg.postspectacular.com/toxiclibs/downloads - - */ - +*/ /* - * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either @@ -95,111 +87,85 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - // You need the controlP5 library from http://www.sojamo.de/libraries/controlP5/ import controlP5.*; //You need the Toxic Libs library: http://hg.postspectacular.com/toxiclibs/downloads - import toxi.geom.*; import toxi.geom.mesh2d.*; import toxi.util.datatypes.*; import toxi.processing.*; -// helper class for rendering -ToxiclibsSupport gfx; - import javax.swing.UIManager; import javax.swing.JFileChooser; +// helper class for rendering +ToxiclibsSupport gfx; +// Feel free to play with these three default settings +float cutoff = 0; +float minDotSize = 1.75; +float dotSizeFactor = 4; +// Max value is normally 10000. Press 'x' key to allow 50000 stipples. (SLOW) +int maxParticles = 2000; - -// Feel free to play with these three default settings: -int maxParticles = 2000; // Max value is normally 10000. Press 'x' key to allow 50000 stipples. (SLOW) -float MinDotSize = 1.75; //2; -float DotSizeFactor = 4; //5; -float cutoff = 0; // White cutoff value - - -int cellBuffer = 100; //Scale each cell to fit in a cellBuffer-sized square window for computing the centroid. - +//Scale each cell to fit in a cellBuffer-sized square window for computing the centroid. +int cellBuffer = 100; // Display window and GUI area sizes: int mainwidth; int mainheight; int borderWidth; int ctrlheight; -int TextColumnStart; - - +int textColumnStart; float lowBorderX; float hiBorderX; float lowBorderY; float hiBorderY; - - -float MaxDotSize; -boolean ReInitiallizeArray; +float maxDotSize; +boolean reInitiallizeArray; boolean pausemode; boolean fileLoaded; -int SaveNow; +boolean saveNow; String savePath; -String[] FileOutput; +String[] fileOutput; -boolean drawSpiral; +boolean fillingCircles; - - -String StatusDisplay = "Initializing, please wait. :)"; +String statusDisplay = "Initializing, please wait. :)"; float millisLastFrame = 0; float frameTime = 0; -String ErrorDisplay = ""; -float ErrorTime; -Boolean ErrorDisp = false; +float errorTime; +String errorDisplay = ""; +boolean errorDisp = false; - -int Generation; +int generation; int particleRouteLength; -int RouteStep; +int routeStep; -boolean showBG; -boolean showPath; -boolean showCells; boolean invertImg; -boolean TempShowCells; -boolean FileModeTSP; +boolean fileModeTSP; +boolean tempShowCells; +boolean showBG, showPath, showCells; int vorPointsAdded; -boolean VoronoiCalculated; - -// Toxic libs library setup: -Voronoi voronoi; -Polygon2D RegionList[]; - -PolygonClipper2D clip; // polygon clipper +boolean voronoiCalculated; int cellsTotal, cellsCalculated, cellsCalculatedLast; +int[] particleRoute; +Vec2D[] particles; -// ControlP5 GUI library variables setup -Textlabel ProgName; -Button OrderOnOff, ImgOnOff, CellOnOff, InvertOnOff, FillCircles, PauseButton; ControlP5 cp5; - - +Voronoi voronoi; +Polygon2D regionList[]; +PolygonClipper2D clip; PImage img, imgload, imgblur; -Vec2D[] particles; -int[] particleRoute; - - - void LoadImageAndScale() { - int tempx = 0; int tempy = 0; @@ -208,45 +174,37 @@ void LoadImageAndScale() { img.loadPixels(); - if (invertImg) - for (int i = 0; i < img.pixels.length; i++) { - img.pixels[i] = color(0); - } else - for (int i = 0; i < img.pixels.length; i++) { - img.pixels[i] = color(255); - } + for (int i = 0; i < img.pixels.length; i++) { + img.pixels[i] = color(invertImg ? 0 : 255); + } img.updatePixels(); - if ( fileLoaded == false) { + if (!fileLoaded) { // Load a demo image, at least until we have a "real" image to work with. - + // Image from: http://commons.wikimedia.org/wiki/File:Kelly,_Grace_(Rear_Window).jpg imgload = loadImage("grace.jpg"); // Load demo image - // Image source: http://commons.wikimedia.org/wiki/File:Kelly,_Grace_(Rear_Window).jpg } if ((imgload.width > mainwidth) || (imgload.height > mainheight)) { - - if (((float) imgload.width / (float)imgload.height) > ((float) mainwidth / (float) mainheight)) + if (((float)imgload.width / (float)imgload.height) > ((float)mainwidth / (float)mainheight)) { imgload.resize(mainwidth, 0); - } else - { + } else { imgload.resize(0, mainheight); } } - if (imgload.height < (mainheight - 2) ) { - tempy = (int) (( mainheight - imgload.height ) / 2) ; + if (imgload.height < (mainheight - 2)) { + tempy = (int)((mainheight - imgload.height) / 2) ; } if (imgload.width < (mainwidth - 2)) { - tempx = (int) (( mainwidth - imgload.width ) / 2) ; + tempx = (int)((mainwidth - imgload.width) / 2) ; } img.copy(imgload, 0, 0, imgload.width, imgload.height, tempx, tempy, imgload.width, imgload.height); // For background image! - /* // Optional gamma correction for background image. img.loadPixels(); @@ -259,42 +217,36 @@ void LoadImageAndScale() { img.pixels[i] = color(floor(255 * pow(tempFloat,GammaValue))); } img.updatePixels(); - */ - + */ imgblur.copy(img, 0, 0, img.width, img.height, 0, 0, img.width, img.height); // This is a duplicate of the background image, that we will apply a blur to, // to reduce "high frequency" noise artifacts. - imgblur.filter(BLUR, 1); // Low-level blur filter to elminate pixel-to-pixel noise artifacts. + // Low-level blur filter to elminate pixel-to-pixel noise artifacts. + imgblur.filter(BLUR, 1); imgblur.loadPixels(); } - -void MainArraysetup() { +void MainArraySetup() { // Main particle array initialization (to be called whenever necessary): - LoadImageAndScale(); // image(img, 0, 0); // SHOW BG IMG particles = new Vec2D[maxParticles]; - // Fill array by "rejection sampling" int i = 0; - while (i < maxParticles) - { - - float fx = lowBorderX + random(hiBorderX - lowBorderX); - float fy = lowBorderY + random(hiBorderY - lowBorderY); + while (i < maxParticles) { + float fx = lowBorderX + random(hiBorderX - lowBorderX); + float fy = lowBorderY + random(hiBorderY - lowBorderY); float p = brightness(imgblur.pixels[ floor(fy)*imgblur.width + floor(fx) ])/255; // OK to use simple floor_ rounding here, because this is a one-time operation, // creating the initial distribution that will be iterated. - if (invertImg) - { + if (invertImg) { p = 1 - p; } @@ -306,150 +258,126 @@ void MainArraysetup() { } particleRouteLength = 0; - Generation = 0; + generation = 0; millisLastFrame = millis(); - RouteStep = 0; - VoronoiCalculated = false; + routeStep = 0; + voronoiCalculated = false; cellsCalculated = 0; vorPointsAdded = 0; voronoi = new Voronoi(); // Erase mesh - TempShowCells = true; - FileModeTSP = false; + tempShowCells = true; + fileModeTSP = false; } -void setup() -{ - - drawSpiral = true; - +void setup() { borderWidth = 6; - mainwidth = 800; mainheight = 600; ctrlheight = 110; - - // size(mainwidth, mainheight + ctrlheight, JAVA2D); - // xWidth: 800 - // yWidth: 600 + 110 = 710 - + fillingCircles = true; size(800, 710); - gfx = new ToxiclibsSupport(this); - - lowBorderX = borderWidth; //mainwidth*0.01; + lowBorderX = borderWidth; //mainwidth*0.01; hiBorderX = mainwidth - borderWidth; //mainwidth*0.98; lowBorderY = borderWidth; // mainheight*0.01; - hiBorderY = mainheight - borderWidth; //mainheight*0.98; + hiBorderY = mainheight - borderWidth; //mainheight*0.98; - int innerWidth = mainwidth - 2 * borderWidth; - int innerHeight = mainheight - 2 * borderWidth; + int innerWidth = mainwidth - 2 * borderWidth; + int innerHeight = mainheight - 2 * borderWidth; - clip=new SutherlandHodgemanClipper(new Rect(lowBorderX, lowBorderY, innerWidth, innerHeight)); + Rect rect = new Rect(lowBorderX, lowBorderY, innerWidth, innerHeight); + clip = new SutherlandHodgemanClipper(rect); - MainArraysetup(); // Main particle array setup + MainArraySetup(); // Main particle array setup frameRate(24); - smooth(); noStroke(); fill(153); // Background fill color, for control section textFont(createFont("SansSerif", 10)); - cp5 = new ControlP5(this); int leftcolumwidth = 225; + int guiTop = mainheight + 15; + int gui2ndRow = 4; // Spacing for firt row after group heading + int guiRowSpacing = 14; // Spacing for subsequent rows + int buttonHeight = mainheight + 19 + int(round(2.25 * guiRowSpacing)); - int GUItop = mainheight + 15; - int GUI2ndRow = 4; // Spacing for firt row after group heading - int GuiRowSpacing = 14; // Spacing for subsequent rows - int GUIFudge = mainheight + 19; // I wish that we didn't need ONE MORE of these stupid spacings. - int loadButtonHeight; + ControlGroup l3 = cp5.addGroup("Primary controls (Changing will restart)", 10, guiTop, 225); - ControlGroup l3 = cp5.addGroup("Primary controls (Changing will restart)", 10, GUItop, 225); + cp5.addSlider("sliderStipples", 10, 10000, maxParticles, 10, gui2ndRow, 150, 10) + .setGroup(l3); - cp5.addSlider("Stipples", 10, 10000, maxParticles, 10, GUI2ndRow, 150, 10).setGroup(l3); + cp5.addButton("buttonInvertImg", 10, 10, gui2ndRow + guiRowSpacing, 190, 10) + .setCaptionLabel("Black stipples, White Background") + .setGroup(l3); - InvertOnOff = cp5.addButton("INVERT_IMG", 10, 10, GUI2ndRow + GuiRowSpacing, 190, 10).setGroup(l3); - InvertOnOff.setCaptionLabel("Black stipples, White Background"); + cp5.addButton("buttonLoadFile", 10, 10, buttonHeight, 175, 10) + .setCaptionLabel("LOAD IMAGE FILE (.PNG, .JPG, or .GIF)"); + cp5.addButton("buttonQuit", 10, 205, buttonHeight, 30, 10) + .setCaptionLabel("Quit"); - loadButtonHeight = GUIFudge + int(round(2.25*GuiRowSpacing)); + cp5.addButton("buttonSaveStipples", 10, 25, buttonHeight + guiRowSpacing, 160, 10) + .setCaptionLabel("Save Stipple File (.SVG format)"); - Button LoadButton = cp5.addButton("LOAD_FILE", 10, 10, loadButtonHeight, 175, 10); - LoadButton.setCaptionLabel("LOAD IMAGE FILE (.PNG, .JPG, or .GIF)"); + cp5.addButton("buttonSavePath", 10, 25, buttonHeight + 2 * guiRowSpacing, 160, 10) + .setCaptionLabel("Save \"TSP\" Path (.SVG format)"); - cp5.addButton("QUIT", 10, 205, loadButtonHeight, 30, 10); + cp5.addButton("buttonFillCircles", 10, 10, buttonHeight + 3 * guiRowSpacing, 190, 10) + .setCaptionLabel("Generate Filled circles in output"); - cp5.addButton("SAVE_STIPPLES", 10, 25, loadButtonHeight + GuiRowSpacing, 160, 10); - cp5.getController("SAVE_STIPPLES").setCaptionLabel("Save Stipple File (.SVG format)"); + ControlGroup l5 = cp5.addGroup("Display Options - Updated on next generation", leftcolumwidth+50, guiTop, 225); - cp5.addButton("SAVE_PATH", 10, 25, loadButtonHeight + 2*GuiRowSpacing, 160, 10); - cp5.getController("SAVE_PATH").setCaptionLabel("Save \"TSP\" Path (.SVG format)"); + cp5.addSlider("sliderMinDotSize", .5, 8, 2, 10, 4, 140, 10) + .setCaptionLabel("Min. Dot Size") + .setValue(minDotSize) + .setGroup(l5); - FillCircles = cp5.addButton("FILL_CIRCLES", 10, 10, loadButtonHeight + 3*GuiRowSpacing, 190, 10); - FillCircles.setCaptionLabel("Generate Filled circles in output"); + cp5.addSlider("sliderDotSizeRange", 0, 20, 5, 10, 18, 140, 10) + .setCaptionLabel("Dot Size Range") + .setValue(dotSizeFactor) + .setGroup(l5); + cp5.addSlider("sliderWhiteCutoff", 0, 1, 0, 10, 32, 140, 10) + .setCaptionLabel("White Cutoff") + .setValue(cutoff) + .setGroup(l5); - ControlGroup l5 = cp5.addGroup("Display Options - Updated on next generation", leftcolumwidth+50, GUItop, 225); + cp5.addButton("buttonImgOnOff", 10, 10, 46, 90, 10) + .setCaptionLabel("Image BG >> Hide") + .setGroup(l5); - cp5.addSlider("Min_Dot_Size", .5, 8, 2, 10, 4, 140, 10).setGroup(l5); - cp5.getController("Min_Dot_Size").setValue(MinDotSize); - cp5.getController("Min_Dot_Size").setCaptionLabel("Min. Dot Size"); + cp5.addButton("buttonCellsOnOff", 10, 110, 46, 90, 10) + .setCaptionLabel("Cells >> Hide") + .setGroup(l5); - cp5.addSlider("Dot_Size_Range", 0, 20, 5, 10, 18, 140, 10).setGroup(l5); - cp5.getController("Dot_Size_Range").setValue(DotSizeFactor); - cp5.getController("Dot_Size_Range").setCaptionLabel("Dot Size Range"); + cp5.addButton("buttonPause", 10, 10, 60, 190, 10) + .setCaptionLabel("Pause (to calculate TSP path)") + .setGroup(l5); - cp5.addSlider("White_Cutoff", 0, 1, 0, 10, 32, 140, 10).setGroup(l5); - cp5.getController("White_Cutoff").setValue(cutoff); - cp5.getController("White_Cutoff").setCaptionLabel("White Cutoff"); + cp5.addButton("buttonOrderOnOff", 10, 10, 74, 190, 10) + .setCaptionLabel("Plotting path >> shown while paused") + .setGroup(l5); + textColumnStart = 2 * leftcolumwidth + 100; + maxDotSize = getMaxDotSize(minDotSize); - ImgOnOff = cp5.addButton("IMG_ON_OFF", 10, 10, 46, 90, 10); - ImgOnOff.setGroup(l5); - ImgOnOff.setCaptionLabel("Image BG >> Hide"); - - CellOnOff = cp5.addButton("CELLS_ON_OFF", 10, 110, 46, 90, 10); - CellOnOff.setGroup(l5); - CellOnOff.setCaptionLabel("Cells >> Hide"); - - PauseButton = cp5.addButton("Pause", 10, 10, 60, 190, 10); - PauseButton.setGroup(l5); - PauseButton.setCaptionLabel("Pause (to calculate TSP path)"); - - OrderOnOff = cp5.addButton("ORDER_ON_OFF", 10, 10, 74, 190, 10); - OrderOnOff.setGroup(l5); - OrderOnOff.setCaptionLabel("Plotting path >> shown while paused"); - - - - - - TextColumnStart = 2 * leftcolumwidth + 100; - - MaxDotSize = MinDotSize * (1 + DotSizeFactor); - - ReInitiallizeArray = false; - pausemode = false; - showBG = false; - invertImg = false; + saveNow = false; + showBG = false; showPath = true; showCells = false; + pausemode = false; + invertImg = false; fileLoaded = false; - SaveNow = 0; + reInitiallizeArray = false; } - -//void setup() { -// selectInput("Select a file to process:", "fileSelected"); -//} - - void fileSelected(File selection) { if (selection == null) { println("Window was closed or the user hit cancel."); @@ -461,287 +389,224 @@ void fileSelected(File selection) { // If a file was selected, print path to file println("Loaded file: " + loadPath); - String[] p = splitTokens(loadPath, "."); - boolean fileOK = false; + String ext = p[p.length - 1].toLowerCase(); - if ( p[p.length - 1].equals("GIF")) - fileOK = true; - if ( p[p.length - 1].equals("gif")) - fileOK = true; - if ( p[p.length - 1].equals("JPG")) - fileOK = true; - if ( p[p.length - 1].equals("jpg")) - fileOK = true; - if ( p[p.length - 1].equals("TGA")) - fileOK = true; - if ( p[p.length - 1].equals("tga")) - fileOK = true; - if ( p[p.length - 1].equals("PNG")) - fileOK = true; - if ( p[p.length - 1].equals("png")) - fileOK = true; + boolean fileOK = false; + fileOK = fileOK || ext.equals("gif"); + fileOK = fileOK || ext.equals("jpg"); + fileOK = fileOK || ext.equals("tga"); + fileOK = fileOK || ext.equals("png"); println("File OK: " + fileOK); if (fileOK) { imgload = loadImage(loadPath); fileLoaded = true; - // MainArraysetup(); - ReInitiallizeArray = true; + reInitiallizeArray = true; } else { // Can't load file - ErrorDisplay = "ERROR: BAD FILE TYPE"; - ErrorTime = millis(); - ErrorDisp = true; + errorDisplay = "ERROR: BAD FILE TYPE"; + errorTime = millis(); + errorDisp = true; } } } - - -void LOAD_FILE(float theValue) { +void buttonLoadFile(float theValue) { println(":::LOAD JPG, GIF or PNG FILE:::"); - selectInput("Select a file to process:", "fileSelected"); // Opens file chooser -} //End Load File - - - -void SAVE_PATH(float theValue) { - FileModeTSP = true; - SAVE_SVG(0); } - - -void SAVE_STIPPLES(float theValue) { - FileModeTSP = false; - SAVE_SVG(0); +void buttonSavePath(float theValue) { + fileModeTSP = true; + saveSvg(0); } - - +void buttonSaveStipples(float theValue) { + fileModeTSP = false; + saveSvg(0); +} void SavefileSelected(File selection) { if (selection == null) { // If a file was not selected println("No output file was selected..."); - ErrorDisplay = "ERROR: NO FILE NAME CHOSEN."; - ErrorTime = millis(); - ErrorDisp = true; + errorDisplay = "ERROR: NO FILE NAME CHOSEN."; + errorTime = millis(); + errorDisp = true; } else { - savePath = selection.getAbsolutePath(); String[] p = splitTokens(savePath, "."); - boolean fileOK = false; - - if ( p[p.length - 1].equals("SVG")) - fileOK = true; - if ( p[p.length - 1].equals("svg")) - fileOK = true; - - if (fileOK == false) - savePath = savePath + ".svg"; - + boolean fileOK = p[p.length - 1].toLowerCase().equals("svg"); + if (!fileOK) savePath = savePath + ".svg"; // If a file was selected, print path to folder println("Save file: " + savePath); - SaveNow = 1; - showPath = true; + saveNow = true; + showPath = true; - ErrorDisplay = "SAVING FILE..."; - ErrorTime = millis(); - ErrorDisp = true; + errorDisplay = "SAVING FILE..."; + errorTime = millis(); + errorDisp = true; } } - - - -void SAVE_SVG(float theValue) { - - if (pausemode != true) { - Pause(0.0); - ErrorDisplay = "Error: PAUSE before saving."; - ErrorTime = millis(); - ErrorDisp = true; +void saveSvg(float theValue) { + if (!pausemode) { + buttonPause(0.0); + errorDisplay = "Error: PAUSE before saving."; + errorTime = millis(); + errorDisp = true; } else { - selectOutput("Output .svg file name:", "SavefileSelected"); } } - - - -void QUIT(float theValue) { +void buttonQuit(float theValue) { exit(); } - -void ORDER_ON_OFF(float theValue) { +void buttonOrderOnOff(float theValue) { + Button orderOnOff = (Button)cp5.getController("buttonOrderOnOff"); if (showPath) { - showPath = false; - OrderOnOff.setCaptionLabel("Plotting path >> Hide"); + showPath = false; + orderOnOff.setCaptionLabel("Plotting path >> Hide"); } else { - showPath = true; - OrderOnOff.setCaptionLabel("Plotting path >> Shown while paused"); + showPath = true; + orderOnOff.setCaptionLabel("Plotting path >> Shown while paused"); } } -void CELLS_ON_OFF(float theValue) { +void buttonCellsOnOff(float theValue) { + Button cellsOnOff = (Button)cp5.getController("buttonCellsOnOff"); if (showCells) { - showCells = false; - CellOnOff.setCaptionLabel("Cells >> Hide"); + showCells = false; + cellsOnOff.setCaptionLabel("Cells >> Hide"); } else { - showCells = true; - CellOnOff.setCaptionLabel("Cells >> Show"); + showCells = true; + cellsOnOff.setCaptionLabel("Cells >> Show"); } } - - -void IMG_ON_OFF(float theValue) { +void buttonImgOnOff(float theValue) { + Button imgOnOffButton = (Button)cp5.getController("buttonImgOnOff"); if (showBG) { - showBG = false; - ImgOnOff.setCaptionLabel("Image BG >> Hide"); + showBG = false; + imgOnOffButton.setCaptionLabel("Image BG >> Hide"); } else { - showBG = true; - ImgOnOff.setCaptionLabel("Image BG >> Show"); + showBG = true; + imgOnOffButton.setCaptionLabel("Image BG >> Show"); } } - -void INVERT_IMG(float theValue) { +void buttonInvertImg(float theValue) { + Slider cutoffSlider = (Slider)cp5.getController("sliderWhiteCutoff"); + Button invertImgButton = (Button)cp5.getController("buttonInvertImg"); if (invertImg) { - invertImg = false; - InvertOnOff.setCaptionLabel("Black stipples, White Background"); - cp5.getController("White_Cutoff").setCaptionLabel("White Cutoff"); + invertImg = false; + invertImgButton.setCaptionLabel("Black stipples, White background"); + cutoffSlider.setCaptionLabel("White Cutoff"); } else { - invertImg = true; - InvertOnOff.setCaptionLabel("White stipples, Black Background"); - cp5.getController("White_Cutoff").setCaptionLabel("Black Cutoff"); + invertImg = true; + invertImgButton.setCaptionLabel("White stipples, Black background"); + cutoffSlider.setCaptionLabel("Black Cutoff"); } - ReInitiallizeArray = true; - pausemode = false; + reInitiallizeArray = true; + pausemode = false; } - - -void FILL_CIRCLES(float theValue) { - if (drawSpiral) { - drawSpiral = false; - FillCircles.setCaptionLabel("Generate Open circles in output"); +void buttonFillCircles(float theValue) { + Button fillCircleButton = (Button)cp5.getController("buttonFillCircles"); + if (fillingCircles) { + fillingCircles = false; + fillCircleButton.setCaptionLabel("Generate Open circles in output"); } else { - drawSpiral = true; - FillCircles.setCaptionLabel("Generate Filled circles in output"); + fillingCircles = true; + fillCircleButton.setCaptionLabel("Generate Filled circles in output"); } } - -void Pause(float theValue) { +void buttonPause(float theValue) { // Main particle array setup (to be repeated if necessary): - - if (pausemode) - { + Button pauseButton = (Button)cp5.getController("buttonPause"); + if (pausemode) { pausemode = false; println("Resuming."); - PauseButton.setCaptionLabel("Pause (to calculate TSP path)"); - } else - { + pauseButton.setCaptionLabel("Pause (to calculate TSP path)"); + } else { pausemode = true; println("Paused. Press PAUSE again to resume."); - PauseButton.setCaptionLabel("Paused (calculating TSP path)"); + pauseButton.setCaptionLabel("Paused (calculating TSP path)"); } - RouteStep = 0; + routeStep = 0; } - -boolean overRect(int x, int y, int width, int height) -{ - if (mouseX >= x && mouseX <= x+width && - mouseY >= y && mouseY <= y+height) { - return true; - } else { - return false; - } +boolean overRect(int x, int y, int width, int height) { + return mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height; } -void Stipples(int inValue) { - - if (maxParticles != (int) inValue) { +void sliderStipples(int inValue) { + if (maxParticles != inValue) { println("Update: Stipple Count -> " + inValue); - ReInitiallizeArray = true; - pausemode = false; + reInitiallizeArray = true; + pausemode = false; } } - - - - -void Min_Dot_Size(float inValue) { - if (MinDotSize != inValue) { - println("Update: Min_Dot_Size -> "+inValue); - MinDotSize = inValue; - MaxDotSize = MinDotSize* (1 + DotSizeFactor); +void sliderMinDotSize(float inValue) { + if (minDotSize != inValue) { + println("Update: sliderMinDotSize -> " + inValue); + minDotSize = inValue; + maxDotSize = getMaxDotSize(minDotSize); } } - -void Dot_Size_Range(float inValue) { - if (DotSizeFactor != inValue) { - println("Update: Dot Size Range -> "+inValue); - DotSizeFactor = inValue; - MaxDotSize = MinDotSize* (1 + DotSizeFactor); +void sliderDotSizeRange(float inValue) { + if (dotSizeFactor != inValue) { + println("Update: Dot Size Range -> " + inValue); + dotSizeFactor = inValue; + maxDotSize = getMaxDotSize(minDotSize); } } - -void White_Cutoff(float inValue) { +void sliderWhiteCutoff(float inValue) { if (cutoff != inValue) { - println("Update: White_Cutoff -> "+inValue); + println("Update: White_Cutoff -> " + inValue); cutoff = inValue; - RouteStep = 0; // Reset TSP path + routeStep = 0; // Reset TSP path } } +float getMaxDotSize(float minDotSize) { + return minDotSize * (1 + dotSizeFactor); +} -void DoBackgrounds() { - if (showBG) - image(img, 0, 0); // Show original (cropped and scaled, but not blurred!) image in background - else { - - if (invertImg) - fill(0); - else - fill(255); - +void doBackgrounds() { + if (showBG) { + image(img, 0, 0); // Show original (cropped and scaled, but not blurred!) image in background + } else { + fill(invertImg ? 0 : 255); rect(0, 0, mainwidth, mainheight); } } -void OptimizePlotPath() -{ +void optimizePlotPath() { int temp; // Calculate and show "optimized" plotting path, beneath points. - StatusDisplay = "Optimizing plotting path"; + statusDisplay = "Optimizing plotting path"; /* - if (RouteStep % 100 == 0) { - println("RouteStep:" + RouteStep); - println("fps = " + frameRate ); - } - */ + if (routeStep % 100 == 0) { + println("RouteStep:" + routeStep); + println("fps = " + frameRate ); + } + */ Vec2D p1; - - if (RouteStep == 0) - { - + if (routeStep == 0) { float cutoffScaled = 1 - cutoff; // Begin process of optimizing plotting route, by flagging particles that will be shown. @@ -750,20 +615,20 @@ void OptimizePlotPath() boolean particleRouteTemp[] = new boolean[maxParticles]; for (int i = 0; i < maxParticles; ++i) { - particleRouteTemp[i] = false; int px = (int) particles[i].x; int py = (int) particles[i].y; - if ((px >= imgblur.width) || (py >= imgblur.height) || (px < 0) || (py < 0)) + if ((px >= imgblur.width) || (py >= imgblur.height) || (px < 0) || (py < 0)) { continue; + } - float v = (brightness(imgblur.pixels[ py*imgblur.width + px ]))/255; + float v = (brightness(imgblur.pixels[py * imgblur.width + px])) / 255; - if (invertImg) + if (invertImg) { v = 1 - v; - + } if (v < cutoffScaled) { particleRouteTemp[i] = true; @@ -774,9 +639,7 @@ void OptimizePlotPath() particleRoute = new int[particleRouteLength]; int tempCounter = 0; for (int i = 0; i < maxParticles; ++i) { - - if (particleRouteTemp[i]) - { + if (particleRouteTemp[i]) { particleRoute[tempCounter] = i; tempCounter++; } @@ -784,23 +647,21 @@ void OptimizePlotPath() // These are the ONLY points to be drawn in the tour. } - if (RouteStep < (particleRouteLength - 2)) - { - + if (routeStep < (particleRouteLength - 2)) { // Nearest neighbor ("Simple, Greedy") algorithm path optimization: - int StopPoint = RouteStep + 1000; // 1000 steps per frame displayed; you can edit this number! + int StopPoint = routeStep + 1000; // 1000 steps per frame displayed; you can edit this number! - if (StopPoint > (particleRouteLength - 1)) + if (StopPoint > (particleRouteLength - 1)) { StopPoint = particleRouteLength - 1; + } - for (int i = RouteStep; i < StopPoint; ++i) { - - p1 = particles[particleRoute[RouteStep]]; + for (int i = routeStep; i < StopPoint; ++i) { + p1 = particles[particleRoute[routeStep]]; int ClosestParticle = 0; float distMin = Float.MAX_VALUE; - for (int j = RouteStep + 1; j < (particleRouteLength - 1); ++j) { + for (int j = routeStep + 1; j < (particleRouteLength - 1); ++j) { Vec2D p2 = particles[particleRoute[j]]; float dx = p1.x - p2.x; @@ -813,33 +674,30 @@ void OptimizePlotPath() } } - temp = particleRoute[RouteStep + 1]; - // p1 = particles[particleRoute[RouteStep + 1]]; - particleRoute[RouteStep + 1] = particleRoute[ClosestParticle]; + temp = particleRoute[routeStep + 1]; + // p1 = particles[particleRoute[routeStep + 1]]; + particleRoute[routeStep + 1] = particleRoute[ClosestParticle]; particleRoute[ClosestParticle] = temp; - if (RouteStep < (particleRouteLength - 1)) - RouteStep++; - else - { + if (routeStep < (particleRouteLength - 1)) { + routeStep++; + } else { println("Now optimizing plot path" ); } } - } else - { // Initial routing is complete + } else { // Initial routing is complete // 2-opt heuristic optimization: // Identify a pair of edges that would become shorter by reversing part of the tour. for (int i = 0; i < 90000; ++i) { // 1000 tests per frame; you can edit this number. - int indexA = floor(random(particleRouteLength - 1)); int indexB = floor(random(particleRouteLength - 1)); - if (Math.abs(indexA - indexB) < 2) + if (Math.abs(indexA - indexB) < 2) { continue; + } - if (indexB < indexA) - { // swap A, B. + if (indexB < indexA) { // swap A, B. temp = indexB; indexB = indexA; indexA = temp; @@ -853,31 +711,28 @@ void OptimizePlotPath() // Original distance: float dx = a0.x - a1.x; float dy = a0.y - a1.y; - float distance = (float) (dx*dx+dy*dy); // Only a comparison; do not need sqrt factor! + float distance = (float)(dx*dx+dy*dy); // Only a comparison; do not need sqrt factor! dx = b0.x - b1.x; dy = b0.y - b1.y; - distance += (float) (dx*dx+dy*dy); // Only a comparison; do not need sqrt factor! + distance += (float)(dx*dx+dy*dy); // Only a comparison; do not need sqrt factor! // Possible shorter distance? dx = a0.x - b0.x; dy = a0.y - b0.y; - float distance2 = (float) (dx*dx+dy*dy); // Only a comparison; do not need sqrt factor! + float distance2 = (float)(dx*dx+dy*dy); // Only a comparison; do not need sqrt factor! dx = a1.x - b1.x; dy = a1.y - b1.y; - distance2 += (float) (dx*dx+dy*dy); // Only a comparison; do not need sqrt factor! + distance2 += (float)(dx*dx+dy*dy); // Only a comparison; do not need sqrt factor! - if (distance2 < distance) - { + if (distance2 < distance) { // Reverse tour between a1 and b0. int indexhigh = indexB; int indexlow = indexA + 1; - // println("Shorten!" + frameRate ); - - while (indexhigh > indexlow) - { + // println("Shorten!" + frameRate ); + while (indexhigh > indexlow) { temp = particleRoute[indexlow]; particleRoute[indexlow] = particleRoute[indexhigh]; particleRoute[indexhigh] = temp; @@ -889,42 +744,32 @@ void OptimizePlotPath() } } - frameTime = (millis() - millisLastFrame)/1000; + frameTime = (millis() - millisLastFrame) / 1000; millisLastFrame = millis(); } - - - - - - -void doPhysics() -{ // Iterative relaxation via weighted Lloyd's algorithm. - +void doPhysics() { // Iterative relaxation via weighted Lloyd's algorithm. int temp; int CountTemp; - if (VoronoiCalculated == false) - { // Part I: Calculate voronoi cell diagram of the points. + if (!voronoiCalculated) { + // Part I: Calculate voronoi cell diagram of the points. - StatusDisplay = "Calculating Voronoi diagram "; + statusDisplay = "Calculating Voronoi diagram "; - // float millisBaseline = millis(); // Baseline for timing studies - // println("Baseline. Time = " + (millis() - millisBaseline) ); + // float millisBaseline = millis(); // Baseline for timing studies + // println("Baseline. Time = " + (millis() - millisBaseline) ); - - if (vorPointsAdded == 0) + if (vorPointsAdded == 0) { voronoi = new Voronoi(); // Erase mesh + } temp = vorPointsAdded + 500; // This line: VoronoiPointsPerPass (Feel free to edit this number.) - if (temp > maxParticles) + if (temp > maxParticles) { temp = maxParticles; + } - // for (int i = vorPointsAdded; i < temp; ++i) { for (int i = vorPointsAdded; i < temp; i++) { - - // Optional, for diagnostics::: // println("particles[i].x, particles[i].y " + particles[i].x + ", " + particles[i].y ); @@ -932,30 +777,27 @@ void doPhysics() vorPointsAdded++; } - if (vorPointsAdded >= maxParticles) - { + if (vorPointsAdded >= maxParticles) { + // println("Points added. Time = " + (millis() - millisBaseline) ); - // println("Points added. Time = " + (millis() - millisBaseline) ); - - cellsTotal = (voronoi.getRegions().size()); + cellsTotal = voronoi.getRegions().size(); vorPointsAdded = 0; cellsCalculated = 0; cellsCalculatedLast = 0; - RegionList = new Polygon2D[cellsTotal]; + regionList = new Polygon2D[cellsTotal]; int i = 0; for (Polygon2D poly : voronoi.getRegions()) { - RegionList[i++] = poly; // Build array of polygons + regionList[i++] = poly; // Build array of polygons } - VoronoiCalculated = true; + voronoiCalculated = true; } - } else - { // Part II: Calculate weighted centroids of cells. + } else { // Part II: Calculate weighted centroids of cells. // float millisBaseline = millis(); // println("fps = " + frameRate ); - StatusDisplay = "Calculating weighted centroids"; + statusDisplay = "Calculating weighted centroids"; temp = cellsCalculated + 500; // This line: CentroidsPerPass (Feel free to edit this number.) // Higher values give slightly faster computation, but a less responsive GUI. @@ -965,38 +807,29 @@ void doPhysics() // Time/frame @ 200: 1.575 @ 50 // Time/frame @ 500: 1.44 @ 50 - if (temp > cellsTotal) - { + if (temp > cellsTotal) { temp = cellsTotal; } for (int i=cellsCalculated; i< temp; i++) { - float xMax = 0; float xMin = mainwidth; float yMax = 0; float yMin = mainheight; float xt, yt; - Polygon2D region = clip.clipPolygon(RegionList[i]); - + Polygon2D region = clip.clipPolygon(regionList[i]); for (Vec2D v : region.vertices) { - xt = v.x; yt = v.y; - if (xt < xMin) - xMin = xt; - if (xt > xMax) - xMax = xt; - if (yt < yMin) - yMin = yt; - if (yt > yMax) - yMax = yt; + if (xt < xMin) xMin = xt; + if (xt > xMax) xMax = xt; + if (yt < yMin) yMin = yt; + if (yt > yMax) yMax = yt; } - float xDiff = xMax - xMin; float yDiff = yMax - yMin; float maxSize = max(xDiff, yDiff); @@ -1007,20 +840,18 @@ void doPhysics() // Maximum voronoi cell extent should be between // cellBuffer/2 and cellBuffer in size. - while (maxSize > cellBuffer) - { + while (maxSize > cellBuffer) { scaleFactor *= 0.5; maxSize *= 0.5; } - while (maxSize < (cellBuffer/2)) - { + while (maxSize < (cellBuffer / 2)) { scaleFactor *= 2; maxSize *= 2; } - if ((minSize * scaleFactor) > (cellBuffer/2)) - { // Special correction for objects of near-unity (square-like) aspect ratio, + if ((minSize * scaleFactor) > (cellBuffer/2)) { + // Special correction for objects of near-unity (square-like) aspect ratio, // which have larger area *and* where it is less essential to find the exact centroid: scaleFactor *= 0.5; } @@ -1032,14 +863,11 @@ void doPhysics() float dSum = 0; float PicDensity = 1.0; - - if (invertImg) + if (invertImg) { for (float x=xMin; x<=xMax; x += StepSize) { for (float y=yMin; y<=yMax; y += StepSize) { - Vec2D p0 = new Vec2D(x, y); if (region.containsPoint(p0)) { - // Thanks to polygon clipping, NO vertices will be beyond the sides of imgblur. PicDensity = 0.001 + (brightness(imgblur.pixels[ round(y)*imgblur.width + round(x) ])); @@ -1048,36 +876,32 @@ void doPhysics() dSum += PicDensity; } } - } else + } + } else { for (float x=xMin; x<=xMax; x += StepSize) { for (float y=yMin; y<=yMax; y += StepSize) { - Vec2D p0 = new Vec2D(x, y); if (region.containsPoint(p0)) { - // Thanks to polygon clipping, NO vertices will be beyond the sides of imgblur. PicDensity = 255.001 - (brightness(imgblur.pixels[ round(y)*imgblur.width + round(x) ])); - xSum += PicDensity * x; ySum += PicDensity * y; dSum += PicDensity; } } } + } - if (dSum > 0) - { + if (dSum > 0) { xSum /= dSum; ySum /= dSum; } Vec2D centr; - - float xTemp = (xSum); - float yTemp = (ySum); - + float xTemp = xSum; + float yTemp = ySum; if ((xTemp <= lowBorderX) || (xTemp >= hiBorderX) || (yTemp <= lowBorderY) || (yTemp >= hiBorderY)) { // If new centroid is computed to be outside the visible region, use the geometric centroid instead. @@ -1088,14 +912,10 @@ void doPhysics() // Enforce sides, if absolutely necessary: (Failure to do so *will* cause a crash, eventually.) - if (xTemp <= lowBorderX) - xTemp = lowBorderX + 1; - if (xTemp >= hiBorderX) - xTemp = hiBorderX - 1; - if (yTemp <= lowBorderY) - yTemp = lowBorderY + 1; - if (yTemp >= hiBorderY) - yTemp = hiBorderY - 1; + if (xTemp <= lowBorderX) xTemp = lowBorderX + 1; + if (xTemp >= hiBorderX) xTemp = hiBorderX - 1; + if (yTemp <= lowBorderY) yTemp = lowBorderY + 1; + if (yTemp >= hiBorderY) yTemp = hiBorderY - 1; } particles[i].x = xTemp; @@ -1104,15 +924,13 @@ void doPhysics() cellsCalculated++; } - // println("cellsCalculated = " + cellsCalculated ); // println("cellsTotal = " + cellsTotal ); - if (cellsCalculated >= cellsTotal) - { - VoronoiCalculated = false; - Generation++; - println("Generation = " + Generation ); + if (cellsCalculated >= cellsTotal) { + voronoiCalculated = false; + generation++; + println("Generation = " + generation ); frameTime = (millis() - millisLastFrame)/1000; millisLastFrame = millis(); @@ -1129,20 +947,20 @@ String makeSpiral ( float xOrigin, float yOrigin, float turns, float radius) String spiralSVG = " 1.0) // For small enough circles, skip the fill, and just draw the circle. + if (turns > 1.0) { // For small enough circles, skip the fill, and just draw the circle. for (int i = startPoint; i <= stopPoint; i = i+1) { angle = i * AngleStep; x = xOrigin + ScaledRadiusPerTurn * angle * cos(angle); y = yOrigin + ScaledRadiusPerTurn * angle * sin(angle); spiralSVG += x + "," + y + " "; } + } // Last turn is a circle: float CircleRad = ScaledRadiusPerTurn * angle; @@ -1155,118 +973,89 @@ String makeSpiral ( float xOrigin, float yOrigin, float turns, float radius) spiralSVG += x + "," + y + " "; } - spiralSVG += "\" />" ; - return spiralSVG; } - - -void draw() -{ - +void draw() { int i = 0; int temp; - float dotScale = (MaxDotSize - MinDotSize); + float dotScale = (maxDotSize - minDotSize); float cutoffScaled = 1 - cutoff; - if (ReInitiallizeArray) { - maxParticles = (int) cp5.getController("Stipples").getValue(); // Only change this here! + if (reInitiallizeArray) { + maxParticles = (int)cp5.getController("sliderStipples").getValue(); // Only change this here! - MainArraysetup(); - ReInitiallizeArray = false; + MainArraySetup(); + reInitiallizeArray = false; } - if (pausemode && (VoronoiCalculated == false)) - OptimizePlotPath(); - else + if (pausemode && !voronoiCalculated) { + optimizePlotPath(); + } else { doPhysics(); + } - - if (pausemode) - { - - DoBackgrounds(); + if (pausemode) { + doBackgrounds(); // Draw paths: if ( showPath ) { - stroke(128, 128, 255); // Stroke color (blue) strokeWeight (1); for ( i = 0; i < (particleRouteLength - 1); ++i) { - Vec2D p1 = particles[particleRoute[i]]; Vec2D p2 = particles[particleRoute[i + 1]]; - line(p1.x, p1.y, p2.x, p2.y); } } - - if (invertImg) - { - stroke(255); - fill (0); - } else - { - stroke(0); - fill(255); - } - - strokeWeight (1); - + stroke(invertImg ? 255 : 0); + fill (invertImg ? 0 : 255); + strokeWeight(1); for ( i = 0; i < particleRouteLength; ++i) { // Only show "routed" particles-- those above the white cutoff. Vec2D p1 = particles[particleRoute[i]]; - int px = (int) p1.x; - int py = (int) p1.y; + int px = (int)p1.x; + int py = (int)p1.y; - float v = (brightness(imgblur.pixels[ py*imgblur.width + px ]))/255; + float v = (brightness(imgblur.pixels[py * imgblur.width + px])) / 255; - if (invertImg) - v = 1 - v; + if (invertImg) v = 1 - v; - if (drawSpiral) - { - strokeWeight (MaxDotSize - v * dotScale); + if (fillingCircles) { + strokeWeight (maxDotSize - v * dotScale); point(px, py); - } else - { - float DotSize = (MaxDotSize - v * dotScale); + } else { + float DotSize = (maxDotSize - v * dotScale); ellipse(px, py, DotSize, DotSize); } } - } else - { // NOT in pause mode. i.e., just displaying stipples. + } else { // NOT in pause mode. i.e., just displaying stipples. if (cellsCalculated == 0) { + doBackgrounds(); - DoBackgrounds(); - - if (Generation == 0) - { - TempShowCells = true; + if (generation == 0) { + tempShowCells = true; } - if (showCells || TempShowCells) { // Draw voronoi cells, over background. + if (showCells || tempShowCells) { // Draw voronoi cells, over background. strokeWeight(1); noFill(); - - if (invertImg && (showBG == false)) // TODO -- if invertImg AND NOT background + if (invertImg && !showBG) { stroke(100); - else + } else { stroke(200); - - // stroke(200); + } i = 0; for (Polygon2D poly : voronoi.getRegions()) { - //RegionList[i++] = poly; + //regionList[i++] = poly; gfx.polygon2D(clip.clipPolygon(poly)); } } @@ -1274,7 +1063,7 @@ void draw() if (showCells) { // Show "before and after" centroids, when polygons are shown. - strokeWeight (MinDotSize); // Normal w/ Min & Max dot size + strokeWeight (minDotSize); // Normal w/ Min & Max dot size for ( i = 0; i < maxParticles; ++i) { int px = (int) particles[i].x; @@ -1287,23 +1076,19 @@ void draw() //float v = (brightness(imgblur.pixels[ py*imgblur.width + px ]))/255; //if (invertImg) //v = 1 - v; - //strokeWeight (MaxDotSize - v * dotScale); + //strokeWeight (maxDotSize - v * dotScale); point(px, py); - } } } } else { // Stipple calculation is still underway - if (TempShowCells) - { - DoBackgrounds(); - TempShowCells = false; + if (tempShowCells) { + doBackgrounds(); + tempShowCells = false; } - - if (invertImg) { stroke(255); fill(0); @@ -1315,27 +1100,22 @@ void draw() strokeWeight(1); for ( i = cellsCalculatedLast; i < cellsCalculated; ++i) { - int px = (int) particles[i].x; int py = (int) particles[i].y; if ((px >= imgblur.width) || (py >= imgblur.height) || (px < 0) || (py < 0)) continue; { - float v = (brightness(imgblur.pixels[ py*imgblur.width + px ]))/255; + float v = (brightness(imgblur.pixels[py * imgblur.width + px])) / 255; - if (invertImg) - v = 1 - v; + if (invertImg) v = 1 - v; if (v < cutoffScaled) { - - if (drawSpiral) - { - strokeWeight (MaxDotSize - v * dotScale); + if (fillingCircles) { + strokeWeight (maxDotSize - v * dotScale); point(px, py); - } else - { - float DotSize = (MaxDotSize - v * dotScale); + } else { + float DotSize = (maxDotSize - v * dotScale); ellipse(px, py, DotSize, DotSize); } } @@ -1351,38 +1131,33 @@ void draw() rect(0, mainheight, mainwidth, height); // Control area fill // Underlay for hyperlink: - if (overRect(TextColumnStart - 10, mainheight + 35, 205, 20) ) - { + if (overRect(textColumnStart - 10, mainheight + 35, 205, 20) ) { fill(150); - rect(TextColumnStart - 10, mainheight + 35, 205, 20); + rect(textColumnStart - 10, mainheight + 35, 205, 20); } fill(255); // Text color - text("StippleGen 2 (v. 2.4.0)", TextColumnStart, mainheight + 15); - text("by Evil Mad Scientist Laboratories", TextColumnStart, mainheight + 30); - text("www.evilmadscientist.com/go/stipple2", TextColumnStart, mainheight + 50); + text("StippleGen 2 (v. 2.4.0)", textColumnStart, mainheight + 15); + text("by Evil Mad Scientist Laboratories", textColumnStart, mainheight + 30); + text("www.evilmadscientist.com/go/stipple2", textColumnStart, mainheight + 50); - text("Generations completed: " + Generation, TextColumnStart, mainheight + 85); - text("Time/Frame: " + frameTime + " s", TextColumnStart, mainheight + 100); + text("Generations completed: " + generation, textColumnStart, mainheight + 85); + text("Time/Frame: " + frameTime + " s", textColumnStart, mainheight + 100); - - if (ErrorDisp) - { + if (errorDisp) { fill(255, 0, 0); // Text color - text(ErrorDisplay, TextColumnStart, mainheight + 70); - if ((millis() - ErrorTime) > 8000) - ErrorDisp = false; - } else - text("Status: " + StatusDisplay, TextColumnStart, mainheight + 70); + text(errorDisplay, textColumnStart, mainheight + 70); + errorDisp = !(millis() - errorTime > 8000); + } else { + text("Status: " + statusDisplay, textColumnStart, mainheight + 70); + } + if (saveNow) { + statusDisplay = "Saving SVG File"; + saveNow = false; - if (SaveNow > 0) { - - StatusDisplay = "Saving SVG File"; - SaveNow = 0; - - FileOutput = loadStrings("header.txt"); + fileOutput = loadStrings("header.txt"); String rowTemp; @@ -1390,34 +1165,27 @@ void draw() int xOffset = (int) (1600 - (SVGscale * mainwidth / 2)); int yOffset = (int) (400 - (SVGscale * mainheight / 2)); - - if (FileModeTSP) - { // Plot the PATH between the points only. - + if (fileModeTSP) { // Plot the PATH between the points only. println("Save TSP File (SVG)"); // Path header:: rowTemp = ""); // End path description + fileOutput = append(fileOutput, "\" />"); // End path description } else { println("Save Stipple File (SVG)"); for ( i = 0; i < particleRouteLength; ++i) { - Vec2D p1 = particles[particleRoute[i]]; int px = floor(p1.x); @@ -1425,62 +1193,50 @@ void draw() float v = (brightness(imgblur.pixels[ py*imgblur.width + px ]))/255; - if (invertImg) - v = 1 - v; + if (invertImg) v = 1 - v; - float dotrad = (MaxDotSize - v * dotScale)/2; + float dotrad = (maxDotSize - v * dotScale) / 2; float xTemp = SVGscale*p1.x + xOffset; float yTemp = SVGscale*p1.y + yOffset; - - if (drawSpiral) - { + if (fillingCircles) { rowTemp = makeSpiral ( xTemp, yTemp, dotrad / 2.0, dotrad); - } else - { + } else { rowTemp = " "; } //Typ: - FileOutput = append(FileOutput, rowTemp); + fileOutput = append(fileOutput, rowTemp); } } - - // SVG footer: - FileOutput = append(FileOutput, ""); - saveStrings(savePath, FileOutput); - FileModeTSP = false; // reset for next time + fileOutput = append(fileOutput, ""); + saveStrings(savePath, fileOutput); + fileModeTSP = false; // reset for next time - if (FileModeTSP) - ErrorDisplay = "TSP Path .SVG file Saved"; - else - ErrorDisplay = "Stipple .SVG file saved "; + if (fileModeTSP) { + errorDisplay = "TSP Path .SVG file Saved"; + } else { + errorDisplay = "Stipple .SVG file saved "; + } - ErrorTime = millis(); - ErrorDisp = true; + errorTime = millis(); + errorDisp = true; } } - - void mousePressed() { - - // rect(TextColumnStart, mainheight, 200, 75); - - if (overRect(TextColumnStart - 15, mainheight + 35, 205, 20) ) + // rect(textColumnStart, mainheight, 200, 75); + if (overRect(textColumnStart - 15, mainheight + 35, 205, 20) ) { link("http://www.evilmadscientist.com/go/stipple2"); + } } - - - void keyPressed() { - if (key == 'x') - { // If this program doesn't run slowly enough for you, + if (key == 'x') { // If this program doesn't run slowly enough for you, // simply press the 'x' key on your keyboard. :) - cp5.getController("Stipples").setMax(50000.0); + cp5.getController("sliderStipples").setMax(50000.0); } -} \ No newline at end of file +}