27template <
class Po
intType,
class LabelType>
28template <
class ResultNumber,
class OtherNumber>
29constexpr std::optional<ResultNumber>
35 return static_cast<ResultNumber
>(
min().y());
37 return static_cast<ResultNumber
>(
max().y());
39 const ResultNumber minX =
static_cast<ResultNumber
>(
min().x());
40 const ResultNumber minY =
static_cast<ResultNumber
>(
min().y());
41 const ResultNumber deltaX =
static_cast<ResultNumber
>(
max().x() -
min().x());
42 const ResultNumber deltaY =
static_cast<ResultNumber
>(
max().y() -
min().y());
44 const ResultNumber
y = minY + (detail::asNumber<ResultNumber>(
x) - minX) * deltaY / deltaX;
59template <
class Po
intType,
class LabelType>
60template <
class ResultNumber,
class OtherNumber>
62 const auto min_y =
min().y() <
max().y() ?
min().y() :
max().y();
63 const auto max_y =
max().y() <
min().y() ?
min().y() :
max().y();
69 return static_cast<ResultNumber
>(
min().x());
72 return static_cast<ResultNumber
>(
max().x());
75 const ResultNumber min_x =
static_cast<ResultNumber
>(
min().x());
76 const ResultNumber min_y_value =
static_cast<ResultNumber
>(
min().y());
77 const ResultNumber delta_x =
static_cast<ResultNumber
>(
max().x() -
min().x());
78 const ResultNumber delta_y =
static_cast<ResultNumber
>(
max().y() -
min().y());
80 return min_x + (detail::asNumber<ResultNumber>(
y) - min_y_value) * delta_x / delta_y;
92template <
class Po
intType,
class LabelType>
93template <
class ResultNumber,
class OtherNumber>
94constexpr std::optional<ResultNumber>
105template <
class Po
intType,
class LabelType>
106template <
class ResultNumber,
class OtherNumber>
107constexpr std::optional<ResultNumber>
127template <
class Po
intType,
class LabelType>
128template <
class ResultNumber,
class OtherNumber>
129constexpr std::optional<ResultNumber>
132 if (
x ==
min().
x()) {
133 return static_cast<ResultNumber
>(
min().y());
138 if (
x ==
min().
x()) {
139 return static_cast<ResultNumber
>(
min().y());
141 if (
x ==
max().
x()) {
142 return static_cast<ResultNumber
>(
max().y());
145 const ResultNumber min_x =
static_cast<ResultNumber
>(
min().x());
146 const ResultNumber min_y =
static_cast<ResultNumber
>(
min().y());
147 const ResultNumber delta_x =
static_cast<ResultNumber
>(
max().x() -
min().x());
148 const ResultNumber delta_y =
static_cast<ResultNumber
>(
max().y() -
min().y());
150 return min_y + (detail::asNumber<ResultNumber>(
x) - min_x) * delta_y / delta_x;
165template <
class Po
intType,
class LabelType>
166template <
class ResultNumber,
class OtherNumber>
167constexpr std::optional<ResultNumber>
170 if (
y ==
min().
y()) {
171 return static_cast<ResultNumber
>(
min().x());
176 if (
y ==
min().
y()) {
177 return static_cast<ResultNumber
>(
min().x());
179 if (
y ==
max().
y()) {
180 return static_cast<ResultNumber
>(
max().x());
183 const ResultNumber min_x =
static_cast<ResultNumber
>(
min().x());
184 const ResultNumber min_y =
static_cast<ResultNumber
>(
min().y());
185 const ResultNumber delta_x =
static_cast<ResultNumber
>(
max().x() -
min().x());
186 const ResultNumber delta_y =
static_cast<ResultNumber
>(
max().y() -
min().y());
188 return min_x + (detail::asNumber<ResultNumber>(
y) - min_y) * delta_x / delta_y;
205template <
class Po
intType,
class LabelType>
206template <
class ResultNumber,
class OtherNumber>
207constexpr std::optional<ResultNumber>
223template <
class Po
intType,
class LabelType>
224template <
class ResultNumber,
class OtherNumber>
225constexpr std::optional<ResultNumber>
239template <
class Po
intType,
class LabelType>
240template <
class ResultNumber,
class OtherNumber>
241constexpr std::optional<ResultNumber>
244 const std::optional<ResultNumber> candidate_y = supporting_line.template
yAtX<ResultNumber>(
x);
245 if (!candidate_y.has_value()) {
249 const ResultNumber candidate_x =
static_cast<ResultNumber
>(
x);
264template <
class Po
intType,
class LabelType>
265template <
class ResultNumber,
class OtherNumber>
266constexpr std::optional<ResultNumber>
269 const std::optional<ResultNumber> candidate_x = supporting_line.template
xAtY<ResultNumber>(
y);
270 if (!candidate_x.has_value()) {
274 const ResultNumber candidate_y =
static_cast<ResultNumber
>(
y);
287template <
class Po
intType,
class LabelType>
288template<
class OtherNumberType>
290 const size_t n = points_.size();
294 using CommonNumberType = std::common_type_t<NumberType, OtherNumberType>;
295 const CommonNumberType target =
296 detail::asNumber<CommonNumberType>(
x) - detail::asNumber<CommonNumberType>(translation_.x());
298 const CommonNumberType min_x =
static_cast<CommonNumberType
>(points_[0].x());
299 const CommonNumberType max_x =
static_cast<CommonNumberType
>(points_[m].x());
300 if (target < min_x || target > max_x) {
303 const bool at_max = (target == max_x);
311 const auto edge = [&](
auto at,
auto pos,
size_t count) {
312 size_t lo = 1, hi = count - 1;
314 const size_t mid = lo + (hi - lo) / 2;
315 const bool past = at_max ? (at(mid) >= target) : (at(mid) > target);
326 const auto lower =
edge(
327 [
this](
size_t i) {
return static_cast<CommonNumberType
>(points_[i].x()); },
328 [](
size_t i) {
return i; },
332 const auto upper =
edge(
333 [
this, n](
size_t s) {
return static_cast<CommonNumberType
>(points_[(n - s) % n].x()); },
334 [n](
size_t s) {
return (n - s) % n; },
337 return std::array<Segment<PointType>, 2>{lower, upper};
343template <
class Po
intType,
class LabelType,
class Storage>
344template <
class OtherNumber>
345constexpr std::optional<std::size_t>
349 using Compare = std::common_type_t<NumberType, OtherNumber>;
350 if (points_.empty()) {
353 const auto tx = translation_.x();
354 if (detail::asNumber<Compare>(
x) <
static_cast<Compare
>(points_.front().x() + tx) ||
355 static_cast<Compare
>(points_.back().x() + tx) < detail::asNumber<Compare>(
x)) {
360 const auto it = std::lower_bound(
361 points_.begin(), points_.end(),
x,
362 [&tx](
const PointType& p,
const OtherNumber& value) {
363 return static_cast<Compare>(p.x() + tx) < detail::asNumber<Compare>(value);
365 assert(it != points_.end());
366 const std::size_t i =
static_cast<std::size_t
>(it - points_.begin());
367 if (
static_cast<Compare
>(it->x() + tx) == detail::asNumber<Compare>(
x)) {
375template <
class Po
intType,
class LabelType,
class Storage>
376template <
class ResultNumber,
class OtherNumber>
377constexpr std::optional<ResultNumber>
379 using Compare = std::common_type_t<NumberType, OtherNumber>;
385 if (detail::asNumber<Compare>(a.x()) == detail::asNumber<Compare>(
x)) {
387 return static_cast<ResultNumber
>(a.y());
395template <
class Po
intType,
class LabelType,
class Storage>
396template <Po
intConcept OtherPo
int>
397constexpr std::optional<std::size_t>
399 using Compare = std::common_type_t<NumberType, typename OtherPoint::NumberType>;
400 const auto idx =
indexAtX(point.x());
405 if (detail::asNumber<Compare>(a.x()) == detail::asNumber<Compare>(point.x())) {
412 const auto tx = translation_.x();
413 const auto it = std::upper_bound(
414 points_.begin() +
static_cast<std::ptrdiff_t
>(*idx), points_.end(), point.x(),
415 [&tx](
const auto& value,
const PointType& p) {
416 return detail::asNumber<Compare>(value) < static_cast<Compare>(p.x() + tx);
418 const PointType top = (*this)[
static_cast<std::size_t
>(it - points_.begin()) - 1];
419 if (detail::asNumber<Compare>(top.y()) < detail::asNumber<Compare>(point.y())) {
432template <
class Po
intType,
class LabelType,
class Storage>
433template <Po
intConcept OtherPo
int>
434constexpr std::optional<std::size_t>
436 using Compare = std::common_type_t<NumberType, typename OtherPoint::NumberType>;
437 const auto idx =
indexAtX(point.x());
442 if (detail::asNumber<Compare>(a.x()) == detail::asNumber<Compare>(point.x())) {
447 if (detail::asNumber<Compare>(a.y()) > detail::asNumber<Compare>(point.y())) {
459template <
class Po
intType,
class LabelType,
class Storage>
460template <Po
intConcept OtherPo
int>
461constexpr std::optional<std::size_t>
463 using Compare = std::common_type_t<NumberType, typename OtherPoint::NumberType>;
464 const auto idx =
indexAtX(point.x());
469 if (detail::asNumber<Compare>(a.x()) == detail::asNumber<Compare>(point.x())) {
473 if (detail::asNumber<Compare>(a.y()) <= detail::asNumber<Compare>(point.y())) {
486template <
class Po
intType,
class LabelType,
class Storage>
487template <Po
intConcept OtherPo
int>
488constexpr std::optional<std::size_t>
490 using Compare = std::common_type_t<NumberType, typename OtherPoint::NumberType>;
491 const auto idx =
indexAtX(point.x());
496 if (detail::asNumber<Compare>(a.x()) == detail::asNumber<Compare>(point.x())) {
500 const auto tx = translation_.x();
501 const auto it = std::upper_bound(
502 points_.begin() +
static_cast<std::ptrdiff_t
>(*idx), points_.end(), point.x(),
503 [&tx](
const auto& value,
const PointType& p) {
504 return detail::asNumber<Compare>(value) < static_cast<Compare>(p.x() + tx);
506 const PointType top = (*this)[
static_cast<std::size_t
>(it - points_.begin()) - 1];
507 if (detail::asNumber<Compare>(top.y()) >= detail::asNumber<Compare>(point.y())) {
518template <
class Po
intType,
class LabelType,
class Storage>
519template <
class LowNumber,
class HighNumber>
520constexpr std::optional<std::pair<std::size_t, std::size_t>>
521MonotoneChain<PointType, LabelType, Storage>::edgeWindow(
const LowNumber& xlo,
const HighNumber& xhi)
const {
522 using CompareLow = std::common_type_t<NumberType, LowNumber>;
523 using CompareHigh = std::common_type_t<NumberType, HighNumber>;
524 if (points_.size() < 2) {
527 const auto tx = translation_.x();
528 if (detail::asNumber<CompareHigh>(xhi) <
static_cast<CompareHigh
>(points_.front().x() + tx) ||
529 static_cast<CompareLow
>(points_.back().x() + tx) <
static_cast<CompareLow
>(xlo)) {
532 std::size_t first = 0;
533 if (
static_cast<CompareLow
>(points_.front().x() + tx) <
static_cast<CompareLow
>(xlo)) {
535 first = *indexAtX(xlo);
542 std::size_t last = points_.size() - 1;
543 if (detail::asNumber<CompareHigh>(xhi) <
static_cast<CompareHigh
>(points_.back().x() + tx)) {
545 const auto it = std::upper_bound(
546 points_.begin(), points_.end(), xhi,
547 [&tx](
const HighNumber& value,
const PointType& p) {
548 return detail::asNumber<CompareHigh>(value) < static_cast<CompareHigh>(p.x() + tx);
550 last =
static_cast<std::size_t
>(it - points_.begin()) - 1;
553 last = std::min(last, points_.size() - 2);
557 return std::pair<std::size_t, std::size_t>{first, last};
Definition arrangement.hpp:67
@ y
Definition intervaltree.hpp:24
@ x
Definition intervaltree.hpp:24
@ edge
Definition bitmatrix.hpp:37
constexpr std::partial_ordering orientationSign(const Point< ANumber, ALabel > &a, const Point< BNumber, BLabel > &b, const Point< CNumber, CLabel > &c)
Classifies the orientation of three points.
Definition orientation.hpp:544
Exact equality of the point sets represented by arbitrary shapes.
constexpr size_t maxIndex() const
Returns the index of the maximum vertex (rightmost and highest in case of ties).
Definition predicates.hpp:1022
constexpr std::optional< std::array< Segment< PointType >, 2 > > edgesAtX(OtherNumberType x) const
Returns two edges of the convex polygon that intersect with the vertical line at x.
Definition atxy.hpp:289
Unoriented infinite line.
Definition line.hpp:52
constexpr bool isHorizontal() const
Returns whether the line is horizontal.
Definition predicates.hpp:466
constexpr const PointType & max() const
Returns the largest stored defining point.
Definition line.hpp:189
constexpr bool isVertical() const
Returns whether the line is vertical.
Definition predicates.hpp:461
constexpr const PointType & min() const
Returns the smallest stored defining point.
Definition line.hpp:180
constexpr std::optional< ResultNumber > xAtY(const OtherNumber &y) const
Returns the x-coordinate of the line at a given y-coordinate, if defined.
Definition atxy.hpp:168
constexpr std::optional< ResultNumber > yAtX(const OtherNumber &x) const
Returns the y-coordinate of the line at a given x-coordinate, if defined.
Definition atxy.hpp:130
constexpr std::optional< std::size_t > isStrictlyAbove(const OtherPoint &point) const
Tests whether the whole chain lies strictly above a point at its x.
Definition atxy.hpp:435
constexpr std::optional< std::size_t > indexAtX(const OtherNumber &x) const
Locates the vertex or edge of the chain at a given x-coordinate.
Definition atxy.hpp:346
constexpr std::optional< std::size_t > isBelow(const OtherPoint &point) const
Tests whether the chain passes weakly below a point.
Definition atxy.hpp:462
PointType_ PointType
Definition monotonechain.hpp:147
constexpr std::optional< std::size_t > isAbove(const OtherPoint &point) const
Tests whether the chain passes weakly above a point.
Definition atxy.hpp:489
constexpr std::optional< ResultNumber > yAtX(const OtherNumber &x) const
Evaluates the y-coordinate of the chain at a given x-coordinate.
Definition atxy.hpp:378
constexpr std::optional< std::size_t > isStrictlyBelow(const OtherPoint &point) const
Tests whether the whole chain lies strictly below a point at its x.
Definition atxy.hpp:398
constexpr std::optional< ResultNumber > xAtY(const OtherNumber &y) const
Returns the x-coordinate of the supporting line at a given y-coordinate, if defined.
Definition atxy.hpp:226
constexpr Line< PointType > asLine() const
Returns the line without orientation.
Definition orientedline.hpp:321
constexpr std::optional< ResultNumber > yAtX(const OtherNumber &x) const
Returns the y-coordinate of the supporting line at a given x-coordinate, if defined.
Definition atxy.hpp:208
constexpr std::optional< ResultNumber > yAtX(const OtherNumber &x) const
Returns the value of the y coordinate for a given x, if it exists.
Definition atxy.hpp:95
constexpr std::optional< ResultNumber > xAtY(const OtherNumber &y) const
Returns the value of the x coordinate for a given y, if it exists.
Definition atxy.hpp:108
Two-dimensional point with optional label payload.
Definition point.hpp:129
constexpr std::optional< ResultNumber > xAtY(const OtherNumber &y) const
Returns the value of the x coordinate for a given y, if it exists.
Definition atxy.hpp:267
constexpr std::optional< ResultNumber > yAtX(const OtherNumber &x) const
Returns the value of the y coordinate for a given x, if it exists.
Definition atxy.hpp:242
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:625
Unoriented closed segment between two endpoints plus optional segment label.
Definition segment.hpp:58
constexpr const PointType & max() const
Returns the largest stored endpoint.
Definition segment.hpp:199
constexpr const PointType & min() const
Returns the smallest stored endpoint.
Definition segment.hpp:190
constexpr std::optional< ResultNumber > yAtX(const OtherNumber &x) const
Returns the value of the y coordinate for a given x, if it exists.
Definition atxy.hpp:30
constexpr std::optional< ResultNumber > xAtY(const OtherNumber &y) const
Returns the value of the x coordinate for a given y, if it exists.
Definition atxy.hpp:61