All files / src/components/VirtualWalkthrough groundPlane.ts

100% Statements 30/30
100% Branches 8/8
100% Functions 2/2
100% Lines 30/30

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50          2x 260x 1x     259x               2x 13x 1x   12x 12x 12x 12x 12x 12x 12x 12x 12x 12x 12x 12x 12x 12x 2x   10x 10x 10x 10x 9x 9x 9x     10x    
import { Vec3 } from 'playcanvas';
 
export type GroundPlane = { normal: Vec3; point: Vec3 };
 
/** Compute Y on the plane defined by `normal` passing through `point` at world XZ coords (x, z). */
export const yOnPlane = (x: number, z: number, normal: Vec3, point: Vec3, fallback: number): number => {
  if (Math.abs(normal.y) < 1e-6) {
    return fallback;
  }
 
  return point.y - (normal.x * (x - point.x) + normal.z * (z - point.z)) / normal.y;
};
 
/**
 * Derive a ground plane from 3 world-space points.
 * Returns a normalized normal (flipped so normal.y >= 0) and a point on the plane,
 * or null when fewer than 3 points are supplied or they are degenerate/collinear.
 */
export const computeGroundPlane = (points: Vec3[]): GroundPlane | null => {
  if (points.length < 3) {
    return null;
  }
  const p0 = points[0];
  const p1 = points[1];
  const p2 = points[2];
  const v1x = p1.x - p0.x;
  const v1y = p1.y - p0.y;
  const v1z = p1.z - p0.z;
  const v2x = p2.x - p0.x;
  const v2y = p2.y - p0.y;
  const v2z = p2.z - p0.z;
  let nx = v1y * v2z - v1z * v2y;
  let ny = v1z * v2x - v1x * v2z;
  let nz = v1x * v2y - v1y * v2x;
  const len = Math.sqrt(nx * nx + ny * ny + nz * nz);
  if (len < 1e-10) {
    return null;
  }
  nx /= len;
  ny /= len;
  nz /= len;
  if (ny < 0) {
    nx = -nx;
    ny = -ny;
    nz = -nz;
  }
 
  return { normal: new Vec3(nx, ny, nz), point: new Vec3(p0.x, p0.y, p0.z) };
};