Compare commits

...

13 Commits
v2.1.1 ... main

Author SHA1 Message Date
mattmcw 1f3a16eea5 Typo in README: minDotSize, maxDotSize and dotSizeFactor are all camel case. 2021-12-20 10:27:19 -05:00
mattmcw 6a3c991dc2 Add configuration options for fillAngle (default 45 degrees) and fillRandom, which will randomize the angle on every dot drawn. Calling this release 2.1.2. 2021-12-08 23:19:39 -05:00
mattmcw 26985553a7 Merge remote-tracking branch 'origin/main' into main 2021-12-08 22:58:47 -05:00
mattmcw f7b4d41715 Improvement in fillCircle: by reducing the number of fill lines in half, the hatching showed visible gaps between lines. This new method ensures a fuller circle. Tested and renders more closely match plotted drawings. 2021-12-08 22:58:31 -05:00
mattmcw 32ee5fbc48 Merge remote-tracking branch 'origin/main' 2021-12-08 01:03:01 -05:00
mattmcw 85c1082fc3 Now I am understanding the magic number 2x used in display: I was not accounting for the standard 96dpi for svg and so, naturally, a 0.75mm pen represented by line=0.75 would need to *actually* be closer to 1.5. The remaining issue is that the svg representation seems to be failing when supplied with the actual line width used in calculations. 2021-12-06 11:17:59 -05:00
mattmcw c5f7d7b4e6 Spell license correctly 2021-12-03 10:45:25 -05:00
mattmcw 742c7182e7 Update language and remove griping about LGPL 2021-12-03 10:29:29 -05:00
mattmcw 782552055a Lines aren't being drawn. Try without removing the line width 2021-12-02 16:11:50 -05:00
mattmcw 41927aec1f Add dot mode. For single-point plots, like for paint pens. 2021-12-02 16:06:15 -05:00
mattmcw 0ccd0643f3 If calculated dot diameter is smaller than minDotSize, set to minDotSize 2021-12-01 13:58:37 -05:00
mattmcw 36928c1eb9 The 2x scalar is breaking rendering. Test without it but otherwise consider issue #2 moot for now. 2021-11-30 18:53:40 -05:00
mattmcw fb853e6480 Resolved this by compressing header.txt into a single line and adding it as a hardcoded variable String[] header, which mimics the output of the file read happening later in the script. Resolves issue #1 2021-11-30 15:27:28 -05:00
2 changed files with 56 additions and 23 deletions

View File

@ -32,7 +32,7 @@ Other variables:
```java
public int canvasWidth = 800;
public int canvasHeight = 600;
public float canvasScalar = 1.25;
public float canvasScalar = 1.0;
public boolean display = true;
public int windowWidth = 800;
@ -49,9 +49,9 @@ public int centroidsPerPass = 500;
public int testsPerFrame = 90000;
public int maxGenerations = 5; //number of generations
public float MinDotSize = 1.25;
public float MaxDotSize;
public float DotSizeFactor = 4;
public float minDotSize = 1.25;
public float maxDotSize;
public float dotSizeFactor = 4;
public int maxParticles = 2000; // Max value is normally 10000.
public float cutoff = 0; // White cutoff value
@ -60,6 +60,7 @@ public boolean gammaCorrection = false;
public float gamma = 1.0;
public boolean fill = false;
public boolean dot = false;
public float line = 1.0;
```

View File

@ -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;\"/>";