Exemplo n.º 1
0
static seg_t *FindSegFromStaleNode(superblock_t *part_list,
    node_t *stale_nd, int *stale_opposite)
{
  seg_t *part;
  int num;

  for (part=part_list->segs; part; part = part->next)
  {
    float_g fa, fb; 

    /* ignore minisegs as partition candidates */
    if (! part->linedef)
      continue;
    
    fa = fabs(UtilPerpDist(part, stale_nd->x, stale_nd->y));
    fb = fabs(UtilPerpDist(part, stale_nd->x + stale_nd->dx, 
         stale_nd->y + stale_nd->dy));

    if (fa < DIST_EPSILON && fb < DIST_EPSILON)
    {
      /* OK found it.  check if runs in same direction */

      (*stale_opposite) = (stale_nd->dx * part->pdx + 
          stale_nd->dy * part->pdy < 0) ? 1 : 0;
 
      return part;
    }
  }

  /* handle sub-blocks recursively */

  for (num=0; num < 2; num++)
  {
    if (! part_list->subs[num])
      continue;

    part = FindSegFromStaleNode(part_list->subs[num], stale_nd,
        stale_opposite);

    if (part)
      return part;
  }

  return NULL;
}
Exemplo n.º 2
0
//
// DivideOneSeg
//
// Apply the partition line to the given seg, taking the necessary
// action (moving it into either the left list, right list, or
// splitting it).
//
// -AJA- I have rewritten this routine based on the EvalPartition
//       routine above (which I've also reworked, heavily).  I think
//       it is important that both these routines follow the exact
//       same logic when determining which segs should go left, right
//       or be split.
//
void DivideOneSeg(seg_t *cur, seg_t *part, 
    superblock_t *left_list, superblock_t *right_list,
    intersection_t ** cut_list)
{
  seg_t *new_seg;

  float_g x, y;

  /* get state of lines' relation to each other */
  float_g a = UtilPerpDist(part, cur->psx, cur->psy);
  float_g b = UtilPerpDist(part, cur->pex, cur->pey);

  boolean_g self_ref = cur->linedef ? cur->linedef->self_ref : FALSE;

  if (cur->source_line == part->source_line)
    a = b = 0;

  /* check for being on the same line */
  if (fabs(a) <= DIST_EPSILON && fabs(b) <= DIST_EPSILON)
  {
    AddIntersection(cut_list, cur->start, part, self_ref);
    AddIntersection(cut_list, cur->end,   part, self_ref);

    // this seg runs along the same line as the partition.  check
    // whether it goes in the same direction or the opposite.

    if (cur->pdx*part->pdx + cur->pdy*part->pdy < 0)
    {
      AddSegToSuper(left_list, cur);
    }
    else
    {
      AddSegToSuper(right_list, cur);
    }

    return;
  }

  /* check for right side */
  if (a > -DIST_EPSILON && b > -DIST_EPSILON)
  {
    if (a < DIST_EPSILON)
      AddIntersection(cut_list, cur->start, part, self_ref);
    else if (b < DIST_EPSILON)
      AddIntersection(cut_list, cur->end, part, self_ref);

    AddSegToSuper(right_list, cur);
    return;
  }
 
  /* check for left side */
  if (a < DIST_EPSILON && b < DIST_EPSILON)
  {
    if (a > -DIST_EPSILON)
      AddIntersection(cut_list, cur->start, part, self_ref);
    else if (b > -DIST_EPSILON)
      AddIntersection(cut_list, cur->end, part, self_ref);

    AddSegToSuper(left_list, cur);
    return;
  }
 
  // when we reach here, we have a and b non-zero and opposite sign,
  // hence this seg will be split by the partition line.
  
  ComputeIntersection(cur, part, a, b, &x, &y);

  new_seg = SplitSeg(cur, x, y);

  AddIntersection(cut_list, cur->end, part, self_ref);

  if (a < 0)
  {
    AddSegToSuper(left_list,  cur);
    AddSegToSuper(right_list, new_seg);
  }
  else
  {
    AddSegToSuper(right_list, cur);
    AddSegToSuper(left_list,  new_seg);
  }
}
Exemplo n.º 3
0
//
// EvalPartitionWorker
//
// Returns TRUE if a "bad seg" was found early.
//
static int EvalPartitionWorker(superblock_t *seg_list, seg_t *part, 
    int best_cost, eval_info_t *info)
{
  seg_t *check;

  float_g qnty;
  float_g a, b, fa, fb;

  int num;
  int factor = cur_info->factor;

  // -AJA- this is the heart of my superblock idea, it tests the
  //       _whole_ block against the partition line to quickly handle
  //       all the segs within it at once.  Only when the partition
  //       line intercepts the box do we need to go deeper into it.

  num = BoxOnLineSide(seg_list, part);

  if (num < 0)
  {
    // LEFT

    info->real_left += seg_list->real_num;
    info->mini_left += seg_list->mini_num;

    return FALSE;
  }
  else if (num > 0)
  {
    // RIGHT

    info->real_right += seg_list->real_num;
    info->mini_right += seg_list->mini_num;
    
    return FALSE;
  }

# define ADD_LEFT()  \
      do {  \
        if (check->linedef) info->real_left += 1;  \
        else                info->mini_left += 1;  \
      } while (0)

# define ADD_RIGHT()  \
      do {  \
        if (check->linedef) info->real_right += 1;  \
        else                info->mini_right += 1;  \
      } while (0)

  /* check partition against all Segs */

  for (check=seg_list->segs; check; check=check->next)
  { 
    // This is the heart of my pruning idea - it catches
    // bad segs early on. Killough

    if (info->cost > best_cost)
      return TRUE;

    /* get state of lines' relation to each other */
    if (check->source_line == part->source_line)
    {
      a = b = fa = fb = 0;
    }
    else
    {
      a = UtilPerpDist(part, check->psx, check->psy);
      b = UtilPerpDist(part, check->pex, check->pey);

      fa = fabs(a);
      fb = fabs(b);
    }

    /* check for being on the same line */
    if (fa <= DIST_EPSILON && fb <= DIST_EPSILON)
    {
      // this seg runs along the same line as the partition.  Check
      // whether it goes in the same direction or the opposite.

      if (check->pdx*part->pdx + check->pdy*part->pdy < 0)
      {
        ADD_LEFT();
      }
      else
      {
        ADD_RIGHT();
      }

      continue;
    }

    // -AJA- check for passing through a vertex.  Normally this is fine
    //       (even ideal), but the vertex could on a sector that we
    //       DONT want to split, and the normal linedef-based checks
    //       may fail to detect the sector being cut in half.  Thanks
    //       to Janis Legzdinsh for spotting this obscure bug.

    if (fa <= DIST_EPSILON || fb <= DIST_EPSILON)
    {
      if (check->linedef && check->linedef->is_precious)
        info->cost += 40 * factor * PRECIOUS_MULTIPLY;
    }

    /* check for right side */
    if (a > -DIST_EPSILON && b > -DIST_EPSILON)
    {
      ADD_RIGHT();

      /* check for a near miss */
      if ((a >= IFFY_LEN && b >= IFFY_LEN) ||
          (a <= DIST_EPSILON && b >= IFFY_LEN) ||
          (b <= DIST_EPSILON && a >= IFFY_LEN))
      {
        continue;
      }
      
      info->near_miss++;

      // -AJA- near misses are bad, since they have the potential to
      //       cause really short minisegs to be created in future
      //       processing.  Thus the closer the near miss, the higher
      //       the cost.

      if (a <= DIST_EPSILON || b <= DIST_EPSILON)
        qnty = IFFY_LEN / MAX(a, b);
      else
        qnty = IFFY_LEN / MIN(a, b);

      info->cost += (int) (100 * factor * (qnty * qnty - 1.0));
      continue;
    }

    /* check for left side */
    if (a < DIST_EPSILON && b < DIST_EPSILON)
    {
      ADD_LEFT();

      /* check for a near miss */
      if ((a <= -IFFY_LEN && b <= -IFFY_LEN) ||
          (a >= -DIST_EPSILON && b <= -IFFY_LEN) ||
          (b >= -DIST_EPSILON && a <= -IFFY_LEN))
      {
        continue;
      }

      info->near_miss++;

      // the closer the miss, the higher the cost (see note above)
      if (a >= -DIST_EPSILON || b >= -DIST_EPSILON)
        qnty = IFFY_LEN / -MIN(a, b);
      else
        qnty = IFFY_LEN / -MAX(a, b);

      info->cost += (int) (70 * factor * (qnty * qnty - 1.0));
      continue;
    }

    // When we reach here, we have a and b non-zero and opposite sign,
    // hence this seg will be split by the partition line.

    info->splits++;

    // If the linedef associated with this seg has a tag >= 900, treat
    // it as precious; i.e. don't split it unless all other options
    // are exhausted. This is used to protect deep water and invisible
    // lifts/stairs from being messed up accidentally by splits.

    if (check->linedef && check->linedef->is_precious)
      info->cost += 100 * factor * PRECIOUS_MULTIPLY;
    else
      info->cost += 100 * factor;

    // -AJA- check if the split point is very close to one end, which
    //       is quite an undesirable situation (producing really short
    //       segs).  This is perhaps _one_ source of those darn slime
    //       trails.  Hence the name "IFFY segs", and a rather hefty
    //       surcharge :->.

    if (fa < IFFY_LEN || fb < IFFY_LEN)
    {
      info->iffy++;

      // the closer to the end, the higher the cost
      qnty = IFFY_LEN / MIN(fa, fb);
      info->cost += (int) (140 * factor * (qnty * qnty - 1.0));
    }
  }

  /* handle sub-blocks recursively */

  for (num=0; num < 2; num++)
  {
    if (! seg_list->subs[num])
      continue;

    if (EvalPartitionWorker(seg_list->subs[num], part, best_cost, info))
      return TRUE;
  }

  /* no "bad seg" was found */
  return FALSE;
}