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