DeSiGNAR  0.5a
Data Structures General Library
segment.H
Go to the documentation of this file.
1 /*
2  This file is part of Designar.
3  Copyright (C) 2017 by Alejandro J. Mujica
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Any user request of this software, write to
19 
20  Alejandro Mujica
21 
22  aledrums@gmail.com
23 */
24 
25 # ifndef DSGSEGMENT_H
26 # define DSGSEGMENT_H
27 
28 # include <point2D.H>
29 
30 namespace Designar
31 {
32 
33  template <class PointT>
34  class GenSegment
35  {
36  PointT src_point;
37  PointT tgt_point;
38 
39  public:
40  using PointType = PointT;
41 
43  : src_point(), tgt_point()
44  {
45  // empty
46  }
47 
48  GenSegment(const PointT & sp, const PointT & tp)
49  : src_point(sp), tgt_point(tp)
50  {
51  // empty
52  }
53 
54  GenSegment(const PointT & sp, PointT && tp)
55  : src_point(sp), tgt_point(std::forward<PointT>(tp))
56  {
57  // empty
58  }
59 
60  GenSegment(PointT && sp, const PointT & tp)
61  : src_point(std::forward<PointT>(sp)), tgt_point(tp)
62  {
63  // empty
64  }
65 
66  GenSegment(PointT && sp, PointT && tp)
67  : src_point(std::forward<PointT>(sp)), tgt_point(std::forward<PointT>(tp))
68  {
69  // empty
70  }
71 
73  : src_point(s.src_point), tgt_point(s.tgt_point)
74  {
75  // empty
76  }
77 
79  : GenSegment()
80  {
81  swap(s);
82  }
83 
85  {
86  if (this == &s)
87  return *this;
88 
89  src_point = s.src_point;
90  tgt_point = s.tgt_point;
91 
92  return *this;
93  }
94 
96  {
97  swap(s);
98  return *this;
99  }
100 
101  void swap(GenSegment & s)
102  {
103  std::swap(src_point, s.src_point);
104  std::swap(tgt_point, s.tgt_point);
105  }
106 
107  const PointT & get_src_point() const
108  {
109  return src_point;
110  }
111 
112  const PointT & get_tgt_point() const
113  {
114  return tgt_point;
115  }
116 
117  void set_src_point(const PointT & sp)
118  {
119  src_point = sp;
120  }
121 
122  void set_src_point(PointT && sp)
123  {
124  src_point = std::move(sp);
125  }
126 
127  void set_tgt_point(const PointT & tp)
128  {
129  tgt_point = tp;
130  }
131 
132  void set_tgt_point(PointT && tp)
133  {
134  tgt_point = std::move(tp);
135  }
136 
137  real_t length() const
138  {
139  return src_point.distance_with(tgt_point);
140  }
141 
142  bool is_to_left_from(const PointT & p) const
143  {
144  return p.is_to_right_from(src_point, tgt_point);
145  }
146 
147  bool is_to_left_on_from(const PointT & p) const
148  {
149  return p.is_to_right_on_from(src_point, tgt_point);
150  }
151 
152  bool is_to_right_from(const PointT & p) const
153  {
154  return p.is_to_left_from(src_point, tgt_point);
155  }
156 
157  bool is_to_right_on_from(const PointT & p) const
158  {
159  return p.is_to_left_on_from(src_point, tgt_point);
160  }
161 
162  bool is_collinear_with(const PointT & p) const
163  {
164  return p.is_collinear_with(src_point, tgt_point);
165  }
166 
167  bool contains_to(const PointT & p) const
168  {
169  return p.is_between(src_point, tgt_point);
170  }
171 
172  bool contains_to(const GenSegment & s) const
173  {
174  return contains_to(s.src_point) and contains_to(s.tgt_point);
175  }
176 
177  bool intersects_properly_with(const GenSegment & s) const
178  {
179  if (s.is_collinear_with(src_point) or s.is_collinear_with(tgt_point) or
180  is_collinear_with(s.src_point) or is_collinear_with(s.tgt_point))
181  return false;
182 
183  return (s.is_to_right_from(src_point) xor
184  s.is_to_right_from(tgt_point)) and
185  (is_to_right_from(s.src_point) xor
186  is_to_right_from(s.tgt_point));
187  }
188 
189  bool intersects_with(const GenSegment & s) const
190  {
192  return true;
193 
194  return contains_to(s.src_point) or contains_to(s.tgt_point) or
195  s.contains_to(src_point) or s.contains_to(tgt_point);
196  }
197 
198  real_t slope() const
199  {
200  if (tgt_point.get_x() == src_point.get_x())
201  {
202  if (src_point.get_y() < tgt_point.get_y())
203  return INF;
204  else
205  return -INF;
206  }
207 
208  return real_t(tgt_point.get_y() - src_point.get_y()) /
209  real_t(tgt_point.get_x() - src_point.get_x());
210  }
211 
212  bool is_parallel_with(const GenSegment & s) const
213  {
214  return slope() == s.slope();
215  }
216 
217  bool is_perpendicular_with(const GenSegment & s) const
218  {
219  real_t ts = slope();
220  real_t ss = s.slope();
221 
222  if (real_equal(ts, 0.))
223  {
224  return real_equal(ss, INF) or real_equal(ss, -INF);
225  }
226 
227  if (real_equal(ts, INF) or real_equal(ts, -INF))
228  return real_equal(ss, 0.);
229 
230  return real_equal(ts, -1. / ss);
231  }
232 
233  GenSegment get_perpendicular(const PointT & p) const
234  {
235  real_t m1 = slope();
236  real_t m2 = -1. / m1;
237 
238  const typename PointT::NumberType & x1 = src_point.get_x();
239  const typename PointT::NumberType & y1 = src_point.get_y();
240 
241  const typename PointT::NumberType & x2 = p.get_x();
242  const typename PointT::NumberType & y2 = p.get_y();
243 
244  const typename PointT::NumberType x =
245  real_t(y2 - y1 + m1 * x1 - m2 * x2) / real_t(m1 - m2);
246 
247  const typename PointT::NumberType y = m1 * (x - x1) + y1;
248 
249  PointT q(x, y);
250  return GenSegment(p, q);
251  }
252 
254  {
255  auto dxt = tgt_point.get_x() - src_point.get_x();
256  auto dyt = tgt_point.get_y() - src_point.get_y();
257  auto dxs = s.tgt_point.get_x() - s.src_point.get_x();
258  auto dys = s.tgt_point.get_y() - s.src_point.get_y();
259 
260  auto dot = dxt * dxs + dyt * dys;
261  auto det = dxt * dys - dyt * dxs;
262 
263  return atan2(det, dot);
264  }
265 
267  {
268  return GenSegment(tgt_point, src_point);
269  }
270 
271  PointT intersection_with(const GenSegment & s) const
272  {
273  if (is_parallel_with(s))
274  throw std::domain_error("Segments are parallels");
275 
276  const typename PointT::NumberType & x1 = src_point.get_x();
277  const typename PointT::NumberType & y1 = src_point.get_y();
278 
279  const typename PointT::NumberType & x2 = s.src_point.get_x();
280  const typename PointT::NumberType & y2 = s.src_point.get_y();
281 
282  const real_t & m1 = slope();
283  const real_t & m2 = s.slope();
284 
285  const typename PointT::NumberType x =
286  real_t(y2 - y1 + m1 * x1 - m2 * x2) / real_t(m1 - m2);
287 
288  const typename PointT::NumberType y = m1 * (x - x1) + y1;
289 
290  return PointT(x, y);
291  }
292 
293  bool is_null() const
294  {
295  return src_point == tgt_point;
296  }
297 
298  bool operator ! () const
299  {
300  return is_null();
301  }
302 
303  bool operator == (const GenSegment & s) const
304  {
305  return src_point == s.src_point and tgt_point == s.tgt_point;
306  }
307 
308  bool operator != (const GenSegment & s) const
309  {
310  return not (*this == s);
311  }
312  };
313 
314  class SegmentInt : public GenSegment<PointInt2D>
315  {
317  using Base::Base;
318  };
319 
320  class Segment : public GenSegment<Point2D>
321  {
322  using Base = GenSegment<Point2D>;
323  using Base::Base;
324  };
325 
326 } // end namespace Designar
327 
328 # endif // DSGSEGMENT_H
bool is_to_right_on_from(const PointT &p) const
Definition: segment.H:157
bool intersects_with(const GenSegment &s) const
Definition: segment.H:189
PointT intersection_with(const GenSegment &s) const
Definition: segment.H:271
bool is_perpendicular_with(const GenSegment &s) const
Definition: segment.H:217
const PointT & get_src_point() const
Definition: segment.H:107
GenSegment(const PointT &sp, const PointT &tp)
Definition: segment.H:48
void set_tgt_point(const PointT &tp)
Definition: segment.H:127
double real_t
Definition: types.H:51
double counterclockwise_angle_with(const GenSegment &s)
Definition: segment.H:253
Definition: segment.H:314
Definition: segment.H:320
bool is_to_left_from(const PointT &p) const
Definition: segment.H:142
bool operator==(const GenSegment &s) const
Definition: segment.H:303
bool is_null() const
Definition: segment.H:293
bool intersects_properly_with(const GenSegment &s) const
Definition: segment.H:177
bool is_collinear_with(const PointT &p) const
Definition: segment.H:162
bool real_equal(T, T)
Definition: math.H:91
constexpr real_t INF
Definition: math.H:38
Definition: point2D.H:241
GenSegment(PointT &&sp, const PointT &tp)
Definition: segment.H:60
void set_src_point(const PointT &sp)
Definition: segment.H:117
bool is_to_right_from(const PointT &p) const
Definition: segment.H:152
bool is_parallel_with(const GenSegment &s) const
Definition: segment.H:212
void set_tgt_point(PointT &&tp)
Definition: segment.H:132
GenSegment & operator=(const GenSegment &s)
Definition: segment.H:84
bool contains_to(const GenSegment &s) const
Definition: segment.H:172
const PointT & get_tgt_point() const
Definition: segment.H:112
real_t length() const
Definition: segment.H:137
bool contains_to(const PointT &p) const
Definition: segment.H:167
bool operator!() const
Definition: segment.H:298
Definition: array.H:32
GenSegment(const PointT &sp, PointT &&tp)
Definition: segment.H:54
GenSegment()
Definition: segment.H:42
real_t slope() const
Definition: segment.H:198
void swap(GenSegment &s)
Definition: segment.H:101
Definition: segment.H:34
bool operator!=(const GenSegment &s) const
Definition: segment.H:308
GenSegment(PointT &&sp, PointT &&tp)
Definition: segment.H:66
GenSegment(const GenSegment &s)
Definition: segment.H:72
void set_src_point(PointT &&sp)
Definition: segment.H:122
bool is_to_left_on_from(const PointT &p) const
Definition: segment.H:147
GenSegment get_perpendicular(const PointT &p) const
Definition: segment.H:233
GenSegment(GenSegment &&s)
Definition: segment.H:78
GenSegment get_opposite() const
Definition: segment.H:266