• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef FOUNDATION_ACE_FRAMEWORKS_BASE_GEOMETRY_NG_RECT_H
17 #define FOUNDATION_ACE_FRAMEWORKS_BASE_GEOMETRY_NG_RECT_H
18 
19 #include <algorithm>
20 #include <array>
21 
22 #include "base/geometry/axis.h"
23 #include "base/geometry/ng/offset_t.h"
24 #include "base/geometry/ng/point_t.h"
25 #include "base/geometry/ng/size_t.h"
26 #include "base/utils/utils.h"
27 
28 namespace OHOS::Ace::NG {
29 template<typename T>
30 class RectT {
31 public:
32     RectT() = default;
33     ~RectT() = default;
34 
RectT(T x,T y,T width,T height)35     RectT(T x, T y, T width, T height)
36     {
37         SetRect(x, y, width, height);
38     }
39 
RectT(const OffsetF & offset,const SizeF & size)40     RectT(const OffsetF& offset, const SizeF& size)
41     {
42         SetOffset(offset);
43         SetSize(size);
44     }
45 
RectT(const OffsetF & topLeftPoint,const OffsetF & bottomRightPoint)46     RectT(const OffsetF& topLeftPoint, const OffsetF& bottomRightPoint)
47     {
48         SetOffset(topLeftPoint);
49         OffsetF sizeOffset = bottomRightPoint - topLeftPoint;
50         SizeF size(sizeOffset.GetX(), sizeOffset.GetY());
51         SetSize(size);
52     }
53 
Reset()54     void Reset()
55     {
56         x_ = 0;
57         y_ = 0;
58         width_ = 0;
59         height_ = 0;
60     }
61 
SetRect(T x,T y,T width,T height)62     void SetRect(T x, T y, T width, T height)
63     {
64         x_ = x;
65         y_ = y;
66         width_ = width;
67         height_ = height;
68     }
69 
SetRect(const OffsetT<T> & offset,const SizeT<T> & size)70     void SetRect(const OffsetT<T>& offset, const SizeT<T>& size)
71     {
72         SetOffset(offset);
73         SetSize(size);
74     }
75 
ApplyScale(T scale)76     void ApplyScale(T scale)
77     {
78         x_ *= scale;
79         y_ *= scale;
80         width_ *= scale;
81         height_ *= scale;
82     }
83 
ApplyScaleAndRound(T scale)84     void ApplyScaleAndRound(T scale)
85     {
86         x_ = round(x_ * scale);
87         y_ = round(y_ * scale);
88         width_ = round(width_ * scale);
89         height_ = round(height_ * scale);
90     }
91 
Left()92     T Left() const
93     {
94         return GreatNotEqual(width_, 0) ? x_ : x_ + width_;
95     }
96 
Top()97     T Top() const
98     {
99         return GreatNotEqual(height_, 0) ? y_ : y_ + height_;
100     }
101 
Right()102     T Right() const
103     {
104         return GreatNotEqual(width_, 0) ? x_ + width_ : x_;
105     }
106 
Bottom()107     T Bottom() const
108     {
109         return GreatNotEqual(height_, 0) ? y_ + height_ : y_;
110     }
111 
GetX()112     T GetX() const
113     {
114         return x_;
115     }
116 
GetY()117     T GetY() const
118     {
119         return y_;
120     }
121 
Width()122     T Width() const
123     {
124         return width_;
125     }
126 
Height()127     T Height() const
128     {
129         return height_;
130     }
131 
MainSize(Axis axis)132     T MainSize(Axis axis) const
133     {
134         return axis == Axis::HORIZONTAL ? width_ : height_;
135     }
136 
SetSize(const SizeT<T> & size)137     void SetSize(const SizeT<T>& size)
138     {
139         width_ = size.Width();
140         height_ = size.Height();
141     }
142 
GetSize()143     SizeT<T> GetSize() const
144     {
145         return SizeT<T>(width_, height_);
146     }
147 
SetOffset(const OffsetT<T> & offset)148     void SetOffset(const OffsetT<T>& offset)
149     {
150         x_ = offset.GetX();
151         y_ = offset.GetY();
152     }
153 
GetOffset()154     OffsetT<T> GetOffset() const
155     {
156         return OffsetT<T>(x_, y_);
157     }
158 
SetLeft(T left)159     void SetLeft(T left)
160     {
161         x_ = left;
162     }
163 
SetTop(T top)164     void SetTop(T top)
165     {
166         y_ = top;
167     }
168 
SetWidth(T width)169     void SetWidth(T width)
170     {
171         width_ = width;
172     }
173 
SetHeight(T height)174     void SetHeight(T height)
175     {
176         height_ = height;
177     }
178 
IsInRegion(const PointT<T> & point)179     bool IsInRegion(const PointT<T>& point) const
180     {
181         return GreatOrEqual(point.GetX(), x_) && LessOrEqual(point.GetX(), x_ + width_) &&
182                GreatOrEqual(point.GetY(), y_) && LessOrEqual(point.GetY(), y_ + height_);
183     }
184 
IsWrappedBy(const RectT & other)185     bool IsWrappedBy(const RectT& other) const
186     {
187         return GreatOrEqual(Left(), other.Left()) && LessOrEqual(Right(), other.Right()) &&
188                GreatOrEqual(Top(), other.Top()) && LessOrEqual(Bottom(), other.Bottom());
189     }
190 
IsValid()191     bool IsValid() const
192     {
193         return NonNegative(width_) && NonNegative(height_);
194     }
195 
IsEmpty()196     bool IsEmpty() const
197     {
198         return NonPositive(width_) || NonPositive(height_);
199     }
200 
Constrain(const RectT & other)201     RectT Constrain(const RectT& other)
202     {
203         T right = Right();
204         T bottom = Bottom();
205         T left = std::clamp(x_, other.Left(), other.Right());
206         T top = std::clamp(y_, other.Top(), other.Bottom());
207         right = std::clamp(right, other.Left(), other.Right()) - left;
208         bottom = std::clamp(bottom, other.Top(), other.Bottom()) - top;
209         return RectT(left, top, right, bottom);
210     }
211 
212     RectT& operator+=(const OffsetT<T>& offset)
213     {
214         x_ += offset.GetX();
215         y_ += offset.GetY();
216         return *this;
217     }
218 
219     RectT& operator-=(const OffsetT<T>& offset)
220     {
221         x_ -= offset.GetX();
222         y_ -= offset.GetY();
223         return *this;
224     }
225 
226     RectT& operator+=(const SizeT<T>& size)
227     {
228         width_ += size.Width();
229         height_ += size.Height();
230         return *this;
231     }
232 
233     RectT& operator-=(const SizeT<T>& size)
234     {
235         width_ -= size.Width();
236         height_ -= size.Height();
237         return *this;
238     }
239 
240     RectT operator+(const OffsetT<T>& offset) const
241     {
242         return RectT(x_ + offset.GetX(), y_ + offset.GetY(), width_, height_);
243     }
244 
245     RectT operator-(const OffsetT<T>& offset) const
246     {
247         return RectT(x_ - offset.GetX(), y_ - offset.GetY(), width_, height_);
248     }
249 
250     RectT operator+(const SizeT<T>& size) const
251     {
252         return RectT(x_, y_, width_ + size.Width(), height_ + size.Height());
253     }
254 
255     RectT operator-(const SizeT<T>& size) const
256     {
257         return RectT(x_, y_, width_ - size.Width(), height_ - size.Height());
258     }
259 
260     RectT operator*(T scale) const
261     {
262         return RectT(x_ * scale, y_ * scale, width_ * scale, height_ * scale);
263     }
264 
265     bool operator==(const RectT& RectT) const
266     {
267         return (GetOffset() == RectT.GetOffset()) && (GetSize() == RectT.GetSize());
268     }
269 
270     bool operator!=(const RectT& RectT) const
271     {
272         return !operator==(RectT);
273     }
274 
IsIntersectWith(const RectT & other)275     bool IsIntersectWith(const RectT& other) const
276     {
277         return !(LessNotEqual(other.Right(), Left()) || GreatNotEqual(other.Left(), Right()) ||
278                  LessNotEqual(other.Bottom(), Top()) || GreatNotEqual(other.Top(), Bottom()));
279     }
280 
IntersectRectT(const RectT & other)281     RectT IntersectRectT(const RectT& other) const
282     {
283         T left = std::max(Left(), other.Left());
284         T right = std::min(Right(), other.Right());
285         T top = std::max(Top(), other.Top());
286         T bottom = std::min(Bottom(), other.Bottom());
287         return RectT(left, top, right - left, bottom - top);
288     }
289 
CombineRectT(const RectT & other)290     RectT CombineRectT(const RectT& other) const
291     {
292         T left = std::min(Left(), other.Left());
293         T right = std::max(Right(), other.Right());
294         T top = std::min(Top(), other.Top());
295         T bottom = std::max(Bottom(), other.Bottom());
296         return RectT(left, top, right - left, bottom - top);
297     }
298 
MagneticAttractedBy(const RectT & magnet)299     OffsetT<T> MagneticAttractedBy(const RectT& magnet)
300     {
301         OffsetT<T> offset { 0.0, 0.0 };
302         if (IsWrappedBy(magnet)) {
303             return offset;
304         }
305 
306         if (LessNotEqual(Left(), magnet.Left())) {
307             offset.SetX(std::max(0.0, std::min(magnet.Left() - Left(), magnet.Right() - Right())));
308         } else if (GreatNotEqual(Right(), magnet.Right())) {
309             offset.SetX(std::min(0.0, std::max(magnet.Left() - Left(), magnet.Right() - Right())));
310         } else {
311             // No need to offset.
312         }
313 
314         if (LessNotEqual(Top(), magnet.Top())) {
315             offset.SetY(std::max(0.0, std::min(magnet.Top() - Top(), magnet.Bottom() - Bottom())));
316         } else if (GreatNotEqual(Bottom(), magnet.Bottom())) {
317             offset.SetY(std::min(0.0, std::max(magnet.Top() - Top(), magnet.Bottom() - Bottom())));
318         } else {
319             // No need to offset.
320         }
321 
322         *this += offset;
323 
324         return offset;
325     }
326 
ToString()327     std::string ToString() const
328     {
329         static const int32_t precision = 2;
330         std::stringstream ss;
331         ss << "RectT (" << std::fixed << std::setprecision(precision) << x_ << ", " << y_ << ") - [";
332         ss << width_;
333         ss << " x ";
334         ss << height_;
335         ss << "]";
336         std::string output = ss.str();
337         return output;
338     }
339 
ToBounds()340     std::string ToBounds() const
341     {
342         static const int32_t precision = 2;
343         std::stringstream ss;
344         ss << "[" << std::fixed << std::setprecision(precision) << x_ << ", " << y_ << "][";
345         if (NearEqual(width_, Infinity<T>())) {
346             ss << "INFINITE";
347         } else {
348             ss << (x_ + width_);
349         }
350         ss << ",";
351         if (NearEqual(height_, Infinity<T>())) {
352             ss << "INFINITE";
353         } else {
354             ss << (y_ + height_);
355         }
356         ss << "]";
357         std::string output = ss.str();
358         return output;
359     }
360 
Center()361     OffsetT<T> Center() const
362     {
363         return OffsetT<T>(width_ / 2.0 + x_, height_ / 2.0 + y_);
364     }
365 
366 private:
367     T x_ = 0;
368     T y_ = 0;
369     T width_ = 0;
370     T height_ = 0;
371 
372     friend class GeometryProperty;
373 };
374 
375 using RectF = RectT<float>;
376 
377 struct EdgeF {
378     EdgeF() = default;
EdgeFEdgeF379     EdgeF(float x, float y) : x(x), y(y) {}
SetXEdgeF380     void SetX(float setX)
381     {
382         x = setX;
383     }
SetYEdgeF384     void SetY(float setY)
385     {
386         y = setY;
387     }
388     EdgeF operator+(const EdgeF& add) const
389     {
390         return EdgeF(x + add.x, y + add.y);
391     }
392     float x = 0.0f;
393     float y = 0.0f;
394 };
395 
396 struct RadiusF {
RadiusFRadiusF397     RadiusF(const EdgeF& radius) : topLeft(radius), topRight(radius), bottomLeft(radius), bottomRight(radius) {}
RadiusFRadiusF398     RadiusF(const EdgeF& topLeft, const EdgeF& topRight, const EdgeF& bottomLeft, const EdgeF& bottomRight)
399         : topLeft(topLeft), topRight(topRight), bottomLeft(bottomLeft), bottomRight(bottomRight)
400     {}
401 
SetCornerRadiusF402     void SetCorner(int32_t pos, const EdgeF& edge)
403     {
404         if (LessNotEqual(pos, 0.0) || GreatOrEqual(pos, data_.size())) {
405             return;
406         }
407         data_[pos] = edge;
408     }
409 
GetCornerRadiusF410     EdgeF GetCorner(int32_t pos) const
411     {
412         if (LessNotEqual(pos, 0.0) || GreatOrEqual(pos, data_.size())) {
413             return EdgeF();
414         }
415         return data_[pos];
416     }
417 
418     union {
419         struct {
420             EdgeF topLeft;
421             EdgeF topRight;
422             EdgeF bottomLeft;
423             EdgeF bottomRight;
424         };
425         std::array<EdgeF, 4> data_;
426     };
427 };
428 
429 class RoundRect {
430 public:
431     enum CornerPos {
432         TOP_LEFT_POS,
433         TOP_RIGHT_POS,
434         BOTTOM_RIGHT_POS,
435         BOTTOM_LEFT_POS,
436     };
437 
438     inline RoundRect() noexcept;
439     inline ~RoundRect() = default;
440 
441     inline RoundRect(const RoundRect& roundRect) noexcept;
442     inline RoundRect(const RectF& rect, float xRad, float yRad) noexcept;
443     inline RoundRect(const RectF& rect, const RadiusF& radius) noexcept;
444 
445     inline void SetCornerRadius(CornerPos pos, float radiusX, float radiusY);
446     inline void SetCornerRadius(float radius);
447     inline EdgeF GetCornerRadius(CornerPos pos) const;
448 
449     inline void SetRect(const RectF& rect);
450     inline RectF GetRect() const;
451 
452     inline void Offset(float dx, float dy);
453 
454 private:
455     RectF rect_;
456     // Four radii are stored: top-left/top-right/bottom-left/bottom-right corner radii.
457     RadiusF radius_;
458 };
459 
RoundRect()460 inline RoundRect::RoundRect() noexcept : radius_(EdgeF(0, 0), EdgeF(0, 0), EdgeF(0, 0), EdgeF(0, 0)) {}
461 
RoundRect(const RoundRect & roundRect)462 inline RoundRect::RoundRect(const RoundRect& roundRect) noexcept : RoundRect()
463 {
464     rect_ = roundRect.rect_;
465     radius_ = roundRect.radius_;
466 }
467 
RoundRect(const RectF & r,float xRad,float yRad)468 inline RoundRect::RoundRect(const RectF& r, float xRad, float yRad) noexcept : RoundRect()
469 {
470     rect_ = r;
471     for (auto& i : radius_.data_) {
472         i = EdgeF(xRad, yRad);
473     }
474 }
475 
RoundRect(const RectF & r,const RadiusF & rad)476 inline RoundRect::RoundRect(const RectF& r, const RadiusF& rad) noexcept : RoundRect()
477 {
478     rect_ = r;
479     radius_ = rad;
480 }
481 
SetCornerRadius(CornerPos pos,float radiusX,float radiusY)482 inline void RoundRect::SetCornerRadius(CornerPos pos, float radiusX, float radiusY)
483 {
484     radius_.SetCorner(pos, EdgeF(radiusX, radiusY));
485 }
486 
SetCornerRadius(float radius)487 inline void RoundRect::SetCornerRadius(float radius)
488 {
489     radius_.SetCorner(TOP_LEFT_POS, EdgeF(radius, radius));
490     radius_.SetCorner(TOP_RIGHT_POS, EdgeF(radius, radius));
491     radius_.SetCorner(BOTTOM_LEFT_POS, EdgeF(radius, radius));
492     radius_.SetCorner(BOTTOM_RIGHT_POS, EdgeF(radius, radius));
493 }
494 
GetCornerRadius(CornerPos pos)495 inline EdgeF RoundRect::GetCornerRadius(CornerPos pos) const
496 {
497     return radius_.GetCorner(pos);
498 }
499 
SetRect(const RectF & rect)500 inline void RoundRect::SetRect(const RectF& rect)
501 {
502     rect_ = rect;
503 }
504 
GetRect()505 inline RectF RoundRect::GetRect() const
506 {
507     return rect_;
508 }
509 } // namespace OHOS::Ace::NG
510 
511 #endif // FOUNDATION_ACE_FRAMEWORKS_BASE_GEOMETRY_NG_RECT_H
512