• 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/log/log.h"
27 #include "base/utils/string_utils.h"
28 #include "base/utils/utils.h"
29 
30 namespace OHOS::Ace::NG {
31 template<typename T>
32 class RectT {
33 public:
34     RectT() = default;
35     ~RectT() = default;
36 
RectT(T x,T y,T width,T height)37     RectT(T x, T y, T width, T height)
38     {
39         SetRect(x, y, width, height);
40     }
41 
RectT(const OffsetF & offset,const SizeF & size)42     RectT(const OffsetF& offset, const SizeF& size)
43     {
44         SetOffset(offset);
45         SetSize(size);
46     }
47 
RectT(const OffsetF & topLeftPoint,const OffsetF & bottomRightPoint)48     RectT(const OffsetF& topLeftPoint, const OffsetF& bottomRightPoint)
49     {
50         SetOffset(topLeftPoint);
51         OffsetF sizeOffset = bottomRightPoint - topLeftPoint;
52         SizeF size(sizeOffset.GetX(), sizeOffset.GetY());
53         SetSize(size);
54     }
55 
Reset()56     void Reset()
57     {
58         x_ = 0;
59         y_ = 0;
60         width_ = 0;
61         height_ = 0;
62     }
63 
SetRect(T x,T y,T width,T height)64     void SetRect(T x, T y, T width, T height)
65     {
66         x_ = x;
67         y_ = y;
68         width_ = width;
69         height_ = height;
70     }
71 
SetRect(const OffsetT<T> & offset,const SizeT<T> & size)72     void SetRect(const OffsetT<T>& offset, const SizeT<T>& size)
73     {
74         SetOffset(offset);
75         SetSize(size);
76     }
77 
ApplyScale(T scale)78     void ApplyScale(T scale)
79     {
80         x_ *= scale;
81         y_ *= scale;
82         width_ *= scale;
83         height_ *= scale;
84     }
85 
ApplyScaleAndRound(T scale)86     void ApplyScaleAndRound(T scale)
87     {
88         x_ = round(x_ * scale);
89         y_ = round(y_ * scale);
90         width_ = round(width_ * scale);
91         height_ = round(height_ * scale);
92     }
93 
Left()94     T Left() const
95     {
96         return GreatNotEqual(width_, 0) ? x_ : x_ + width_;
97     }
98 
Top()99     T Top() const
100     {
101         return GreatNotEqual(height_, 0) ? y_ : y_ + height_;
102     }
103 
Right()104     T Right() const
105     {
106         return GreatNotEqual(width_, 0) ? x_ + width_ : x_;
107     }
108 
Bottom()109     T Bottom() const
110     {
111         return GreatNotEqual(height_, 0) ? y_ + height_ : y_;
112     }
113 
GetX()114     T GetX() const
115     {
116         return x_;
117     }
118 
GetY()119     T GetY() const
120     {
121         return y_;
122     }
123 
Width()124     T Width() const
125     {
126         return width_;
127     }
128 
Height()129     T Height() const
130     {
131         return height_;
132     }
133 
MainSize(Axis axis)134     T MainSize(Axis axis) const
135     {
136         return axis == Axis::HORIZONTAL ? width_ : height_;
137     }
138 
SetSize(const SizeT<T> & size)139     void SetSize(const SizeT<T>& size)
140     {
141         width_ = size.Width();
142         height_ = size.Height();
143     }
144 
GetSize()145     SizeT<T> GetSize() const
146     {
147         return SizeT<T>(width_, height_);
148     }
149 
SetOffset(const OffsetT<T> & offset)150     void SetOffset(const OffsetT<T>& offset)
151     {
152         x_ = offset.GetX();
153         y_ = offset.GetY();
154     }
155 
GetOffset()156     OffsetT<T> GetOffset() const
157     {
158         return OffsetT<T>(x_, y_);
159     }
160 
SetLeft(T left)161     void SetLeft(T left)
162     {
163         x_ = left;
164     }
165 
SetTop(T top)166     void SetTop(T top)
167     {
168         y_ = top;
169     }
170 
SetWidth(T width)171     void SetWidth(T width)
172     {
173         width_ = width;
174     }
175 
SetHeight(T height)176     void SetHeight(T height)
177     {
178         height_ = height;
179     }
180 
IsInRegion(const PointT<T> & point)181     bool IsInRegion(const PointT<T>& point) const
182     {
183         if (NearZero(width_) || NearZero(height_)) {
184             return false;
185         }
186         return GreatOrEqual(point.GetX(), x_) && LessOrEqual(point.GetX(), x_ + width_) &&
187                GreatOrEqual(point.GetY(), y_) && LessOrEqual(point.GetY(), y_ + height_);
188     }
189 
IsInnerRegion(const PointT<T> & point)190     bool IsInnerRegion(const PointT<T>& point) const
191     {
192         return GreatNotEqual(point.GetX(), x_) && LessNotEqual(point.GetX(), x_ + width_) &&
193                GreatNotEqual(point.GetY(), y_) && LessNotEqual(point.GetY(), y_ + height_);
194     }
195 
IsWrappedBy(const RectT & other)196     bool IsWrappedBy(const RectT& other) const
197     {
198         return GreatOrEqual(Left(), other.Left()) && LessOrEqual(Right(), other.Right()) &&
199                GreatOrEqual(Top(), other.Top()) && LessOrEqual(Bottom(), other.Bottom());
200     }
201 
IsValid()202     bool IsValid() const
203     {
204         return NonNegative(width_) && NonNegative(height_);
205     }
206 
IsEmpty()207     bool IsEmpty() const
208     {
209         return NonPositive(width_) || NonPositive(height_);
210     }
211 
Constrain(const RectT & other)212     RectT Constrain(const RectT& other)
213     {
214         T right = Right();
215         T bottom = Bottom();
216         T left = std::clamp(x_, other.Left(), other.Right());
217         T top = std::clamp(y_, other.Top(), other.Bottom());
218         right = std::clamp(right, other.Left(), other.Right()) - left;
219         bottom = std::clamp(bottom, other.Top(), other.Bottom()) - top;
220         return RectT(left, top, right, bottom);
221     }
222 
223     RectT& operator+=(const OffsetT<T>& offset)
224     {
225         x_ += offset.GetX();
226         y_ += offset.GetY();
227         return *this;
228     }
229 
230     RectT& operator-=(const OffsetT<T>& offset)
231     {
232         x_ -= offset.GetX();
233         y_ -= offset.GetY();
234         return *this;
235     }
236 
237     RectT& operator+=(const SizeT<T>& size)
238     {
239         width_ += size.Width();
240         height_ += size.Height();
241         return *this;
242     }
243 
244     RectT& operator+=(const RectT<T>& rect)
245     {
246         x_ += rect.x_;
247         y_ += rect.y_;
248         width_ += rect.Width();
249         height_ += rect.Height();
250         return *this;
251     }
252 
253     RectT& operator-=(const RectT<T>& rect)
254     {
255         x_ -= rect.x_;
256         y_ -= rect.y_;
257         width_ -= rect.Width();
258         height_ -= rect.Height();
259         return *this;
260     }
261 
262     RectT& operator-=(const SizeT<T>& size)
263     {
264         width_ -= size.Width();
265         height_ -= size.Height();
266         return *this;
267     }
268 
269     RectT operator+(const OffsetT<T>& offset) const
270     {
271         return RectT(x_ + offset.GetX(), y_ + offset.GetY(), width_, height_);
272     }
273 
274     RectT operator-(const OffsetT<T>& offset) const
275     {
276         return RectT(x_ - offset.GetX(), y_ - offset.GetY(), width_, height_);
277     }
278 
279     RectT operator+(const SizeT<T>& size) const
280     {
281         return RectT(x_, y_, width_ + size.Width(), height_ + size.Height());
282     }
283 
284     RectT operator+(const RectT<T>& rect) const
285     {
286         return RectT(x_ + rect.x_, y_ + rect.y_, width_ + rect.Width(), height_ + rect.Height());
287     }
288 
289     RectT operator-(const RectT<T>& rect) const
290     {
291         return RectT(x_ - rect.x_, y_ - rect.y_, width_ - rect.Width(), height_ - rect.Height());
292     }
293 
294     RectT operator-(const SizeT<T>& size) const
295     {
296         return RectT(x_, y_, width_ - size.Width(), height_ - size.Height());
297     }
298 
299     RectT operator*(T scale) const
300     {
301         return RectT(x_ * scale, y_ * scale, width_ * scale, height_ * scale);
302     }
303 
304     bool operator==(const RectT& RectT) const
305     {
306         return (GetOffset() == RectT.GetOffset()) && (GetSize() == RectT.GetSize());
307     }
308 
309     bool operator!=(const RectT& RectT) const
310     {
311         return !operator==(RectT);
312     }
313 
IsIntersectWith(const RectT & other)314     bool IsIntersectWith(const RectT& other) const
315     {
316         return !(LessNotEqual(other.Right(), Left()) || GreatNotEqual(other.Left(), Right()) ||
317                  LessNotEqual(other.Bottom(), Top()) || GreatNotEqual(other.Top(), Bottom()));
318     }
319 
IsInnerIntersectWith(const RectT & other)320     bool IsInnerIntersectWith(const RectT& other) const
321     {
322         return !(LessOrEqual(other.Right(), Left()) || GreatOrEqual(other.Left(), Right()) ||
323                  LessOrEqual(other.Bottom(), Top()) || GreatOrEqual(other.Top(), Bottom()));
324     }
325 
IsInnerIntersectWithRound(const RectT & other)326     bool IsInnerIntersectWithRound(const RectT& other) const
327     {
328         return !(LessOrEqual(other.Right(), Left() + 1.0) || GreatOrEqual(other.Left() + 1.0, Right()) ||
329                  LessOrEqual(other.Bottom(), Top() + 1.0) || GreatOrEqual(other.Top() + 1.0, Bottom()));
330     }
331 
IntersectRectT(const RectT & other)332     RectT IntersectRectT(const RectT& other) const
333     {
334         T left = std::max(Left(), other.Left());
335         T right = std::min(Right(), other.Right());
336         T top = std::max(Top(), other.Top());
337         T bottom = std::min(Bottom(), other.Bottom());
338         return RectT(left, top, right - left, bottom - top);
339     }
340 
CombineRectT(const RectT & other)341     RectT CombineRectT(const RectT& other) const
342     {
343         T left = std::min(Left(), other.Left());
344         T right = std::max(Right(), other.Right());
345         T top = std::min(Top(), other.Top());
346         T bottom = std::max(Bottom(), other.Bottom());
347         return RectT(left, top, right - left, bottom - top);
348     }
349 
MagneticAttractedBy(const RectT & magnet)350     OffsetT<T> MagneticAttractedBy(const RectT& magnet)
351     {
352         OffsetT<T> offset { 0.0, 0.0 };
353         if (IsWrappedBy(magnet)) {
354             return offset;
355         }
356 
357         if (LessNotEqual(Left(), magnet.Left())) {
358             offset.SetX(std::max(0.0, std::min(magnet.Left() - Left(), magnet.Right() - Right())));
359         } else if (GreatNotEqual(Right(), magnet.Right())) {
360             offset.SetX(std::min(0.0, std::max(magnet.Left() - Left(), magnet.Right() - Right())));
361         } else {
362             // No need to offset.
363         }
364 
365         if (LessNotEqual(Top(), magnet.Top())) {
366             offset.SetY(std::max(0.0, std::min(magnet.Top() - Top(), magnet.Bottom() - Bottom())));
367         } else if (GreatNotEqual(Bottom(), magnet.Bottom())) {
368             offset.SetY(std::min(0.0, std::max(magnet.Top() - Top(), magnet.Bottom() - Bottom())));
369         } else {
370             // No need to offset.
371         }
372 
373         *this += offset;
374 
375         return offset;
376     }
377 
ToString()378     std::string ToString() const
379     {
380         static const int32_t precision = 2;
381         std::stringstream ss;
382         ss << "RectT (" << std::fixed << std::setprecision(precision) << x_ << ", " << y_ << ") - [";
383         ss << width_;
384         ss << " x ";
385         ss << height_;
386         ss << "]";
387         std::string output = ss.str();
388         return output;
389     }
390 
391     // for example str = RectT (0.00, 0.00) - [0.00 x 0.00]
FromString(const std::string & str)392     static RectT FromString(const std::string& str)
393     {
394         static const int32_t valueSize = 4;
395 
396         std::vector<T> vals;
397         std::string val;
398         for (auto& it : str) {
399             if ((it >= '0' && it <= '9') || (it == '.' && !val.empty())) {
400                 val += it;
401             } else {
402                 if (!val.empty()) {
403                     vals.emplace_back(StringUtils::StringToFloat(val));
404                     val.clear();
405                 }
406             }
407         }
408 
409         if (vals.size() != valueSize) {
410             LOGE("UITree |ERROR| invalid str=%{public}s", str.c_str());
411             return RectT();
412         }
413 
414         int32_t index = 0;
415         T x = vals[index++];
416         T y = vals[index++];
417         T width = vals[index++];
418         T height = vals[index++];
419         return RectT(x, y, width, height);
420     }
421 
ToBounds()422     std::string ToBounds() const
423     {
424         static const int32_t precision = 2;
425         std::stringstream ss;
426         ss << "[" << std::fixed << std::setprecision(precision) << x_ << ", " << y_ << "],[";
427         if (NearEqual(width_, Infinity<T>())) {
428             ss << "INFINITE";
429         } else {
430             ss << (x_ + width_);
431         }
432         ss << ",";
433         if (NearEqual(height_, Infinity<T>())) {
434             ss << "INFINITE";
435         } else {
436             ss << (y_ + height_);
437         }
438         ss << "]";
439         std::string output = ss.str();
440         return output;
441     }
442 
Center()443     OffsetT<T> Center() const
444     {
445         return OffsetT<T>(width_ / 2.0 + x_, height_ / 2.0 + y_);
446     }
447 
448 private:
449     T x_ = 0;
450     T y_ = 0;
451     T width_ = 0;
452     T height_ = 0;
453 
454     friend class GeometryProperty;
455 };
456 
457 using RectF = RectT<float>;
458 using RectInt = RectT<int32_t>;
459 
460 struct EdgeF {
461     EdgeF() = default;
EdgeFEdgeF462     EdgeF(float x, float y) : x(x), y(y) {}
SetXEdgeF463     void SetX(float setX)
464     {
465         x = setX;
466     }
SetYEdgeF467     void SetY(float setY)
468     {
469         y = setY;
470     }
471     EdgeF operator+(const EdgeF& add) const
472     {
473         return EdgeF(x + add.x, y + add.y);
474     }
475     float x = 0.0f;
476     float y = 0.0f;
477 };
478 
479 struct RadiusF {
RadiusFRadiusF480     RadiusF(const EdgeF& radius) : topLeft(radius), topRight(radius), bottomLeft(radius), bottomRight(radius) {}
RadiusFRadiusF481     RadiusF(const EdgeF& topLeft, const EdgeF& topRight, const EdgeF& bottomLeft, const EdgeF& bottomRight)
482         : topLeft(topLeft), topRight(topRight), bottomLeft(bottomLeft), bottomRight(bottomRight)
483     {}
484 
SetCornerRadiusF485     void SetCorner(int32_t pos, const EdgeF& edge)
486     {
487         if (LessNotEqual(pos, 0.0) || GreatOrEqual(pos, data_.size())) {
488             return;
489         }
490         data_[pos] = edge;
491     }
492 
GetCornerRadiusF493     EdgeF GetCorner(int32_t pos) const
494     {
495         if (LessNotEqual(pos, 0.0) || GreatOrEqual(pos, data_.size())) {
496             return EdgeF();
497         }
498         return data_[pos];
499     }
500 
501     union {
502         struct {
503             EdgeF topLeft;
504             EdgeF topRight;
505             EdgeF bottomLeft;
506             EdgeF bottomRight;
507         };
508         std::array<EdgeF, 4> data_;
509     };
510 };
511 
512 class RoundRect {
513 public:
514     enum CornerPos {
515         TOP_LEFT_POS,
516         TOP_RIGHT_POS,
517         BOTTOM_RIGHT_POS,
518         BOTTOM_LEFT_POS,
519     };
520 
521     inline RoundRect() noexcept;
522     inline ~RoundRect() = default;
523 
524     inline RoundRect(const RoundRect& roundRect) noexcept;
525     inline RoundRect(const RectF& rect, float xRad, float yRad) noexcept;
526     inline RoundRect(const RectF& rect, const RadiusF& radius) noexcept;
527 
528     inline void SetCornerRadius(CornerPos pos, float radiusX, float radiusY);
529     inline void SetCornerRadius(float radius);
530     inline EdgeF GetCornerRadius(CornerPos pos) const;
531 
532     inline void SetRect(const RectF& rect);
533     inline RectF GetRect() const;
534 
535     inline void Offset(float dx, float dy);
536 
537 private:
538     RectF rect_;
539     // Four radii are stored: top-left/top-right/bottom-left/bottom-right corner radii.
540     RadiusF radius_;
541 };
542 
RoundRect()543 inline RoundRect::RoundRect() noexcept : radius_(EdgeF(0, 0), EdgeF(0, 0), EdgeF(0, 0), EdgeF(0, 0)) {}
544 
RoundRect(const RoundRect & roundRect)545 inline RoundRect::RoundRect(const RoundRect& roundRect) noexcept : RoundRect()
546 {
547     rect_ = roundRect.rect_;
548     radius_ = roundRect.radius_;
549 }
550 
RoundRect(const RectF & r,float xRad,float yRad)551 inline RoundRect::RoundRect(const RectF& r, float xRad, float yRad) noexcept : RoundRect()
552 {
553     rect_ = r;
554     for (auto& i : radius_.data_) {
555         i = EdgeF(xRad, yRad);
556     }
557 }
558 
RoundRect(const RectF & r,const RadiusF & rad)559 inline RoundRect::RoundRect(const RectF& r, const RadiusF& rad) noexcept : RoundRect()
560 {
561     rect_ = r;
562     radius_ = rad;
563 }
564 
SetCornerRadius(CornerPos pos,float radiusX,float radiusY)565 inline void RoundRect::SetCornerRadius(CornerPos pos, float radiusX, float radiusY)
566 {
567     radius_.SetCorner(pos, EdgeF(radiusX, radiusY));
568 }
569 
SetCornerRadius(float radius)570 inline void RoundRect::SetCornerRadius(float radius)
571 {
572     radius_.SetCorner(TOP_LEFT_POS, EdgeF(radius, radius));
573     radius_.SetCorner(TOP_RIGHT_POS, EdgeF(radius, radius));
574     radius_.SetCorner(BOTTOM_LEFT_POS, EdgeF(radius, radius));
575     radius_.SetCorner(BOTTOM_RIGHT_POS, EdgeF(radius, radius));
576 }
577 
GetCornerRadius(CornerPos pos)578 inline EdgeF RoundRect::GetCornerRadius(CornerPos pos) const
579 {
580     return radius_.GetCorner(pos);
581 }
582 
SetRect(const RectF & rect)583 inline void RoundRect::SetRect(const RectF& rect)
584 {
585     rect_ = rect;
586 }
587 
GetRect()588 inline RectF RoundRect::GetRect() const
589 {
590     return rect_;
591 }
592 } // namespace OHOS::Ace::NG
593 
594 #endif // FOUNDATION_ACE_FRAMEWORKS_BASE_GEOMETRY_NG_RECT_H
595