|
|
|
@ -9,12 +9,10 @@
|
|
|
|
|
a config file. Arguments take precedence over the config file.
|
|
|
|
|
|
|
|
|
|
Why do it this way? So that the stippling process can be run headless with a config file
|
|
|
|
|
storing the majority of the settings and the command line arguments handling things
|
|
|
|
|
such as input and output file names. Why do that? So this process can be tied into
|
|
|
|
|
automated image generation processes.
|
|
|
|
|
or command line arguments. Why do that? So this application can be used for
|
|
|
|
|
automated image generation.
|
|
|
|
|
|
|
|
|
|
Begrudgingly but respectfully releasing this in accordance with the original LGPL license,
|
|
|
|
|
though I would prefer to use MIT or ISC which I consider to have fewer encumbrances.
|
|
|
|
|
License: LGPL 2.1
|
|
|
|
|
|
|
|
|
|
*******************************************************************************
|
|
|
|
|
HISTORY
|
|
|
|
@ -113,6 +111,9 @@ public class Config {
|
|
|
|
|
public float gamma = 1.0;
|
|
|
|
|
|
|
|
|
|
public boolean fill = false;
|
|
|
|
|
public float fillAngle = 45.0;
|
|
|
|
|
public boolean fillRandom = false;
|
|
|
|
|
public boolean dot = false;
|
|
|
|
|
public float line = 1.0;
|
|
|
|
|
|
|
|
|
|
public String mode = "stipple"; //tsp
|
|
|
|
@ -286,6 +287,15 @@ public class Config {
|
|
|
|
|
case "fill" :
|
|
|
|
|
fill = boolOrDie(name, val);
|
|
|
|
|
break;
|
|
|
|
|
case "fillAngle" :
|
|
|
|
|
fillAngle = floatOrDie(name, val);
|
|
|
|
|
break;
|
|
|
|
|
case "fillRandom" :
|
|
|
|
|
fillRandom = boolOrDie(name, val);
|
|
|
|
|
break;
|
|
|
|
|
case "dot" :
|
|
|
|
|
dot = boolOrDie(name, val);
|
|
|
|
|
break;
|
|
|
|
|
case "line" :
|
|
|
|
|
line = floatOrDie(name, val);
|
|
|
|
|
break;
|
|
|
|
@ -359,6 +369,8 @@ PGraphics canvas;
|
|
|
|
|
Vec2D[] particles;
|
|
|
|
|
int[] particleRoute;
|
|
|
|
|
|
|
|
|
|
String[] header = {"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><!-- Created for Inkscape (http://www.inkscape.org/) --><svg xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:cc=\"http://creativecommons.org/ns#\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" width=\"{{WIDTH}}\" height=\"{{HEIGHT}}\" id=\"svg2985\" version=\"1.1\" inkscape:version=\"0.48.1 r9760\"> <defs id=\"defs2987\" /> <sodipodi:namedview id=\"base\" pagecolor=\"#ffffff\" bordercolor=\"#666666\" borderopacity=\"1.0\" inkscape:pageopacity=\"0.0\" inkscape:pageshadow=\"2\" inkscape:zoom=\"0.35\" inkscape:cx=\"0\" inkscape:cy=\"0\" inkscape:document-units=\"px\" inkscape:current-layer=\"layer1\" showgrid=\"false\" /> <metadata id=\"metadata2990\"> <rdf:RDF> <cc:Work rdf:about=\"\"> <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" /> <dc:title /> </cc:Work> </rdf:RDF> </metadata> <g inkscape:label=\"Layer 1\" inkscape:groupmode=\"layer\" id=\"layer1\"> <g>"};
|
|
|
|
|
|
|
|
|
|
void LoadImageAndScale() {
|
|
|
|
|
int tempx = 0;
|
|
|
|
|
int tempy = 0;
|
|
|
|
@ -1126,7 +1138,7 @@ public float[] line_circle_p(float x0, float y0, float x1, float y1, float cx, f
|
|
|
|
|
**/
|
|
|
|
|
ArrayList<float[]> fillCircle (float x, float y, float d, float angle, float line) {
|
|
|
|
|
ArrayList<float[]> output = new ArrayList<float[]>();
|
|
|
|
|
float r = (d / 2.0) - line;
|
|
|
|
|
float r = (d / 2.0);
|
|
|
|
|
float perpAngle = (angle + 90.0) % 360.0;
|
|
|
|
|
float perpRadian = radians(perpAngle);
|
|
|
|
|
float radian = radians(angle);
|
|
|
|
@ -1141,9 +1153,9 @@ ArrayList<float[]> fillCircle (float x, float y, float d, float angle, float lin
|
|
|
|
|
float testY = 0;
|
|
|
|
|
float[] intersect;
|
|
|
|
|
|
|
|
|
|
for (int i = -floor(lines / 2); i < floor(lines / 2); i++) {
|
|
|
|
|
perpX = x + ((line * (i + 0.5)) * cos(perpRadian));
|
|
|
|
|
perpY = y + ((line * (i + 0.5)) * sin(perpRadian));
|
|
|
|
|
for (int i = -lines; i < lines; i++) {
|
|
|
|
|
perpX = x + ( ( (line / 2) * (i + 0.5) ) * cos(perpRadian));
|
|
|
|
|
perpY = y + ( ( (line / 2) * (i + 0.5) ) * sin(perpRadian));
|
|
|
|
|
testX = perpX + (d * cos(radian));
|
|
|
|
|
testY = perpY + (d * sin(radian));
|
|
|
|
|
|
|
|
|
@ -1169,7 +1181,7 @@ ArrayList<float[]> fillCircle (float x, float y, float d, float angle, float lin
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dist(startX, startY, endX, endY) > line) {
|
|
|
|
|
float[] linePoints = {startX, startY, endX, endY};
|
|
|
|
|
float[] linePoints = { startX, startY, endX, endY };
|
|
|
|
|
output.add(linePoints);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1184,6 +1196,7 @@ void draw () {
|
|
|
|
|
float dotRad;
|
|
|
|
|
float dotDiam;
|
|
|
|
|
float cutoffScaled = 1 - config.cutoff;
|
|
|
|
|
float hatchAngle;
|
|
|
|
|
ArrayList<float[]> hatchLines;
|
|
|
|
|
|
|
|
|
|
canvas.beginDraw();
|
|
|
|
@ -1283,6 +1296,15 @@ void draw () {
|
|
|
|
|
canvas.strokeWeight(1.0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!FileModeTSP && config.dot) {
|
|
|
|
|
canvas.noStroke();
|
|
|
|
|
if (config.invert) {
|
|
|
|
|
canvas.fill(255);
|
|
|
|
|
} else {
|
|
|
|
|
canvas.fill(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (FileModeTSP) {
|
|
|
|
|
OptimizePlotPath();
|
|
|
|
|
canvas.background(config.invert ? 0 : 255);
|
|
|
|
@ -1310,10 +1332,14 @@ void draw () {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (v < cutoffScaled) {
|
|
|
|
|
dotDiam = (config.maxDotSize - v * dotScale) * 2.0 * config.canvasScalar;
|
|
|
|
|
dotDiam = (config.maxDotSize - v * dotScale) * config.canvasScalar;
|
|
|
|
|
if (dotDiam < config.minDotSize) {
|
|
|
|
|
dotDiam = config.minDotSize;
|
|
|
|
|
}
|
|
|
|
|
canvas.ellipse(px, py, dotDiam, dotDiam);
|
|
|
|
|
if (config.fill) {
|
|
|
|
|
hatchLines = fillCircle(px, py, dotDiam, 45.0, config.line * config.canvasScalar);
|
|
|
|
|
if (!config.dot && config.fill) {
|
|
|
|
|
hatchAngle = config.fillRandom ? random(0.0, 360.0) : config.fillAngle;
|
|
|
|
|
hatchLines = fillCircle(px, py, dotDiam, hatchAngle, config.line * config.canvasScalar);
|
|
|
|
|
if (hatchLines.size() > 0) {
|
|
|
|
|
for (float[] linePoints : hatchLines) {
|
|
|
|
|
canvas.line(linePoints[0], linePoints[1], linePoints[2], linePoints[3]);
|
|
|
|
@ -1373,7 +1399,7 @@ void draw () {
|
|
|
|
|
OptimizePlotPath();
|
|
|
|
|
}
|
|
|
|
|
StatusDisplay = "Saving SVG File";
|
|
|
|
|
FileOutput = loadStrings("header.txt");
|
|
|
|
|
FileOutput = header;
|
|
|
|
|
String rowTemp;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < FileOutput.length; i++) {
|
|
|
|
@ -1393,7 +1419,7 @@ void draw () {
|
|
|
|
|
println("Saving TSP File (SVG)");
|
|
|
|
|
println(config.outputSVG);
|
|
|
|
|
// Path header::
|
|
|
|
|
rowTemp = "<path style=\"fill:none;stroke:black;stroke-width:1px;stroke-linejoin:round;stroke-linecap:round;\" d=\"M ";
|
|
|
|
|
rowTemp = "<path style=\"fill:none;stroke:black;stroke-width:"+ config.line +";stroke-linejoin:round;stroke-linecap:round;\" d=\"M ";
|
|
|
|
|
FileOutput = append(FileOutput, rowTemp);
|
|
|
|
|
|
|
|
|
|
for ( i = 0; i < particleRouteLength; ++i) {
|
|
|
|
@ -1432,12 +1458,18 @@ void draw () {
|
|
|
|
|
|
|
|
|
|
float xTemp = SVGscale * p1.x + xOffset;
|
|
|
|
|
float yTemp = SVGscale * p1.y + yOffset;
|
|
|
|
|
|
|
|
|
|
rowTemp = "<circle cx=\"" + xTemp + "\" cy=\"" + yTemp + "\" r=\"" + dotRad +
|
|
|
|
|
|
|
|
|
|
if (config.dot) {
|
|
|
|
|
rowTemp = "<path d=\"M " + xTemp + "," + yTemp + " L " + (xTemp + 0.01 ) + "," + yTemp + "\" style=\"fill:none;stroke:black;stroke-width:" + dotRad + ";\"/>";
|
|
|
|
|
} else {
|
|
|
|
|
rowTemp = "<circle cx=\"" + xTemp + "\" cy=\"" + yTemp + "\" r=\"" + dotRad +
|
|
|
|
|
"\" style=\"fill:none;stroke:black;stroke-width:1;\"/>";
|
|
|
|
|
// Typ: <circle cx="1600" cy="450" r="3" style="fill:none;stroke:black;stroke-width:2;"/>
|
|
|
|
|
if (config.fill) {
|
|
|
|
|
hatchLines = fillCircle(xTemp, yTemp, dotRad * 2.0, 45.0, config.line);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!config.dot && config.fill) {
|
|
|
|
|
hatchAngle = config.fillRandom ? random(0.0, 360.0) : config.fillAngle;
|
|
|
|
|
hatchLines = fillCircle(xTemp, yTemp, dotRad * 2.0, hatchAngle, config.line);
|
|
|
|
|
if (hatchLines.size() > 0) {
|
|
|
|
|
for (float[] linePoints : hatchLines) {
|
|
|
|
|
rowTemp += "<line x1=\"" + linePoints[0] + "\" y1=\"" + linePoints[1] + "\" x2=\"" + linePoints[2] + "\" y2=\"" + linePoints[3] + "\" style=\"fill:none;stroke:black;stroke-width:1;\"/>";
|
|
|
|
|