zxing-cpp v3.0
Loading...
Searching...
No Matches
Quadrilateral.h
Go to the documentation of this file.
1/*
2* Copyright 2020 Axel Waggershauser
3*/
4// SPDX-License-Identifier: Apache-2.0
5
6#pragma once
7
8#include "Point.h"
9
10#ifdef ZXING_INTERNAL
11#include "ZXAlgorithms.h"
12#endif
13
14#include <array>
15#include <cmath>
16#include <string>
17
18namespace ZXing {
19
28template <typename T>
29class Quadrilateral : public std::array<T, 4>
30{
31 using Base = std::array<T, 4>;
32 using Base::at;
33public:
34 using Point = T;
35
36 Quadrilateral() = default;
37 Quadrilateral(T tl, T tr, T br, T bl) : Base{tl, tr, br, bl} {}
38 template <typename U>
40 : Quadrilateral(Point(tl), Point(tr), Point(br), Point(bl))
41 {}
42
43 constexpr Point topLeft() const noexcept { return at(0); }
44 constexpr Point topRight() const noexcept { return at(1); }
45 constexpr Point bottomRight() const noexcept { return at(2); }
46 constexpr Point bottomLeft() const noexcept { return at(3); }
47
50 double orientation() const
51 {
52 auto centerLine = (topRight() + bottomRight()) - (topLeft() + bottomLeft());
53 if (centerLine == Point{})
54 return 0.;
55 auto centerLineF = normalized(centerLine);
56 return std::atan2(centerLineF.y, centerLineF.x);
57 }
58};
59
62
63template <typename T>
64std::string ToString(const Quadrilateral<PointT<T>>& points)
65{
66 std::string res;
67 for (const auto& p : points)
68 res += std::to_string(p.x) + "x" + std::to_string(p.y) + (&p == &points.back() ? "" : " ");
69 return res;
70}
71
72#ifdef ZXING_INTERNAL
73
74template <typename PointT = PointF>
75Quadrilateral<PointT> Rectangle(int width, int height, typename PointT::value_t margin = 0)
76{
77 return {
78 PointT{margin, margin}, {width - margin, margin}, {width - margin, height - margin}, {margin, height - margin}};
79}
80
81template <typename PointT = PointF>
82Quadrilateral<PointT> Rectangle(int x0, int x1, int y0, int y1, typename PointT::value_t o)
83{
84 return {PointT{x0 + o, y0 + o}, {x1 + o, y0 + o}, {x1 + o, y1 + o}, {x0 + o, y1 + o}};
85}
86
87template <typename PointT = PointF>
88Quadrilateral<PointT> Rectangle(int left, int top, int width, int height)
89{
90 int right = left + width - 1;
91 int bottom = top + height - 1;
92
93 return {PointT{left, top}, {right, top}, {right, bottom}, {left, bottom}};
94}
95
96template <typename PointT = PointF>
97Quadrilateral<PointT> CenteredSquare(int size)
98{
99 return Scale(Quadrilateral(PointT{-1, -1}, {1, -1}, {1, 1}, {-1, 1}), size / 2);
100}
101
102template <typename PointT = PointI>
103Quadrilateral<PointT> Line(int y, int xStart, int xStop)
104{
105 return {PointT{xStart, y}, {xStop, y}, {xStop, y}, {xStart, y}};
106}
107
108template <typename PointT>
109bool IsConvex(const Quadrilateral<PointT>& poly)
110{
111 const int N = Size(poly);
112 bool sign = false;
113
114 typename PointT::value_t m = INFINITY, M = 0;
115
116 for(int i = 0; i < N; i++)
117 {
118 auto d1 = poly[(i + 2) % N] - poly[(i + 1) % N];
119 auto d2 = poly[i] - poly[(i + 1) % N];
120 auto cp = cross(d1, d2);
121
122 // TODO: see if the isInside check for all boundary points in GridSampler is still required after fixing the wrong fabs()
123 // application in the following line
124 UpdateMinMax(m, M, std::fabs(cp));
125
126 if (i == 0)
127 sign = cp > 0;
128 else if (sign != (cp > 0))
129 return false;
130 }
131
132 // It turns out being convex is not enough to prevent a "numerical instability"
133 // that can cause the corners being projected inside the image boundaries but
134 // some points near the corners being projected outside. This has been observed
135 // where one corner is almost in line with two others. The M/m ratio is below 2
136 // for the complete existing sample set. For very "skewed" QRCodes a value of
137 // around 3 is realistic. A value of 14 has been observed to trigger the
138 // instability.
139 return M / m < 4.0;
140}
141
142template <typename PointT>
143Quadrilateral<PointT> Scale(const Quadrilateral<PointT>& q, int factor)
144{
145 return {factor * q[0], factor * q[1], factor * q[2], factor * q[3]};
146}
147
148template <typename PointT>
150{
151 return {q[0] + offset, q[1] + offset, q[2] + offset, q[3] + offset};
152}
153
154template <typename PointT>
155PointT Center(const Quadrilateral<PointT>& q)
156{
157 return Reduce(q) / Size(q);
158}
159
160template <typename PointT>
161Quadrilateral<PointT> RotatedCorners(const Quadrilateral<PointT>& q, int n = 1, bool mirror = false)
162{
164 std::rotate_copy(q.begin(), q.begin() + ((n + 4) % 4), q.end(), res.begin());
165 if (mirror)
166 std::swap(res[1], res[3]);
167 return res;
168}
169
170template <typename PointT>
171bool IsInside(const PointT& p, const Quadrilateral<PointT>& q)
172{
173 // Test if p is on the same side (right or left) of all polygon segments
174 int pos = 0, neg = 0;
175 for (int i = 0; i < Size(q); ++i)
176 (cross(p - q[i], q[(i + 1) % Size(q)] - q[i]) < 0 ? neg : pos)++;
177 return pos == 0 || neg == 0;
178}
179
180template <typename PointT>
182{
183 auto [minX, maxX] = std::minmax({q[0].x, q[1].x, q[2].x, q[3].x});
184 auto [minY, maxY] = std::minmax({q[0].y, q[1].y, q[2].y, q[3].y});
185 return {PointT{minX, minY}, {maxX, minY}, {maxX, maxY}, {minX, maxY}};
186}
187
188template <typename PointT>
189bool HaveIntersectingBoundingBoxes(const Quadrilateral<PointT>& a, const Quadrilateral<PointT>& b)
190{
191 auto bba = BoundingBox(a), bbb = BoundingBox(b);
192
193 bool x = bbb.topRight().x < bba.topLeft().x || bbb.topLeft().x > bba.topRight().x;
194 bool y = bbb.bottomLeft().y < bba.topLeft().y || bbb.topLeft().y > bba.bottomLeft().y;
195 return !(x || y);
196}
197
198template <typename PointT>
200{
201 auto dist2First = [r = a[0]](auto s, auto t) { return distance(s, r) < distance(t, r); };
202 // rotate points such that the the two topLeft points are closest to each other
203 auto offset = std::min_element(b.begin(), b.end(), dist2First) - b.begin();
204
206 for (int i = 0; i < 4; ++i)
207 res[i] = (a[i] + b[(i + offset) % 4]) / 2;
208
209 return res;
210}
211
212#endif
213
214} // ZXing
215
A simple class representing a quadrilateral defined by its four corner points.
Definition Quadrilateral.h:30
double orientation() const
Definition Quadrilateral.h:50
constexpr Point topRight() const noexcept
Definition Quadrilateral.h:44
T Point
Definition Quadrilateral.h:34
Quadrilateral(T tl, T tr, T br, T bl)
Definition Quadrilateral.h:37
constexpr Point bottomLeft() const noexcept
Definition Quadrilateral.h:46
constexpr Point bottomRight() const noexcept
Definition Quadrilateral.h:45
constexpr Point topLeft() const noexcept
Definition Quadrilateral.h:43
Quadrilateral(PointT< U > tl, PointT< U > tr, PointT< U > br, PointT< U > bl)
Definition Quadrilateral.h:39
Definition Barcode.h:26
Quadrilateral< PointI > QuadrilateralI
Definition Quadrilateral.h:61
Quadrilateral< PointF > QuadrilateralF
Definition Quadrilateral.h:60
std::string ToString(BarcodeFormat format)
A simple 2D point class template.
Definition Point.h:21
T value_t
Definition Point.h:22