AUI Framework  master
Cross-platform module-based framework for developing C++20 desktop applications
ARect.h
1/*
2 * AUI Framework - Declarative UI toolkit for modern C++20
3 * Copyright (C) 2020-2024 Alex2772 and Contributors
4 *
5 * SPDX-License-Identifier: MPL-2.0
6 *
7 * This Source Code Form is subject to the terms of the Mozilla Public
8 * License, v. 2.0. If a copy of the MPL was not distributed with this
9 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 */
11
12#pragma once
13
14#include "APoint2D.h"
15#include "ALineSegment.h"
16#include <array>
17#include <range/v3/algorithm/any_of.hpp>
18
23template<typename T>
24struct ARect {
25 APoint2D<T> p1, p2;
26
27 static ARect fromTopLeftPositionAndSize(APoint2D<T> position, APoint2D<T> size) {
28 return { .p1 = position, .p2 = position + size };
29 }
30
31 static ARect fromCenterPositionAndSize(APoint2D<T> position, APoint2D<T> size) {
32 return { .p1 = position - size / static_cast<T>(2), .p2 = position + size / static_cast<T>(2) };
33 }
34
35 [[nodiscard]]
36 bool operator==(const ARect&) const noexcept = default;
37
38 [[nodiscard]]
39 APoint2D<T> leftTop() const noexcept {
40 return min();
41 }
42
43 [[nodiscard]]
44 APoint2D<T> rightBottom() const noexcept {
45 return max();
46 }
47
48 [[nodiscard]]
49 APoint2D<T> rightTop() const noexcept {
50 return { glm::max(p1.x, p2.x), glm::min(p1.y, p2.y) };
51 }
52
53 [[nodiscard]]
54 APoint2D<T> leftBottom() const noexcept {
55 return { glm::min(p1.x, p2.x), glm::max(p1.y, p2.y) };
56 }
57
58 [[nodiscard]]
59 bool isInside(APoint2D<T> other) const noexcept {
60 return glm::all(glm::greaterThan(other, p1)) && glm::all(glm::lessThan(other, p2));
61 }
62
63 [[nodiscard]]
64 bool isIntersects(APoint2D<T> other) const noexcept {
65 return glm::all(glm::greaterThanEqual(other, p1)) && glm::all(glm::lessThanEqual(other, p2));
66 }
67
68 [[nodiscard]]
69 std::array<APoint2D<T>, 4> vertices() const noexcept {
70 return std::array<APoint2D<T>, 4>{
71 p1,
72 APoint2D<T>(p1.x, p2.y),
73 APoint2D<T>(p2.x, p1.y),
74 p2
75 };
76 }
77
78 [[nodiscard]]
79 APoint2D<T> center() const noexcept {
80 return (p1 + p2) / static_cast<T>(2);
81 }
82
83 [[nodiscard]]
84 APoint2D<T> min() const noexcept {
85 return glm::min(p1, p2);
86 }
87
88 [[nodiscard]]
89 APoint2D<T> max() const noexcept {
90 return glm::max(p1, p2);
91 }
92
93 [[nodiscard]]
94 T area() const noexcept {
95 return size().x * size().y;
96 }
97
98 [[nodiscard]]
99 ALineSegment<T> topLineSegment() const noexcept {
100 return { .p1 = APoint2D<T>(p1.x, p1.y), .p2 = APoint2D<T>(p2.x, p1.y) };
101 }
102
103 [[nodiscard]]
104 ALineSegment<T> leftLineSegment() const noexcept {
105 return { .p1 = APoint2D<T>(p1.x, p1.y), .p2 = APoint2D<T>(p1.x, p2.y) };
106 }
107
108 [[nodiscard]]
109 ALineSegment<T> rightLineSegment() const noexcept {
110 return { .p1 = APoint2D<T>(p2.x, p1.y), .p2 = APoint2D<T>(p2.x, p2.y) };
111 }
112
113
114 [[nodiscard]]
115 ALineSegment<T> bottomLineSegment() const noexcept {
116 return { .p1 = APoint2D<T>(p1.x, p2.y), .p2 = APoint2D<T>(p2.x, p2.y) };
117 }
118
122 [[nodiscard]]
123 bool isIntersects(ARect other) const noexcept {
124 // equal rects intersects.
125 if (*this == other) {
126 return true;
127 }
128
129 // at least one of their point
130 if (ranges::any_of(other.vertices(), [&](APoint2D<T> p) { return isIntersects(p); })) {
131 return true;
132 }
133
134 // at least one of our point
135 if (ranges::any_of(vertices(), [&](APoint2D<T> p) { return other.isIntersects(p); })) {
136 return true;
137 }
138
139 {
140 auto verticalLines = [](const ARect& r) {
141 return std::array<ALineSegment<T>, 2>{ r.leftLineSegment(), r.rightLineSegment() };
142 };
143 auto horizontalLines = [](const ARect& r) {
144 return std::array<ALineSegment<T>, 2>{ r.topLineSegment(), r.bottomLineSegment() };
145 };
146
147 // this
148 // +------+
149 // | |
150 //+-----+------+-----+
151 //| | | |
152 //| | | | other
153 //| | | |
154 //+-----+------+-----+
155 // | |
156 // +------+
157 if (ranges::any_of(verticalLines(*this), [&](const ALineSegment<T>& l) {
158 return ranges::any_of(horizontalLines(other), [&](const ALineSegment<T>& r) {
159 return l.isIntersects(r);
160 });
161 })) {
162 return true;
163 }
164
165 // other
166 // +------+
167 // | |
168 //+-----+------+-----+
169 //| | | |
170 //| | | | this
171 //| | | |
172 //+-----+------+-----+
173 // | |
174 // +------+
175 if (ranges::any_of(horizontalLines(*this), [&](const ALineSegment<T>& l) {
176 return ranges::any_of(verticalLines(other), [&](const ALineSegment<T>& r) {
177 return l.isIntersects(r);
178 });
179 })) {
180 return true;
181 }
182 }
183
184 return false;
185 }
186
187 [[nodiscard]]
188 APoint2D<T> size() const noexcept {
189 return glm::abs(p2 - p1);
190 }
191
192 ARect& translate(glm::ivec2 by) noexcept {
193 p1 += by;
194 p2 += by;
195 return *this;
196 }
197};
glm::vec< 2, T > APoint2D
2D point.
Definition: APoint2D.h:21
2D line segment.
Definition: ALineSegment.h:22
Axis aligned 2D rectangle.
Definition: ARect.h:24
bool isIntersects(ARect other) const noexcept
Definition: ARect.h:123