Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2023 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #ifndef MU_ENGRAVING_SHAPE_H
24 : #define MU_ENGRAVING_SHAPE_H
25 :
26 : #include <functional>
27 : #include <optional>
28 :
29 : #include "draw/types/geometry.h"
30 : #include "draw/types/transform.h"
31 :
32 : #include "engraving/types/types.h"
33 :
34 : namespace muse::draw {
35 : class Painter;
36 : class Transform;
37 : }
38 :
39 : namespace mu::engraving {
40 : class EngravingItem;
41 :
42 : //---------------------------------------------------------
43 : // ShapeElement
44 : //---------------------------------------------------------
45 :
46 : struct ShapeElement : public RectF {
47 : public:
48 :
49 483359 : ShapeElement(const RectF& f, const EngravingItem* p, bool ignoreForLayout)
50 483359 : : RectF(f), m_item(p), m_ignoreForLayout(ignoreForLayout) {}
51 3107951 : ShapeElement(const RectF& f, const EngravingItem* p)
52 3107951 : : RectF(f), m_item(p) {}
53 12276 : ShapeElement(const RectF& f)
54 12276 : : RectF(f) {}
55 :
56 15308325 : const EngravingItem* item() const { return m_item; }
57 135600 : void setItem(const EngravingItem* item) { m_item = item; }
58 1924769 : bool ignoreForLayout() const { return m_ignoreForLayout; }
59 :
60 : private:
61 : const EngravingItem* m_item = nullptr;
62 : bool m_ignoreForLayout = false;
63 : };
64 :
65 : //---------------------------------------------------------
66 : // Shape
67 : //---------------------------------------------------------
68 :
69 : class Shape
70 : {
71 : public:
72 :
73 : enum class Type : unsigned char {
74 : Fixed, // fixed size, like just bbox
75 : // FixedX, // not implemented (reserved)
76 : // FixedY, // not implemented (reserved)
77 : Composite // composed of other shapes
78 : };
79 :
80 3539613 : Shape(Type t = Type::Fixed)
81 3539613 : : m_type(t) {}
82 1909825 : Shape(const RectF& r, const EngravingItem* p = nullptr, Type t = Type::Fixed)
83 1909825 : : m_type(t) { setBBox(r, p); }
84 : Shape(const std::vector<RectF>& rects, const EngravingItem* p = nullptr);
85 :
86 1909825 : Type type() const { return m_type; }
87 : bool isComposite() const { return m_type == Type::Composite; }
88 :
89 172 : size_t size() const { return m_elements.size(); }
90 115904 : bool empty() const { return m_elements.empty(); }
91 746442 : void clear() { m_elements.clear(); }
92 :
93 : bool equal(const Shape& sh) const
94 : {
95 : if (m_type != sh.m_type) {
96 : return false;
97 : }
98 :
99 : switch (m_type) {
100 : case Type::Fixed: return this->bbox() == sh.bbox();
101 : case Type::Composite: return this->m_elements == sh.m_elements;
102 : }
103 :
104 : return true;
105 : }
106 :
107 : // Fixed
108 : void setBBox(const RectF& r, const EngravingItem* p = nullptr);
109 : void addBBox(const RectF& r);
110 :
111 : // Composite
112 : void add(const Shape& s);
113 : void add(const ShapeElement& shapeEl);
114 483359 : void add(const RectF& r, const EngravingItem* p, bool ignoreForLayout) { add(ShapeElement(r, p, ignoreForLayout)); }
115 1124099 : void add(const RectF& r, const EngravingItem* p) { add(ShapeElement(r, p)); }
116 12276 : void add(const RectF& r) { add(ShapeElement(r)); }
117 :
118 : void remove(const RectF&);
119 : void remove(const Shape&);
120 : template<typename Predicate>
121 693433 : inline bool remove_if(Predicate p)
122 : {
123 693433 : size_t origSize = m_elements.size();
124 693433 : m_elements.erase(std::remove_if(m_elements.begin(), m_elements.end(), p), m_elements.end());
125 693433 : invalidateBBox();
126 693433 : return origSize != m_elements.size();
127 : }
128 :
129 : // ---
130 :
131 5289105 : const std::vector<ShapeElement>& elements() const { return m_elements; }
132 150006 : std::vector<ShapeElement>& elements() { return m_elements; }
133 : std::vector<RectF> toRects() const;
134 :
135 : std::optional<ShapeElement> find_if(const std::function<bool(const ShapeElement&)>& func) const;
136 : std::optional<ShapeElement> find_first(ElementType type) const;
137 : std::optional<ShapeElement> get_first() const;
138 :
139 : void removeInvisibles();
140 : void removeTypes(const std::set<ElementType>& types);
141 :
142 : void addHorizontalSpacing(EngravingItem* item, double left, double right);
143 :
144 : Shape& translate(const PointF&);
145 : void translateX(double);
146 : void translateY(double);
147 : Shape translated(const PointF&) const;
148 : Shape& scale(const SizeF&);
149 : Shape scaled(const SizeF&) const;
150 : Shape& adjust(double xp1, double yp1, double xp2, double yp2);
151 : Shape adjusted(double xp1, double yp1, double xp2, double yp2) const;
152 : Shape& pad(double p);
153 : Shape padded(double p) const;
154 : Shape& transform(const muse::draw::Transform& t);
155 : Shape transformed(const muse::draw::Transform& t);
156 :
157 : const RectF& bbox() const;
158 : double minVerticalDistance(const Shape&, double minHorizontalClearance = 0.0) const;
159 : double verticalClearance(const Shape&, double minHorizontalDistance = 0.0) const;
160 : double topDistance(const PointF&) const;
161 : double bottomDistance(const PointF&) const;
162 : double left() const;
163 : double right() const;
164 : double top() const;
165 : double bottom() const;
166 : double width() const;
167 : double height() const;
168 : double topAtX(double x) const;
169 : double bottomAtX(double x) const;
170 : double rightMostEdgeAtHeight(double yAbove, double yBelow) const;
171 : double leftMostEdgeAtHeight(double yAbove, double yBelow) const;
172 : double leftMostEdgeAtTop() const;
173 :
174 : bool contains(const PointF&) const;
175 : bool intersects(const RectF& rr) const;
176 : bool intersects(const Shape& other) const;
177 : bool clearsVertically(const Shape& a) const;
178 :
179 : void paint(muse::draw::Painter& painter) const;
180 :
181 : private:
182 :
183 : void invalidateBBox();
184 :
185 : Type m_type = Type::Fixed;
186 : std::vector<ShapeElement> m_elements;
187 : mutable RectF m_bbox; // cache
188 : };
189 :
190 : void dump(const ShapeElement& sh, std::stringstream& ss);
191 : void dump(const Shape& sh, std::stringstream& ss);
192 : std::string dump(const Shape& sh);
193 :
194 : //---------------------------------------------------------
195 : // intersects
196 : //---------------------------------------------------------
197 :
198 12091950 : inline static bool intersects(double a, double b, double c, double d, double minClearance = 0.0)
199 : {
200 12091950 : if (a == b || c == d) {
201 194711 : return false;
202 : }
203 11897239 : return (b + minClearance > c) && (a < d + minClearance);
204 : }
205 : } // namespace mu::engraving
206 :
207 : #endif
|