three.js - triangulate planet

by mmalex

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.js"></script>
<script src="https://threejs.org/examples/js/controls/TrackballControls.js"></script>
<script src="http://mbnsay.com/rayys/assets/js/Delaunator.js"></script>
<button id="btn" onclick="start()">Generate</button>
<div id="progress">Click to start mesh generation process, it will take a while.</div>

CSS

#progress {
  position: fixed;
  padding-left: 100px;
  top: 0;
  left: 0;
  right: 0;
  z-index: 9;
  height: 32px;
  line-height: 32px;
  font-size: 11px;
  font-family: monospace;
  background-color: rgba(0, 0, 0, 0.75);
  color: white;
}

#btn {
    z-index: 10;
    position: fixed;
    top: 5px;
    left: 5px;
}

body {
  margin: 0;
  padding: 0;
  overflow: hidden;
}

JavaScript

/* Draw GeoJSON

Iterates through the latitude and longitude values, converts the values to XYZ coordinates, and draws the geoJSON geometries.

*/

let TRIANGULATION_DENSITY = 5;
let WIREFRAME = false;

function verts2array(coords) {
  let flat = [];
  for (let k = 0; k < coords.length; k++) {
    flat.push(coords[k][0], coords[k][1]);
  }
  return flat;
}

function array2verts(arr) {
  let coords = [];
  for (let k = 0; k < arr.length; k += 2) {
    coords.push([arr[k], arr[k + 1]]);
  }
  return coords;
}

function findBBox(points) {
  let min = {
    x: 1e99,
    y: 1e99
  };
  let max = {
    x: -1e99,
    y: -1e99
  };
  for (var point_num = 0; point_num < points.length; point_num++) {
    if (points[point_num][0] < min.x) {
      min.x = points[point_num][0];
    }
    if (points[point_num][0] > max.x) {
      max.x = points[point_num][0];
    }
    if (points[point_num][1] < min.y) {
      min.y = points[point_num][1];
    }
    if (points[point_num][1] > max.y) {
      max.y = points[point_num][1];
    }
  }
  return {
    min: min,
    max: max
  };
}

function isInside(point, vs) {
  // ray-casting algorithm based on
  // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html

  var x = point[0],
    y = point[1];

  var inside = false;
  for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
    var xi = vs[i][0],
      yi = vs[i][1];
    var xj = vs[j][0],
      yj = vs[j][1];

    var intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
    if (intersect) inside = !inside;
  }

  return inside;
}

function genInnerVerts(points) {
  let res = [];
  for (let k = 0; k < points.length; k++) {
    res.push(points[k]);
  }

  let bbox = findBBox(points);

  let step = TRIANGULATION_DENSITY;
  let k = 0;
  for (let x = bbox.min.x + step / 2; x < bbox.max.x; x += step) {
    for (let y = bbox.min.y + step / 2; y < bbox.max.y; y += step) {
      let newp = [x, y];
      if (isInside(newp, points)) {
       ...