Exemplo n.º 1
0
void Cluster::computeSizeAndPositions()
{
  // This process is described in Frank van Ham's Master's thesis, p. 24
  // Recurse into the tree (depth first)
  for (unsigned int i = 0; i < descendants.size(); ++i)
  {
    descendants[i]->computeSizeAndPositions();
  }

  /* Compute the cluster radius r such that all states fit nicely into the
   * cluster. Suppose the cluster has N states and every state is visualized by
   * a circle with radius 0.1. Suppose we want the total area of all states
   * to fill a quarter of the circle that represents the cluster. This way,
   * there is (hopefully) enough room left for transitions and space between the
   * states.
   * So: N * pi * 0.1^2 = 0.25 * pi * r^2
   * Hence: r = sqrt( N * 0.04 )
   */
  topRadius = sqrt(states.size()*0.04f);

  if (descendants.size() == 0)
  {
    baseRadius = topRadius;
    bc_radius = topRadius;
    bc_height = 1.0f;
  }
  else if (descendants.size() == 1)
  {
    Cluster* desc = *descendants.begin();
    baseRadius = desc->getTopRadius();
    bc_radius = max(topRadius,desc->getBCRadius());
    bc_height = desc->getBCHeight() + 1.0f;
    desc->center();
  }
  else     // descendants.size() > 1
  {
    // sort descendants by size in ascending order
    sort(descendants.begin(),descendants.end(),Comp_BCVolume());

    // determine whether a unique smallest descendant exists
    Cluster* smallest = descendants[0];
    Cluster* nextSmallest = descendants[1];

    bool uniqueSmallest = ((nextSmallest->getBCVolume()-smallest->getBCVolume()) /
                           smallest->getBCVolume()) > 0.01f;

    // determine whether a unique largest descendant exists
    Cluster* largest = descendants[descendants.size()-1];
    Cluster* nextLargest = descendants[descendants.size()-2];

    bool uniqueLargest = ((nextLargest->getBCVolume()-largest->getBCVolume()) /
                          largest->getBCVolume()) < -0.01f;

    // invariant: descendants in range [x,y) have not been assigned a position
    int x = 0;
    int y = static_cast<int>(descendants.size());

    float bcr_center = 0.0f;  // BC radius of largest descendant in center
    float bcr_rim = largest->getBCRadius();  // BC radius of largest descendant on rim
    if (uniqueLargest)
    {
      // center the largest descendant
      largest->center();
      --y;
      bcr_center = largest->getBCRadius();
      bcr_rim = nextLargest->getBCRadius();
    }
    else
    {
      if (uniqueSmallest)
      {
        // center the smallest descendant
        smallest->center();
        ++x;
        bcr_center = smallest->getBCRadius();
      }
    }

    // compute the radius of the base of the cylinder and the cluster's size
    float minRimRadius = 0.0f;
    if (y-x > 1)
    {
      minRimRadius = (float)(bcr_rim / sin(PI / (y-x)));
    }
    baseRadius = max(bcr_center + bcr_rim + 0.01f,minRimRadius);
    bc_radius = max(bcr_center + bcr_rim + 0.01f,minRimRadius +bcr_rim);
    bc_radius = max(topRadius,bc_radius);
    bc_height = 0.0f;
    for (unsigned int i = 0; i < descendants.size(); ++i)
    {
      if (descendants[i]->getBCHeight() > bc_height)
      {
        bc_height = descendants[i]->getBCHeight();
      }
    }
    bc_height += 1.0f;

    // Divide the remaining descendants over the rim of the circle. First take
    // the two largest unpositioned clusters and place them opposite to each
    // other, then do the same for the two smallest unpositioned clusters. Keep
    // repeating these steps until all clusters have been positioned. So if the
    // list of clusters (sorted ascending by size) is [ 0, 1, 2, 3, 4, 5 ] then
    // the clusters are placed in the following order (starting at angle 0 and
    // going counter-clockwise): 5, 0, 3, 4, 1, 2

    int i = 0;
    int h = (y-x) / 2 + (y-x) % 2;
    float angle = 360.0f / (y-x);
    while (x != y)
    {
      if (i % 2 == 1)
      {
        descendants[x]->setPosition(i*angle);
        ++x;
        if (x != y)
        {
          descendants[x]->setPosition((h+i)*angle);
          ++x;
        }
      }
      else
      {
        descendants[y-1]->setPosition(i*angle);
        --y;
        if (x != y)
        {
          descendants[y-1]->setPosition((h+i)*angle);
          --y;
        }
      }
      ++i;
    }
  }
}
Exemplo n.º 2
0
void Cluster::computeSizeAndPositions_FSM()
{
  // This process is described in Frank van Ham's Master's thesis, p. 24
  // Recurse into the tree (depth first)
  for (unsigned int i = 0; i < descendants.size(); ++i)
  {
    descendants[i]->computeSizeAndPositions_FSM();
  }

  /* Compute the cluster radius r such that all states fit nicely into the
   * cluster. Suppose the cluster has N states and every state is visualized by
   * a circle with radius 0.1. Suppose we want the total area of all states
   * to fill a quarter of the circle that represents the cluster. This way,
   * there is (hopefully) enough room left for transitions and space between the
   * states.
   * So: N * pi * 0.1^2 = 0.25 * pi * r^2
   * Hence: r = sqrt( N * 0.04 )
   */
  topRadius = states.size()/(2*static_cast<float>(PI));

  if (descendants.size() == 0)
  {
    baseRadius = topRadius;
    bc_radius = topRadius;
    bc_height = 1.0f;
  }
  else if (descendants.size() == 1)
  {
    Cluster* desc = *descendants.begin();
    baseRadius = desc->getTopRadius();
    bc_radius = max(topRadius,desc->getBCRadius());
    bc_height = desc->getBCHeight() + 1.0f;
    desc->center();

  }
  else     // descendants.size() > 1
  {
    // sort descendants by size in ascending order
    sort(descendants.begin(),descendants.end(),Comp_BCRadius());

    // determine whether a unique smallest descendant exists
    Cluster* smallest = descendants[0];
    Cluster* nextSmallest = descendants[1];
    bool uniqueSmallest = ((nextSmallest->getBCRadius()-smallest->getBCRadius()) /
                           smallest->getBCRadius()) > 0.01f;

    // determine whether a unique largest descendant exists
    Cluster* largest = descendants[descendants.size()-1];
    Cluster* nextLargest = descendants[descendants.size()-2];
    bool uniqueLargest = ((nextLargest->getBCRadius()-largest->getBCRadius()) /
                          largest->getBCRadius()) < -0.01f;

    // invariant: descendants in range [x,y) have not been assigned a position
    int x = 0;
    int y = static_cast<int>(descendants.size());
    float bcr_center = 0.0f;  // BC radius of largest descendant in center
    float bcr_rim = largest->getBCRadius();  // BC radius of largest descendant on rim
    if (uniqueLargest)
    {
      // center the largest descendant
      largest->center();
      --y;
      bcr_center = largest->getBCRadius();
      bcr_rim = nextLargest->getBCRadius();
    }
    if (uniqueSmallest && (!uniqueLargest || !smallest->hasDescendants()))
    {
      // center the smallest descendant
      smallest->center();
      ++x;
      if (!uniqueLargest)
      {
        bcr_center = smallest->getBCRadius();
      }
      if (y-x == 0)
      {
        bcr_rim = 0.0f;
      }
    }
    if (y-x == 1)
    {
      ++y;
      bcr_rim = largest->getBCRadius();
      if (smallest->isCentered())
      {
        bcr_center = smallest->getBCRadius();
      }
    }

    // compute the radius of the base of the cylinder and the cluster's size
    float min_radius1 = 0.0f;
    if (y-x > 1)
    {
      min_radius1 = (float)(bcr_rim / sin(PI / (y-x)));
    }
    float min_radius2 = bcr_center;
    if (y-x > 0)
    {
      min_radius2 += bcr_rim + 0.01f;
    }
    baseRadius = max(min_radius1,min_radius2);
    bc_radius = max(min_radius1 + bcr_rim,min_radius2);
    bc_radius = max(topRadius,bc_radius);
    bc_height = 0.0f;
    for (unsigned int i = 0; i < descendants.size(); ++i)
    {
      if (descendants[i]->getBCHeight() > bc_height)
      {
        bc_height = descendants[i]->getBCHeight();
      }
    }
    bc_height += 1.0f;

    // Divide the remaining descendants over the rim of the circle.
    float angle = 360.0f / (y-x);
    int i = 0;
    while (x+i != y)
    {
      descendants[x+i]->setPosition(i*angle);
      ++i;
    }
  }
}