void KMCentersTree::split_by_mid_point(
  int start_ind, int end_ind, int &cut_dim, double &cut_val, int &n_lo) {
  KMPoint *lo,*hi;
  lo = bnd_box_->get_point(0);
  hi = bnd_box_->get_point(1);
  // find the long side with the largest spread (the cutting dimension)
  double max_length = bnd_box_->max_length();
  double max_spread = -1;
  for (int d = 0; d < data_points_->get_dim(); d++) {
    if (std::abs((*hi)[d] - (*lo)[d]-max_length) <1E-6){
      double spr = spread(start_ind,end_ind,d);
      if (spr > max_spread) {
        max_spread = spr;
        cut_dim = d;
      }
    }
  }
  // find the splitting value
  double ideal_cut_val = ((*lo)[cut_dim] + (*hi)[cut_dim])/2;
  //min_max represent the minimal and maximal
  //values of points along the cutting dimension
  std::pair<double,double> min_max =
    limits_along_dimension(start_ind,end_ind, cut_dim);
  //slide to min or max as needed
  if (ideal_cut_val < min_max.first)
    cut_val = min_max.first;
  else if (ideal_cut_val > min_max.second)
    cut_val = min_max.second;
  else
    cut_val = ideal_cut_val;
  // permute points accordingly
  std::pair<int,int>
    break_ind = split_by_plane(start_ind,end_ind,cut_dim, cut_val);
  IMP_LOG(VERBOSE, "split by mid point for indexes: "
          << start_ind << " to " << end_ind << "break index: "
          << break_ind.first << " to " << break_ind.second << std::endl);
  //set n_lo such that each side of the split will contain at least one point
  n_lo = (start_ind+end_ind)/2;
  // if ideal_cut_val < min (y >= 1), we set n_lo = 1 (so there is one
  // point on left)
  if (ideal_cut_val < min_max.first) n_lo = start_ind+1;
  // if ideal_cut_val > max (x <= n-1), we set n_lo = n-1 (so there is one
  // point on right).
  else if (ideal_cut_val > min_max.second) n_lo = end_ind;
  // Otherwise, we select n_lo as close to the middle of  [x..y] as possbile
  else if (break_ind.first > n_lo) n_lo = break_ind.first;
  else if (break_ind.second < n_lo) n_lo = break_ind.second;
}
示例#2
0
/*
 * receiver - points to the base room frustum, which portal leads to - it's taken from the portal!
 * returns a pointer to newly generated frustum.
 */
std::shared_ptr<Frustum> Frustum::portalFrustumIntersect(Portal *portal, std::shared_ptr<Frustum> emitter, Render *render)
{
    assert(emitter);
    if(!portal->dest_room)
        return nullptr;

    if(portal->normal.distance(render->camera()->m_pos) < -SPLIT_EPSILON)    // non face or degenerate to the line portal
    {
        return nullptr;
    }

    if(!portal->dest_room->frustum.empty() && emitter->hasParent(portal->dest_room->frustum.front()))
    {
        return nullptr;                                                        // Abort infinite loop!
    }

    bool in_dist = false, in_face = false;
    for(const btVector3& v : portal->vertices)
    {
        if(!in_dist && render->camera()->frustum->norm.distance(v) < render->camera()->m_distFar)
            in_dist = true;
        if(!in_face && emitter->norm.distance(v) > 0.0)
            in_face = true;
        if(in_dist && in_face)
            break;
    }

    if(!in_dist || !in_face)
        return nullptr;

    /*
     * Search for the first free room's frustum
     */
    portal->dest_room->frustum.emplace_back(std::make_shared<Frustum>());
    auto current_gen = portal->dest_room->frustum.back();

    current_gen->splitPrepare(portal);                       // prepare for clipping

    if(current_gen->split_by_plane(emitter->norm))               // splitting by main frustum clip plane
    {
        for(size_t i = 0; i < emitter->vertices.size(); i++)
        {
            const auto& n = emitter->planes[i];
            if(!current_gen->split_by_plane(n))
            {
                portal->dest_room->frustum.pop_back();
                return nullptr;
            }
        }

        current_gen->genClipPlanes(render->camera());                      // all is OK, let's generate clip planes

        current_gen->parent = emitter;                                      // add parent pointer
        current_gen->parents_count = emitter->parents_count + 1;
        if(portal->dest_room->max_path < current_gen->parents_count)
        {
            portal->dest_room->max_path = current_gen->parents_count;       // maximum path to the room
        }
        return current_gen;
    }

    portal->dest_room->frustum.pop_back();

    return nullptr;
}