Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
generic-interval.h
Go to the documentation of this file.
1/*
5 * Copyright 2011 Krzysztof KosiƄski <tweenk.pl@gmail.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it either under the terms of the GNU Lesser General Public
9 * License version 2.1 as published by the Free Software Foundation
10 * (the "LGPL") or, at your option, under the terms of the Mozilla
11 * Public License Version 1.1 (the "MPL"). If you do not alter this
12 * notice, a recipient may use your version of this file under either
13 * the MPL or the LGPL.
14 *
15 * You should have received a copy of the LGPL along with this library
16 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * You should have received a copy of the MPL along with this library
19 * in the file COPYING-MPL-1.1
20 *
21 * The contents of this file are subject to the Mozilla Public License
22 * Version 1.1 (the "License"); you may not use this file except in
23 * compliance with the License. You may obtain a copy of the License at
24 * http://www.mozilla.org/MPL/
25 *
26 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28 * the specific language governing rights and limitations.
29 */
30
31#ifndef LIB2GEOM_SEEN_GENERIC_INTERVAL_H
32#define LIB2GEOM_SEEN_GENERIC_INTERVAL_H
33
34#include <algorithm>
35#include <cassert>
36#include <iostream>
37#include <optional>
38#include <tuple>
39#include <boost/functional/hash.hpp>
40#include <2geom/coord.h>
41
42namespace Geom {
43
44template <typename C>
45class GenericOptInterval;
46
51template <typename C>
53 : CoordTraits<C>::IntervalOps
54{
57protected:
58 C _b[2] = { 0, 0 };
59public:
62
63 constexpr GenericInterval() = default;
65 explicit constexpr GenericInterval(C u) { _b[0] = _b[1] = u; }
67 constexpr GenericInterval(C u, C v) {
68 if (u <= v) {
69 _b[0] = u; _b[1] = v;
70 } else {
71 _b[0] = v; _b[1] = u;
72 }
73 }
74
82 template <typename InputIterator>
83 static CInterval from_range(InputIterator start, InputIterator end) {
84 assert(start != end);
86 for (; start != end; ++start) result.expandTo(*start);
87 return result;
88 }
90 static CInterval from_array(C const *c, unsigned n) {
91 return from_range(c, c + n);
92 }
94
97 constexpr C min() const { return _b[0]; }
98 constexpr C max() const { return _b[1]; }
99 constexpr C extent() const { return max() - min(); }
100 constexpr C middle() const { return (max() + min()) / 2; }
101 constexpr bool isSingular() const { return min() == max(); }
102 C operator[](unsigned i) const { assert(i < 2); return _b[i]; }
103 constexpr C operator[](Dim2 d) const { return _b[d]; }
104 constexpr C clamp(C val) const {
105 return std::clamp(val, min(), max());
106 }
108 C nearestEnd(C val) const {
109 C dmin = std::abs(val - min()), dmax = std::abs(val - max());
110 return dmin <= dmax ? min() : max();
111 }
112 // Structured binding support
113 template <size_t I> constexpr C get() const { static_assert(I < 2); return _b[I]; }
115
118
119 constexpr bool contains(C val) const {
120 return min() <= val && val <= max();
121 }
123 constexpr bool contains(CInterval const &val) const {
124 return min() <= val.min() && val.max() <= max();
125 }
127 constexpr bool intersects(CInterval const &val) const {
128 return contains(val.min()) || contains(val.max()) || val.contains(*this);
129 }
131
134 //TODO: NaN handleage for the next two?
138 constexpr void setMin(C val) {
139 if (val > _b[1]) {
140 _b[0] = _b[1] = val;
141 } else {
142 _b[0] = val;
143 }
144 }
148 constexpr void setMax(C val) {
149 if (val < _b[0]) {
150 _b[1] = _b[0] = val;
151 } else {
152 _b[1] = val;
153 }
154 }
156 constexpr void setEnds(C a, C b) {
157 if (a <= b) {
158 _b[0] = a;
159 _b[1] = b;
160 } else {
161 _b[0] = b;
162 _b[1] = a;
163 }
164 }
166 constexpr void expandTo(C val) {
167 if (val < _b[0]) _b[0] = val;
168 if (val > _b[1]) _b[1] = val; // no else, as we want to handle NaN
169 }
175 constexpr void expandBy(C amount) {
176 _b[0] -= amount;
177 _b[1] += amount;
178 if (_b[0] > _b[1]) {
179 C halfway = (_b[0] + _b[1]) / 2;
180 _b[0] = _b[1] = halfway;
181 }
182 }
187 constexpr void unionWith(CInterval const &a) {
188 if (a._b[0] < _b[0]) _b[0] = a._b[0];
189 if (a._b[1] > _b[1]) _b[1] = a._b[1];
190 }
192
195 //IMPL: OffsetableConcept
196 //TODO: rename output_type to something else in the concept
197 using output_type = C;
199 constexpr Self &operator+=(C amnt) {
200 _b[0] += amnt; _b[1] += amnt;
201 return *this;
202 }
204 constexpr Self &operator-=(C amnt) {
205 _b[0] -= amnt; _b[1] -= amnt;
206 return *this;
207 }
208
210 constexpr Self operator-() const { return { -_b[1], -_b[0] }; }
211 // IMPL: AddableConcept
215 constexpr Self &operator+=(CInterval const &o) {
216 _b[0] += o._b[0];
217 _b[1] += o._b[1];
218 return *this;
219 }
224 constexpr Self &operator-=(CInterval const &o) {
225 // equal to *this += -o
226 _b[0] -= o._b[1];
227 _b[1] -= o._b[0];
228 return *this;
229 }
233 constexpr Self &operator|=(CInterval const &o) {
234 unionWith(o);
235 return *this;
236 }
238 constexpr bool operator==(CInterval const &other) const {
239 return min() == other.min() && max() == other.max();
240 }
242};
243
246template <typename C>
248 return a | b;
249}
250
255template <typename C>
257 : public std::optional<typename CoordTraits<C>::IntervalType>
258 , boost::orable< GenericOptInterval<C>
259 , boost::andable< GenericOptInterval<C>
260 >>
261{
264 using Base = std::optional<CInterval>;
265public:
268
269 constexpr GenericOptInterval() = default;
273 constexpr GenericOptInterval(C u) : Base(CInterval(u)) {}
275 constexpr GenericOptInterval(C u, C v) : Base(CInterval(u, v)) {}
276
285 template <typename InputIterator>
286 static GenericOptInterval<C> from_range(InputIterator start, InputIterator end) {
287 if (start == end) {
288 return {};
289 }
290 return CInterval::from_range(start, end);
291 }
293
295 constexpr bool empty() const { return !*this; }
296
298 constexpr void unionWith(GenericOptInterval<C> const &a) {
299 if (a) {
300 if (*this) { // check that we are not empty
301 (*this)->unionWith(*a);
302 } else {
303 *this = *a;
304 }
305 }
306 }
307 constexpr void intersectWith(GenericOptInterval<C> const &o) {
308 if (o && *this) {
309 C u = std::max((*this)->min(), o->min());
310 C v = std::min((*this)->max(), o->max());
311 if (u <= v) {
312 *this = CInterval(u, v);
313 return;
314 }
315 }
316 *this = {};
317 }
319 unionWith(o);
320 return *this;
321 }
323 intersectWith(o);
324 return *this;
325 }
326
327 // The equality operators inherited from std::optional don't work with derived types, because
328 // the template overload ignores that the derived type is also an optional. It would result in
329 // `GenericInterval() != GenericInterval()` being true.
330 template <typename U, typename = std::enable_if_t<std::is_base_of_v<Base, U>>>
331 constexpr bool operator==(U const &other) const {
332 return static_cast<Base const &>(*this) == static_cast<Base const &>(other);
333 }
334 template <typename U, typename = std::enable_if_t<std::is_base_of_v<Base, U>>>
335 constexpr bool operator!=(U const &other) const {
336 return static_cast<Base const &>(*this) != static_cast<Base const &>(other);
337 }
338};
339
342template <typename C>
348template <typename C>
352
353template <typename C>
354inline std::ostream &operator<<(std::ostream &out,
355 GenericInterval<C> const &I) {
356 return out << "Interval(" << I.min() << ", " << I.max() << ")";
357}
358
359template <typename C>
360inline std::ostream &operator<<(std::ostream &out,
361 GenericOptInterval<C> const &I) {
362 return I ? (out << *I) : (out << "Interval (empty)");
363}
364
365} // namespace Geom
366
367// Structured binding support
368template <typename C> struct std::tuple_size<Geom::GenericInterval<C>> : std::integral_constant<size_t, 2> {};
369template <size_t I, typename C> struct std::tuple_element<I, Geom::GenericInterval<C>> { using type = C; };
370
371// Hash support
372template <typename C> struct std::hash<Geom::GenericInterval<C>>
373{
374 size_t operator()(Geom::GenericInterval<C> const &a) const noexcept {
375 size_t hash = 0;
376 boost::hash_combine(hash, a.min());
377 boost::hash_combine(hash, a.max());
378 return hash;
379 }
380};
381
382#endif // LIB2GEOM_SEEN_GENERIC_INTERVAL_H
383
384/*
385 Local Variables:
386 mode:c++
387 c-file-style:"stroustrup"
388 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
389 indent-tabs-mode:nil
390 fill-column:99
391 End:
392*/
393// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
A range of numbers which is never empty.
constexpr void setMin(C val)
Set the lower boundary of the interval.
constexpr C operator[](Dim2 d) const
C operator[](unsigned i) const
constexpr C extent() const
static CInterval from_range(InputIterator start, InputIterator end)
Create an interval containing a range of values.
constexpr bool contains(CInterval const &val) const
Check whether the interval includes the given interval.
static CInterval from_array(C const *c, unsigned n)
Create an interval from a C-style array of values it should contain.
constexpr bool operator==(CInterval const &other) const
Test for interval equality.
constexpr Self & operator+=(CInterval const &o)
Add two intervals.
constexpr void setEnds(C a, C b)
Set both ends of the interval simultaneously.
constexpr GenericInterval(C u, C v)
Create an interval that contains all points between u and v.
constexpr void expandTo(C val)
Extend the interval to include the given number.
constexpr Self & operator|=(CInterval const &o)
Union two intervals.
constexpr C clamp(C val) const
constexpr GenericInterval()=default
Create an interval that contains only zero.
constexpr Self & operator+=(C amnt)
Offset the interval by a specified amount.
constexpr bool isSingular() const
constexpr C min() const
constexpr Self operator-() const
Return an interval mirrored about 0.
constexpr Self & operator-=(C amnt)
Offset the interval by the negation of the specified amount.
constexpr C max() const
constexpr C get() const
constexpr bool intersects(CInterval const &val) const
Check whether the intervals have any common elements.
constexpr GenericInterval(C u)
Create an interval that contains a single point.
C nearestEnd(C val) const
Return the closer end of the interval.
GenericInterval< C > unify(GenericInterval< C > const &a, GenericInterval< C > const &b)
Union two intervals.
constexpr Self & operator-=(CInterval const &o)
Subtract two intervals.
constexpr void unionWith(CInterval const &a)
Union the interval with another one.
constexpr bool contains(C val) const
Check whether the interval includes this number.
constexpr void setMax(C val)
Set the upper boundary of the interval.
constexpr void expandBy(C amount)
Expand or shrink the interval in both directions by the given amount.
typename CoordTraits< C >::IntervalType CInterval
constexpr C middle() const
A range of numbers that can be empty.
constexpr GenericOptInterval< C > & operator&=(OptCInterval const &o)
constexpr void unionWith(GenericOptInterval< C > const &a)
Union with another interval, gracefully handling empty ones.
constexpr GenericOptInterval(C u)
Create an interval containing a single point.
constexpr GenericOptInterval(C u, C v)
Create an interval containing a range of numbers.
constexpr bool operator!=(U const &other) const
constexpr GenericOptInterval(GenericInterval< C > const &a)
Wrap an existing interval.
typename CoordTraits< C >::OptIntervalType OptCInterval
constexpr GenericOptInterval< C > & operator|=(OptCInterval const &o)
GenericOptInterval< C > intersect(GenericInterval< C > const &a, GenericInterval< C > const &b)
Intersect two intervals and return a possibly empty range of numbers.
static GenericOptInterval< C > from_range(InputIterator start, InputIterator end)
Create a possibly empty interval containing a range of values.
GenericOptInterval< C > operator&(GenericInterval< C > const &a, GenericInterval< C > const &b)
Intersect two intervals and return a possibly empty range of numbers.
constexpr void intersectWith(GenericOptInterval< C > const &o)
typename CoordTraits< C >::IntervalType CInterval
std::optional< CInterval > Base
constexpr GenericOptInterval()=default
Create an empty interval.
constexpr bool operator==(U const &other) const
constexpr bool empty() const
Check whether this interval is empty.
Integral and real coordinate types and some basic utilities.
Css & result
double c[8][4]
Dim2
2D axis enumeration (X or Y).
Definition coord.h:48
Geom::Point start
Geom::Point end
Various utility functions.
Definition affine.h:22
std::ostream & operator<<(std::ostream &os, const Bezier &b)
Definition bezier.h:372
Traits class used with coordinate types.
Definition coord.h:105
size_t operator()(Geom::GenericInterval< C > const &a) const noexcept