Procedural Poutsa Generator
in HTML5 canvas and JS.
( you can try the code on jsfiddle, here : https://jsfiddle.net/ef7Lw3kr/3/ )
function Randomcolorset() {
// To colorize each poutsaki, we use a color wheel,
// and we randomly choose two matching and
// one contrasting color from the colorwheel.
this.colorwheel = ["#FF0000","#FF8000","#FFFF00",
"#80FF00","#00FF00","#00FF80",
"#00FFFF","#0080FF","#0000FF",
"#8000FF","#FF00FF","#FF0080"];
this.getrandom = function() {
var mc1 = Math.floor(Math.random()*this.colorwheel.length);
var mc2 = (mc1 + 1) % this.colorwheel.length;
if (Math.random() > 0.5) {
var tmp = mc2;
mc2 = mc1;
mc1 = tmp;
}
var cc = (mc1 + this.colorwheel.length / 2) % this.colorwheel.length;
randset = [this.colorwheel[mc1], this.colorwheel[mc2], this.colorwheel[cc]];
return randset;
}
}
function Poutsaki(x, y, length, trihes, petsa, colorset, rotation, tsoureki_factors) {
this.length = length;
// We only parametrize on length, then we derive penile width
// using the Golden Ratio, to give our poutsakia
// aesthetically pleasing, harmonic element size proportions.
// Just like the Parthenon.
this.width = length / 1.618;
this.x = x;
this.y = y;
this.trihes = trihes;
this.petsa = petsa;
this.colorset = colorset;
this.rotation = rotation;
this.tsoureki_factors = tsoureki_factors;
this.paint = function(ctx) {
var ctx = canvas.getContext('2d');
ctx.rotate(this.rotation);
ctx.lineWidth = this.petsa;
ctx.fillStyle = this.colorset[0];
ctx.beginPath();
ctx.arc(this.x + (this.width / 2), this.y, (this.width / 2), Math.PI, 0);
ctx.stroke();
ctx.fill();
ctx.beginPath();
ctx.moveTo(this.x + (this.width / 2), this.y - (this.width / 2));
ctx.lineTo(this.x + (this.width / 2), this.y - (this.width / 4));
ctx.stroke();
ctx.fillStyle = this.colorset[1];
ctx.beginPath();
ctx.rect(this.x, this.y, this.width, this.length);
ctx.stroke();
ctx.fill();
ctx.fillStyle = this.colorset[2];
for (arhidi = 0; arhidi < 2 ; arhidi++) {
var arhidoffset = arhidi * this.width;
ctx.beginPath();
var tsoureki = (this.width / 2) * this.tsoureki_factors[arhidi];
ctx.arc(this.x + arhidoffset, this.y + this.length, (this.width / 2) + tsoureki, 0, 2 * Math.PI);
ctx.stroke();
ctx.fill();
// The trihes drawing algorithm needs some improvement,
// but it's quite good for a demo.
// Perhaps we could use bezier curves for the trihes.
for (trihindex = 0; trihindex < trihes; trihindex++) {
var a = Math.random() * 2 * Math.PI;
var r = (this.width / 2) * Math.sqrt(Math.random());
var x1 = this.x + arhidoffset + (r * Math.cos(a));
var y1 = this.y + this.length + (r * Math.sin(a));
ctx.beginPath();
ctx.moveTo(x1,y1);
r = this.width * Math.sqrt(Math.random());
x1 = this.x + arhidoffset + (r * Math.cos(a));
y1 = this.y + this.length + (r * Math.sin(a));
ctx.lineTo(x1, y1);
ctx.stroke();
}
}
}
}
function initcanvas() {
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var maxpoutses = 10 + (50 * Math.random());
var cs = new Randomcolorset();
for (poutsarithmos = 0; poutsarithmos < maxpoutses ; poutsarithmos++) {
var length = 200 * Math.random();
var x = length + 1000 * Math.random();
var y = length + 400 * Math.random();
// We have no concrete real world model on
// the distribution of number of trihes per
// arhidi.
// But as the primary author lives in Asia, and the
// trihes algorithm is not yet perfect, we choose to
// somewhat limit the hairness of our poutsakia to
// cater to prevailing social norms.
// Feel free to adjust for your testes.
var trihes = (Math.random() < 0.2 ? 20 * Math.random() : 0);
var petsa = (4 * Math.random());
var colorset = cs.getrandom();
var rotation = 2 * Math.PI * Math.random();
// Real world arhidia never have the exact same size.
// One could convincingly argue that a penis
// generation algorithm has to express the
// idealized, abstract, platonic Ideal of a
// poutsa, rather than any concrete, material
// poutsa incarnations. But as any practician
// can tell you, catering for the real world,
// practical cases is usually more necessary than
// achieving strict correctness.
// To hit the perfect balance, we slightly vary the
// dimensions of each arhidi in 33% of the cases,
// using a random tsoureki factor capped to max 10%
var tsoureki_factors = [ 0, 0 ];
if (Math.random() < 0.33) {
tsoureki_factors[0] = 0.1 * (0.5 - Math.random());
tsoureki_factors[1] = 0.1 * (0.5 - Math.random());
}
var peos = new Poutsaki(x, y, length, trihes, petsa, colorset, rotation, tsoureki_factors);
peos.paint(canvas);
}
}
}
// To colorize each poutsaki, we use a color wheel,
// and we randomly choose two matching and
// one contrasting color from the colorwheel.
this.colorwheel = ["#FF0000","#FF8000","#FFFF00",
"#80FF00","#00FF00","#00FF80",
"#00FFFF","#0080FF","#0000FF",
"#8000FF","#FF00FF","#FF0080"];
this.getrandom = function() {
var mc1 = Math.floor(Math.random()*this.colorwheel.length);
var mc2 = (mc1 + 1) % this.colorwheel.length;
if (Math.random() > 0.5) {
var tmp = mc2;
mc2 = mc1;
mc1 = tmp;
}
var cc = (mc1 + this.colorwheel.length / 2) % this.colorwheel.length;
randset = [this.colorwheel[mc1], this.colorwheel[mc2], this.colorwheel[cc]];
return randset;
}
}
function Poutsaki(x, y, length, trihes, petsa, colorset, rotation, tsoureki_factors) {
this.length = length;
// We only parametrize on length, then we derive penile width
// using the Golden Ratio, to give our poutsakia
// aesthetically pleasing, harmonic element size proportions.
// Just like the Parthenon.
this.width = length / 1.618;
this.x = x;
this.y = y;
this.trihes = trihes;
this.petsa = petsa;
this.colorset = colorset;
this.rotation = rotation;
this.tsoureki_factors = tsoureki_factors;
this.paint = function(ctx) {
var ctx = canvas.getContext('2d');
ctx.rotate(this.rotation);
ctx.lineWidth = this.petsa;
ctx.fillStyle = this.colorset[0];
ctx.beginPath();
ctx.arc(this.x + (this.width / 2), this.y, (this.width / 2), Math.PI, 0);
ctx.stroke();
ctx.fill();
ctx.beginPath();
ctx.moveTo(this.x + (this.width / 2), this.y - (this.width / 2));
ctx.lineTo(this.x + (this.width / 2), this.y - (this.width / 4));
ctx.stroke();
ctx.fillStyle = this.colorset[1];
ctx.beginPath();
ctx.rect(this.x, this.y, this.width, this.length);
ctx.stroke();
ctx.fill();
ctx.fillStyle = this.colorset[2];
for (arhidi = 0; arhidi < 2 ; arhidi++) {
var arhidoffset = arhidi * this.width;
ctx.beginPath();
var tsoureki = (this.width / 2) * this.tsoureki_factors[arhidi];
ctx.arc(this.x + arhidoffset, this.y + this.length, (this.width / 2) + tsoureki, 0, 2 * Math.PI);
ctx.stroke();
ctx.fill();
// The trihes drawing algorithm needs some improvement,
// but it's quite good for a demo.
// Perhaps we could use bezier curves for the trihes.
for (trihindex = 0; trihindex < trihes; trihindex++) {
var a = Math.random() * 2 * Math.PI;
var r = (this.width / 2) * Math.sqrt(Math.random());
var x1 = this.x + arhidoffset + (r * Math.cos(a));
var y1 = this.y + this.length + (r * Math.sin(a));
ctx.beginPath();
ctx.moveTo(x1,y1);
r = this.width * Math.sqrt(Math.random());
x1 = this.x + arhidoffset + (r * Math.cos(a));
y1 = this.y + this.length + (r * Math.sin(a));
ctx.lineTo(x1, y1);
ctx.stroke();
}
}
}
}
function initcanvas() {
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var maxpoutses = 10 + (50 * Math.random());
var cs = new Randomcolorset();
for (poutsarithmos = 0; poutsarithmos < maxpoutses ; poutsarithmos++) {
var length = 200 * Math.random();
var x = length + 1000 * Math.random();
var y = length + 400 * Math.random();
// We have no concrete real world model on
// the distribution of number of trihes per
// arhidi.
// But as the primary author lives in Asia, and the
// trihes algorithm is not yet perfect, we choose to
// somewhat limit the hairness of our poutsakia to
// cater to prevailing social norms.
// Feel free to adjust for your testes.
var trihes = (Math.random() < 0.2 ? 20 * Math.random() : 0);
var petsa = (4 * Math.random());
var colorset = cs.getrandom();
var rotation = 2 * Math.PI * Math.random();
// Real world arhidia never have the exact same size.
// One could convincingly argue that a penis
// generation algorithm has to express the
// idealized, abstract, platonic Ideal of a
// poutsa, rather than any concrete, material
// poutsa incarnations. But as any practician
// can tell you, catering for the real world,
// practical cases is usually more necessary than
// achieving strict correctness.
// To hit the perfect balance, we slightly vary the
// dimensions of each arhidi in 33% of the cases,
// using a random tsoureki factor capped to max 10%
var tsoureki_factors = [ 0, 0 ];
if (Math.random() < 0.33) {
tsoureki_factors[0] = 0.1 * (0.5 - Math.random());
tsoureki_factors[1] = 0.1 * (0.5 - Math.random());
}
var peos = new Poutsaki(x, y, length, trihes, petsa, colorset, rotation, tsoureki_factors);
peos.paint(canvas);
}
}
}