1// Scintilla source code edit control
2/** @file Geometry.h
3 ** Classes and functions for geometric and colour calculations.
4 **/
5// Copyright 2020 by Neil Hodgson <neilh@scintilla.org>
6// The License.txt file describes the conditions under which this software may be distributed.
7
8#ifndef GEOMETRY_H
9#define GEOMETRY_H
10
11namespace Scintilla::Internal {
12
13typedef double XYPOSITION;
14typedef double XYACCUMULATOR;
15
16/**
17 * A geometric point class.
18 * Point is similar to the Win32 POINT and GTK+ GdkPoint types.
19 */
20class Point {
21public:
22 XYPOSITION x;
23 XYPOSITION y;
24
25 constexpr explicit Point(XYPOSITION x_=0, XYPOSITION y_=0) noexcept : x(x_), y(y_) {
26 }
27
28 static constexpr Point FromInts(int x_, int y_) noexcept {
29 return Point(static_cast<XYPOSITION>(x_), static_cast<XYPOSITION>(y_));
30 }
31
32 constexpr bool operator==(Point other) const noexcept {
33 return (x == other.x) && (y == other.y);
34 }
35
36 constexpr bool operator!=(Point other) const noexcept {
37 return (x != other.x) || (y != other.y);
38 }
39
40 constexpr Point operator+(Point other) const noexcept {
41 return Point(x + other.x, y + other.y);
42 }
43
44 constexpr Point operator-(Point other) const noexcept {
45 return Point(x - other.x, y - other.y);
46 }
47
48 // Other automatically defined methods (assignment, copy constructor, destructor) are fine
49};
50
51
52/**
53 * A geometric interval class.
54 */
55class Interval {
56public:
57 XYPOSITION left;
58 XYPOSITION right;
59 constexpr bool operator==(const Interval &other) const noexcept {
60 return (left == other.left) && (right == other.right);
61 }
62 constexpr XYPOSITION Width() const noexcept { return right - left; }
63 constexpr bool Empty() const noexcept {
64 return Width() <= 0;
65 }
66 constexpr bool Intersects(Interval other) const noexcept {
67 return (right > other.left) && (left < other.right);
68 }
69};
70
71/**
72 * A geometric rectangle class.
73 * PRectangle is similar to Win32 RECT.
74 * PRectangles contain their top and left sides, but not their right and bottom sides.
75 */
76class PRectangle {
77public:
78 XYPOSITION left;
79 XYPOSITION top;
80 XYPOSITION right;
81 XYPOSITION bottom;
82
83 constexpr explicit PRectangle(XYPOSITION left_=0, XYPOSITION top_=0, XYPOSITION right_=0, XYPOSITION bottom_ = 0) noexcept :
84 left(left_), top(top_), right(right_), bottom(bottom_) {
85 }
86
87 static constexpr PRectangle FromInts(int left_, int top_, int right_, int bottom_) noexcept {
88 return PRectangle(static_cast<XYPOSITION>(left_), static_cast<XYPOSITION>(top_),
89 static_cast<XYPOSITION>(right_), static_cast<XYPOSITION>(bottom_));
90 }
91
92 // Other automatically defined methods (assignment, copy constructor, destructor) are fine
93
94 constexpr bool operator==(const PRectangle &rc) const noexcept {
95 return (rc.left == left) && (rc.right == right) &&
96 (rc.top == top) && (rc.bottom == bottom);
97 }
98 constexpr bool Contains(Point pt) const noexcept {
99 return (pt.x >= left) && (pt.x <= right) &&
100 (pt.y >= top) && (pt.y <= bottom);
101 }
102 constexpr bool ContainsWholePixel(Point pt) const noexcept {
103 // Does the rectangle contain all of the pixel to left/below the point
104 return (pt.x >= left) && ((pt.x+1) <= right) &&
105 (pt.y >= top) && ((pt.y+1) <= bottom);
106 }
107 constexpr bool Contains(PRectangle rc) const noexcept {
108 return (rc.left >= left) && (rc.right <= right) &&
109 (rc.top >= top) && (rc.bottom <= bottom);
110 }
111 constexpr bool Intersects(PRectangle other) const noexcept {
112 return (right > other.left) && (left < other.right) &&
113 (bottom > other.top) && (top < other.bottom);
114 }
115 void Move(XYPOSITION xDelta, XYPOSITION yDelta) noexcept {
116 left += xDelta;
117 top += yDelta;
118 right += xDelta;
119 bottom += yDelta;
120 }
121
122 constexpr PRectangle Inset(XYPOSITION delta) const noexcept {
123 return PRectangle(left + delta, top + delta, right - delta, bottom - delta);
124 }
125
126 constexpr PRectangle Inset(Point delta) const noexcept {
127 return PRectangle(left + delta.x, top + delta.y, right - delta.x, bottom - delta.y);
128 }
129
130 constexpr Point Centre() const noexcept {
131 return Point((left + right) / 2, (top + bottom) / 2);
132 }
133
134 constexpr XYPOSITION Width() const noexcept { return right - left; }
135 constexpr XYPOSITION Height() const noexcept { return bottom - top; }
136 constexpr bool Empty() const noexcept {
137 return (Height() <= 0) || (Width() <= 0);
138 }
139};
140
141enum class Edge { left, top, bottom, right };
142
143PRectangle Clamp(PRectangle rc, Edge edge, XYPOSITION position) noexcept;
144PRectangle Side(PRectangle rc, Edge edge, XYPOSITION size) noexcept;
145
146Interval Intersection(Interval a, Interval b) noexcept;
147PRectangle Intersection(PRectangle rc, Interval horizontalBounds) noexcept;
148Interval HorizontalBounds(PRectangle rc) noexcept;
149
150XYPOSITION PixelAlign(XYPOSITION xy, int pixelDivisions) noexcept;
151XYPOSITION PixelAlignFloor(XYPOSITION xy, int pixelDivisions) noexcept;
152
153Point PixelAlign(const Point &pt, int pixelDivisions) noexcept;
154
155PRectangle PixelAlign(const PRectangle &rc, int pixelDivisions) noexcept;
156PRectangle PixelAlignOutside(const PRectangle &rc, int pixelDivisions) noexcept;
157
158/**
159* Holds an RGBA colour with 8 bits for each component.
160*/
161constexpr const float componentMaximum = 255.0f;
162class ColourRGBA {
163 int co;
164public:
165 constexpr explicit ColourRGBA(int co_ = 0) noexcept : co(co_) {
166 }
167
168 constexpr ColourRGBA(unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha=0xff) noexcept :
169 ColourRGBA(red | (green << 8) | (blue << 16) | (alpha << 24)) {
170 }
171
172 constexpr ColourRGBA(ColourRGBA cd, unsigned int alpha) noexcept :
173 ColourRGBA(cd.OpaqueRGB() | (alpha << 24)) {
174 }
175
176 static constexpr ColourRGBA FromRGB(int co_) noexcept {
177 return ColourRGBA(co_ | (0xffu << 24));
178 }
179
180 static constexpr ColourRGBA FromIpRGB(intptr_t co_) noexcept {
181 return ColourRGBA(static_cast<int>(co_) | (0xffu << 24));
182 }
183
184 constexpr ColourRGBA WithoutAlpha() const noexcept {
185 return ColourRGBA(co & 0xffffff);
186 }
187
188 constexpr ColourRGBA Opaque() const noexcept {
189 return ColourRGBA(co | (0xffu << 24));
190 }
191
192 constexpr int AsInteger() const noexcept {
193 return co;
194 }
195
196 constexpr int OpaqueRGB() const noexcept {
197 return co & 0xffffff;
198 }
199
200 // Red, green and blue values as bytes 0..255
201 constexpr unsigned char GetRed() const noexcept {
202 return co & 0xff;
203 }
204 constexpr unsigned char GetGreen() const noexcept {
205 return (co >> 8) & 0xff;
206 }
207 constexpr unsigned char GetBlue() const noexcept {
208 return (co >> 16) & 0xff;
209 }
210 constexpr unsigned char GetAlpha() const noexcept {
211 return (co >> 24) & 0xff;
212 }
213
214 // Red, green, blue, and alpha values as float 0..1.0
215 constexpr float GetRedComponent() const noexcept {
216 return GetRed() / componentMaximum;
217 }
218 constexpr float GetGreenComponent() const noexcept {
219 return GetGreen() / componentMaximum;
220 }
221 constexpr float GetBlueComponent() const noexcept {
222 return GetBlue() / componentMaximum;
223 }
224 constexpr float GetAlphaComponent() const noexcept {
225 return GetAlpha() / componentMaximum;
226 }
227
228 constexpr bool operator==(const ColourRGBA &other) const noexcept {
229 return co == other.co;
230 }
231
232 constexpr bool IsOpaque() const noexcept {
233 return GetAlpha() == 0xff;
234 }
235
236 ColourRGBA MixedWith(ColourRGBA other) const noexcept;
237 ColourRGBA MixedWith(ColourRGBA other, double proportion) const noexcept;
238};
239
240/**
241* Holds an RGBA colour and stroke width to stroke a shape.
242*/
243class Stroke {
244public:
245 ColourRGBA colour;
246 XYPOSITION width;
247 constexpr Stroke(ColourRGBA colour_, XYPOSITION width_=1.0) noexcept :
248 colour(colour_), width(width_) {
249 }
250 constexpr float WidthF() const noexcept {
251 return static_cast<float>(width);
252 }
253};
254
255/**
256* Holds an RGBA colour to fill a shape.
257*/
258class Fill {
259public:
260 ColourRGBA colour;
261 constexpr Fill(ColourRGBA colour_) noexcept :
262 colour(colour_) {
263 }
264};
265
266/**
267* Holds a pair of RGBA colours and stroke width to fill and stroke a shape.
268*/
269class FillStroke {
270public:
271 Fill fill;
272 Stroke stroke;
273 constexpr FillStroke(ColourRGBA colourFill_, ColourRGBA colourStroke_, XYPOSITION widthStroke_=1.0) noexcept :
274 fill(colourFill_), stroke(colourStroke_, widthStroke_) {
275 }
276 constexpr FillStroke(ColourRGBA colourBoth, XYPOSITION widthStroke_=1.0) noexcept :
277 fill(colourBoth), stroke(colourBoth, widthStroke_) {
278 }
279};
280
281/**
282* Holds an element of a gradient with an RGBA colour and a relative position.
283*/
284class ColourStop {
285public:
286 XYPOSITION position;
287 ColourRGBA colour;
288 constexpr ColourStop(XYPOSITION position_, ColourRGBA colour_) noexcept :
289 position(position_), colour(colour_) {
290 }
291};
292
293}
294
295#endif
296