• 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 
IsInnerRegion(const PointT<T> & point)186     bool IsInnerRegion(const PointT<T>& point) const
187     {
188         return GreatNotEqual(point.GetX(), x_) && LessNotEqual(point.GetX(), x_ + width_) &&
189                GreatNotEqual(point.GetY(), y_) && LessNotEqual(point.GetY(), y_ + height_);
190     }
191 
IsWrappedBy(const RectT & other)192     bool IsWrappedBy(const RectT& other) const
193     {
194         return GreatOrEqual(Left(), other.Left()) && LessOrEqual(Right(), other.Right()) &&
195                GreatOrEqual(Top(), other.Top()) && LessOrEqual(Bottom(), other.Bottom());
196     }
197 
IsValid()198     bool IsValid() const
199     {
200         return NonNegative(width_) && NonNegative(height_);
201     }
202 
IsEmpty()203     bool IsEmpty() const
204     {
205         return NonPositive(width_) || NonPositive(height_);
206     }
207 
Constrain(const RectT & other)208     RectT Constrain(const RectT& other)
209     {
210         T right = Right();
211         T bottom = Bottom();
212         T left = std::clamp(x_, other.Left(), other.Right());
213         T top = std::clamp(y_, other.Top(), other.Bottom());
214         right = std::clamp(right, other.Left(), other.Right()) - left;
215         bottom = std::clamp(bottom, other.Top(), other.Bottom()) - top;
216         return RectT(left, top, right, bottom);
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 OffsetT<T>& offset)
227     {
228         x_ -= offset.GetX();
229         y_ -= offset.GetY();
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 SizeT<T>& size)
241     {
242         width_ -= size.Width();
243         height_ -= size.Height();
244         return *this;
245     }
246 
247     RectT operator+(const OffsetT<T>& offset) const
248     {
249         return RectT(x_ + offset.GetX(), y_ + offset.GetY(), width_, height_);
250     }
251 
252     RectT operator-(const OffsetT<T>& offset) const
253     {
254         return RectT(x_ - offset.GetX(), y_ - offset.GetY(), width_, height_);
255     }
256 
257     RectT operator+(const SizeT<T>& size) const
258     {
259         return RectT(x_, y_, width_ + size.Width(), height_ + size.Height());
260     }
261 
262     RectT operator-(const SizeT<T>& size) const
263     {
264         return RectT(x_, y_, width_ - size.Width(), height_ - size.Height());
265     }
266 
267     RectT operator*(T scale) const
268     {
269         return RectT(x_ * scale, y_ * scale, width_ * scale, height_ * scale);
270     }
271 
272     bool operator==(const RectT& RectT) const
273     {
274         return (GetOffset() == RectT.GetOffset()) && (GetSize() == RectT.GetSize());
275     }
276 
277     bool operator!=(const RectT& RectT) const
278     {
279         return !operator==(RectT);
280     }
281 
IsIntersectWith(const RectT & other)282     bool IsIntersectWith(const RectT& other) const
283     {
284         return !(LessNotEqual(other.Right(), Left()) || GreatNotEqual(other.Left(), Right()) ||
285                  LessNotEqual(other.Bottom(), Top()) || GreatNotEqual(other.Top(), Bottom()));
286     }
287 
IsInnerIntersectWith(const RectT & other)288     bool IsInnerIntersectWith(const RectT& other) const
289     {
290         return !(LessOrEqual(other.Right(), Left()) || GreatOrEqual(other.Left(), Right()) ||
291                  LessOrEqual(other.Bottom(), Top()) || GreatOrEqual(other.Top(), Bottom()));
292     }
293 
IntersectRectT(const RectT & other)294     RectT IntersectRectT(const RectT& other) const
295     {
296         T left = std::max(Left(), other.Left());
297         T right = std::min(Right(), other.Right());
298         T top = std::max(Top(), other.Top());
299         T bottom = std::min(Bottom(), other.Bottom());
300         return RectT(left, top, right - left, bottom - top);
301     }
302 
CombineRectT(const RectT & other)303     RectT CombineRectT(const RectT& other) const
304     {
305         T left = std::min(Left(), other.Left());
306         T right = std::max(Right(), other.Right());
307         T top = std::min(Top(), other.Top());
308         T bottom = std::max(Bottom(), other.Bottom());
309         return RectT(left, top, right - left, bottom - top);
310     }
311 
MagneticAttractedBy(const RectT & magnet)312     OffsetT<T> MagneticAttractedBy(const RectT& magnet)
313     {
314         OffsetT<T> offset { 0.0, 0.0 };
315         if (IsWrappedBy(magnet)) {
316             return offset;
317         }
318 
319         if (LessNotEqual(Left(), magnet.Left())) {
320             offset.SetX(std::max(0.0, std::min(magnet.Left() - Left(), magnet.Right() - Right())));
321         } else if (GreatNotEqual(Right(), magnet.Right())) {
322             offset.SetX(std::min(0.0, std::max(magnet.Left() - Left(), magnet.Right() - Right())));
323         } else {
324             // No need to offset.
325         }
326 
327         if (LessNotEqual(Top(), magnet.Top())) {
328             offset.SetY(std::max(0.0, std::min(magnet.Top() - Top(), magnet.Bottom() - Bottom())));
329         } else if (GreatNotEqual(Bottom(), magnet.Bottom())) {
330             offset.SetY(std::min(0.0, std::max(magnet.Top() - Top(), magnet.Bottom() - Bottom())));
331         } else {
332             // No need to offset.
333         }
334 
335         *this += offset;
336 
337         return offset;
338     }
339 
ToString()340     std::string ToString() const
341     {
342         static const int32_t precision = 2;
343         std::stringstream ss;
344         ss << "RectT (" << std::fixed << std::setprecision(precision) << x_ << ", " << y_ << ") - [";
345         ss << width_;
346         ss << " x ";
347         ss << height_;
348         ss << "]";
349         std::string output = ss.str();
350         return output;
351     }
352 
353     // for example str = RectT (0.00, 0.00) - [0.00 x 0.00]
FromString(const std::string & str)354     static RectT FromString(const std::string& str)
355     {
356         static const int32_t valueSize = 4;
357 
358         std::vector<T> vals;
359         std::string val;
360         for (auto& it : str) {
361             if ((it >= '0' && it <= '9') || (it == '.' && !val.empty())) {
362                 val += it;
363             } else {
364                 if (!val.empty()) {
365                     vals.push_back(StringUtils::StringToFloat(val));
366                     val.clear();
367                 }
368             }
369         }
370 
371         if (vals.size() != valueSize) {
372             LOGE("UITree |ERROR| invalid str=%{public}s", str.c_str());
373             return RectT();
374         }
375 
376         int32_t index = 0;
377         T x = vals[index++];
378         T y = vals[index++];
379         T width = vals[index++];
380         T height = vals[index++];
381         return RectT(x, y, width, height);
382     }
383 
ToBounds()384     std::string ToBounds() const
385     {
386         static const int32_t precision = 2;
387         std::stringstream ss;
388         ss << "[" << std::fixed << std::setprecision(precision) << x_ << ", " << y_ << "],[";
389         if (NearEqual(width_, Infinity<T>())) {
390             ss << "INFINITE";
391         } else {
392             ss << (x_ + width_);
393         }
394         ss << ",";
395         if (NearEqual(height_, Infinity<T>())) {
396             ss << "INFINITE";
397         } else {
398             ss << (y_ + height_);
399         }
400         ss << "]";
401         std::string output = ss.str();
402         return output;
403     }
404 
Center()405     OffsetT<T> Center() const
406     {
407         return OffsetT<T>(width_ / 2.0 + x_, height_ / 2.0 + y_);
408     }
409 
410 private:
411     T x_ = 0;
412     T y_ = 0;
413     T width_ = 0;
414     T height_ = 0;
415 
416     friend class GeometryProperty;
417 };
418 
419 using RectF = RectT<float>;
420 
421 struct EdgeF {
422     EdgeF() = default;
EdgeFEdgeF423     EdgeF(float x, float y) : x(x), y(y) {}
SetXEdgeF424     void SetX(float setX)
425     {
426         x = setX;
427     }
SetYEdgeF428     void SetY(float setY)
429     {
430         y = setY;
431     }
432     EdgeF operator+(const EdgeF& add) const
433     {
434         return EdgeF(x + add.x, y + add.y);
435     }
436     float x = 0.0f;
437     float y = 0.0f;
438 };
439 
440 struct RadiusF {
RadiusFRadiusF441     RadiusF(const EdgeF& radius) : topLeft(radius), topRight(radius), bottomLeft(radius), bottomRight(radius) {}
RadiusFRadiusF442     RadiusF(const EdgeF& topLeft, const EdgeF& topRight, const EdgeF& bottomLeft, const EdgeF& bottomRight)
443         : topLeft(topLeft), topRight(topRight), bottomLeft(bottomLeft), bottomRight(bottomRight)
444     {}
445 
SetCornerRadiusF446     void SetCorner(int32_t pos, const EdgeF& edge)
447     {
448         if (LessNotEqual(pos, 0.0) || GreatOrEqual(pos, data_.size())) {
449             return;
450         }
451         data_[pos] = edge;
452     }
453 
GetCornerRadiusF454     EdgeF GetCorner(int32_t pos) const
455     {
456         if (LessNotEqual(pos, 0.0) || GreatOrEqual(pos, data_.size())) {
457             return EdgeF();
458         }
459         return data_[pos];
460     }
461 
462     union {
463         struct {
464             EdgeF topLeft;
465             EdgeF topRight;
466             EdgeF bottomLeft;
467             EdgeF bottomRight;
468         };
469         std::array<EdgeF, 4> data_;
470     };
471 };
472 
473 class RoundRect {
474 public:
475     enum CornerPos {
476         TOP_LEFT_POS,
477         TOP_RIGHT_POS,
478         BOTTOM_RIGHT_POS,
479         BOTTOM_LEFT_POS,
480     };
481 
482     inline RoundRect() noexcept;
483     inline ~RoundRect() = default;
484 
485     inline RoundRect(const RoundRect& roundRect) noexcept;
486     inline RoundRect(const RectF& rect, float xRad, float yRad) noexcept;
487     inline RoundRect(const RectF& rect, const RadiusF& radius) noexcept;
488 
489     inline void SetCornerRadius(CornerPos pos, float radiusX, float radiusY);
490     inline void SetCornerRadius(float radius);
491     inline EdgeF GetCornerRadius(CornerPos pos) const;
492 
493     inline void SetRect(const RectF& rect);
494     inline RectF GetRect() const;
495 
496     inline void Offset(float dx, float dy);
497 
498 private:
499     RectF rect_;
500     // Four radii are stored: top-left/top-right/bottom-left/bottom-right corner radii.
501     RadiusF radius_;
502 };
503 
RoundRect()504 inline RoundRect::RoundRect() noexcept : radius_(EdgeF(0, 0), EdgeF(0, 0), EdgeF(0, 0), EdgeF(0, 0)) {}
505 
RoundRect(const RoundRect & roundRect)506 inline RoundRect::RoundRect(const RoundRect& roundRect) noexcept : RoundRect()
507 {
508     rect_ = roundRect.rect_;
509     radius_ = roundRect.radius_;
510 }
511 
RoundRect(const RectF & r,float xRad,float yRad)512 inline RoundRect::RoundRect(const RectF& r, float xRad, float yRad) noexcept : RoundRect()
513 {
514     rect_ = r;
515     for (auto& i : radius_.data_) {
516         i = EdgeF(xRad, yRad);
517     }
518 }
519 
RoundRect(const RectF & r,const RadiusF & rad)520 inline RoundRect::RoundRect(const RectF& r, const RadiusF& rad) noexcept : RoundRect()
521 {
522     rect_ = r;
523     radius_ = rad;
524 }
525 
SetCornerRadius(CornerPos pos,float radiusX,float radiusY)526 inline void RoundRect::SetCornerRadius(CornerPos pos, float radiusX, float radiusY)
527 {
528     radius_.SetCorner(pos, EdgeF(radiusX, radiusY));
529 }
530 
SetCornerRadius(float radius)531 inline void RoundRect::SetCornerRadius(float radius)
532 {
533     radius_.SetCorner(TOP_LEFT_POS, EdgeF(radius, radius));
534     radius_.SetCorner(TOP_RIGHT_POS, EdgeF(radius, radius));
535     radius_.SetCorner(BOTTOM_LEFT_POS, EdgeF(radius, radius));
536     radius_.SetCorner(BOTTOM_RIGHT_POS, EdgeF(radius, radius));
537 }
538 
GetCornerRadius(CornerPos pos)539 inline EdgeF RoundRect::GetCornerRadius(CornerPos pos) const
540 {
541     return radius_.GetCorner(pos);
542 }
543 
SetRect(const RectF & rect)544 inline void RoundRect::SetRect(const RectF& rect)
545 {
546     rect_ = rect;
547 }
548 
GetRect()549 inline RectF RoundRect::GetRect() const
550 {
551     return rect_;
552 }
553 } // namespace OHOS::Ace::NG
554 
555 #endif // FOUNDATION_ACE_FRAMEWORKS_BASE_GEOMETRY_NG_RECT_H
556