LCOV - code coverage report
Current view: top level - maps/random/rmgen/placer/centered - ClumpPlacer.js (source / functions) Hit Total Coverage
Test: lcov.info Lines: 2 51 3.9 %
Date: 2023-04-02 12:52:40 Functions: 0 4 0.0 %

          Line data    Source code
       1             : /**
       2             :  * Generates a roughly circular clump of points.
       3             :  *
       4             :  * @param {number} size - The average number of points in the clump. Correlates to the area of the circle.
       5             :  * @param {number} coherence - How much the radius of the clump varies (1 = circle, 0 = very random).
       6             :  * @param {number} smoothness - How smooth the border of the clump is (1 = few "peaks", 0 = very jagged).
       7             :  * @param {number} [failfraction] - Percentage of place attempts allowed to fail.
       8             :  * @param {Vector2D} [centerPosition] - Tile coordinates of placer center.
       9             :  */
      10             : function ClumpPlacer(size, coherence, smoothness, failFraction = 0, centerPosition = undefined)
      11             : {
      12           0 :         this.size = size;
      13           0 :         this.coherence = coherence;
      14           0 :         this.smoothness = smoothness;
      15           0 :         this.failFraction = failFraction;
      16           0 :         this.centerPosition = undefined;
      17             : 
      18           0 :         if (centerPosition)
      19           0 :                 this.setCenterPosition(centerPosition);
      20             : }
      21             : 
      22           6 : ClumpPlacer.prototype.setCenterPosition = function(position)
      23             : {
      24           0 :         this.centerPosition = deepfreeze(position.clone().round());
      25             : };
      26             : 
      27           6 : ClumpPlacer.prototype.place = function(constraint)
      28             : {
      29             :         // Preliminary bounds check
      30           0 :         if (!g_Map.inMapBounds(this.centerPosition) || !constraint.allows(this.centerPosition))
      31           0 :                 return undefined;
      32             : 
      33           0 :         var points = [];
      34             : 
      35           0 :         var size = g_Map.getSize();
      36           0 :         var gotRet = new Array(size).fill(0).map(p => new Uint8Array(size)); // booleans
      37           0 :         var radius = Math.sqrt(this.size / Math.PI);
      38           0 :         var perim = 4 * radius * 2 * Math.PI;
      39           0 :         var intPerim = Math.ceil(perim);
      40             : 
      41           0 :         var ctrlPts = 1 + Math.floor(1.0/Math.max(this.smoothness,1.0/intPerim));
      42             : 
      43           0 :         if (ctrlPts > radius * 2 * Math.PI)
      44           0 :                 ctrlPts = Math.floor(radius * 2 * Math.PI) + 1;
      45             : 
      46           0 :         var noise = new Float32Array(intPerim);                 //float32
      47           0 :         var ctrlCoords = new Float32Array(ctrlPts+1);   //float32
      48           0 :         var ctrlVals = new Float32Array(ctrlPts+1);             //float32
      49             : 
      50             :         // Generate some interpolated noise
      51           0 :         for (var i=0; i < ctrlPts; i++)
      52             :         {
      53           0 :                 ctrlCoords[i] = i * perim / ctrlPts;
      54           0 :                 ctrlVals[i] = randFloat(0, 2);
      55             :         }
      56             : 
      57           0 :         let c = 0;
      58           0 :         let looped = 0;
      59           0 :         for (let i = 0; i < intPerim; ++i)
      60             :         {
      61           0 :                 if (ctrlCoords[(c+1) % ctrlPts] < i && !looped)
      62             :                 {
      63           0 :                         c = (c+1) % ctrlPts;
      64           0 :                         if (c == ctrlPts-1)
      65           0 :                                 looped = 1;
      66             :                 }
      67             : 
      68           0 :                 noise[i] = cubicInterpolation(
      69             :                         1,
      70             :                         (i - ctrlCoords[c]) / ((looped ? perim : ctrlCoords[(c + 1) % ctrlPts]) - ctrlCoords[c]),
      71             :                         ctrlVals[(c + ctrlPts - 1) % ctrlPts],
      72             :                         ctrlVals[c],
      73             :                         ctrlVals[(c + 1) % ctrlPts],
      74             :                         ctrlVals[(c + 2) % ctrlPts]);
      75             :         }
      76             : 
      77           0 :         let failed = 0;
      78           0 :         let count = 0;
      79           0 :         for (let stepAngle = 0; stepAngle < intPerim; ++stepAngle)
      80             :         {
      81           0 :                 let position = this.centerPosition.clone();
      82           0 :                 let radiusUnitVector = new Vector2D(0, 1).rotate(-2 * Math.PI * stepAngle / perim);
      83           0 :                 let maxRadiusSteps = Math.ceil(radius * (1 + (1 - this.coherence) * noise[stepAngle]));
      84             : 
      85           0 :                 count += maxRadiusSteps;
      86           0 :                 for (let stepRadius = 0; stepRadius < maxRadiusSteps; ++stepRadius)
      87             :                 {
      88           0 :                         let tilePos = position.clone().floor();
      89             : 
      90           0 :                         if (g_Map.inMapBounds(tilePos) && constraint.allows(tilePos))
      91             :                         {
      92           0 :                                 if (!gotRet[tilePos.x][tilePos.y])
      93             :                                 {
      94           0 :                                         gotRet[tilePos.x][tilePos.y] = 1;
      95           0 :                                         points.push(tilePos);
      96             :                                 }
      97             :                         }
      98             :                         else
      99           0 :                                 ++failed;
     100             : 
     101           0 :                         position.add(radiusUnitVector);
     102             :                 }
     103             :         }
     104             : 
     105           0 :         return failed > count * this.failFraction ? undefined : points;
     106             : };

Generated by: LCOV version 1.14