Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
point.H
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
44# ifndef POINT_H
45# define POINT_H
46
47# include <cmath>
48
49# include <cstddef>
50# include <limits>
51
52# include <iomanip>
53# include <string>
54
55# include <ahAssert.H>
56# include <ahUtils.H>
57# include <ah-errors.H>
58#include <utility>
59
60# include <gmpfrxx.h>
61
69
70inline double geom_number_to_double(const Geom_Number & n)
71{
72 return n.get_d();
73}
74
75inline std::ostream &operator <<(std::ostream & o, const Geom_Number & n)
76{
77 o << n.get_d();
78 return o;
79}
80
81// TODO: provide helpers for rotating special figures (e.g., ellipses) by
82// rotating the Cartesian axes instead of recomputing points from scratch.
83
84
85constexpr double PI = 3.1415926535897932384626433832795028841971693993751;
86constexpr double PI_2 = PI / 2.0;
87constexpr double PI_4 = PI / 4.0;
88
89
90class Point;
91class Polar_Point;
92class Segment;
93class Triangle;
94class Ellipse;
95
96
98inline Geom_Number
99area_of_parallelogram(const Point & a, const Point & b, const Point & c);
100
101
104inline Geom_Number pitag(const Geom_Number & x, const Geom_Number & y)
105{
106 return hypot(mpfr_class(x), mpfr_class(y));
107}
108
111{
112 return atan(mpfr_class(m));
113}
114
116inline Geom_Number arctan2(const Geom_Number & m, const Geom_Number & n)
117{
118 return atan2(mpfr_class(m), mpfr_class(n));
119}
120
123{
124 return sin(mpfr_class(x));
125}
126
129{
130 return cos(mpfr_class(x));
131}
132
135{
136 return sqrt(mpfr_class(x));
137}
138
140{
141 // Geom_Object(const Geom_Object & ) { /* empty */ }
142
143 Geom_Object() = default;
144
145 virtual ~Geom_Object() = default;
146};
147
155class Point : public Geom_Object
156{
157 friend class Segment;
158 friend class Triangle;
159 friend class Polar_Point;
160
163
164public:
165 Point() : Geom_Object(), x(0), y(0)
166 { /* empty */
167 }
168
171 : Geom_Object(), x(__x), y(__y)
172 {
173 // empty
174 }
175
177 // Point(const Point & p) : Geom_Object(*this), x(p.x), y(p.y)
178 // {
179 // // empty
180 // }
181
183 inline Point(const Polar_Point & pp);
184
185 bool operator ==(const Point & point) const
186 {
187 return x == point.x and y == point.y;
188 }
189
190 bool operator !=(const Point & point) const
191 {
192 return not (*this == point);
193 }
194
195 Point operator +(const Point & p) const
196 {
197 return {x + p.x, y + p.y};
198 }
199
201 {
202 x += p.x;
203 y += p.y;
204
205 return *this;
206 }
207
208 Point operator -(const Point & p) const
209 {
210 return {x - p.x, y - p.y};
211 }
212
214 {
215 x -= p.x;
216 y -= p.y;
217
218 return *this;
219 }
220
222 {
223 return x;
224 }
225
227 {
228 return y;
229 }
230
232 [[nodiscard]] bool is_colinear_with(const Point & p1, const Point & p2) const
233 {
234 return area_of_parallelogram(*this, p1, p2) == 0;
235 }
236
238 [[nodiscard]] inline bool is_colinear_with(const Segment & s) const;
239
241 [[nodiscard]] bool is_to_left_from(const Point & p1, const Point & p2) const
242 {
243 return area_of_parallelogram(p1, p2, *this) > 0;
244 }
245
247 [[nodiscard]] bool is_to_right_from(const Point & p1, const Point & p2) const
248 {
249 return area_of_parallelogram(p1, p2, *this) < 0;
250 }
251
253 [[nodiscard]] bool is_to_left_on_from(const Point & p1, const Point & p2) const
254 {
255 return not is_to_right_from(p1, p2);
256 }
257
259 [[nodiscard]] bool is_to_right_on_from(const Point & p1, const Point & p2) const
260 {
261 return not is_to_left_from(p1, p2);
262 }
263
265 [[nodiscard]] bool is_clockwise_with(const Point & p1, const Point & p2) const
266 {
267 return area_of_parallelogram(*this, p1, p2) < 0;
268 }
269
270 [[nodiscard]] inline bool is_to_left_from(const Segment & s) const;
271
272 [[nodiscard]] inline bool is_to_right_from(const Segment & s) const;
273
274 [[nodiscard]] inline bool is_clockwise_with(const Segment & s) const;
275
277 [[nodiscard]] bool is_between(const Point & p1, const Point & p2) const
278 {
279 if (not this->is_colinear_with(p1, p2))
280 return false;
281
282 if (p1.get_x() == p2.get_x())
283 return (p1.get_y() <= this->get_y() and this->get_y() <= p2.get_y())
284 or (p1.get_y() >= this->get_y() and (this->get_y() >= p2.get_y()));
285
286 return (p1.get_x() <= this->get_x() and (this->get_x() <= p2.get_x()))
287 or (p1.get_x() >= this->get_x() and (this->get_x() >= p2.get_x()));
288 }
289
291 [[nodiscard]] const Point &nearest_point(const Point & p1, const Point & p2) const
292 {
293 return this->distance_with(p1) < this->distance_with(p2) ? p1 : p2;
294 }
295
297 [[nodiscard]] inline bool is_inside(const Segment & s) const;
298
300 [[nodiscard]] inline bool is_inside(const Ellipse & e) const;
301
303 [[nodiscard]] inline bool intersects_with(const Ellipse & e) const;
304
306 [[nodiscard]] std::string to_string() const
307 {
308 return "(" + std::to_string(geom_number_to_double(x)) + "," +
309 std::to_string(geom_number_to_double(y)) + ")";
310 }
311
313 operator std::string() const { return to_string(); }
314
316 [[nodiscard]] inline Geom_Number distance_squared_to(const Point & that) const;
317
319 [[nodiscard]] inline Geom_Number distance_with(const Point & p) const;
320
321 [[nodiscard]] const Point &highest_point() const { return *this; }
322
323 [[nodiscard]] const Point &lowest_point() const { return *this; }
324
325 [[nodiscard]] const Point &leftmost_point() const { return *this; }
326
327 [[nodiscard]] const Point &rightmost_point() const { return *this; }
328};
329
330extern const Point NullPoint;
331
332
343{
344 friend class Point;
345
348
349public:
351 [[nodiscard]] const Geom_Number &get_r() const { return r; }
352
354 [[nodiscard]] const Geom_Number &get_theta() const { return theta; }
355
356 Polar_Point(const Geom_Number & __r, const Geom_Number & __theta)
357 : r(__r), theta(__theta)
358 {
359 // empty
360 }
361
364 {
365 const Geom_Number & x = p.x;
366 const Geom_Number & y = p.y;
367
368 r = pitag(x, y);
369 theta = arctan2(y, x);
370 }
371
374
376 [[nodiscard]] Quadrant get_quadrant() const
377 {
378 const Point cartesian(*this);
379 const bool east = cartesian.get_x() >= 0;
380 const bool north = cartesian.get_y() >= 0;
381
382 if (east and north)
383 return First;
384 if (not east and north)
385 return Second;
386 if (not east and not north)
387 return Third;
388 return Fourth;
389 }
390
392 [[nodiscard]] std::string to_string() const
393 {
394 return "[" + std::to_string(geom_number_to_double(r)) + "," +
395 std::to_string(geom_number_to_double(theta)) + "]";
396 }
397
398 Polar_Point() : r(0), theta(0)
399 { /* empty */
400 }
401};
402
403
404inline
406 : x(pp.r * cosinus(pp.theta)), y(pp.r * sinus(pp.theta))
407{
408 // empty
409}
410
411
416class Segment : public Geom_Object
417{
418 friend class Point;
419 friend class Triangle;
420
422
423 [[nodiscard]] double compute_slope() const
424 {
425 if (tgt.x == src.x)
426 {
427 if (src.y < tgt.y)
428 return std::numeric_limits<double>::max();
429 return -std::numeric_limits<double>::max();
430 }
431
432 const Geom_Number __slope = (tgt.y - src.y) / (tgt.x - src.x);
433
434 return __slope.get_d();
435 }
436
437public:
438 bool operator ==(const Segment & s) const
439 {
440 return src == s.src and tgt == s.tgt;
441 }
442
443 bool operator !=(const Segment & s) const
444 {
445 return not (*this == s);
446 }
447
448 [[nodiscard]] const Point &highest_point() const
449 {
450 return src.y > tgt.y ? src : tgt;
451 }
452
453 [[nodiscard]] const Point &lowest_point() const
454 {
455 return src.y < tgt.y ? src : tgt;
456 }
457
458 [[nodiscard]] const Point &leftmost_point() const
459 {
460 return src.x < tgt.x ? src : tgt;
461 }
462
463 [[nodiscard]] const Point &rightmost_point() const
464 {
465 return src.x > tgt.x ? src : tgt;
466 }
467
468 [[nodiscard]] const Point &get_src_point() const { return src; }
469
470 [[nodiscard]] const Point &get_tgt_point() const { return tgt; }
471
472 Segment() = default;
473
474 // Segment(const Segment & s)
475 // : Geom_Object(), src(s.src), tgt(s.tgt)
476 // {
477 // // empty
478 // }
479
480 Segment(Point __src, const Point & __tgt)
481 : Geom_Object(), src(std::move(__src)), tgt(__tgt)
482 {
483 // empty
484 }
485
486private:
496 static
497 Point compute_tgt_point(const Point & __src, // Point of origin
498 const Geom_Number & m, // slope
499 const Geom_Number & d) // segment length
500 {
501 const Geom_Number den2 = 1 + m * m;
502
503 const Geom_Number den = square_root(den2);
504
505 const Geom_Number x = __src.x + d / den;
506
507 const Geom_Number y = __src.y + d * m / den;
508
509 return {x, y};
510 }
511
512public:
523 Segment(Point __src, // source point
524 const Geom_Number & m, // slope
525 const Geom_Number & l) // segment length
526 : Geom_Object(), src(std::move(__src)), tgt(compute_tgt_point(src, m, l))
527 {
528 // empty
529 }
530
532 Segment(const Segment & sg, const Geom_Number & dist)
533 {
534 const Segment perp = sg.mid_perpendicular(dist);
535
536 const Point mid_point = sg.mid_point();
537
538 const Point diff_point = mid_point - perp.get_src_point();
539
540 src = sg.get_src_point() + diff_point;
541 tgt = sg.get_tgt_point() + diff_point;
542 }
543
544 [[nodiscard]] double slope() const
545 {
546 return compute_slope();
547 }
548
550 [[nodiscard]] double counterclockwise_angle_with(const Segment & s) const
551 {
552 const Geom_Number x1 = tgt.x - src.x;
553 const Geom_Number x2 = s.tgt.x - s.src.x;
554 const Geom_Number y1 = tgt.y - src.y;
555 const Geom_Number y2 = s.tgt.y - s.src.y;
556 const Geom_Number dot = x1 * x2 + y1 * y2;
557 const Geom_Number det = x1 * y2 - y1 * x2;
558
559 const Geom_Number angle = arctan2(det, dot);
560
561 if (angle == 0)
562 return 0;
563
564 if (angle < 0)
565 return -angle.get_d();
566
567 return 2 * PI - angle.get_d();
568 }
569
571 [[nodiscard]] double counterclockwise_angle() const
572 {
573 const Segment x_axis(Point(0, 0), Point(1, 0));
574 return counterclockwise_angle_with(x_axis);
575 }
576
578 [[nodiscard]] Geom_Number size() const
579 {
580 return pitag(tgt.x - src.x, tgt.y - src.y);
581 }
582
584 [[nodiscard]] bool is_colinear_with(const Point & p) const
585 {
586 return p.is_colinear_with(src, tgt);
587 }
588
590 [[nodiscard]] bool is_to_left_from(const Point & p) const
591 {
592 return p.is_to_right_from(*this);
593 }
594
596 [[nodiscard]] bool is_to_right_from(const Point & p) const
597 {
598 return p.is_to_left_from(*this);
599 }
600
602 [[nodiscard]] Point mid_point() const
603 {
604 const Geom_Number x = (src.get_x() + tgt.get_x()) / 2;
605 const Geom_Number y = (src.get_y() + tgt.get_y()) / 2;
606
607 return {x, y};
608 }
609
610
612 [[nodiscard]] const Point &nearest_point(const Point & p) const
613 {
615 }
616
618 [[nodiscard]] Segment get_perpendicular(const Point & p) const
619 {
620 if (src == tgt)
621 return *this;
622
623 // Special-case horizontal segments so we can return a vertical segment.
624 if (src.get_y() == tgt.get_y())
625 return {Point(p.get_x(), src.get_y()), p};
626
627 // Likewise for vertical segments.
628 if (src.get_x() == tgt.get_x())
629 return {Point(src.get_x(), p.get_y()), p};
630
631 const auto m1 = Geom_Number(slope());
632
633 // calculate the slope of the new segment
634 const Geom_Number m2 = -Geom_Number(1.0) / m1;
635
636 // Find the intersection point between both lines.
637 const Geom_Number & x1 = src.get_x();
638 const Geom_Number & y1 = src.get_y();
639 const Geom_Number & x2 = p.get_x();
640 const Geom_Number & y2 = p.get_y();
641
642 const Geom_Number x = (y2 - y1 + m1 * x1 - m2 * x2) / (m1 - m2);
643 const Geom_Number y = m1 * (x - x1) + y1;
644
645 // The perpendicular segment goes from the intersection to p.
646 return {Point(x, y), p};
647 }
648
650 [[nodiscard]] Segment mid_perpendicular(const Geom_Number & dist) const
651 {
652 // Translate target to the origin and convert to polar coordinates.
653 const Polar_Point tgt_polar(tgt - src);
654
655 const Geom_Number& arc_tgt_src = tgt_polar.get_theta();
656
657 Geom_Number arc_perp_pt = arctan(dist / (tgt_polar.get_r() / 2));
658
659 const Geom_Number mperp = dist / (tgt_polar.get_r() / 2);
660
661 // Distance from src to the perpendicular point.
662 Geom_Number perp_r = pitag(dist, tgt_polar.get_r() / 2);
663
664 if (tgt_polar.get_r() < 0)
665 perp_r = -perp_r;
666
667 if (tgt_polar.get_theta() < 0)
668 arc_perp_pt = -arc_perp_pt;
669
670 // Perpendicular point to the left of the segment (polar coordinates).
671 const Polar_Point polar_perp_pt_l(perp_r, arc_tgt_src + arc_perp_pt);
672
673 // Perpendicular point to the right of the segment (polar coordinates).
674 const Polar_Point polar_perp_pt_r(perp_r, arc_tgt_src - arc_perp_pt);
675
676 // Convert back to rectangular coordinates.
677 const Point p1(Point(polar_perp_pt_l) + src);
678 const Point p2(Point(polar_perp_pt_r) + src);
679
680 // Return the segment in counterclockwise order with respect to @c this.
681 if (p1.is_to_right_from(*this))
682 return {p1, p2};
683 return {p2, p1};
684 }
685
687 [[nodiscard]] bool intersects_properly_with(const Segment & s) const
688 {
689 // Reject degenerate colinear configurations first.
691 s.src.is_colinear_with(*this) or s.tgt.is_colinear_with(*this))
692 return false;
693
694 // There is a proper intersection when each segment straddles the other.
695 return (src.is_to_left_from(s) xor tgt.is_to_left_from(s)) and
696 s.src.is_to_left_from(*this) xor s.tgt.is_to_left_from(*this);
697 }
698
700 [[nodiscard]] bool contains_to(const Point & p) const
701 {
702 return p.is_between(src, tgt);
703 }
704
706 [[nodiscard]] bool contains_to(const Segment & s) const
707 {
708 return (s.get_src_point().is_between(src, tgt) and
710 }
711
713 [[nodiscard]] bool intersects_with(const Segment & s) const
714 {
715 if (this->intersects_properly_with(s))
716 return true;
717
718 return (this->contains_to(s.src) or this->contains_to(s.tgt) or
719 s.contains_to(this->src) or s.contains_to(this->tgt));
720 }
721
722 [[nodiscard]] inline bool intersects_with(const Triangle & t) const;
723
724 [[nodiscard]] inline bool intersects_with(const Ellipse & e) const;
725
727 [[nodiscard]] bool is_parallel_with(const Segment & s) const
728 {
729 return slope() == s.slope();
730 }
731
733 [[nodiscard]] Point intersection_with(const Segment & s) const
734 {
735 ah_domain_error_if(this->is_parallel_with(s)) << "Segments are parallels";
736
737 const Geom_Number & x1 = this->src.x;
738 const Geom_Number & y1 = this->src.y;
739
740 const Geom_Number & x2 = s.src.x;
741 const Geom_Number & y2 = s.src.y;
742
743 const Geom_Number & m1 = this->slope();
744 const Geom_Number & m2 = s.slope();
745
746 const Geom_Number x = (y2 - y1 + m1 * x1 - m2 * x2) / (m1 - m2);
747
748 const Geom_Number y = m1 * (x - x1) + y1;
749
750 return {x, y};
751 }
752
753 // TODO: consider polar-based sense calculation to avoid branching.
754
756 enum Sense { E, NE, N, NW, W, S, SW, SE };
757
758 [[nodiscard]] Sense sense() const
759 {
760 if (src.x < tgt.x) // headed east?
761 {
762 if (src.y < tgt.y) // and north?
763 return NE;
764 if (src.y > tgt.y) // and south?
765 return SE;
766 return E;
767 }
768
769 if (src.x > tgt.x) // headed west?
770 {
771 if (src.y < tgt.y) // and north?
772 return NW;
773 if (src.y > tgt.y) // and south?
774 return SW;
775 return W;
776 }
777
778 // Vertical segment: if target is above source, heading north; else south.
779 return src.y < tgt.y ? N : S;
780 }
781
783 void enlarge_src(const Geom_Number & __dist)
784 {
785 const double m = slope();
786
787 Point p = compute_tgt_point(src, m, -__dist);
788
789 if (const Segment s(p, src); s.size() < __dist) // fallback to extending forward
790 p = compute_tgt_point(src, m, __dist);
791
792 src = p;
793 }
794
796 void enlarge_tgt(const Geom_Number & __dist)
797 {
798 const double m = slope();
799
800 Point p = compute_tgt_point(tgt, m, __dist);
801
802 if (const Segment s(tgt, p); s.size() < __dist)
803 p = compute_tgt_point(tgt, m, -__dist);
804
805 tgt = p;
806 }
807
809 [[nodiscard]] std::string to_string() const
810 {
811 return src.to_string() + tgt.to_string();
812 }
813
814 operator std::string() const
815 {
816 return to_string();
817 }
818
820 void rotate(const double & angle)
821 {
822 if (angle == 0)
823 return;
824
825 const Polar_Point ptgt(tgt - src); // target in polar coordinates
826
827 // move by angle radians, convert back, and translate to source frame
828 tgt = Polar_Point(ptgt.get_r(), ptgt.get_theta() + angle);
829 tgt = tgt + src;
830 }
831
832 // Return the intersection segment with triangle t (if any).
833 [[nodiscard]] inline Segment intersection_with(const Triangle & t) const;
834
835 // Return the intersection segment with ellipse e (if any).
836 [[nodiscard]] inline Segment intersection_with(const Ellipse & e) const;
837};
838
839// Return true if this point lies inside segment s.
840inline bool Point::is_inside(const Segment & s) const
841{
842 return s.contains_to(*this);
843}
844
845// Return true if this point is colinear with segment s.
846inline bool Point::is_colinear_with(const Segment & s) const
847{
848 return this->is_colinear_with(s.src, s.tgt);
849}
850
851// Return true if this point is to the left of segment s.
852inline bool Point::is_to_left_from(const Segment & s) const
853{
854 return this->is_to_left_from(s.src, s.tgt);
855}
856
857// Return true if this point is to the right of segment s.
858inline bool Point::is_to_right_from(const Segment & s) const
859{
860 return this->is_to_right_from(s.src, s.tgt);
861}
862
863// Return true if the sequence (this, segment) is clockwise.
864inline bool Point::is_clockwise_with(const Segment & s) const
865{
866 return this->is_clockwise_with(s.src, s.tgt);
867}
868
869
870// Return the squared Euclidean distance to that.
872{
873 const Geom_Number dx = this->x - that.x;
874 const Geom_Number dy = this->y - that.y;
875 return dx * dx + dy * dy;
876}
877
878
879// Return the Euclidean distance to p.
881{
882 const Segment seg(*this, p);
883
884 return seg.size();
885}
886
887
888/*****************************************************************
889
890 Fundamental triangle class
891
892 Basic helper for polygon triangulation algorithms.
893 */
894class Triangle : public Geom_Object
895{
896 friend class Point;
897 friend class Segment;
898
900
902
903public:
904 Triangle(const Point & __p1, const Point & __p2, const Point & __p3)
905 : p1(__p1), p2(__p2), p3(__p3)
906 {
908
910 << "The three points of triangle are colinears";
911 }
912
913 Triangle(Point p, const Segment & s)
914 : p1(std::move(p)), p2(s.src), p3(s.tgt)
915 {
917
919 << "The three points of triangle are collinear";
920 }
921
922 Triangle(const Segment & s, const Point & p)
923 : p1(s.src), p2(s.tgt), p3(p)
924 {
926
928 << "The three points of triangle are collinear";
929 }
930
932 {
933 return abs(__area);
934 }
935
937 [[nodiscard]] bool is_clockwise() const
938 {
939 return __area >= 0;
940 }
941
942 [[nodiscard]] const Point &highest_point() const
943 {
944 const Point & max = p1.y > p2.y ? p1 : p2;
945
946 return p3.y > max.y ? p3 : max;
947 }
948
949 [[nodiscard]] const Point &lowest_point() const
950 {
951 const Point & min = p1.y < p2.y ? p1 : p2;
952
953 return p3.y < min.y ? p3 : min;
954 }
955
956 [[nodiscard]] const Point &leftmost_point() const
957 {
958 const Point & min = p1.x < p2.x ? p1 : p2;
959
960 return p3.x < min.x ? p3 : min;
961 }
962
963 [[nodiscard]] const Point &rightmost_point() const
964 {
965 const Point & max = p1.x > p2.x ? p1 : p2;
966
967 return p3.x > max.x ? p3 : max;
968 }
969
970 [[nodiscard]] const Point &get_p1() const { return p1; }
971
972 [[nodiscard]] const Point &get_p2() const { return p2; }
973
974 [[nodiscard]] const Point &get_p3() const { return p3; }
975
977 [[nodiscard]] bool contains_to(const Point & p) const
978 {
979 const bool s = p.is_to_left_from(p1, p2);
980
981 if (p.is_to_left_from(p2, p3) != s)
982 return false;
983
984 if (p.is_to_left_from(p3, p1) != s)
985 return false;
986
987 return true;
988 }
989
991 [[nodiscard]] Segment intersection_with(const Segment & s) const
992 {
993 return s.intersection_with(*this);
994 }
995};
996
998{
1001
1002public:
1003 [[nodiscard]] const Geom_Number &get_xmin() const { return xmin; }
1004
1005 [[nodiscard]] const Geom_Number &get_ymin() const { return ymin; }
1006
1007 [[nodiscard]] const Geom_Number &get_xmax() const { return xmax; }
1008
1009 [[nodiscard]] const Geom_Number &get_ymax() const { return ymax; }
1010
1011 Rectangle() : xmin(0), ymin(0), xmax(0), ymax(0)
1012 {
1013 // empty
1014 }
1015
1016 Rectangle(const Geom_Number & __xmin, const Geom_Number & __ymin,
1017 const Geom_Number & __xmax, const Geom_Number & __ymax)
1018 : xmin(__xmin), ymin(__ymin), xmax(__xmax), ymax(__ymax)
1019 {
1020 ah_range_error_if(xmax < xmin or ymax < ymin) << "Invalid rectangle";
1021 }
1022
1023 void set_rect(const Geom_Number & __xmin, const Geom_Number & __ymin,
1024 const Geom_Number & __xmax, const Geom_Number & __ymax)
1025 {
1026 ah_range_error_if(__xmax < __xmin or __ymax < __ymin)
1027 << "Invalid rectangle";
1028
1029 xmin = __xmin;
1030 ymin = __ymin;
1031 xmax = __xmax;
1032 ymax = __ymax;
1033 }
1034
1035 [[nodiscard]] Geom_Number width() const { return xmax - xmin; }
1036
1037 [[nodiscard]] Geom_Number height() const { return ymax - ymin; }
1038
1039 // does this axis-aligned rectangle intersect that one?
1040 [[nodiscard]] bool intersects(const Rectangle & that) const
1041 {
1042 return this->xmax >= that.xmin and this->ymax >= that.ymin and
1043 that.xmax >= this->xmin and that.ymax >= this->ymin;
1044 }
1045
1046 [[nodiscard]] Geom_Number distance_squared_to(const Point & p) const
1047 {
1048 Geom_Number dx = 0.0, dy = 0.0;
1049 if (p.get_x() < xmin)
1050 dx = p.get_x() - xmin;
1051 else if (p.get_x() > xmax)
1052 dx = p.get_x() - xmax;
1053
1054 if (p.get_y() < ymin)
1055 dy = p.get_y() - ymin;
1056 else if (p.get_y() > ymax)
1057 dy = p.get_y() - ymax;
1058
1059 return dx * dx + dy * dy;
1060 }
1061
1062 // distance from p to the closest point on this axis-aligned rectangle
1063 [[nodiscard]] Geom_Number distance_to(const Point & p) const
1064 {
1066 }
1067
1068 // does this axis-aligned rectangle contain p?
1069 [[nodiscard]] bool contains(const Point & p) const
1070 {
1071 return p.get_x() >= xmin and p.get_x() <= xmax and
1072 p.get_y() >= ymin and p.get_y() <= ymax;
1073 }
1074};
1075
1076// Returns true if this segment intersects one or two edges of triangle @p t.
1077inline bool Segment::intersects_with(const Triangle & t) const
1078{
1079 return (this->intersects_with(Segment(t.get_p1(), t.get_p2())) or
1080 this->intersects_with(Segment(t.get_p2(), t.get_p3())) or
1081 this->intersects_with(Segment(t.get_p3(), t.get_p1())));
1082}
1083
1084
1085// Returns the segment resulting from intersecting this segment with triangle @p t.
1086// If an endpoint lies inside the triangle, the intersection degenerates to a
1087// point, which can be used to test if a point belongs to @p t.
1089{
1091 << "segment does not intersects with triangle";
1092
1093 Point p[2];
1094
1095 int i = 0;
1096
1097 try
1098 { // check intersection against edge p1-p2
1099 p[i] = this->intersection_with(Segment(t.get_p1(), t.get_p2()));
1100
1101 if (t.contains_to(p[i]))
1102 ++i; // intersection detected
1103 }
1104 catch (std::domain_error &)
1105 {
1106 // No intersection with the previous edge; continue.
1107 }
1108
1109 try
1110 { // check intersection against edge p2-p3
1111 p[i] = this->intersection_with(Segment(t.get_p2(), t.get_p3()));
1112
1113 if (t.contains_to(p[i]))
1114 ++i; // intersection detected
1115 }
1116 catch (std::domain_error &)
1117 {
1118 // No intersection with the previous edge; continue.
1119 }
1120
1121 if (i == 2) // two intersection points already collected
1122 return {p[0], p[1]};
1123
1124 try
1125 { // check intersection against edge p3-p1
1126 p[i] = this->intersection_with(Segment(t.get_p3(), t.get_p1()));
1127 }
1128 catch (std::domain_error &)
1129 {
1130 throw; // should be unreachable because intersection was confirmed
1131 }
1132
1133 // Result depends on the number of intersection points captured.
1134 return i == 1 ? Segment(p[0], p[0]) : Segment(p[0], p[1]);
1135}
1136
1137
1138/*****************************************************************
1139
1140 Fundamental ellipse class
1141
1142 Represents an axis-aligned ellipse centered at @p center with horizontal
1143 radius @p hr and vertical radius @p vr.
1144 */
1145class Ellipse : public Geom_Object
1146{
1147 friend class Point;
1148
1149 /*
1150 The ellipse is defined relative to its center (xc, yc) by:
1151
1152 2 2
1153 (y - yc) (x - xc)
1154 --------- + --------- = 1
1155 2 2
1156 vr hr
1157 */
1158
1159 Point center; // ellipse center
1160
1161 Geom_Number hr; // horizontal radius (parameter a)
1162 Geom_Number vr; // vertical radius (parameter b)
1163
1164public:
1165 Ellipse(Point __center,
1166 const Geom_Number & __hr,
1167 const Geom_Number & __vr)
1168 : center(std::move(__center)), hr(__hr), vr(__vr)
1169 {
1170 // empty
1171 }
1172
1173 Ellipse(const Ellipse & e) = default;
1174
1175
1176 Ellipse() = default;
1177
1178 [[nodiscard]] const Point &get_center() const { return center; }
1179
1180 [[nodiscard]] const Geom_Number &get_hradius() const { return hr; }
1181
1182 [[nodiscard]] const Geom_Number &get_vradius() const { return vr; }
1183
1184 static bool is_clockwise() { return false; }
1185
1186 [[nodiscard]] Point highest_point() const
1187 {
1188 return {center.get_x(), center.get_y() + vr};
1189 }
1190
1191 [[nodiscard]] Point lowest_point() const
1192 {
1193 return {center.get_x(), center.get_y() - vr};
1194 }
1195
1196 [[nodiscard]] Point leftmost_point() const
1197 {
1198 return {center.get_x() - hr, center.get_y()};
1199 }
1200
1201 [[nodiscard]] Point rightmost_point() const
1202 {
1203 return {center.get_x() + hr, center.get_y()};
1204 }
1205
1206 /* Computes the tangents to this ellipse with slope @p m.
1207
1208 Derived from the line equation:
1209
1210 y = m x + sqrt(a^2 m^2 + b^2)
1211
1212 which corresponds to tangents to an ellipse centered at the origin.
1213
1214 This comes from substituting y = mx + y0 into the simplified ellipse
1215 equation at (0,0):
1216
1217 2 2
1218 y x
1219 --- + --- = 1
1220 2 2
1221 vr hr
1222
1223 WARNING: floating-point precision loss may appear due to irrational values.
1224
1225 @p s1 and @p s2 are the tangent segments; @p m is the slope.
1226 */
1227 void
1228 compute_tangents(Segment & s1, Segment & s2, const Geom_Number & m) const
1229 {
1230 if (m == 0)
1231 {
1232 s1 = Segment(center + Point(-hr, vr), center + Point(hr, vr));
1233 s2 = Segment(center + Point(-hr, -vr), center + Point(hr, -vr));
1234
1235 return;
1236 }
1237
1238 const Geom_Number product = hr * hr * m * m + vr * vr;
1239
1240 // intersection with the axis if the ellipse were centered at the origin
1241 const Geom_Number y1 = square_root(product);
1242
1243 const Geom_Number x1 = -y1 / m;
1244
1245 // when the ellipse is centered at (0,0), the tangent points are
1246 // (0, y1) and (0, -y1). For an ellipse centered at @p center we
1247 // translate them along the line (0,0)--center.
1248
1249 const Segment t1 = Segment(center + Point(x1, 0), center + Point(0, y1));
1250
1251 const Segment t2 = Segment(center + Point(-x1, 0), center + Point(0, -y1));
1252
1253 // tangent segments may be longer than required. For each one pick the
1254 // endpoint closest to the center.
1255
1256 // decide tangent length using the largest radius.
1257 const Geom_Number tangent_size = hr > vr ? hr : vr;
1258
1259 { // compute distances from center to tangent endpoints
1260 const Geom_Number dsrc = center.distance_with(t1.get_src_point());
1261 const Geom_Number dtgt = center.distance_with(t1.get_tgt_point());
1262
1263 if (dsrc < dtgt) // choose point nearest to center
1264 {
1265 s1 = Segment(t1.get_src_point(), m, tangent_size);
1266 s1.enlarge_src(tangent_size);
1267 }
1268 else
1269 {
1270 s1 = Segment(t1.get_tgt_point(), m, tangent_size);
1271 s1.enlarge_tgt(tangent_size);
1272 }
1273 }
1274
1275 { // compute distances for the second tangent
1276 const Geom_Number dsrc = center.distance_with(t2.get_src_point());
1277 const Geom_Number dtgt = center.distance_with(t2.get_tgt_point());
1278
1279 if (dsrc < dtgt) // choose point nearest to center
1280 {
1281 s2 = Segment(t2.get_src_point(), m, tangent_size);
1282 s2.enlarge_src(tangent_size);
1283 }
1284 else
1285 {
1286 s2 = Segment(t2.get_tgt_point(), m, tangent_size);
1287 s2.enlarge_tgt(tangent_size);
1288 }
1289 }
1290 }
1291
1292 // Returns true if segment @p s intersects the ellipse.
1293 [[nodiscard]] bool intersects_with(const Segment & s) const
1294 {
1295 Segment tg1;
1296 Segment tg2;
1297
1298 compute_tangents(tg1, tg2, s.slope()); // build both parallel tangents
1299
1300 // intersection exists if @p s lies between both tangents
1301 return (s.is_to_left_from(tg1.get_src_point()) xor
1303 }
1304
1305private:
1306 // Computes ( (p.x - xc)^2 / a^2 + (p.y - yc)^2 / b^2 ) which helps to
1307 // determine whether @p p is inside the ellipse (<= 1), on the border (=1),
1308 // or outside (> 1).
1309 [[nodiscard]] Geom_Number compute_radius(const Point & p) const
1310 {
1311 Geom_Number x2 = (p.get_x() - center.get_x());
1312 x2 = x2 * x2;
1313
1314 Geom_Number y2 = (p.get_y() - center.get_y());
1315 y2 = y2 * y2;
1316
1317 return x2 / (hr * hr) + y2 / (vr * vr);
1318 }
1319
1320public:
1321 // Returns true if point @p p lies inside this ellipse.
1322 [[nodiscard]] bool contains_to(const Point & p) const
1323 {
1324 return compute_radius(p) <= 1;
1325 }
1326
1327 // Returns true if point @p p lies exactly on the ellipse curve.
1328 [[nodiscard]] bool intersects_with(const Point & p) const
1329 {
1330 return compute_radius(p) == 1;
1331 }
1332
1333 /*
1334 Segment intersection routines. Solve the system composed of the ellipse
1335 equation
1336
1337 2 2
1338 y x
1339 eq1 -- + -- = 1
1340 2 2
1341 b a
1342
1343 and the segment line equation
1344
1345 eq2 y - yr = m*(x - xr)
1346
1347 where (xr, yr) is a point on the line once it is translated to the
1348 ellipse-centered coordinate system.
1349
1350 The explicit solutions (obtained, for example, via
1351 maxima: solve([eq1, eq2], [x, y])) are:
1352
1353 2 2 2 2 2 2 2 2 2
1354 a b sqrt(- yr + 2 m xr yr - m xr + a m + b ) + a m yr - a m xr
1355x1 = - ----------------------------------------------------------------------
1356 2 2 2
1357 a m + b
1358
1359 2 2 2 2 2 2 2 2
1360 a b m sqrt(- yr + 2 m xr yr - m xr + a m + b ) - b yr + b m xr
1361y1 = - ----------------------------------------------------------------------
1362 2 2 2
1363 a m + b
1364
1365 2 2 2 2 2 2 2 2 2
1366 a b sqrt(- yr + 2 m xr yr - m xr + a m + b ) - a m yr + a m xr
1367x2 = ----------------------------------------------------------------------
1368 2 2 2
1369 a m + b
1370
1371 2 2 2 2 2 2 2 2
1372 a b m sqrt(- yr + 2 m xr yr - m xr + a m + b ) + b yr - b m xr
1373y2 = ----------------------------------------------------------------------
1374 2 2 2
1375 a m + b
1376
1377 These formulas assume the ellipse is centered at (0, 0).
1378
1379 To compute the actual intersection: translate the segment so the ellipse
1380 center lands at the origin, evaluate the expressions above, and translate
1381 the resulting segment back to the real center.
1382
1383 BUG: there remains a numerical issue when the line passes through the
1384 ellipse center; graphpic-generated code still disagrees between the
1385 two solutions even though they should match.
1386 */
1387 [[nodiscard]] Segment intersection_with(const Segment & sg) const
1388 {
1389 ah_domain_error_if(not intersects_with(sg)) << "there is no intersection";
1390
1391 const Geom_Number & a = hr;
1392 const Geom_Number & b = vr;
1393
1394 const Geom_Number a2 = a * a;
1395 const Geom_Number b2 = b * b;
1396
1397 const Geom_Number ab = a * b;
1398
1399 // Segment translated to coordinate system with origin at (xc, yc).
1400 const Segment sg_new(sg.get_src_point() - center,
1401 sg.get_tgt_point() - center);
1402
1403 const Point pr = sg_new.get_tgt_point();
1404
1405 const Geom_Number & xr = pr.get_x();
1406 const Geom_Number & yr = pr.get_y();
1407
1408 const Geom_Number m = sg_new.slope();
1409
1410 assert(m == sg.slope());
1411
1412 const Geom_Number m2 = m * m;
1413
1414 const Geom_Number yr2 = yr * yr;
1415
1416 const Geom_Number xr2 = xr * xr;
1417
1418 assert(m2 >= 0 and yr2 >= 0 and xr2 >= 0);
1419
1420 const Geom_Number a2m2_plus_b2 = a2 * m2 + b2;
1421
1422 Geom_Number ab_root = -yr2 + 2 * m * xr * yr - m2 * xr2 + a2m2_plus_b2;
1423 ab_root = ab * square_root(ab_root);
1424
1425 const Geom_Number ab_m_root = m * ab_root;
1426
1427 const Geom_Number yr_minus_m_xr = yr - m * xr;
1428
1429 const Geom_Number sumx = a2 * m * yr_minus_m_xr;
1430
1431 const Geom_Number sumy = b2 * yr_minus_m_xr;
1432
1433 // With the main calculations done, compute the final values.
1434
1435 const Geom_Number x1 = -(ab_root + sumx) / a2m2_plus_b2;
1436
1437 const Geom_Number y1 = -(ab_m_root - sumy) / a2m2_plus_b2;
1438
1439 const Geom_Number x2 = (ab_root - sumx) / a2m2_plus_b2;
1440
1441 const Geom_Number y2 = (ab_m_root + sumy) / a2m2_plus_b2;
1442
1443 // Since results are for the ellipse at (0,0), translate the intersection
1444 // points back to the actual ellipse center.
1445
1446 const Point src = Point(x1, y1) + center;
1447 const Point tgt = Point(x2, y2) + center;
1448
1449 return Segment(src, tgt);
1450 }
1451};
1452
1453// Return true if this point lies inside ellipse e.
1454inline bool Point::is_inside(const Ellipse & e) const
1455{
1456 return e.contains_to(*this);
1457}
1458
1459// Return true if this point lies exactly on ellipse e.
1460inline bool Point::intersects_with(const Ellipse & e) const
1461{
1462 return e.intersects_with(*this);
1463}
1464
1465// Return true if this segment intersects ellipse e.
1466inline bool Segment::intersects_with(const Ellipse & e) const
1467{
1468 return e.intersects_with(*this);
1469}
1470
1471// Return the segment defined by the two intersection points between this
1472// segment and ellipse e.
1474{
1475 return e.intersection_with(*this);
1476}
1477
1478/*****************************************************************
1479
1480 Fundamental text primitive
1481
1482 Utility to draw text strings on the plane. Offsets are not stored because
1483 callers can shift the reference point directly.
1484*/
1485
1486/* Estimate the count of printable characters in a LaTeX string (skipping '\',
1487 '$', '{', '}', etc.).
1488*/
1489inline size_t aproximate_string_size(const std::string & str)
1490{
1491 const char *ptr = str.c_str();
1492
1493 size_t __len = 0;
1494 for (int i = 0; true; /* empty */)
1495 {
1496 switch (ptr[i])
1497 {
1498 case '\\':
1499 // Skip all characters that compose the LaTeX command.
1500 for (++i; isalnum(ptr[i]) and ptr[i] != '\0'; /* nothing */)
1501 ++i;
1502 ++__len;
1503 break;
1504
1505 case '$':
1506 case '{':
1507 case '}':
1508 case '\n':
1509 ++i;
1510 break;
1511
1512 case '\0':
1513 return __len;
1514
1515 default:
1516 ++__len;
1517 ++i;
1518 break;
1519 }
1520 }
1521}
1522
1523class Text : public Geom_Object
1524{
1526
1527 std::string str;
1528
1529 size_t __len;
1530
1531public:
1532 static const double font_width_in_points;
1533
1534 static const double font_height_in_points;
1535
1536 Text(const Point & __p, const std::string & __str)
1537 : p(__p), str(__str), __len(aproximate_string_size(__str))
1538 {
1539 // empty
1540 }
1541
1543 { /* empty */
1544 }
1545
1546 const size_t &len() const { return __len; }
1547
1548 const Point &get_point() const
1549 {
1550 return p;
1551 }
1552
1553 const std::string &get_str() const { return str; }
1554
1556 {
1557 return p;
1558 }
1559
1561 {
1562 return p;
1563 }
1564
1566 {
1567 return p;
1568 }
1569
1571 {
1572 return p;
1573 }
1574};
1575
1576inline Geom_Number
1577area_of_parallelogram(const Point & a, const Point & b, const Point & c)
1578{
1579 return ((b.get_x() - a.get_x()) * (c.get_y() - a.get_y()) -
1580 (c.get_x() - a.get_x()) * (b.get_y() - a.get_y()));
1581}
1582
1583
1584# endif // POINT_H
Exception handling system with formatted messages for Aleph-w.
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:522
#define ah_range_error_if(C)
Throws std::range_error if condition holds.
Definition ah-errors.H:207
Debug assertion and warning utilities.
General utility functions and helpers.
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
Geom_Number compute_radius(const Point &p) const
Definition point.H:1309
const Geom_Number & get_vradius() const
Definition point.H:1182
const Geom_Number & get_hradius() const
Definition point.H:1180
Geom_Number hr
Definition point.H:1161
void compute_tangents(Segment &s1, Segment &s2, const Geom_Number &m) const
Definition point.H:1228
Point lowest_point() const
Definition point.H:1191
Segment intersection_with(const Segment &sg) const
Definition point.H:1387
Ellipse(Point __center, const Geom_Number &__hr, const Geom_Number &__vr)
Definition point.H:1165
const Point & get_center() const
Definition point.H:1178
Ellipse(const Ellipse &e)=default
Point center
Definition point.H:1159
bool intersects_with(const Point &p) const
Definition point.H:1328
bool intersects_with(const Segment &s) const
Definition point.H:1293
static bool is_clockwise()
Definition point.H:1184
friend class Point
Definition point.H:1147
Geom_Number vr
Definition point.H:1162
Ellipse()=default
Point leftmost_point() const
Definition point.H:1196
bool contains_to(const Point &p) const
Definition point.H:1322
Point rightmost_point() const
Definition point.H:1201
Point highest_point() const
Definition point.H:1186
Rectangular point in the plane.
Definition point.H:156
Point & operator-=(const Point &p)
Definition point.H:213
const Geom_Number & get_y() const
Returns y value.
Definition point.H:226
const Point & highest_point() const
Definition point.H:321
const Point & nearest_point(const Point &p1, const Point &p2) const
Return the nearest point (to this) between p1 and p2.
Definition point.H:291
bool is_inside(const Segment &s) const
Returns true if this is inside of segment s.
Definition point.H:840
const Point & leftmost_point() const
Definition point.H:325
bool is_to_right_from(const Point &p1, const Point &p2) const
Return true if this is to right from points p1 and p2.
Definition point.H:247
Geom_Number x
Definition point.H:161
bool intersects_with(const Ellipse &e) const
Returns true if this intersects ellipse e.
Definition point.H:1460
bool is_colinear_with(const Point &p1, const Point &p2) const
Returns true if this is colinear with p1 and p2.
Definition point.H:232
Point operator+(const Point &p) const
Definition point.H:195
bool is_to_left_on_from(const Point &p1, const Point &p2) const
Return true if this is to left from (or on) points p1 and p2.
Definition point.H:253
bool is_clockwise_with(const Point &p1, const Point &p2) const
Returns true if the sequence this-p1-p2 is clockwise.
Definition point.H:265
const Point & rightmost_point() const
Definition point.H:327
bool is_to_left_from(const Point &p1, const Point &p2) const
Return true if this is to left from points p1 and p2.
Definition point.H:241
std::string to_string() const
Return a string representation of this.
Definition point.H:306
bool is_between(const Point &p1, const Point &p2) const
Returns true if this is between p1 and p2.
Definition point.H:277
Geom_Number distance_with(const Point &p) const
Returns the Euclidean distance between this and p.
Definition point.H:880
Geom_Number y
Definition point.H:162
Point(const Geom_Number &__x, const Geom_Number &__y)
Builds a new point in coordinates (__x, __y)
Definition point.H:170
const Point & lowest_point() const
Definition point.H:323
bool operator!=(const Point &point) const
Definition point.H:190
bool is_to_right_on_from(const Point &p1, const Point &p2) const
Return true if this is to right from (or on) points p1 and p2.
Definition point.H:259
Point()
Definition point.H:165
Point & operator+=(const Point &p)
Definition point.H:200
Point operator-(const Point &p) const
Definition point.H:208
Geom_Number distance_squared_to(const Point &that) const
Returns the square distance between this y that.
Definition point.H:871
const Geom_Number & get_x() const
Returns x value.
Definition point.H:221
bool operator==(const Point &point) const
Definition point.H:185
Polar representation of a 2D point.
Definition point.H:343
Geom_Number r
Definition point.H:346
Quadrant
Enumerate polar quadrants in counterclockwise order.
Definition point.H:373
const Geom_Number & get_theta() const
Returns the angle.
Definition point.H:354
std::string to_string() const
Convert to string representation "[r,theta]".
Definition point.H:392
Polar_Point(const Point &p)
Construct from Cartesian coordinates (origin at (0,0)).
Definition point.H:363
Polar_Point(const Geom_Number &__r, const Geom_Number &__theta)
Definition point.H:356
Quadrant get_quadrant() const
Return the quadrant where the point lies (origin defaults to First).
Definition point.H:376
Polar_Point()
Definition point.H:398
Geom_Number theta
Definition point.H:347
const Geom_Number & get_r() const
Returns the magnitude.
Definition point.H:351
bool contains(const Point &p) const
Definition point.H:1069
void set_rect(const Geom_Number &__xmin, const Geom_Number &__ymin, const Geom_Number &__xmax, const Geom_Number &__ymax)
Definition point.H:1023
Geom_Number xmin
Definition point.H:999
const Geom_Number & get_xmin() const
Definition point.H:1003
Geom_Number ymin
Definition point.H:999
const Geom_Number & get_ymin() const
Definition point.H:1005
const Geom_Number & get_xmax() const
Definition point.H:1007
Geom_Number height() const
Definition point.H:1037
Geom_Number distance_squared_to(const Point &p) const
Definition point.H:1046
Geom_Number ymax
Definition point.H:1000
Rectangle(const Geom_Number &__xmin, const Geom_Number &__ymin, const Geom_Number &__xmax, const Geom_Number &__ymax)
Definition point.H:1016
Geom_Number distance_to(const Point &p) const
Definition point.H:1063
bool intersects(const Rectangle &that) const
Definition point.H:1040
Rectangle()
Definition point.H:1011
const Geom_Number & get_ymax() const
Definition point.H:1009
Geom_Number xmax
Definition point.H:1000
Geom_Number width() const
Definition point.H:1035
Fundamental segment defined by two points.
Definition point.H:417
const Point & get_tgt_point() const
Definition point.H:470
Segment get_perpendicular(const Point &p) const
Construct the segment perpendicular to this passing through p.
Definition point.H:618
Segment()=default
std::string to_string() const
Return "(src)(tgt)" textual form.
Definition point.H:809
const Point & nearest_point(const Point &p) const
Return whichever endpoint is nearer to p.
Definition point.H:612
Sense
Cardinal directions associated with a segment.
Definition point.H:756
@ SE
Definition point.H:756
@ N
Definition point.H:756
@ NW
Definition point.H:756
@ W
Definition point.H:756
@ E
Definition point.H:756
@ NE
Definition point.H:756
@ SW
Definition point.H:756
@ S
Definition point.H:756
bool is_colinear_with(const Point &p) const
Return true if p is colinear with this segment.
Definition point.H:584
void enlarge_tgt(const Geom_Number &__dist)
Extend the segment by __dist from the target endpoint.
Definition point.H:796
double counterclockwise_angle_with(const Segment &s) const
Compute the counterclockwise wise angle respect another segment s.
Definition point.H:550
double counterclockwise_angle() const
Compute the counterclockwise angle of this respect x-axis.
Definition point.H:571
Point intersection_with(const Segment &s) const
Compute intersection point solving point-slope equations for both lines.
Definition point.H:733
static Point compute_tgt_point(const Point &__src, const Geom_Number &m, const Geom_Number &d)
Computes the target point of a segment given the source point, slope and length.
Definition point.H:497
double compute_slope() const
Definition point.H:423
const Point & rightmost_point() const
Definition point.H:463
Geom_Number size() const
Return the Euclidean length of the segment (distance between endpoints).
Definition point.H:578
const Point & lowest_point() const
Definition point.H:453
bool intersects_with(const Segment &s) const
Return true if s intersects this segment (including endpoints).
Definition point.H:713
bool is_to_left_from(const Point &p) const
Return true if this segment is to the left of point p.
Definition point.H:590
Point tgt
Definition point.H:421
Segment(Point __src, const Geom_Number &m, const Geom_Number &l)
Builds a new segment given source point, slope and length.
Definition point.H:523
friend class Point
Definition point.H:418
Point mid_point() const
Return the midpoint of this segment.
Definition point.H:602
Segment mid_perpendicular(const Geom_Number &dist) const
Return the perpendicular chord of length 2*dist through the midpoint.
Definition point.H:650
const Point & highest_point() const
Definition point.H:448
void enlarge_src(const Geom_Number &__dist)
Extend the segment by __dist from the source endpoint.
Definition point.H:783
bool contains_to(const Point &p) const
Return true if p lies on this segment.
Definition point.H:700
bool is_to_right_from(const Point &p) const
Return true if this segment is to the right of point p.
Definition point.H:596
Point src
Definition point.H:421
bool operator!=(const Segment &s) const
Definition point.H:443
bool operator==(const Segment &s) const
Definition point.H:438
Segment(Point __src, const Point &__tgt)
Definition point.H:480
const Point & leftmost_point() const
Definition point.H:458
const Point & get_src_point() const
Definition point.H:468
bool contains_to(const Segment &s) const
Return true if s lies entirely inside this segment.
Definition point.H:706
Sense sense() const
Definition point.H:758
bool is_parallel_with(const Segment &s) const
Return true if s has the same slope.
Definition point.H:727
void rotate(const double &angle)
Rotate the segment by angle (radians) around the source point.
Definition point.H:820
double slope() const
Definition point.H:544
bool intersects_properly_with(const Segment &s) const
Return true if the segments intersect at interior points only.
Definition point.H:687
Segment(const Segment &sg, const Geom_Number &dist)
Builds a new segment parallel to sg and with a distance dist.
Definition point.H:532
Definition point.H:1524
static const double font_width_in_points
Definition point.H:1532
Text(const Point &__p, const std::string &__str)
Definition point.H:1536
const Point & get_point() const
Definition point.H:1548
std::string str
Definition point.H:1527
const std::string & get_str() const
Definition point.H:1553
size_t __len
Definition point.H:1529
Point leftmost_point() const
Definition point.H:1565
Text()
Definition point.H:1542
Point p
Definition point.H:1525
const size_t & len() const
Definition point.H:1546
Point highest_point() const
Definition point.H:1555
Point lowest_point() const
Definition point.H:1560
static const double font_height_in_points
Definition point.H:1534
Point rightmost_point() const
Definition point.H:1570
Triangle(const Segment &s, const Point &p)
Definition point.H:922
Triangle(Point p, const Segment &s)
Definition point.H:913
const Point & highest_point() const
Definition point.H:942
const Point & rightmost_point() const
Definition point.H:963
const Point & get_p1() const
Definition point.H:970
const Point & lowest_point() const
Definition point.H:949
Point p3
Definition point.H:899
Geom_Number area() const
Definition point.H:931
const Point & leftmost_point() const
Definition point.H:956
bool is_clockwise() const
Returns true if the triangle vertices are ordered clockwise.
Definition point.H:937
Segment intersection_with(const Segment &s) const
Returns the intersection segment between this triangle and segment s.
Definition point.H:991
Point p1
Definition point.H:899
const Point & get_p3() const
Definition point.H:974
Triangle(const Point &__p1, const Point &__p2, const Point &__p3)
Definition point.H:904
bool contains_to(const Point &p) const
Returns true if point p lies inside this triangle.
Definition point.H:977
Geom_Number __area
Definition point.H:901
Point p2
Definition point.H:899
const Point & get_p2() const
Definition point.H:972
__gmp_expr< typename __gmp_resolve_expr< T, V >::value_type, __gmp_binary_expr< __gmp_expr< T, U >, __gmp_expr< V, W >, __gmp_hypot_function > > hypot(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4112
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_y1_function > > y1(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4103
__gmp_expr< mpfr_t, mpfr_t > mpfr_class
Definition gmpfrxx.h:2446
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_cos_function > > cos(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4069
__gmp_expr< typename __gmp_resolve_expr< T, V >::value_type, __gmp_binary_expr< __gmp_expr< T, U >, __gmp_expr< V, W >, __gmp_max_function > > max(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4110
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_sin_function > > sin(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4070
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_sqrt_function > > sqrt(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4058
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_abs_function > > abs(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4051
__gmp_expr< typename __gmp_resolve_expr< T, V >::value_type, __gmp_binary_expr< __gmp_expr< T, U >, __gmp_expr< V, W >, __gmp_atan2_function > > atan2(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4078
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_atan_function > > atan(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4077
__gmp_expr< typename __gmp_resolve_expr< T, V >::value_type, __gmp_binary_expr< __gmp_expr< T, U >, __gmp_expr< V, W >, __gmp_min_function > > min(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4111
static mpfr_t y
Definition mpfr_mul_d.c:3
DynList< T > maps(const C &c, Op op)
Classic map operation.
STL namespace.
mpq_class Geom_Number
Numeric type used by the geometry module.
Definition point.H:68
constexpr double PI
Definition point.H:85
const Point NullPoint
Definition point.C:41
constexpr double PI_2
Definition point.H:86
Geom_Number pitag(const Geom_Number &x, const Geom_Number &y)
Return the Euclidean distance.
Definition point.H:104
constexpr double PI_4
Definition point.H:87
Geom_Number arctan2(const Geom_Number &m, const Geom_Number &n)
Two-argument arc tangent (wrapper over mpfr).
Definition point.H:116
double geom_number_to_double(const Geom_Number &n)
Definition point.H:70
Geom_Number arctan(const Geom_Number &m)
Arc tangent of m (wrapper over mpfr).
Definition point.H:110
std::ostream & operator<<(std::ostream &o, const Geom_Number &n)
Definition point.H:75
Geom_Number square_root(const Geom_Number &x)
Square root of x (wrapper over mpfr).
Definition point.H:134
Geom_Number cosinus(const Geom_Number &x)
Cosine of x (wrapper over mpfr).
Definition point.H:128
Geom_Number sinus(const Geom_Number &x)
Sine of x (wrapper over mpfr).
Definition point.H:122
size_t aproximate_string_size(const std::string &str)
Definition point.H:1489
Geom_Number area_of_parallelogram(const Point &a, const Point &b, const Point &c)
Compute the area of parallelogram defined by vectors a->b and b->c.
Definition point.H:1577
virtual ~Geom_Object()=default
Geom_Object()=default
DynList< int > l