rect.cpp 4.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
// Copyright (c) 2012-2017 VideoStitch SAS
// Copyright (c) 2018 stitchEm

#include "rect.hpp"

#include <algorithm>

namespace VideoStitch {
namespace Core {

void Rect::growToAlignTo(int x, int y) {
  if (empty()) {
    return;
  }
  left_ = (left_ / x) * x;
  top_ = (top_ / y) * y;
}

void Rect::growToMultipleSizeOf(int x, int y) {
  if (empty()) {
    return;
  }
  if (getWidth() % x) {
    right_ += x - (getWidth() % x);
  }
  if (getHeight() % y) {
    bottom_ += y - (getHeight() % y);
  }
  assert(getWidth() % x == 0);
  assert(getHeight() % y == 0);
}

void Rect::getInterAndUnion(const Rect &a, const Rect &b, Rect &iRect, Rect &uRect, unsigned wrapWidth) {
  uRect.top_ = std::min(a.top_, b.top_);
  uRect.bottom_ = std::max(a.bottom_, b.bottom_);
  uRect.left_ = std::min(a.left_, b.left_);
  uRect.right_ = std::max(a.right_, b.right_);

  // Need to handle the following cases
  if (std::max(a.right_, b.right_) >= wrapWidth && std::min(a.right_, b.right_) < wrapWidth) {
    /**
     *  *-------------------------*
     *  |    *-------------*      |
     *  |----+---*         |  *- -|
     *  |    |   |         |  |   |
     *  |    |   |         |  |   |
     *  |    *---+---------*  |   |
     *  |--------*            *---|
     *  |                         |
     *  *-------------------------*
     **/
    if (a.right() % wrapWidth < std::max(a.left_, b.left_) && b.right() % wrapWidth < std::max(a.left_, b.left_) &&
        std::min(a.left_, b.left_) <= std::max(a.right_, b.right_) - wrapWidth) {
      iRect.top_ = std::max(a.top_, b.top_);
      iRect.bottom_ = std::min(a.bottom_, b.bottom_);
      iRect.left_ = std::min(a.left_, b.left_);
      iRect.right_ = std::max(a.right_, b.right_) - wrapWidth;

      uRect.top_ = std::min(a.top_, b.top_);
      uRect.bottom_ = std::max(a.bottom_, b.bottom_);
      uRect.left_ = std::max(a.left_, b.left_);
      uRect.right_ = std::min(a.right_, b.right_) + wrapWidth;
      return;
    } else {
      /**
       *  *-------------------------*
       *  |    *-------------*      |
       *  |--* |         *---|------|
       *  |  | |         |   |      |
       *  |  | |         |   |      |
       *  |  | *---------|---*      |
       *  |--*           *----------|
       *  |                         |
       *  *-------------------------*
       **/
      if (std::max(a.left_, b.left_) < std::min(a.right_, b.right_) &&
          std::min(a.left_, b.left_) > std::max(a.right_, b.right_) - wrapWidth) {
        iRect.top_ = std::max(a.top_, b.top_);
        iRect.bottom_ = std::min(a.bottom_, b.bottom_);
        iRect.left_ = std::max(a.left_, b.left_);
        iRect.right_ = std::min(a.right_, b.right_);
        return;
      }
    }
  }

  /**
   * We must handle the following case:
   *
   *  *-------------------------*
   *  |    *----------------*   |
   *  |----+---*          *-+---|
   *  |    |   |          | |   |
   *  |    |   |          | |   |
   *  |    *---+----------+-*   |
   *  |--------*          *-----|
   *  |                         |
   *  *-------------------------*
   *
   * The intersection will be the smallest area rectangle of the two possible rectangles.
   *
   * the intersections are either (in order):
   *   - [a.left, b.right] and [b.left, a.right], in which case the two possibilities are [a.left, a.right] and [b.left,
   * b.right].
   *   - [b.left, a.right] and [a.left, b.right], in which case the two possibilities are [b.left, b.right] and [a.left,
   * a.right].
   */
  iRect.top_ = std::max(a.top_, b.top_);
  iRect.bottom_ = std::min(a.bottom_, b.bottom_);
  if (uRect.right_ >= (int)wrapWidth && uRect.right_ - (int)wrapWidth >= uRect.left_) {
    if (a.getWidth() < b.getWidth()) {
      iRect.left_ = a.left_;
      iRect.right_ = a.right_;
    } else {
      iRect.left_ = b.left_;
      iRect.right_ = b.right_;
    }
    // uRect's anchor is arbitrary, but it must contain iRetc
    if (iRect.right_ >= (int)wrapWidth) {
      // make uRect wrap, choose to center iRect within uRect
      uRect.left_ = iRect.left_ - (int)(wrapWidth - iRect.getWidth()) / 2;
      if (uRect.left_ < 0) {
        uRect.left_ = 0;
      }
      uRect.right_ = uRect.left_ + (int)wrapWidth - 1;
    } else {
      // make uRect NOT wrap
      uRect.left_ = 0;
      uRect.right_ = (int)wrapWidth - 1;
    }
  } else {
    iRect.left_ = std::max(a.left_, b.left_);
    iRect.right_ = std::min(a.right_, b.right_);
  }
}

}  // namespace Core
}  // namespace VideoStitch