ens3 :Ошибка поиска имени хоста | sudo ifconfig до ens3

Ответ, данный @mxmlnkn, является отличным началом, но, к сожалению, методология расчета покрываемой площади неверна, когда 3 или более окон находятся поверх целевого окна.

Чтобы понять почему, представьте, что есть 3 окна (, которые мы назовем X, YиZ)поверх целевого окнаT); далее предположим, что все эти окна имеют одинаковые координаты. Тогда данное решение сначала прибавит |X ∩ T|+|Y ∩ T|+|Z ∩ T|=3*windowArea, а затем вычтет |(X U Y) ∩ T| + |(X U Z) ∩ T| + |(Y U Z) ∩ T| =3*windowArea, что приведет к вычислению чистой площади 0. Ошибка здесь в том, что мы на самом деле «двойной счет» пытаемся компенсировать «двойной счет». Чтобы исправить это, мы добавляем |X ∩ Y ∩ Z ∩ T|. Это понятие формализовано принципом включения -исключения (, см. здесь).

«Покрытая площадь» может быть определена как (простите за бессистемное математическое обозначение, unix.stackexchange.comне позволяетLaTeX)

(A_1 U A_2 U... U A_n) ∩ B

, где A_1, A_2,..., A_n— окна, расположенные поверх целевого окна, а B— целевое окно.

Мы можем использовать Принцип включения -Исключения для расширения (A_1 U A_2 U... U A_n). Затем мы можем распределить пересечение с Bпо этому результату.

Конкретно это приводит к следующему алгоритму (C++):

bool windowIsVisible(Display *display, Window window, float threshold) {
  // Indicates whether a window is fully covered
  if (!windowIsViewable(display, window)) {
    return false;
  }

  auto rootWindow = DefaultRootWindow(display);
  auto coords = getWindowCoords(display, rootWindow, window);

  if (coords.size() <= 1) {
    return true;
  }

  float area = (coords[0][2]-coords[0][0]) * (coords[0][3]-coords[0][1]);
  float coveredArea = 0;

  auto selector = std::vector(coords.size()-1);
  for (int i = 0; i < selector.size(); i++) {
    std::fill(selector.begin(), selector.begin()+i+1, true);
    std::fill(selector.begin()+i+1, selector.end(), false);

    auto selectedWindows = std::vector>(i);
    do {
      selectedWindows.clear();
      for (int j = 0; j < selector.size(); j++) {
        if (selector[j]) selectedWindows.push_back(coords[j+1]);
      }
      selectedWindows.push_back(coords[0]);
      coveredArea += pow(-1, i)*calculateWindowOverlap(selectedWindows);
    } while (std::prev_permutation(selector.begin(), selector.end()));
  }

  float tol = 1e-4;
  return (1 - ((float)coveredArea)/((float)area) + tol) >= threshold;
}

int calculateWindowOverlap(std::vector> windowCoords) {
  if (windowCoords.size() == 0) {
    return 0;
  }

  std::vector intersect = windowCoords[0];
  for (int i = 1; i < windowCoords.size(); i++) {
    intersect[0] = std::max(intersect[0], windowCoords[i][0]);
    intersect[1] = std::max(intersect[1], windowCoords[i][1]);
    intersect[2] = std::min(intersect[2], windowCoords[i][2]);
    intersect[3] = std::min(intersect[3], windowCoords[i][3]);
  }
  return std::max(0, intersect[2]-intersect[0]) *
    std::max(0, intersect[3]-intersect[1]);
}

std::vector> getWindowCoords(Display *display,
  Window queryWindow, Window targetWindow,
  bool *reachedTargetPtr = nullptr, int absX = 0, int absY = 0) {
  // Gather geometry of all windows in higher zorder
  std::vector> coords = {};

  bool reachedTarget = false;
  if (!reachedTargetPtr) {
    reachedTargetPtr = &reachedTarget;
  }

  Window rWindow;
  Window parentWindow;
  Window *childrenWindows;
  unsigned int numChildren;
  XQueryTree(display, queryWindow, &rWindow, &parentWindow,
    &childrenWindows, &numChildren);

  for (int i = 0; i < numChildren; i++) {
    if (childrenWindows[i] == targetWindow) {
      *reachedTargetPtr = true;
    }

    XWindowAttributes windowAttributes;
    XGetWindowAttributes(display, childrenWindows[i], &windowAttributes);
    if (*reachedTargetPtr && windowAttributes.map_state == IsViewable &&
      windowAttributes.c_class != InputOnly) {
      coords.push_back(std::vector {
        windowAttributes.x + absX,
        windowAttributes.y + absY,
        windowAttributes.x + absX + windowAttributes.width,
        windowAttributes.y + absY + windowAttributes.height });
    }

    if (childrenWindows[i] != targetWindow) {
      auto childCoords = getWindowCoords(display, childrenWindows[i],
        targetWindow, reachedTargetPtr, absX + windowAttributes.x,
        absY + windowAttributes.y);

      coords.reserve(coords.size() + childCoords.size());
      coords.insert(coords.end(), childCoords.begin(), childCoords.end());
    }
  }

  return coords;
}

По сути, для k=1,2,...,nмы находим все комбинации n choose k. Затем мы вычисляем площадь пересечения этих окон вместе с целевым окном,и добавить/вычесть результат из бегущей области (в соответствии с условием (-1)^(k-1)Принципа включения -Исключения.

Я реализовал это в простом инструменте, который сделал здесь . Кроме того, это, по сути, расширение задачи Rectangle Area II из leetcode. Есть несколько более эффективных способов сделать это (, проверьте раздел решений ), но я лично обнаружил, что математически интуитивный способ обеспечивает достаточную производительность.

0
15.11.2021, 01:30
0 ответов

Теги

Похожие вопросы