X和Y轴的簇数组

时间:2019-05-29 16:08:41

标签: javascript canvas

我有一个看起来像这样的数组

tiles = [{
    x: 0,
    y: 0,
    land: false //true = land false = water
}];

目标是在画布上自动生成一个行星,但是我想对陆地和海洋进行聚类(随机数量)。我已经取得了使它看起来不错的效果,但是我想要更大的陆地和海洋质量,而不是要有任何带有土地/水的“洞”单砖。

我尝试了一些if语句,其中的百分比是水或土地,但我无法将其聚类到比我现在所拥有的更多。我做了一个较小的,结果很好,我希望代码段中的一个可以对图像和链接中的内容进行聚类。 Codepen for the img example

tldr:我希望数组由布尔区域聚类

我该如何进行呢?

enter image description here

var tileNum = 0;
var tiles;
var colorsLand;
var colorsWater;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var tileSize = 1;
canvas.width = canvas.height = 730;
// 'size' is grid size, not the actual pixel size painted on screen
var size = Math.ceil(canvas.width / tileSize);


function generatePlanet() {
  tileNum = 0;
  tiles = [{
    x: 0,
    y: 0,
    land: false
  }];

  //Retrive colors        

  colorsLand = interpolateColors(getColor(true), getColor(true), 6000);
  colorsWater = interpolateColors(getColor(false), getColor(false), 6000);

  //Creates a array of my tiles and sets either water or land to them and calculates the % of being water/land
  for (var i = 0; i < (size * size); i++) {
    var currentTile = tiles[tiles.length - 1];
    if (currentTile.x <= (size - 1)) {
      var isLand = false;

      if (tiles.length >= (size * 2) && (
          tiles[tiles.length - 1].land ||
          tiles[tiles.length - 2].land ||
          tiles[tiles.length - (size)].land ||
          tiles[tiles.length - (size * 2)].land ||
          tiles[tiles.length - (size - 1)].land ||
          tiles[tiles.length - (size - 2)].land
        )) {
        isLand = (Math.floor(Math.random() * 100) + 1) > 66;
      } else if (tiles.length >= (size * 2) && (!tiles[tiles.length - 1].land ||
          !tiles[tiles.length - 2].land ||
          !tiles[tiles.length - (size)].land ||
          !tiles[tiles.length - (size * 2)].land ||
          !tiles[tiles.length - (size - 1)].land ||
          !tiles[tiles.length - (size - 2)].land
        )) {
        isLand = (Math.floor(Math.random() * 1000) + 1) > 999;
      }
      tiles.push({
        x: currentTile.x + 1,
        y: currentTile.y,
        land: isLand
      });
    } else {
      tiles.push({
        x: 1,
        y: currentTile.y + 1,
        land: isLand
      });
    }
  }
  drawPlanet()
}


//retrive a random color if it's a land tile i want it dark water i want light
function getColor(land) {
  while (true) {
    var r = Math.floor(Math.random() * 256) + 1
    var g = Math.floor(Math.random() * 256) + 1
    var b = Math.floor(Math.random() * 256) + 1
    var hsp = Math.sqrt(
      0.299 * (r * r) +
      0.587 * (g * g) +
      0.114 * (b * b)
    );
    //light color
    if (hsp > 127.5 && land == false) {
      return [r, g, b];
    }
    //dark color
    else if (hsp < 127.5 && land == true) {
      return [r, g, b];
    }
  }
}

//these 2 functions interpolateColor(s) takes 2 colors and gives me 'steps' colors between
function interpolateColors(color1, color2, steps) {
  var stepFactor = 1 / (steps - 1),
    interpolatedColorArray = [];

  for (var i = 0; i < steps; i++) {
    interpolatedColorArray.push(toUint32AARRGGBB(interpolateColor(color1, color2, stepFactor * i)));
  }
  return interpolatedColorArray;
}

function toUint32AARRGGBB(arr) {
  return Number('0xFF' + arr.map(toHexString2).join(''))
}

function toHexString2(val) {
  return val.toString(16)
    .padStart(2, '0'); // padStart may need a polyfill
}

function interpolateColor(color1, color2, factor) {
  if (arguments.length < 3) {
    factor = 0.5;
  }
  var result = color1.slice();
  for (var i = 0; i < 3; i++) {
    result[i] = Math.round(result[i] + factor * (color2[i] - color1[i]));
  }
  return result;
};

//retrives a random color for land
function rndLandColor() {
  return colorsLand[Math.floor(Math.random() * 5999) + 1];
}
//retrives a random color for water
function rndWaterColor() {
  return colorsWater[Math.floor(Math.random() * 5999) + 1];
}

// now drawing synchronously:
function drawPlanet() {

  var gridsize = size;
  //   var rad = gridsize / 2;

  // generate an ImageData, the size of our pixel grid
  var imgData = new ImageData(gridsize, gridsize);
  // work directly on Uint32 values (0xAARRGGBB on LittleEndian)
  var data = new Uint32Array(imgData.data.buffer);

  var score, y, x;
  for (y = 0; y < gridsize; y++) {
    for (x = 0; x < gridsize; x++) {
      score = 0;

      //fill in holes in the land that is bigger then 1
      if (tiles[tileNum - (gridsize + 1)] !== undefined && tiles[tileNum + (size + 1)] !== undefined) {
        if (tiles[tileNum].land == false) {
          score++;
        }
        if (tiles[tileNum - 1].land == true) {
          score++;
        }
        if (tiles[tileNum + 1].land == true) {
          score++;
        }
        if (tiles[tileNum + (gridsize + 1)].land == true) {
          score++;
        }
        if (tiles[tileNum - (gridsize + 1)].land == true) {
          score++;
        }
      }

      if (score >= 2) {
        color = rndLandColor();
      }

      //cover single land tiles with water (if water tile is up,down,left and right of this tile)
      else if (
        tiles[tileNum - (gridsize + 1)] !== undefined &&
        tiles[tileNum + (gridsize + 1)] !== undefined &&
        tiles[tileNum - 1].land == false &&
        tiles[tileNum + 1].land == false &&
        tiles[tileNum - (gridsize + 1)].land == false &&
        tiles[tileNum + (gridsize + 1)].land == false) {


        color = rndWaterColor();
      }

      //cover single water tiles with land (if land tile is up,down,left and right of this tile)
      else if (
        tiles[tileNum - (gridsize + 1)] !== undefined &&
        tiles[tileNum + (gridsize + 1)] !== undefined &&
        tiles[tileNum - 1].land == true &&
        tiles[tileNum + 1].land == true &&
        tiles[tileNum - (gridsize + 1)].land == true &&
        tiles[tileNum + (gridsize + 1)].land == true) {
        color = rndLandColor();
      }
      //cover tile with land
      else if (tiles[tileNum] !== undefined && tiles[tileNum].land == true) {
        color = rndLandColor();
      }

      //cover tile with water
      else if (tiles[tileNum] !== undefined && tiles[tileNum].land == false) {
        color = rndWaterColor();
      }

      tileNum++;
      data[(y * gridsize) + x] = color;
    }
  }
  // all done populating the ImageData
  // put it on the context at scale(1,1)
  ctx.putImageData(imgData, 0, 0);
  // remove antialiasing
  ctx.imageSmoothingEnabled = false;
  // up-scale
  ctx.scale(tileSize, tileSize);
  // draw the canvas over itself
  ctx.drawImage(ctx.canvas, 0, 0);
  ctx.setTransform(1, 0, 0, 1, 0, 0);
}

generatePlanet();
#canvas {
  border: 10px solid #000000;
  border-radius: 50%;
  /* background-color: aquamarine; */
}

.container {
  width: 720px;
  height: 720px;
  position: relative;
}

.gradient {
  position: absolute;
  height: 745px;
  width: 745px;
  top: 0;
  left: 0;
  border-radius: 50%;
  opacity: 0.8;
}
<button onclick="generatePlanet()">GENERATE</button>
<div class="container">
  <img class="gradient" src="https://www.mediafire.com/convkey/1f5a/cgu50lw1ehcp4fq6g.jpg" />
  <canvas id="canvas" width="710" height="710"></canvas>
</div>

0 个答案:

没有答案