kopia lustrzana https://github.com/gwygonik/SquiggleDraw
Major rewrite of rendering
- Rewrote curve generation to use curved splines instead of polylines that sample sine waves. Eliminates aliasing (e.g., at high frequency settings) and improves plot quality. - Added "connect ends" GUI control. Reverses every other line and adds curved endcaps to eliminate pen lifts while plotting - Cap maximum frequency, based on line width. - Reduce maximum value of frequency GUI control - Remove white background from generated PDF files - Added list of contributors - Automated Processing code cleanuppull/12/head
rodzic
622c822172
commit
f014669c85
|
@ -3,8 +3,24 @@
|
|||
// A processing sketch by Gregg Wygonik
|
||||
//
|
||||
// https://github.com/gwygonik/SquiggleDraw
|
||||
//
|
||||
// Contributions
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Additional credits
|
||||
|
||||
Contributions by Maksim Surguy
|
||||
https://github.com/msurguy
|
||||
|
||||
Contributions by Ivan Moroz (sNow)
|
||||
https://github.com/sNow32/a
|
||||
|
||||
Contributions by Windell H. Oskay
|
||||
www.evilmadscientist.com
|
||||
https://github.com/evil-mad/
|
||||
|
||||
*/
|
||||
|
||||
|
||||
import controlP5.*;
|
||||
import processing.svg.*;
|
||||
|
@ -17,7 +33,6 @@ PShape liner;
|
|||
PImage p1;
|
||||
PImage p2;
|
||||
|
||||
|
||||
int ystep = 160;
|
||||
int ymult = 6;
|
||||
int xstep = 3;
|
||||
|
@ -29,9 +44,9 @@ float r = 0.0;
|
|||
float a = 0.0;
|
||||
int strokeWidth = 1;
|
||||
|
||||
float startx,starty, z;
|
||||
float startx, starty, z;
|
||||
|
||||
int b,oldb;
|
||||
int b, oldb;
|
||||
int maxB = 255;
|
||||
int minB = 0;
|
||||
|
||||
|
@ -43,64 +58,70 @@ boolean needsReload = true;
|
|||
|
||||
boolean invert = false;
|
||||
|
||||
boolean connectEnds = false;
|
||||
|
||||
//! TODO: scroll bar for big images
|
||||
|
||||
|
||||
String imageName = "Rachel-Carson.jpg";
|
||||
|
||||
void setup() {
|
||||
size(100,100);
|
||||
size(100, 100);
|
||||
//surface.setResizable(true);
|
||||
loadMainImage(imageName);
|
||||
createSecondaryImage();
|
||||
|
||||
gui = new ControlP5(this);
|
||||
gui.addSlider("sldLines").setSize(130,30).setCaptionLabel("Number of Lines").setPosition(10,20).setRange(10,200).setValue(120).setColorCaptionLabel(color(0));
|
||||
gui.addSlider("sldLines").setSize(130, 30).setCaptionLabel("Number of Lines").setPosition(10, 20).setRange(10, 200).setValue(120).setColorCaptionLabel(color(0));
|
||||
gui.getController("sldLines").getCaptionLabel().align(ControlP5.LEFT, ControlP5.TOP_OUTSIDE);
|
||||
|
||||
gui.addToggle("tglInvert").setCaptionLabel("Invert Colors").setPosition(10,80).setValue(false).setMode(ControlP5.SWITCH).setColorCaptionLabel(color(0));
|
||||
gui.addToggle("tglInvert").setCaptionLabel("Invert Colors").setPosition(10, 80).setValue(false).setMode(ControlP5.SWITCH).setColorCaptionLabel(color(0));
|
||||
gui.getController("tglInvert").getCaptionLabel().align(ControlP5.LEFT, ControlP5.TOP_OUTSIDE);
|
||||
|
||||
gui.addSlider("sldAmplitude").setSize(130,30).setCaptionLabel("Squiggle Strength").setPosition(10,140).setRange(0,20).setValue(13).setColorCaptionLabel(color(0));
|
||||
gui.addToggle("tglConnect").setCaptionLabel("Connect Ends").setPosition(80, 80).setValue(false).setMode(ControlP5.SWITCH).setColorCaptionLabel(color(0));
|
||||
gui.getController("tglConnect").getCaptionLabel().align(ControlP5.LEFT, ControlP5.TOP_OUTSIDE);
|
||||
|
||||
gui.addSlider("sldAmplitude").setSize(130, 30).setCaptionLabel("Squiggle Strength").setPosition(10, 140).setRange(0, 20).setValue(13).setColorCaptionLabel(color(0));
|
||||
gui.getController("sldAmplitude").getCaptionLabel().align(ControlP5.LEFT, ControlP5.TOP_OUTSIDE);
|
||||
|
||||
gui.addSlider("sldXSpacing").setSize(130,30).setCaptionLabel("Detail").setPosition(10,200).setRange(1,30).setValue(28).setColorCaptionLabel(color(0));
|
||||
gui.addSlider("sldXSpacing").setSize(130, 30).setCaptionLabel("Detail").setPosition(10, 200).setRange(1, 30).setValue(28).setColorCaptionLabel(color(0));
|
||||
gui.getController("sldXSpacing").getCaptionLabel().align(ControlP5.LEFT, ControlP5.TOP_OUTSIDE);
|
||||
|
||||
gui.addSlider("sldXFrequency").setSize(130,30).setCaptionLabel("Frequency").setPosition(10,260).setRange(5.0,256.0).setValue(128.0).setColorCaptionLabel(color(0));
|
||||
gui.addSlider("sldXFrequency").setSize(130, 30).setCaptionLabel("Frequency").setPosition(10, 260).setRange(5.0, 200.0).setValue(128.0).setColorCaptionLabel(color(0));
|
||||
gui.getController("sldXFrequency").getCaptionLabel().align(ControlP5.LEFT, ControlP5.TOP_OUTSIDE);
|
||||
|
||||
gui.addSlider("sldImgScale").setSize(130,30).setCaptionLabel("Resolution Scale").setPosition(10,320).setRange(1,3).setValue(3).setColorCaptionLabel(color(0));
|
||||
gui.addSlider("sldImgScale").setSize(130, 30).setCaptionLabel("Resolution Scale").setPosition(10, 320).setRange(1, 3).setValue(3).setColorCaptionLabel(color(0));
|
||||
gui.getController("sldImgScale").getCaptionLabel().align(ControlP5.LEFT, ControlP5.TOP_OUTSIDE);
|
||||
|
||||
gui.addSlider("lineWidth").setSize(130,30).setCaptionLabel("Line Width").setPosition(10,380).setRange(1,10).setValue(5).setColorCaptionLabel(color(0));
|
||||
gui.addSlider("lineWidth").setSize(130, 30).setCaptionLabel("Line Width").setPosition(10, 380).setRange(1, 10).setValue(5).setColorCaptionLabel(color(0));
|
||||
gui.getController("lineWidth").getCaptionLabel().align(ControlP5.LEFT, ControlP5.TOP_OUTSIDE);
|
||||
|
||||
gui.addSlider("minBrightness").setSize(130,30).setCaptionLabel("Black Point").setPosition(10,440).setRange(0,255).setValue(0).setColorCaptionLabel(color(0));
|
||||
gui.addSlider("minBrightness").setSize(130, 30).setCaptionLabel("Black Point").setPosition(10, 440).setRange(0, 255).setValue(0).setColorCaptionLabel(color(0));
|
||||
gui.getController("minBrightness").getCaptionLabel().align(ControlP5.LEFT, ControlP5.TOP_OUTSIDE);
|
||||
|
||||
gui.addSlider("maxBrightness").setSize(130,30).setCaptionLabel("White Point").setPosition(10,500).setRange(0,255).setValue(255).setColorCaptionLabel(color(0));
|
||||
gui.addSlider("maxBrightness").setSize(130, 30).setCaptionLabel("White Point").setPosition(10, 500).setRange(0, 255).setValue(255).setColorCaptionLabel(color(0));
|
||||
gui.getController("maxBrightness").getCaptionLabel().align(ControlP5.LEFT, ControlP5.TOP_OUTSIDE);
|
||||
|
||||
// added: .setTriggerEvent(Bang.RELEASE)
|
||||
// now you don't have to click 's' to save. save button work fine now.
|
||||
gui.addBang("bangLoad").setSize(130,30).setTriggerEvent(Bang.RELEASE).setCaptionLabel("Load image").setPosition(10,600).setColorCaptionLabel(color(255));
|
||||
gui.addBang("bangLoad").setSize(130, 30).setTriggerEvent(Bang.RELEASE).setCaptionLabel("Load image").setPosition(10, 600).setColorCaptionLabel(color(255));
|
||||
gui.getController("bangLoad").getCaptionLabel().align(ControlP5.CENTER, ControlP5.CENTER);
|
||||
|
||||
gui.addBang("bangSave").setSize(130,30).setCaptionLabel("Save SVG").setPosition(10,660).setColorCaptionLabel(color(255));
|
||||
gui.addBang("bangSave").setSize(130, 30).setCaptionLabel("Save SVG").setPosition(10, 660).setColorCaptionLabel(color(255));
|
||||
gui.getController("bangSave").getCaptionLabel().align(ControlP5.CENTER, ControlP5.CENTER);
|
||||
|
||||
|
||||
// add 'default' button
|
||||
gui.addBang("bangDefault").setSize(130,30).setCaptionLabel("Default").setPosition(10,720).setColorCaptionLabel(color(255));
|
||||
gui.addBang("bangDefault").setSize(130, 30).setCaptionLabel("Default").setPosition(10, 720).setColorCaptionLabel(color(255));
|
||||
gui.getController("bangDefault").getCaptionLabel().align(ControlP5.CENTER, ControlP5.CENTER);
|
||||
|
||||
|
||||
//// add 'fit' button. fit image to window size
|
||||
//gui.addBang("bangFit").setSize(65, 30).setCaptionLabel("Fit").setPosition(10, 780).setColorCaptionLabel(color(255));
|
||||
//gui.getController("bangFit").getCaptionLabel().align(ControlP5.CENTER, ControlP5.CENTER);
|
||||
|
||||
|
||||
//// add 'full' button. load orig image size
|
||||
//gui.addBang("bangFull").setSize(65, 30).setCaptionLabel("Full").setPosition(10 + 66, 780).setColorCaptionLabel(color(255));
|
||||
//gui.getController("bangFull").getCaptionLabel().align(ControlP5.CENTER, ControlP5.CENTER);
|
||||
|
||||
|
||||
smooth();
|
||||
background(255);
|
||||
shapeMode(CORNER);
|
||||
|
@ -111,31 +132,32 @@ void loadMainImage(String inImageName) {
|
|||
println("loadMainImage");
|
||||
//isInit = true;
|
||||
p1 = loadImage(inImageName);
|
||||
|
||||
|
||||
int tempheight = p1.height;
|
||||
if (tempheight < 720 + 120)
|
||||
tempheight = 720 + 120;
|
||||
|
||||
|
||||
surface.setSize(p1.width + 150, tempheight);
|
||||
|
||||
// filter image
|
||||
p1.filter(GRAY);
|
||||
p1.filter(BLUR,2);
|
||||
p1.filter(BLUR, 2);
|
||||
if (invert) {
|
||||
p1.filter(INVERT);
|
||||
}
|
||||
|
||||
|
||||
needsReload = true;
|
||||
redrawImage();
|
||||
}
|
||||
|
||||
void createSecondaryImage() {
|
||||
p2 = createImage(p1.width*imageScaleUp,p1.height*imageScaleUp,ALPHA);
|
||||
p2.copy(p1,0,0,p1.width,p1.height,0,0,p1.width*imageScaleUp,p1.height*imageScaleUp);
|
||||
p2 = createImage(p1.width*imageScaleUp, p1.height*imageScaleUp, ALPHA);
|
||||
p2.copy(p1, 0, 0, p1.width, p1.height, 0, 0, p1.width*imageScaleUp, p1.height*imageScaleUp);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
if (isRunning) {
|
||||
|
||||
if (isRecording) {
|
||||
// save to file
|
||||
// was: beginRecord(SVG, "squiggleImage_" + millis() + ".svg");
|
||||
|
@ -162,40 +184,309 @@ void createPic() {
|
|||
createSecondaryImage();
|
||||
needsReload = false;
|
||||
}
|
||||
|
||||
|
||||
stroke(0);
|
||||
noFill();
|
||||
strokeWeight(strokeWidth);
|
||||
|
||||
|
||||
startx = 0.0;
|
||||
starty = 0.0;
|
||||
|
||||
s = createShape(GROUP);
|
||||
|
||||
for (int y=0;y<p2.height;y+=p2.height/ystep) {
|
||||
|
||||
liner = createShape(PShape.PATH);
|
||||
liner.beginShape();
|
||||
a = 0.0;
|
||||
liner.vertex(0,y);
|
||||
|
||||
for (int x = 1;x<p2.width;x+=xstep) {
|
||||
b = (int)alpha(p2.get(x,y));
|
||||
b = max(minB,b);
|
||||
z = max(maxB-b,0);
|
||||
r = z/ystep*ymult;
|
||||
a += z/xsmooth;
|
||||
liner.vertex(x,y+sin(a)*r);
|
||||
}
|
||||
liner.endShape();
|
||||
s.addChild(liner);
|
||||
}
|
||||
|
||||
if (!isRecording)
|
||||
background(255);
|
||||
s.scale(1.0/imageScaleUp);
|
||||
shape(s,isRecording ? 0 : 150,0);
|
||||
|
||||
float scaleFactor = 1.0/imageScaleUp;
|
||||
float xOffset = isRecording ? 0 : 150;
|
||||
|
||||
float deltaPhase;
|
||||
float deltaX;
|
||||
float deltaAmpl;
|
||||
|
||||
/*
|
||||
The minimum phase increment should give about 40 vertices minimum
|
||||
across x. 40 vertices -> 10 * 2 pi.
|
||||
*/
|
||||
float minPhaseIncr = 10 * TWO_PI / (p2.width / xstep);
|
||||
|
||||
/*
|
||||
Maximum phase increment (frequency cap) is based on line thickness and x step size.
|
||||
|
||||
A full period of oscillation needn't be less than
|
||||
2 * strokeWidth in total width.
|
||||
|
||||
The maximum number of full cycles that should be permitted in a
|
||||
horizontal distance of xstep should be:
|
||||
N = total width/width per cycle = xstep / (2 * strokeWidth)
|
||||
|
||||
The maximum phase increment in distance xstep should then be:
|
||||
|
||||
maxPhaseIncr = 2 Pi * N = 2 * Pi * xstep / (2 * strokeWidth)
|
||||
= 2Pi * xstep / strokeWidth
|
||||
|
||||
We do not need to include the scaling factors, since
|
||||
both the step size and stroke width are scaled the same way.
|
||||
*/
|
||||
|
||||
|
||||
float maxPhaseIncr = TWO_PI * xstep / strokeWidth;
|
||||
|
||||
strokeWeight(strokeWidth * scaleFactor);
|
||||
|
||||
if (connectEnds)
|
||||
{
|
||||
beginShape();
|
||||
}
|
||||
|
||||
boolean oddRow = false;
|
||||
boolean finalRow = false;
|
||||
boolean reverseRow;
|
||||
float lastX;
|
||||
float scaledYstep = p2.height/ystep;
|
||||
|
||||
for (int y=0; y<p2.height; y+=scaledYstep) {
|
||||
|
||||
if (!connectEnds)
|
||||
{
|
||||
beginShape();
|
||||
}
|
||||
|
||||
oddRow = !oddRow;
|
||||
if (y + (scaledYstep ) >= p2.height)
|
||||
finalRow = true;
|
||||
|
||||
if (connectEnds && !oddRow)
|
||||
reverseRow = true;
|
||||
else
|
||||
reverseRow = false;
|
||||
|
||||
a = 0.0;
|
||||
|
||||
// Add initial "extra" point to give splines a consistent visual endpoint,
|
||||
// IF we are not connecting rows.
|
||||
|
||||
if (reverseRow)
|
||||
{
|
||||
if (!connectEnds || y == 0)
|
||||
{
|
||||
// Always add the extra initial point if we're not connecting the ends, or if this is the first row.
|
||||
curveVertex(xOffset + scaleFactor * (p2.width + 0.1 * xstep), scaleFactor * y);
|
||||
}
|
||||
curveVertex(xOffset + scaleFactor * (p2.width), scaleFactor * y);
|
||||
} else
|
||||
{
|
||||
if (!connectEnds || y == 0)
|
||||
{
|
||||
// Always add the extra initial point if we're not connecting the ends, or if this is the first row.
|
||||
curveVertex(xOffset - scaleFactor * ( 0.1 * xstep), y * scaleFactor);
|
||||
}
|
||||
curveVertex(xOffset, y * scaleFactor);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Step along width of image.
|
||||
|
||||
For each step, get the image brightness for that XY position,
|
||||
and constrain it to our bright/dark cutoff window.
|
||||
|
||||
Accumulated phase: increment by scaled brightness, so that the frequency
|
||||
increases in certain areas of the image. Phase only advances with pigment,
|
||||
not simply by traversing across the image in X.
|
||||
|
||||
Amplitude: A simple multiplier based on local brightness.
|
||||
|
||||
To have high quality generated curves for display and plotting, we would like to:
|
||||
|
||||
(1) Avoid aliasing. Aliasing happens when we plot a signal at a poorly
|
||||
representative set of points. By undersampling -- e.g., less than once per
|
||||
period -- you can very easily see what appears to be a sine wave, but does
|
||||
not actually represent the actual function being sampled.
|
||||
|
||||
Two potential methods to avoid aliasing:
|
||||
(A) Increase the number of points, to ensure that some minimum number
|
||||
of points are sampeled per period, or
|
||||
(B) Plot the function at specific points {x_i} that are determined by
|
||||
the value of the function f(x) at those points, e.g., at every crest,
|
||||
trough, and zero crossing.
|
||||
|
||||
(2) Place relatively few control points.
|
||||
CNC software tends to follow simply defined curves more easily than
|
||||
paths with a great many closely-spaced points.
|
||||
Side benefit: Potentially smaller file size.
|
||||
|
||||
(3) Place an upper bound on the maximum frequency.
|
||||
Above a certain frequency, with a finite-width pen, increasing the frequency
|
||||
does not make the plot any darker.
|
||||
|
||||
|
||||
To achieve these goals, we will try:
|
||||
|
||||
(1) Putting x-points (vertices) at every crest, trough, and zero crossing.
|
||||
Point x-positions may be approximated as necessary by interpolation.
|
||||
|
||||
(2) Using Processing's curveVertex method, to create curvy lines
|
||||
(Catmull–Rom splines). These will only approximate sine waves, but
|
||||
should work well for this particular application.
|
||||
|
||||
(3) Using the GUI line-width control to control the maximum frequency.
|
||||
|
||||
*/
|
||||
|
||||
float phase = 0.0;
|
||||
float lastPhase = 0; // accumulated phase at previous vertex
|
||||
float lastAmpl = 0; // amplitude at previous vertex
|
||||
boolean finalStep = false;
|
||||
|
||||
int x;
|
||||
|
||||
if (reverseRow)
|
||||
{
|
||||
x = p2.width;
|
||||
lastX = p2.width;
|
||||
} else
|
||||
{
|
||||
x = 1;
|
||||
lastX = 1;
|
||||
}
|
||||
|
||||
|
||||
while (finalStep == false) { // Iterate over each each x-step in the row
|
||||
|
||||
if (reverseRow)
|
||||
{ // Moving left to right on even rows
|
||||
x -= xstep;
|
||||
if (x - xstep < 1)
|
||||
finalStep = true;
|
||||
else
|
||||
finalStep = false;
|
||||
} else
|
||||
{ // Moving right to left as usual
|
||||
x += xstep;
|
||||
if (x + xstep >= p2.width)
|
||||
finalStep = true;
|
||||
else
|
||||
finalStep = false;
|
||||
}
|
||||
|
||||
b = (int)alpha(p2.get(x, y));
|
||||
b = max(minB, b);
|
||||
z = max(maxB-b, 0); // Brightness trimmed to range.
|
||||
|
||||
r = z/ystep*ymult; // ymult: Amplitude
|
||||
|
||||
/*
|
||||
Enforce a minimum phase increment, to prevent large gaps in splines
|
||||
This will add extra vertices in flat regions, but the amplitude remains
|
||||
unaffected (near-zero amplitude), so it does not cause a significant
|
||||
visual effect.
|
||||
*/
|
||||
|
||||
float df = z/xsmooth;
|
||||
if (df < minPhaseIncr)
|
||||
df = minPhaseIncr;
|
||||
|
||||
/*
|
||||
Enforce a maximum phase increment -- a frequency cap -- to prevent
|
||||
unnecessary plotting time. Once the frequency is so high that the line widths
|
||||
of neighboring crests overlap, there is no added benefit to having higher
|
||||
frequency; it's just wasting memory (and ink + time, if plotting).
|
||||
*/
|
||||
|
||||
if (df > maxPhaseIncr)
|
||||
df = maxPhaseIncr;
|
||||
|
||||
phase += df; // xsmooth: Frequency
|
||||
|
||||
deltaX = x - lastX; // Distance between image sample location x and previous vertex
|
||||
|
||||
deltaAmpl = r - lastAmpl;
|
||||
|
||||
deltaPhase = phase - lastPhase; // Change in phase since last *vertex*
|
||||
// (Vertices do not fall along the x "grid", but where they need to.)
|
||||
|
||||
if (!finalStep) // Skip to end points if this is the final step.
|
||||
if (deltaPhase > HALF_PI) // Only add vertices if true.
|
||||
{
|
||||
/*
|
||||
Linearly interpolate phase and amplitude since last vertex added.
|
||||
This treats the frequency as constant
|
||||
between subsequent x-samples of the source image.
|
||||
*/
|
||||
|
||||
int vertexCount = floor( deltaPhase / HALF_PI); // Add this many vertices
|
||||
|
||||
float integerPart = ((vertexCount * HALF_PI) / deltaPhase);
|
||||
// "Integer" fraction (in terms of pi/2 phase segments) of deltaX.
|
||||
|
||||
float deltaX_truncate = deltaX * integerPart;
|
||||
// deltaX_truncate: "Integer" part (in terms of pi/2 segments) of deltaX.
|
||||
|
||||
float xPerVertex = deltaX_truncate / vertexCount;
|
||||
float amplPerVertex = (integerPart * deltaAmpl) / vertexCount;
|
||||
|
||||
// Add the vertices:
|
||||
for (int i = 0; i < vertexCount; i = i+1) {
|
||||
|
||||
lastX = lastX + xPerVertex;
|
||||
lastPhase = lastPhase + HALF_PI;
|
||||
lastAmpl = lastAmpl + amplPerVertex;
|
||||
|
||||
curveVertex(xOffset + scaleFactor * lastX, scaleFactor *(y+sin(lastPhase)*lastAmpl));
|
||||
}
|
||||
} else if (finalStep)
|
||||
{ // Add a vertex if this is the last point on the row,
|
||||
// even if there's not a full pi/2 of phase.
|
||||
|
||||
curveVertex(xOffset + scaleFactor * x, scaleFactor *(y+sin(phase)*r));
|
||||
lastX = x;
|
||||
}
|
||||
}
|
||||
|
||||
// Add final "extra" point to give splines a consistent visual endpoint:
|
||||
if (reverseRow)
|
||||
{
|
||||
curveVertex(xOffset, y * scaleFactor);
|
||||
if (!connectEnds || finalRow)
|
||||
{
|
||||
// Always add the extra final point if we're not connecting the ends, or if this is the first row.
|
||||
curveVertex(xOffset - scaleFactor * ( 0.1 * xstep), y * scaleFactor);
|
||||
}
|
||||
} else
|
||||
{
|
||||
curveVertex(xOffset + scaleFactor * (p2.width), scaleFactor * y);
|
||||
if (!connectEnds || finalRow)
|
||||
{
|
||||
// Always add the extra final point if we're not connecting the ends, or if this is the first row.
|
||||
curveVertex(xOffset + scaleFactor * (p2.width + 0.1 * xstep), scaleFactor * y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (connectEnds && !finalRow) // Add curvy end connectors
|
||||
if (reverseRow)
|
||||
{
|
||||
curveVertex(xOffset - scaleFactor * ( 0.1 * xstep + scaledYstep/3), (y + scaledYstep/2) * scaleFactor );
|
||||
} else
|
||||
{
|
||||
curveVertex(xOffset + scaleFactor * (p2.width + 0.1 * xstep + scaledYstep/3), (y + scaledYstep/2) * scaleFactor );
|
||||
}
|
||||
|
||||
|
||||
if (!connectEnds)
|
||||
{
|
||||
endShape();
|
||||
}
|
||||
}
|
||||
|
||||
if (connectEnds)
|
||||
{
|
||||
endShape();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void fileSelected(File selection) {
|
||||
if (selection == null) {
|
||||
println("Window was closed or the cancel selected.");
|
||||
|
@ -232,7 +523,7 @@ void fileSelected(File selection) {
|
|||
loadMainImage(imageName);
|
||||
createSecondaryImage();
|
||||
redrawImage();
|
||||
} else {
|
||||
} else {
|
||||
// Can't load file
|
||||
println("ERROR: BAD FILE TYPE");
|
||||
}
|
||||
|
@ -271,6 +562,12 @@ void tglInvert(boolean value) {
|
|||
redrawImage();
|
||||
}
|
||||
|
||||
void tglConnect(boolean value) {
|
||||
connectEnds = value;
|
||||
needsReload = true;
|
||||
redrawImage();
|
||||
}
|
||||
|
||||
void lineWidth(int value) {
|
||||
strokeWidth = value;
|
||||
redrawImage();
|
||||
|
@ -310,18 +607,19 @@ void redrawImage() {
|
|||
}
|
||||
|
||||
void keyPressed() {
|
||||
if (key == ' ') {
|
||||
if (key == ' ') {
|
||||
// nothing here
|
||||
} else if (key == 's') { // save
|
||||
isRecording = true;
|
||||
isRunning = true;
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bangDefault() {
|
||||
gui.getController("sldLines").setValue(120);
|
||||
gui.getController("tglInvert").setValue(0);
|
||||
gui.getController("tglConnect").setValue(0);
|
||||
gui.getController("sldAmplitude").setValue(13);
|
||||
gui.getController("sldXSpacing").setValue(28);
|
||||
gui.getController("sldXFrequency").setValue(128);
|
||||
|
@ -342,4 +640,4 @@ void bangDefault() {
|
|||
// println("Full");
|
||||
// isInit = false;
|
||||
// loadMainImage(imageName);
|
||||
//}
|
||||
//}
|
Ładowanie…
Reference in New Issue