<commit_before>import Vector2 from '../vector2'
// TODO: don't use this directly, refer to it from game so this is completely separate
import {Time} from '../constants/private'

// https://www.geometrictools.com/Documentation/MethodOfSeparatingAxes.pdf
// See section on "moving objects"

// if it overlaps, return the projection vector
function checkProjectionOverlap(vertices1, vertices2, vector, MTV) {
  let min1 = Infinity
  let max1 = -Infinity
  let min2 = Infinity
  let max2 = -Infinity
  vertices1.map(function(vertex) {
    let val = Vector2.ProjectScalar(vertex, vector)
    min1 = Math.min(min1, val)
    max1 = Math.max(max1, val)
  })

  vertices2.map(function(vertex) {
    let val = Vector2.ProjectScalar(vertex, vector)
    min2 = Math.min(min2, val)
    max2 = Math.max(max2, val)
  })

  // no overlap
  if (min1 > max2 || max1 < min2) {
    return null
  } else {
    // the magnitude of the overlap
    let newMTVMagnitude = Math.min(max2 - min1, max1 - min2)
    let vectorMag = vector.mag()
    // if the magnitude is smaller than the magnitude of the current mtv then we should update
    // the mtv with the new values
    if (newMTVMagnitude < MTV.mag()) {
      MTV.x = vector.x * newMTVMagnitude / vectorMag
      MTV.y = vector.y * newMTVMagnitude / vectorMag
    }
    return MTV
  }
}

// TODO: for now it assumes both gobs are convex
// returns null if no collision, otherwise returns MTV
// http://www.metanetsoftware.com/technique/tutorialA.html
export function SAT(gob1, gob2) {
  // get the absolute vertices
  let vertices1 = gob1.getAABB()
  let vertices2 = gob2.getAABB()

  // gather the normals
  let normals1 = gob1.getNormals()
  let normals2 = gob2.getNormals()

  let MTV = new Vector2(-Infinity, -Infinity)

  // for each normal, project both shapes onto the normal. if they don't intersect, then immediately return false.
  // otherwise return true at the end
  for (let i=0; i<normals1.length; i++) {
    MTV = checkProjectionOverlap(vertices1, vertices2, normals1[i], MTV)
    if (MTV == null) {
      return false
    }
  }

  for (let i=0; i<normals2.length; i++) {
    MTV = checkProjectionOverlap(vertices1, vertices2, normals2[i], MTV)
    if (MTV == null) {
      return false
    }
  }

  // TODO: adjust the gobs here instead of in collision engine
  resolveStaticCollision(gob1, gob2, MTV)

  return true
}

/* resolve a collision between two non-moving objects (project them out) */
export function resolveStaticCollision(gob1, gob2, MTV) {
  // first project gob1 and gob2 out of the MTV by determining the proportion of VELOCITY
  let v1m = gob1.velocity.mag()
  let v2m = gob2.velocity.mag()

  let totalVelocity = v1m + v2m

  let p1 = v1m / (v1m + v2m)
  let p2 = v2m / (v2m + v1m)

  let [left, right] = gob1.position.x >= gob2.position.x ? [gob2, gob1] : [gob1, gob2]
  let [top, bottom] = gob1.position.y >= gob2.position.y ? [gob2, gob1] : [gob1, gob2]

  right.position.x += MTV.x
  bottom.position.y -= MTV.y
}

// TODO: Have restitution ONLY BE APPLIED for normal velocities
// ALSO TODO: Have restitution be applied PER OBJEcT. It's just easier to
// think about that way. if you don't want an object to have energy lost in
// collistion, just set the mass to 0!
// http://vobarian.com/collisions/2dcollisions2.pdf
function adjustPhysicsVelocity(gob1, gob2, normal) {
  // tangent is the normal of the normal
  const tangent = normal.orthol()
  // const unitNormal = Vector2.Normalized(normal)

  const unitNormal = Vector2.Normalized(normal)
  const unitTangent = Vector2.Normalized(tangent)

  const m1 = gob1.mass
  const m2 = gob2.mass

  const v1n = Vector2.ProjectScalar(gob1.velocity, normal)
  const v1t = Vector2.ProjectScalar(gob1.velocity, tangent)
  const v2n = Vector2.ProjectScalar(gob2.velocity, normal)
  const v2t = Vector2.ProjectScalar(gob2.velocity, tangent)

  // coefficient of restitution == bounciness
  // See http://www.box2dflash.org/docs/2.0.2/manual#Friction_and_Restitution
  // const restitution = Math.max(gob1.bounce, gob2.bounce)
  //
  // Instead of having a single restitution value, we just use restitution
  // per object. this way, dev's can more easily imagine how individual objects
  // are affected by collisions
  //
  // (v1n * (m1 - m2) + 2 * m2 * v2n) / (m1 + m2)
  const newv1n = gob1.bounce * (v1n * (m1 - m2) + 2 * m2 * v2n) / (m1 + m2)
  const newv1t = v1t

  // coefficient of restitution == bounciness
  // (v2n * (m2 - m1) + 2 * m1 * v1n) / (m1 + m2)
  const newv2n = gob2.bounce * (v2n * (m2 - m1) + 2 * m1 * v1n) / (m1 + m2)
  const newv2t = v2t<commit_msg>add tangential friction<commit_after>import Vector2 from '../vector2'
// TODO: don't use this directly, refer to it from game so this is completely separate
import {Time} from '../constants/private'

// https://www.geometrictools.com/Documentation/MethodOfSeparatingAxes.pdf
// See section on "moving objects"

// if it overlaps, return the projection vector
function checkProjectionOverlap(vertices1, vertices2, vector, MTV) {
  let min1 = Infinity
  let max1 = -Infinity
  let min2 = Infinity
  let max2 = -Infinity
  vertices1.map(function(vertex) {
    let val = Vector2.ProjectScalar(vertex, vector)
    min1 = Math.min(min1, val)
    max1 = Math.max(max1, val)
  })

  vertices2.map(function(vertex) {
    let val = Vector2.ProjectScalar(vertex, vector)
    min2 = Math.min(min2, val)
    max2 = Math.max(max2, val)
  })

  // no overlap
  if (min1 > max2 || max1 < min2) {
    return null
  } else {
    // the magnitude of the overlap
    let newMTVMagnitude = Math.min(max2 - min1, max1 - min2)
    let vectorMag = vector.mag()
    // if the magnitude is smaller than the magnitude of the current mtv then we should update
    // the mtv with the new values
    if (newMTVMagnitude < MTV.mag()) {
      MTV.x = vector.x * newMTVMagnitude / vectorMag
      MTV.y = vector.y * newMTVMagnitude / vectorMag
    }
    return MTV
  }
}

// TODO: for now it assumes both gobs are convex
// returns null if no collision, otherwise returns MTV
// http://www.metanetsoftware.com/technique/tutorialA.html
export function SAT(gob1, gob2) {
  // get the absolute vertices
  let vertices1 = gob1.getAABB()
  let vertices2 = gob2.getAABB()

  // gather the normals
  let normals1 = gob1.getNormals()
  let normals2 = gob2.getNormals()

  let MTV = new Vector2(-Infinity, -Infinity)

  // for each normal, project both shapes onto the normal. if they don't intersect, then immediately return false.
  // otherwise return true at the end
  for (let i=0; i<normals1.length; i++) {
    MTV = checkProjectionOverlap(vertices1, vertices2, normals1[i], MTV)
    if (MTV == null) {
      return false
    }
  }

  for (let i=0; i<normals2.length; i++) {
    MTV = checkProjectionOverlap(vertices1, vertices2, normals2[i], MTV)
    if (MTV == null) {
      return false
    }
  }

  // TODO: adjust the gobs here instead of in collision engine
  resolveStaticCollision(gob1, gob2, MTV)

  return true
}

/* resolve a collision between two non-moving objects (project them out) */
export function resolveStaticCollision(gob1, gob2, MTV) {
  // first project gob1 and gob2 out of the MTV by determining the proportion of VELOCITY
  let v1m = gob1.velocity.mag()
  let v2m = gob2.velocity.mag()

  let totalVelocity = v1m + v2m

  let p1 = v1m / (v1m + v2m)
  let p2 = v2m / (v2m + v1m)

  let [left, right] = gob1.position.x >= gob2.position.x ? [gob2, gob1] : [gob1, gob2]
  let [top, bottom] = gob1.position.y >= gob2.position.y ? [gob2, gob1] : [gob1, gob2]

  right.position.x += MTV.x
  bottom.position.y -= MTV.y
}

// TODO: Have restitution ONLY BE APPLIED for normal velocities
// ALSO TODO: Have restitution be applied PER OBJEcT. It's just easier to
// think about that way. if you don't want an object to have energy lost in
// collistion, just set the mass to 0!
// http://vobarian.com/collisions/2dcollisions2.pdf
function adjustPhysicsVelocity(gob1, gob2, normal) {
  // tangent is the normal of the normal
  const tangent = normal.orthol()
  // const unitNormal = Vector2.Normalized(normal)

  const unitNormal = Vector2.Normalized(normal)
  const unitTangent = Vector2.Normalized(tangent)

  const m1 = gob1.mass
  const m2 = gob2.mass

  const v1n = Vector2.ProjectScalar(gob1.velocity, normal)
  const v1t = Vector2.ProjectScalar(gob1.velocity, tangent)
  const v2n = Vector2.ProjectScalar(gob2.velocity, normal)
  const v2t = Vector2.ProjectScalar(gob2.velocity, tangent)

  // coefficient of restitution == bounciness
  // See http://www.box2dflash.org/docs/2.0.2/manual#Friction_and_Restitution
  // const restitution = Math.max(gob1.bounce, gob2.bounce)
  //
  // Instead of having a single restitution value, we just use restitution
  // per object. this way, dev's can more easily imagine how individual objects
  // are affected by collisions
  //
  // (v1n * (m1 - m2) + 2 * m2 * v2n) / (m1 + m2)
  const newv1n = gob1.bounce * (v1n * (m1 - m2) + 2 * m2 * v2n) / (m1 + m2)
  // for tangent values, we need to adjust it according to the friction
  const newv1t = Math.max(0, 1 - gob1.friction) * v1t

  // coefficient of restitution == bounciness
  // (v2n * (m2 - m1) + 2 * m1 * v1n) / (m1 + m2)
  const newv2n = gob2.bounce * (v2n * (m2 - m1) + 2 * m1 * v1n) / (m1 + m2)
  const newv2t = Math.max(0, 1 - gob2.friction) * v2t
{'fraction_non_alphanumeric': 0.11427038626609443, 'fraction_numerical': 0.03304721030042918, 'mean_word_length': 3.1537433155080214, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 9, 'https://': 2, 'lorem ipsum': 0, 'www.': 6, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6243760', 'n_tokens_mistral': 3391, 'n_tokens_neox': 3241, 'n_words': 1007}