Daily Creative Coding

元「30 min. Processing」。毎日、Creative Codingします。

動く点でドロネー三角形分割

/*
 * moving triangles
 *
 * @author aadebdeb
 * @date 2017/02/09
 */
 
var MARGIN = 200;
var vertices;
var hueVal;


function setup() {
  createCanvas(windowWidth, windowHeight);
  frameRate(20);
  colorMode(HSB, 360, 100, 100);
  hueVal = random(50);
  vertices = [];
  for (var i = 0; i < 50; i++) {
    var v = new Vertex(createVector(random(-MARGIN, width + MARGIN), random(-MARGIN, height + MARGIN)));
    vertices.push(v);
  }
}

function mousePressed() {
  hueVal = random(360);
}

function drawTriangles() {
  background(hueVal, 70, 70);
  
  delaunayTriangulation = new DelaunayTriangulation();

  for (var i = 0; i < vertices.length; i++) {
    delaunayTriangulation.add(vertices[i]);
  }
  
  var triangles = delaunayTriangulation.getTriangles();
  for (var ti = 0; ti < triangles.length; ti++) {
    var t = triangles[ti];
    var sat = 0;
    var bri = 0;
    for(var vi = 0; vi < 3; vi++) {
      var v = t.vertices[vi];
      sat += v.sat;
      bri += v.bri;
    }
    sat /= 3;
    bri /= 3;
    fill(hueVal, sat, bri);
    stroke(hueVal, sat, bri);
    t.render();
  }
}

function draw() {
  drawTriangles();
  for (var i = 0; i < vertices.length; i++) {
    vertices[i].update();
  }
}

function DelaunayTriangulation() {
  this.triangles = [];
  this.vertices = [];
  this.superVertices = [];
  
  this.render = function() {
    for(var i = 0; i < this.triangles.length; i++) {
      this.triangles[i].render();
    }
  }
  
  this.add = function(v) {
    
    for (var i = 0; i < this.vertices.length; i++) {
      if(v.loc.x == this.vertices[i].loc.x && v.loc.y == this.vertices[i].loc.y) {
        return;
      }
    }
    
    this.vertices.push(v);
    var nextTriangles = [];
    var newTriangles = [];
    for (var ti = 0; ti < this.triangles.length; ti++) {
      var tri = this.triangles[ti];
      if(tri.circumCircle.isInCircle(v.loc)) {
        newTriangles = newTriangles.concat(tri.divide(v));
      } else {
        nextTriangles.push(tri);
      }
    }
    
    for (var ti = 0; ti < newTriangles.length; ti++) {
      var tri = newTriangles[ti];
      var isIllegal = false;
      for (var vi = 0; vi < this.vertices.length; vi++) {
        if (this.isIllegalTriangle(tri, this.vertices[vi])) {
          isIllegal = true;
          break;
        }
      }
      if (!isIllegal) {
        nextTriangles.push(tri);
      }
    }
    
    this.triangles = nextTriangles;      
  }
  
  this.getTriangles = function() {
    var ts = [];
    
    for (var ti = 0; ti < this.triangles.length; ti++) {
      var t = this.triangles[ti];
      var hasSuperVertex = false;
      for (var vi = 0; vi < 3; vi++) {
        if (t.isContain(this.superVertices[vi])) {
          hasSuperVertex = true;
        }
      }
      if (!hasSuperVertex) {
        ts.push(t);
      }
    }
    
    return ts;
  }
  
  this.getTrianglesWithSuperTriangle = function() {
    return this.triangles;
  }
  
  this.isIllegalTriangle = function(t, v) {
    if(t.isContain(v)) {
      return false;
    }
    return t.circumCircle.isInCircle(v.loc);
  }
  
  var center = createVector(width / 2, height / 2);
  var radius = sqrt(sq(width) + sq(height)) / 2;
  var v1 = new Vertex(createVector(center.x - sqrt(3) * radius, center.y - radius));
  var v2 = new Vertex(createVector(center.x + sqrt(3) * radius, center.y - radius));
  var v3 = new Vertex(createVector(center.x, center.y +  2 * radius));
  var t = new Triangle([v1, v2, v3]);
  
  this.superVertices.push(v1);
  this.superVertices.push(v2);
  this.superVertices.push(v3);
  this.vertices.push(v1);
  this.vertices.push(v2);
  this.vertices.push(v3);
  this.triangles.push(t);
  
}

function Triangle(vertices) {
  this.vertices = vertices;
  
  var v1 = this.vertices[0].loc;
  var v2 = this.vertices[1].loc;
  var v3 = this.vertices[2].loc;
  var c = 2 * ((v2.x - v1.x) * (v3.y - v1.y) - (v2.y - v1.y) * (v3.x - v1.x));
  var x = ((v3.y - v1.y) * (sq(v2.x) - sq(v1.x) + sq(v2.y) - sq(v1.y)) + (v1.y - v2.y) * (sq(v3.x) - sq(v1.x) + sq(v3.y) - sq(v1.y))) / c;
  var y = ((v1.x - v3.x) * (sq(v2.x) - sq(v1.x) + sq(v2.y) - sq(v1.y)) + (v2.x - v1.x) * (sq(v3.x) - sq(v1.x) + sq(v3.y) - sq(v1.y))) / c;
  var center = createVector(x, y);
  var radius = v1.dist(center);
  this.circumCircle = new Circle(center, radius);
  
  this.render = function() {
    beginShape();
    for (var i = 0; i < 3; i++) {
      var v = this.vertices[i].loc;
      vertex(v.x, v.y);
    }
    endShape(CLOSE);
  }
  
  this.divide = function(v) {
    var tris = [];
    for (var i = 0; i < 3; i++) {
      var j = i == 2? 0: i + 1;
      tris.push(new Triangle([this.vertices[i], this.vertices[j], v]));
    }
    return tris;
  }
  
  this.isContain = function(v) {
    for (var i = 0; i < 3; i++) {
      if (this.vertices[i] === v) {
        return true;
      }
    }
    return false;
  }
  
}

function Circle(center, radius) {
  this.center = center;
  this.radius = radius;
  
  this.isInCircle = function(v) {
    return this.center.dist(v) < this.radius;
  }
}

function Vertex(loc) {
  this.loc = loc;
  var velAng = random(TWO_PI);
  var velSize = 2.5;
  this.vel = createVector(velSize * cos(velAng), velSize * sin(velAng));
  this.sat = random(50, 100);
  this.bri = random(30, 100);
  
  this.update = function() {
    this.loc.add(this.vel);
    if (this.loc.x < -MARGIN || this.loc.x > width + MARGIN) {
      this.vel.x *= -1;
      this.loc.x += this.vel.x;
    }
    if (this.loc.y < -MARGIN || this.loc.y > height + MARGIN) {
      this.vel.y *= -1;
      this.loc.y += this.vel.y;
    }
  }
}
f:id:aa_debdeb:20170206215649j:plain