Blob Blame History Raw

#include "phisics.h"



void phLinkUnreg(PhLink *l) {
  if (!l->cell) return;
  l->next->prev = l->prev; l->prev->next = l->next;
  if (l->next == l) *l->cell = NULL; else
    if (*l->cell == l) *l->cell = l->next;
  l->cell = NULL;
  l->prev = l->next = NULL;
}


void phLinkReg(PhLink *l, PhCell *c) {
  if (l->cell == c) return;
  phLinkUnreg(l);
  if (*c) {
    l->next = *c;
    l->prev = l->next->prev;
    l->next->prev = l;
    l->prev->next = l;
  } else {
    *c = l;
    l->next = l->prev = l;
  }
  l->cell = c;
}



void phNodeUnregCell(PhNode *n)
  { for(int i = 0; i < 4; ++i) phLinkUnreg(n->l+i); }

  
void phNodeRegCell(PhNode *n, PhCell *c, int stride) {
  if (n->l->cell == c) return;
  phLinkReg(n->l+0, c);
  phLinkReg(n->l+1, c+1);
  phLinkReg(n->l+2, c+stride);
  phLinkReg(n->l+3, c+stride+1);
}


void phNodeUpdateCell(PhNode *n) {
  if (n->group && n->group->ph)
    phNodeRegCell(n, physicsCell(n->group->ph, n->p), n->group->ph->hw*2);
  else
    phNodeUnregCell(n);
}


void phNodeUnreg(PhNode *n) {
  if (!n->group) return;
  phNodeUnregCell(n);
  *(n->prev ? &n->prev->next : &n->group->first) = n->next;
  *(n->next ? &n->next->prev : &n->group->last) = n->prev;
  n->prev = n->next = NULL;
  n->group = NULL;
}

  
void phNodeReg(PhNode *n, PhGroup *g) {
  if (n->group == g) return;
  phNodeUnreg(n);
  for(int i = 0; i < 4; ++i) n->l[i].node = n;
  n->group = g;
  n->prev = g->last;
  *(n->prev ? &n->prev->next : &g->first) = g->last = n;
  phNodeUpdateCell(n);
}


int phNodeBound(PhNode *n, Vec b0, Vec b1) {
  double d;
  int res = 0;
  d = n->p.x - b0.x - n->r; if (d < 0) n->p.x -= d, res = 1;
  d = b1.x - n->p.x - n->r; if (d < 0) n->p.x += d, res = 1;
  d = n->p.y - b0.y - n->r; if (d < 0) n->p.y -= d, res = 1;
  d = b1.y - n->p.y - n->r; if (d < 0) n->p.y += d, res = 1;
  if (res) phNodeUpdateCell(n);
  return res;
}


int phNodeCollision(PhNode *n) {
  if (!n->group || !n->group->ph) return 0;
  PhNode *chain = n;
  unsigned int mark = ++n->group->ph->lastMark;
  for(int i = 0; i < 4; ++i) {
    PhLink *link = n->l+i;
    for(PhLink *l = link->next; l && l != link; l = l->next) {
      PhNode *m = l->node;
      if (m >= n || m->mark == mark) continue;
      m->mark = mark;
      
      if (n->group == m->group) continue;
      
      double r = n->r + m->r;
      Vec d = vsub(m->p, n->p);
      double l2 = vlen2(d);
      if (!(l2 < r*r)) continue;
      
      double l = sqrt(l2);
      d = vmul(d, (r*1.001 - l)/l/2);
      n->p = vsub(n->p, d);
      m->p = vadd(m->p, d);
      m->chain = chain;
      chain = m;
    }
  }
  if (chain == n) return 0;
  
  int res = 0;
  while(chain) {
    phNodeUpdateCell(chain);
    PhNode *nn = chain->chain;
    chain->chain = NULL;
    chain = nn;
    ++res;
  }
  return res;
}