Showing posts with label canvas. Show all posts
Showing posts with label canvas. Show all posts

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