-
Notifications
You must be signed in to change notification settings - Fork 0
/
lineseg.h
148 lines (131 loc) · 4.7 KB
/
lineseg.h
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//
// Created by jens on 02/09/23.
//
#ifndef VEC2POLY_LINESEG_H
#define VEC2POLY_LINESEG_H
#include <exception>
#include <optional>
#include <list>
#include <set>
#include <iosfwd>
#include <utility>
#include <memory>
#include <functional>
#include "point.h"
#include "pntalloc.h"
class BadLineSegment : public std::exception {
char const *const msg_;
public:
BadLineSegment() : msg_("Bad Line Segment") {};
BadLineSegment(char const *msg) : msg_(msg) {}
char const *what() const noexcept override { return msg_; }
};
class BadPath : public std::exception {
char const *const msg_;
public:
BadPath() : msg_("Bad Path") {};
BadPath(char const *msg) : msg_(msg) {}
char const *what() const noexcept override { return msg_; }
};
class lineseg {
private:
/** The line segment is a point from A to B */
pathpoint a_, b_;
/** Once the points are defined we can calculate the vector A->B */
double dx_, dy_;
void recalculate()
{
dx_ = b_->x() - a_->x();
dy_ = b_->y() - a_->y();
}
public:
lineseg(pntalloc &alloc, point a, point b) : a_(alloc.make_point(a)), b_(alloc.make_point(b)), dx_(b.x() - a.x()), dy_(b.y() - a.y())
{
#if 0
if(dx_*dx_+dy_*dy_ < point::tol2)
throw BadLineSegment();
#endif
}
lineseg(pntalloc &alloc, point a, pathpoint b) : a_(alloc.make_point(a)), b_(b)
{
recalculate();
}
lineseg(pntalloc &, pathpoint a, pathpoint b) noexcept : a_(a), b_(b)
{
recalculate();
}
/* Note copying a line segment should not increase the use counter */
lineseg(lineseg const &) = default;
lineseg(lineseg &&) = default;
lineseg &operator=(lineseg const &) = delete;
lineseg &operator=(lineseg &&) = default;
~lineseg() {}
/* Equality: are line segments equal if one is the reverse of the other? */
bool operator==(lineseg const &other) const noexcept
{
return a_ == other.a_ && b_ == other.b_;
}
pathpoint first() const noexcept { return a_; }
pathpoint second() const noexcept { return b_; }
pathpoint last() const noexcept { return b_; }
//std::pair<pathpoint,pathpoint> endpoints() const noexcept { return std::pair(a_, b_); }
/** Reverse in-place */
//void rev() noexcept { std::swap(a_,b_); }
/** Split a line segment into two parts at a given point along its length
* The line segment is shortened and the remaining segment is returned.
*
* If the present line segment is A->B and it is split at C, then the current
* object is turned into A->C and a new segment C->B is returned.
*
* There is no check that C is on the line segment so in general we always get A->C->B.
* However, there _is_ a check that the split point is not already an endpoint
* (which would make one line segment invalid)
*
* @param p The point to split at
* @return The remaining segment (from the split point to B)
*/
lineseg split_at(pntalloc &alloc, point p);
bool is_endpoint(point p) const noexcept
{
return a_->equals(p) || b_->equals(p);
}
friend std::optional<point> intersects(lineseg const &v, lineseg const &w);
friend std::ostream &operator<<(std::ostream &, lineseg const &);
};
class world;
/** A path is a sequence of line segments where each segment begins where the previous finished
*
*/
class path {
private:
/** List of line segments forming this path.
* Line segments should be connected and non-degenerate (not a point)
*/
std::list<lineseg> path_;
/** Whether we have been assigned a polygon to live in */
bool used_;
/** Empty path constructor is private as worlds are not allowed to have empty paths */
path() : path_{}, used_(false) {}
public:
/** Construct path connecting at least two points */
path(pntalloc &alloc, std::initializer_list<point> q);
path(path const &);
path(path &&) = default;
path &operator=(path const &) = default;
path &operator=(path &&) = default;
/** Split the path at every one of the given points
* Additional paths will be passed to the iterator
* @tparam newpath inserter callback for new paths
* @tparam at Points to split at
*/
void split_path(std::vector<path> &result, const std::vector<point> &at);
bool is_used() const noexcept { return used_; }
void set_used() noexcept { used_ = true; }
bool operator==(path const &) const noexcept = default;
auto begin() const noexcept { return path_.begin(); }
auto end() const noexcept { return path_.end(); }
/* This breaks encapsulation but can be Fixed Later(tm) */
friend class world;
friend std::ostream &operator<<(std::ostream &, path const &);
};
#endif //VEC2POLY_LINESEG_H