We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Hi! I did a sketch that converts the strokes of a svg image to an animated pencil drawing: https://forum.processing.org/two/discussion/18979/get-stroke-color-of-svg-drawing
It would be great to be able to convert a fill to a scribbled path that looks like drawn by hand, too. Almost similar to a scribble effect in inkscape or illustrator. Once it is a stroke it could also be animated. Did someone already do something similar? What would be a good way of doing that?
Using geomerative it is possible to shift a line over the image, get the intersection points and draw lines first between all first and second, than between all third and fourth intersection points. But it is hard (impossible for me) to get control points for bezier curves this way. Below is a fast sketch with curvevertices, that does not produce a vector path of course. (it does not care about lifting the pen either)
Another approach could be to move a "pentip" over the fill, set vertices and let the "pentip" walk back or in another (random) direction once it leaves the fillarea. Trial and error. Then make a curvy path through the vertices afterwards. (bezier again...). Something like a collision detection for strange shapes with cutouts possibly.
Any ideas, suggestions or perfectly working solutions ;-)? best regards Jens
Here is the mentioned sketch:
import processing.opengl.*;
import geomerative.*;
RShape shp;
RShape cuttingLine = RG.getLine(0 , 0, 0, 0);
int rnd = 50;
void setup() {
size(700, 700);
smooth();
// VERY IMPORTANT: Allways initialize the library before using it
RG.init(this);
//RG.setPolygonizer(RG.ADAPTATIVE);
shp = RG.loadShape("M.svg"); // circle.svg
//shp = RG.centerIn(shp, g);
RG.ignoreStyles();
background(255);
}
void draw() {
fill(255,30);
rect(0,0,width,height);
translate(200, 200);
noFill();
curveTightness(random(0,0.5)); // def 1
beginShape();
stroke(0, 100);
strokeWeight(2);
for (int counter = 0; counter < width; counter = counter + 10+(int)random(rnd)) {
// Draw the shape
//RG.shape(shp);
// Create and draw a cutting line
cuttingLine = RG.getLine(counter+ random(-rnd,rnd) , 0, 0, counter+ random(-rnd,rnd));
//RG.shape(cuttingLine);
// Get the intersection points
RPoint[] ps = shp.getIntersections(cuttingLine);
if (ps != null) {
if (ps.length > 1) {
//line(ps[0].x, ps[0].y, ps[1].x, ps[1].y);
curveVertex(ps[1].x, ps[1].y);
curveVertex(ps[0].x, ps[0].y);
}
}
counter = counter + 10;
cuttingLine = RG.getLine(counter + random(-rnd,rnd), 0, 0, counter + random(-rnd,rnd));
ps = shp.getIntersections(cuttingLine);
if (ps != null) {
if (ps.length > 1) {
curveVertex(ps[0].x, ps[0].y);
curveVertex(ps[1].x, ps[1].y);
}
}
}
endShape();
beginShape();
for (int counter = 0; counter < width; counter = counter + 10 + (int)random(rnd)) {
cuttingLine = RG.getLine(counter+ random(-rnd,rnd), 0, 0, counter+random(-rnd,rnd));
RPoint[] ps = shp.getIntersections(cuttingLine);
if (ps != null) {
if (ps.length > 3) {
curveVertex(ps[3].x, ps[3].y);
curveVertex(ps[2].x, ps[2].y);
}
}
counter = counter + 10;
cuttingLine = RG.getLine(counter+ random(-rnd,rnd), 0, 0, counter+ random(-rnd,rnd));
ps = shp.getIntersections(cuttingLine);
if (ps != null) {
if (ps.length > 3) {
curveVertex(ps[2].x, ps[2].y);
curveVertex(ps[3].x, ps[3].y);
}
}
}
endShape();
}
Here is a simple path made with inkscape to try the sketch (save as "M.svg" in "data"):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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"
version="1.1"
id="svg2"
viewBox="0 0 247.85716 239.28571"
height="67.531746mm"
width="69.950798mm">
<defs
id="defs4" />
<metadata
id="metadata7">
<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></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(-180.35713,-224.14791)"
id="layer1">
<path
id="path4324"
d="m 186.92312,458.88793 19.1929,-223.24371 60.10408,0.50508 26.76904,68.69037 49.49747,-69.19545 65.65992,0 -3.03046,215.66757 -61.11423,0.50508 -3.53553,-115.15739 -57.07362,53.033 -30.80965,-71.21575 -9.09138,137.88582 z"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
</svg>
Answers
If you are creating fill scribbles by connecting a points list into a curve, I wonder if you could generate your points list with standard bouncing ball code.
If the shapes are very complex you could do bounce checking within a mask -- bounce if the mask pixel is black. Expensive to compute, but you would only have to calculate the scribble array once per shape -- not every draw pass. Then you could alter the scribble by drifting or rotating the precomputed point list.
Another very different approach to hand-drawn fill effects is use shaders -- usually hatching or crosshatching shaders.
https://github.com/atduskgreg/Processing-Shader-Examples/tree/master/hatchShader
https://www.clicktorelease.com/code/cross-hatching/
http://www.idiotsguides.com/arts-and-entertainment/fine-art-techniques/drawing-101-shading-techniques/
Have you tried the Handy processing library ?
@BigFred -- very cool. Nice examples, beautiful implementation of hachures / hatching.