LCOV - code coverage report
Current view: top level - maps/random/rmgen/placer/noncentered - PathPlacer.js (source / functions) Hit Total Coverage
Test: lcov.info Lines: 1 53 1.9 %
Date: 2023-04-02 12:52:40 Functions: 0 3 0.0 %

          Line data    Source code
       1             : /**
       2             :  * Creates a winding path between two points.
       3             :  *
       4             :  * @param {Vector2D} start - Starting position of the path.
       5             :  * @param {Vector2D} end - Endposition of the path.
       6             :  * @param {number} width - Number of tiles between two sides of the path.
       7             :  * @param {number} waviness - 0 is a straight line, higher numbers are.
       8             :  * @param {number} smoothness - the higher the number, the smoother the path.
       9             :  * @param {number} offset - Maximum amplitude of waves along the path. 0 is straight line.
      10             :  * @param {number} tapering - How much the width of the path changes from start to end.
      11             :  *   If positive, the width will decrease by that factor.
      12             :  *   If negative the width will increase by that factor.
      13             :  */
      14             : function PathPlacer(start, end, width, waviness, smoothness, offset, tapering, failFraction = 0)
      15             : {
      16           0 :         this.start = start;
      17           0 :         this.end = end;
      18           0 :         this.width = width;
      19           0 :         this.waviness = waviness;
      20           0 :         this.smoothness = smoothness;
      21           0 :         this.offset = offset;
      22           0 :         this.tapering = tapering;
      23           0 :         this.failFraction = failFraction;
      24             : }
      25             : 
      26           6 : PathPlacer.prototype.place = function(constraint)
      27             : {
      28           0 :         let pathLength = this.start.distanceTo(this.end);
      29             : 
      30           0 :         let numStepsWaviness = 1 + Math.floor(pathLength / 4 * this.waviness);
      31           0 :         let numStepsLength = 1 + Math.floor(pathLength / 4 * this.smoothness);
      32           0 :         let offset = 1 + Math.floor(pathLength / 4 * this.offset);
      33             : 
      34             :         // Generate random offsets
      35           0 :         let ctrlVals = new Float32Array(numStepsWaviness);
      36           0 :         for (let j = 1; j < numStepsWaviness - 1; ++j)
      37           0 :                 ctrlVals[j] = randFloat(-offset, offset);
      38             : 
      39             :         // Interpolate for smoothed 1D noise
      40           0 :         let totalSteps = numStepsWaviness * numStepsLength;
      41           0 :         let noise = new Float32Array(totalSteps + 1);
      42           0 :         for (let j = 0; j < numStepsWaviness; ++j)
      43           0 :                 for (let k = 0; k < numStepsLength; ++k)
      44           0 :                         noise[j * numStepsLength + k] = cubicInterpolation(
      45             :                                 1,
      46             :                                 k / numStepsLength,
      47             :                                 ctrlVals[(j + numStepsWaviness - 1) % numStepsWaviness],
      48             :                                 ctrlVals[j],
      49             :                                 ctrlVals[(j + 1) % numStepsWaviness],
      50             :                                 ctrlVals[(j + 2) % numStepsWaviness]);
      51             : 
      52             :         // Add smoothed noise to straight path
      53           0 :         let pathPerpendicular = Vector2D.sub(this.end, this.start).normalize().perpendicular();
      54           0 :         let segments1 = [];
      55           0 :         let segments2 = [];
      56             : 
      57           0 :         for (let j = 0; j < totalSteps; ++j)
      58             :         {
      59             :                 // Interpolated points along straight path
      60           0 :                 let step1 = j / totalSteps;
      61           0 :                 let step2 = (j + 1) / totalSteps;
      62           0 :                 let stepStart = Vector2D.add(Vector2D.mult(this.start, 1 - step1), Vector2D.mult(this.end, step1));
      63           0 :                 let stepEnd = Vector2D.add(Vector2D.mult(this.start, 1 - step2), Vector2D.mult(this.end, step2));
      64             : 
      65             :                 // Find noise offset points
      66           0 :                 let noiseStart = Vector2D.add(stepStart, Vector2D.mult(pathPerpendicular, noise[j]));
      67           0 :                 let noiseEnd = Vector2D.add(stepEnd, Vector2D.mult(pathPerpendicular, noise[j + 1]));
      68           0 :                 let noisePerpendicular = Vector2D.sub(noiseEnd, noiseStart).normalize().perpendicular();
      69             : 
      70           0 :                 let taperedWidth = (1 - step1 * this.tapering) * this.width / 2;
      71             : 
      72           0 :                 segments1.push(Vector2D.sub(noiseStart, Vector2D.mult(noisePerpendicular, taperedWidth)).round());
      73           0 :                 segments2.push(Vector2D.add(noiseEnd, Vector2D.mult(noisePerpendicular, taperedWidth)).round());
      74             :         }
      75             : 
      76             :         // Draw path segments
      77           0 :         let size = g_Map.getSize();
      78           0 :         let gotRet = new Array(size).fill(0).map(i => new Uint8Array(size));
      79           0 :         let retVec = [];
      80           0 :         let failed = 0;
      81             : 
      82           0 :         for (let j = 0; j < segments1.length - 1; ++j)
      83             :         {
      84           0 :                 let points = new ConvexPolygonPlacer([segments1[j], segments1[j + 1], segments2[j], segments2[j + 1]], Infinity).place(new NullConstraint());
      85           0 :                 if (!points)
      86           0 :                         continue;
      87             : 
      88           0 :                 for (let point of points)
      89             :                 {
      90           0 :                         if (!constraint.allows(point))
      91             :                         {
      92           0 :                                 if (!this.failFraction)
      93           0 :                                         return undefined;
      94             : 
      95           0 :                                 ++failed;
      96           0 :                                 continue;
      97             :                         }
      98             : 
      99           0 :                         if (g_Map.inMapBounds(point) && !gotRet[point.x][point.y])
     100             :                         {
     101           0 :                                 retVec.push(point);
     102           0 :                                 gotRet[point.x][point.y] = 1;
     103             :                         }
     104             :                 }
     105             :         }
     106             : 
     107           0 :         return failed > this.failFraction * this.width * pathLength ? undefined : retVec;
     108             : };

Generated by: LCOV version 1.14