1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
// Scintilla source code edit control
/** @file Geometry.cxx
** Helper functions for geometric calculations.
**/
// Copyright 2020 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
#include <cstdint>
#include <cmath>
#include <algorithm>
#include "Geometry.h"
namespace {
constexpr unsigned int Mixed(unsigned char a, unsigned char b, double proportion) noexcept {
return static_cast<unsigned int>(a + proportion * (b - a));
}
}
namespace Scintilla::Internal {
PRectangle Clamp(PRectangle rc, Edge edge, XYPOSITION position) noexcept {
switch (edge) {
case Edge::left:
return PRectangle(std::clamp(position, rc.left, rc.right), rc.top, rc.right, rc.bottom);
case Edge::top:
return PRectangle(rc.left, std::clamp(position, rc.top, rc.bottom), rc.right, rc.bottom);
case Edge::right:
return PRectangle(rc.left, rc.top, std::clamp(position, rc.left, rc.right), rc.bottom);
case Edge::bottom:
default:
return PRectangle(rc.left, rc.top, rc.right, std::clamp(position, rc.top, rc.bottom));
}
}
PRectangle Side(PRectangle rc, Edge edge, XYPOSITION size) noexcept {
switch (edge) {
case Edge::left:
return PRectangle(rc.left, rc.top, std::min(rc.left + size, rc.right), rc.bottom);
case Edge::top:
return PRectangle(rc.left, rc.top, rc.right, std::min(rc.top + size, rc.bottom));
case Edge::right:
return PRectangle(std::max(rc.left, rc.right - size), rc.top, rc.right, rc.bottom);
case Edge::bottom:
default:
return PRectangle(rc.left, std::max(rc.top, rc.bottom - size), rc.right, rc.bottom);
}
}
Interval Intersection(Interval a, Interval b) noexcept {
const XYPOSITION leftMax = std::max(a.left, b.left);
const XYPOSITION rightMin = std::min(a.right, b.right);
// If the result would have a negative width. make empty instead.
const XYPOSITION rightResult = (rightMin >= leftMax) ? rightMin : leftMax;
return { leftMax, rightResult };
}
PRectangle Intersection(PRectangle rc, Interval horizontalBounds) noexcept {
const Interval intersection = Intersection(HorizontalBounds(rc), horizontalBounds);
return PRectangle(intersection.left, rc.top, intersection.right, rc.bottom);
}
Interval HorizontalBounds(PRectangle rc) noexcept {
return { rc.left, rc.right };
}
XYPOSITION PixelAlign(XYPOSITION xy, int pixelDivisions) noexcept {
return std::round(xy * pixelDivisions) / pixelDivisions;
}
XYPOSITION PixelAlignFloor(XYPOSITION xy, int pixelDivisions) noexcept {
return std::floor(xy * pixelDivisions) / pixelDivisions;
}
Point PixelAlign(const Point &pt, int pixelDivisions) noexcept {
return Point(
std::round(pt.x * pixelDivisions) / pixelDivisions,
std::round(pt.y * pixelDivisions) / pixelDivisions);
}
PRectangle PixelAlign(const PRectangle &rc, int pixelDivisions) noexcept {
// Move left and right side to nearest pixel to avoid blurry visuals.
// The top and bottom should be integers but floor them to make sure.
// `pixelDivisions` is commonly 1 except for 'retina' displays where it is 2.
// On retina displays, the positions should be moved to the nearest device
// pixel which is the nearest half logical pixel.
return PRectangle(
std::round(rc.left * pixelDivisions) / pixelDivisions,
PixelAlignFloor(rc.top, pixelDivisions),
std::round(rc.right * pixelDivisions) / pixelDivisions,
PixelAlignFloor(rc.bottom, pixelDivisions));
}
PRectangle PixelAlignOutside(const PRectangle &rc, int pixelDivisions) noexcept {
// Move left and right side to extremes (floor(left) ceil(right)) to avoid blurry visuals.
return PRectangle(
std::floor(rc.left * pixelDivisions) / pixelDivisions,
std::floor(rc.top * pixelDivisions) / pixelDivisions,
std::ceil(rc.right * pixelDivisions) / pixelDivisions,
std::floor(rc.bottom * pixelDivisions) / pixelDivisions);
}
ColourRGBA ColourRGBA::MixedWith(ColourRGBA other) const noexcept {
const unsigned int red = (GetRed() + other.GetRed()) / 2;
const unsigned int green = (GetGreen() + other.GetGreen()) / 2;
const unsigned int blue = (GetBlue() + other.GetBlue()) / 2;
const unsigned int alpha = (GetAlpha() + other.GetAlpha()) / 2;
return ColourRGBA(red, green, blue, alpha);
}
ColourRGBA ColourRGBA::MixedWith(ColourRGBA other, double proportion) const noexcept {
return ColourRGBA(
Mixed(GetRed(), other.GetRed(), proportion),
Mixed(GetGreen(), other.GetGreen(), proportion),
Mixed(GetBlue(), other.GetBlue(), proportion),
Mixed(GetAlpha(), other.GetAlpha(), proportion));
}
}
|