* Determine if a certain link crosses through the area given by the dpi with some lee way. * @param pta First end of the link. * @param ptb Second end of the link. * @param dpi Visible area. * @param padding Width or thickness of the link. * @return If the link or any of its "thickness" is visible. This may return false positives. */
| 141 | * @return If the link or any of its "thickness" is visible. This may return false positives. |
| 142 | */ |
| 143 | inline bool LinkGraphOverlay::IsLinkVisible(Point pta, Point ptb, const DrawPixelInfo *dpi, int padding) const |
| 144 | { |
| 145 | const int left = dpi->left - padding; |
| 146 | const int right = dpi->left + dpi->width + padding; |
| 147 | const int top = dpi->top - padding; |
| 148 | const int bottom = dpi->top + dpi->height + padding; |
| 149 | |
| 150 | /* |
| 151 | * This method is an implementation of the Cohen-Sutherland line-clipping algorithm. |
| 152 | * See: https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm |
| 153 | */ |
| 154 | |
| 155 | const uint8_t INSIDE = 0; // 0000 |
| 156 | const uint8_t LEFT = 1; // 0001 |
| 157 | const uint8_t RIGHT = 2; // 0010 |
| 158 | const uint8_t BOTTOM = 4; // 0100 |
| 159 | const uint8_t TOP = 8; // 1000 |
| 160 | |
| 161 | int x0 = pta.x; |
| 162 | int y0 = pta.y; |
| 163 | int x1 = ptb.x; |
| 164 | int y1 = ptb.y; |
| 165 | |
| 166 | auto out_code = [&](int x, int y) -> uint8_t { |
| 167 | uint8_t out = INSIDE; |
| 168 | if (x < left) { |
| 169 | out |= LEFT; |
| 170 | } else if (x > right) { |
| 171 | out |= RIGHT; |
| 172 | } |
| 173 | if (y < top) { |
| 174 | out |= TOP; |
| 175 | } else if (y > bottom) { |
| 176 | out |= BOTTOM; |
| 177 | } |
| 178 | return out; |
| 179 | }; |
| 180 | |
| 181 | uint8_t c0 = out_code(x0, y0); |
| 182 | uint8_t c1 = out_code(x1, y1); |
| 183 | |
| 184 | while (true) { |
| 185 | if (c0 == 0 || c1 == 0) return true; |
| 186 | if ((c0 & c1) != 0) return false; |
| 187 | |
| 188 | if (c0 & TOP) { // point 0 is above the clip window |
| 189 | x0 = x0 + (int)(((int64_t) (x1 - x0)) * ((int64_t) (top - y0)) / ((int64_t) (y1 - y0))); |
| 190 | y0 = top; |
| 191 | } else if (c0 & BOTTOM) { // point 0 is below the clip window |
| 192 | x0 = x0 + (int)(((int64_t) (x1 - x0)) * ((int64_t) (bottom - y0)) / ((int64_t) (y1 - y0))); |
| 193 | y0 = bottom; |
| 194 | } else if (c0 & RIGHT) { // point 0 is to the right of clip window |
| 195 | y0 = y0 + (int)(((int64_t) (y1 - y0)) * ((int64_t) (right - x0)) / ((int64_t) (x1 - x0))); |
| 196 | x0 = right; |
| 197 | } else if (c0 & LEFT) { // point 0 is to the left of clip window |
| 198 | y0 = y0 + (int)(((int64_t) (y1 - y0)) * ((int64_t) (left - x0)) / ((int64_t) (x1 - x0))); |
| 199 | x0 = left; |
| 200 | } |
no test coverage detected