Friday, June 07, 2019

Procedural Poutsa Generator


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);
        }
      }
    }