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