OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "cc/base/reverse_spiral_iterator.h" |
| 6 |
| 7 #include <algorithm> |
| 8 |
| 9 namespace cc { |
| 10 |
| 11 ReverseSpiralIterator::ReverseSpiralIterator() |
| 12 : around_index_rect_(-1, -1, -1, -1), |
| 13 consider_index_rect_(-1, -1, -1, -1), |
| 14 ignore_index_rect_(-1, -1, -1, -1), |
| 15 index_x_(-1), |
| 16 index_y_(-1) {} |
| 17 |
| 18 ReverseSpiralIterator::ReverseSpiralIterator( |
| 19 const IndexRect& around_index_rect, |
| 20 const IndexRect& consider_index_rect, |
| 21 const IndexRect& ignore_index_rect) |
| 22 : around_index_rect_(around_index_rect), |
| 23 consider_index_rect_(consider_index_rect), |
| 24 ignore_index_rect_(ignore_index_rect), |
| 25 index_x_(-1), |
| 26 index_y_(-1), |
| 27 direction_(LEFT), |
| 28 delta_x_(-1), |
| 29 delta_y_(0), |
| 30 current_step_(0), |
| 31 horizontal_step_count_(0), |
| 32 vertical_step_count_(0) { |
| 33 // Figure out the maximum distance from the around edge to consider edge. |
| 34 int max_distance = 0; |
| 35 max_distance = std::max( |
| 36 max_distance, around_index_rect_.top() - consider_index_rect_.top()); |
| 37 max_distance = std::max( |
| 38 max_distance, around_index_rect_.left() - consider_index_rect_.left()); |
| 39 max_distance = std::max(max_distance, consider_index_rect_.bottom() - |
| 40 around_index_rect_.bottom()); |
| 41 max_distance = std::max( |
| 42 max_distance, consider_index_rect_.right() - around_index_rect_.right()); |
| 43 |
| 44 // The step count is the length of the edge |
| 45 // (around_index_rect_.num_indices_x()) plus twice the max distance to pad |
| 46 // (to the right and to the left). This way the initial rect is the size |
| 47 // proportional to the center, but big enough to cover the consider rect. |
| 48 // |
| 49 // C = consider rect |
| 50 // A = around rect |
| 51 // . = area of the padded around rect |
| 52 // md = max distance (note in the picture below, there's md written vertically |
| 53 // as well). |
| 54 // I = initial starting position |
| 55 // |
| 56 // |md| |md| |
| 57 // |
| 58 // - .......... |
| 59 // m .......... |
| 60 // d .......... |
| 61 // - CCCCCCC... |
| 62 // CCCCAAC... |
| 63 // CCCCAAC... |
| 64 // - .......... |
| 65 // m .......... |
| 66 // d .......... |
| 67 // - ..........I |
| 68 vertical_step_count_ = around_index_rect_.num_indices_y() + 2 * max_distance; |
| 69 horizontal_step_count_ = |
| 70 around_index_rect_.num_indices_x() + 2 * max_distance; |
| 71 |
| 72 // Start with one to the right of the padded around rect. |
| 73 index_x_ = around_index_rect_.right() + max_distance + 1; |
| 74 index_y_ = around_index_rect_.bottom() + max_distance; |
| 75 |
| 76 // The current index is outside a valid tile, so advance immediately. |
| 77 ++(*this); |
| 78 } |
| 79 |
| 80 ReverseSpiralIterator::operator bool() const { |
| 81 return index_x_ != -1 && index_y_ != -1; |
| 82 } |
| 83 |
| 84 ReverseSpiralIterator& ReverseSpiralIterator::operator++() { |
| 85 while (!around_index_rect_.Contains(index_x_, index_y_)) { |
| 86 if (needs_direction_switch()) |
| 87 switch_direction(); |
| 88 |
| 89 index_x_ += delta_x_; |
| 90 index_y_ += delta_y_; |
| 91 ++current_step_; |
| 92 |
| 93 if (around_index_rect_.Contains(index_x_, index_y_)) { |
| 94 break; |
| 95 } else if (consider_index_rect_.Contains(index_x_, index_y_)) { |
| 96 // If the tile is in the consider rect but not in ignore rect, then it's a |
| 97 // valid tile to visit. |
| 98 if (!ignore_index_rect_.Contains(index_x_, index_y_)) |
| 99 break; |
| 100 |
| 101 // Steps needed to reach the very edge of the ignore rect, while remaining |
| 102 // inside it (so that the continue would take us outside). |
| 103 int steps_to_edge = 0; |
| 104 switch (direction_) { |
| 105 case UP: |
| 106 steps_to_edge = index_y_ - ignore_index_rect_.top(); |
| 107 break; |
| 108 case LEFT: |
| 109 steps_to_edge = index_x_ - ignore_index_rect_.left(); |
| 110 break; |
| 111 case DOWN: |
| 112 steps_to_edge = ignore_index_rect_.bottom() - index_y_; |
| 113 break; |
| 114 case RIGHT: |
| 115 steps_to_edge = ignore_index_rect_.right() - index_x_; |
| 116 break; |
| 117 } |
| 118 |
| 119 // We need to switch directions in |max_steps|. |
| 120 int max_steps = current_step_count() - current_step_; |
| 121 |
| 122 int steps_to_take = std::min(steps_to_edge, max_steps); |
| 123 DCHECK_GE(steps_to_take, 0); |
| 124 |
| 125 index_x_ += steps_to_take * delta_x_; |
| 126 index_y_ += steps_to_take * delta_y_; |
| 127 current_step_ += steps_to_take; |
| 128 } else { |
| 129 // We're not in the consider rect. |
| 130 |
| 131 int max_steps = current_step_count() - current_step_; |
| 132 int steps_to_take = max_steps; |
| 133 |
| 134 // We might hit the consider rect before needing to switch directions: |
| 135 // update steps to take. |
| 136 switch (direction_) { |
| 137 case UP: |
| 138 if (consider_index_rect_.valid_column(index_x_) && |
| 139 consider_index_rect_.bottom() < index_y_) |
| 140 steps_to_take = index_y_ - consider_index_rect_.bottom() - 1; |
| 141 break; |
| 142 case LEFT: |
| 143 if (consider_index_rect_.valid_row(index_y_) && |
| 144 consider_index_rect_.right() < index_x_) |
| 145 steps_to_take = index_x_ - consider_index_rect_.right() - 1; |
| 146 break; |
| 147 case DOWN: |
| 148 if (consider_index_rect_.valid_column(index_x_) && |
| 149 consider_index_rect_.top() > index_y_) |
| 150 steps_to_take = consider_index_rect_.top() - index_y_ - 1; |
| 151 break; |
| 152 case RIGHT: |
| 153 if (consider_index_rect_.valid_row(index_y_) && |
| 154 consider_index_rect_.left() > index_x_) |
| 155 steps_to_take = consider_index_rect_.left() - index_x_ - 1; |
| 156 break; |
| 157 } |
| 158 steps_to_take = std::min(steps_to_take, max_steps); |
| 159 DCHECK_GE(steps_to_take, 0); |
| 160 |
| 161 index_x_ += steps_to_take * delta_x_; |
| 162 index_y_ += steps_to_take * delta_y_; |
| 163 current_step_ += steps_to_take; |
| 164 } |
| 165 } |
| 166 |
| 167 // Once we enter the around rect, we're done. |
| 168 if (around_index_rect_.Contains(index_x_, index_y_)) { |
| 169 index_x_ = -1; |
| 170 index_y_ = -1; |
| 171 } |
| 172 |
| 173 return *this; |
| 174 } |
| 175 |
| 176 bool ReverseSpiralIterator::needs_direction_switch() const { |
| 177 return current_step_ >= current_step_count(); |
| 178 } |
| 179 |
| 180 void ReverseSpiralIterator::switch_direction() { |
| 181 // Note that delta_x_ and delta_y_ always remain between -1 and 1. |
| 182 int new_delta_y = delta_x_; |
| 183 delta_x_ = -delta_y_; |
| 184 delta_y_ = new_delta_y; |
| 185 |
| 186 current_step_ = 0; |
| 187 direction_ = static_cast<Direction>((direction_ + 1) % 4); |
| 188 |
| 189 if (direction_ == UP || direction_ == DOWN) { |
| 190 --vertical_step_count_; |
| 191 --horizontal_step_count_; |
| 192 |
| 193 // We should always end up in an around rect at some point. |
| 194 // Since the direction is now vertical, we have to ensure that we will |
| 195 // advance. |
| 196 DCHECK_GE(horizontal_step_count_, 1); |
| 197 DCHECK_GE(vertical_step_count_, 1); |
| 198 } |
| 199 } |
| 200 |
| 201 } // namespace cc |
OLD | NEW |