Aleph-w  1.9
General library for algorithms and data structures
point.H
1 
2 /* Aleph-w
3 
4  / \ | | ___ _ __ | |__ __ __
5  / _ \ | |/ _ \ '_ \| '_ \ ____\ \ /\ / / Data structures & Algorithms
6  / ___ \| | __/ |_) | | | |_____\ V V / version 1.9b
7  /_/ \_\_|\___| .__/|_| |_| \_/\_/ https://github.com/lrleon/Aleph-w
8  |_|
9 
10  This file is part of Aleph-w library
11 
12  Copyright (c) 2002-2018 Leandro Rabindranath Leon & Alejandro Mujica
13 
14  This program is free software: you can redistribute it and/or modify
15  it under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  This program is distributed in the hope that it will be useful, but
20  WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22  General Public License for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with this program. If not, see <https://www.gnu.org/licenses/>.
26 */
27 # ifndef POINT_H
28 # define POINT_H
29 
30 # include <cmath>
31 
32 # include <cstddef>
33 # include <limits>
34 
35 # include <iomanip>
36 # include <string>
37 
38 # include <ahAssert.H>
39 # include <ahUtils.H>
40 
41 # include <gmpfrxx.h>
42 
43 typedef mpq_class Geom_Number;
44 
45 inline double geom_number_to_double(const Geom_Number & n)
46 {
47  return n.get_d();
48 }
49 
50 inline std::ostream & operator << (std::ostream & o, const Geom_Number & n)
51 {
52  o << n.get_d();
53  return o;
54 }
55 
56 // TODO: rotación de figuras especiales como la elipse mediante
57 // rotación del eje cartesiano
58 
59 
60 const double PI = 3.1415926535897932384626433832795028841971693993751;
61 const double PI_2 = PI/2;
62 const double PI_4 = PI_2/2.0;
63 
64 
65 class Point;
66 class Polar_Point;
67 class Segment;
68 class Triangle;
69 class Ellipse;
70 
71 
73 inline Geom_Number
74 area_of_parallelogram(const Point & a, const Point & b, const Point & c);
75 
76 
78 inline Geom_Number pitag(const Geom_Number & x, const Geom_Number & y)
79 {
80  return hypot(mpfr_class(x), mpfr_class(y));
81 }
82 
83 inline Geom_Number arctan(const Geom_Number & m)
84 {
85  return atan(mpfr_class(m));
86 }
87 
88 inline Geom_Number arctan2(const Geom_Number & m, const Geom_Number & n)
89 {
90  return atan2(mpfr_class(m), mpfr_class(n));
91 }
92 
93 inline Geom_Number sinus(const Geom_Number & x)
94 {
95  return sin(mpfr_class(x));
96 }
97 
98 inline Geom_Number cosinus(const Geom_Number & x)
99 {
100  return cos(mpfr_class(x));
101 }
102 
103 inline Geom_Number square_root(const Geom_Number & x)
104 {
105  return sqrt(mpfr_class(x));
106 }
107 
108 struct Geom_Object
109 {
110  Geom_Object(const Geom_Object & ) { /* empty */ }
111 
112  Geom_Object() { /* empty */ }
113 
114  virtual ~Geom_Object() { /* empty */ }
115 };
116 
124 class Point : public Geom_Object
125 {
126  friend class Segment;
127  friend class Triangle;
128  friend class Polar_Point;
129 
130  Geom_Number x;
131  Geom_Number y;
132 
133 public:
134 
135  Point() : Geom_Object(), x(0), y(0) { /* empty */ }
136 
138  Point(const Geom_Number & __x, const Geom_Number & __y)
139  : Geom_Object(), x(__x), y(__y)
140  {
141  // empty
142  }
143 
145  Point(const Point & p) : Geom_Object(*this), x(p.x), y(p.y)
146  {
147  // empty
148  }
149 
151  inline Point(const Polar_Point & pp);
152 
153  bool operator == (const Point & point) const
154  {
155  return x == point.x and y == point.y;
156  }
157 
158  bool operator != (const Point & point) const
159  {
160  return not (*this == point);
161  }
162 
163  Point operator + (const Point & p) const
164  {
165  return Point(x + p.x, y + p.y);
166  }
167 
168  Point & operator += (const Point & p)
169  {
170  x += p.x;
171  y += p.y;
172 
173  return *this;
174  }
175 
176  Point operator - (const Point & p) const
177  {
178  return Point(x - p.x, y - p.y);
179  }
180 
181  Point & operator -= (const Point & p)
182  {
183  x -= p.x;
184  y -= p.y;
185 
186  return *this;
187  }
188 
189  const Geom_Number & get_x() const
190  {
191  return x;
192  }
193 
194  const Geom_Number & get_y() const
195  {
196  return y;
197  }
198 
200  bool is_colinear_with(const Point & p1, const Point & p2) const
201  {
202  return area_of_parallelogram(*this, p1, p2) == 0;
203  }
204 
206  inline bool is_colinear_with(const Segment & s) const;
207 
209  bool is_to_left_from(const Point & p1, const Point & p2) const
210  {
211  return area_of_parallelogram(p1, p2, *this) > 0;
212  }
213 
215  bool is_to_right_from(const Point & p1, const Point & p2) const
216  {
217  return area_of_parallelogram(p1, p2, *this) < 0;
218  }
219 
221  bool is_to_left_on_from(const Point & p1, const Point & p2) const
222  {
223  return not is_to_right_from(p1, p2);
224  }
225 
227  bool is_to_right_on_from(const Point & p1, const Point & p2) const
228  {
229  return not is_to_left_from(p1, p2);
230  }
231 
233  bool is_clockwise_with(const Point & p1, const Point & p2) const
234  {
235  return area_of_parallelogram(*this, p1, p2) < 0;
236  }
237 
238  inline bool is_to_left_from(const Segment & s) const;
239 
240  inline bool is_to_right_from(const Segment & s) const;
241 
242  inline bool is_clockwise_with(const Segment & s) const;
243 
245  bool is_between(const Point & p1, const Point & p2) const
246  {
247  if (not this->is_colinear_with(p1, p2))
248  return false;
249 
250  if (p1.get_x() == p2.get_x())
251  return ((p1.get_y() <= this->get_y()) and (this->get_y() <= p2.get_y()))
252  or ((p1.get_y() >= this->get_y()) and (this->get_y() >= p2.get_y()));
253 
254  return ((p1.get_x() <= this->get_x()) and (this->get_x() <= p2.get_x()))
255  or ((p1.get_x() >= this->get_x()) and (this->get_x() >= p2.get_x()));
256  }
257 
259  const Point & nearest_point(const Point & p1, const Point & p2) const
260  {
261  return this->distance_with(p1) < this->distance_with(p2) ? p1 : p2;
262  }
263 
265  inline bool is_inside(const Segment & s) const;
266 
268  inline bool is_inside(const Ellipse & e) const;
269 
271  inline bool intersects_with(const Ellipse & e) const;
272 
274  std::string to_string() const
275  {
276  return "(" + std::to_string(geom_number_to_double(x)) + "," +
277  std::to_string(geom_number_to_double(y)) + ")";
278  }
279 
281  operator std::string () const { return to_string(); }
282 
284  inline Geom_Number distance_squared_to(const Point & that) const;
285 
287  inline Geom_Number distance_with(const Point & p) const;
288 
289  const Point & highest_point() const { return *this; }
290 
291  const Point & lowest_point() const { return *this; }
292 
293  const Point & leftmost_point() const { return *this; }
294 
295  const Point & rightmost_point() const { return *this; }
296 };
297 
298 extern const Point NullPoint;
299 
300 
308 class Polar_Point : public Geom_Object
309 {
310  friend class Point;
311 
312  Geom_Number r;
313  Geom_Number theta;
314 
315 public:
316 
318  const Geom_Number & get_r() const { return r; }
319 
321  const Geom_Number & get_theta() const { return theta; }
322 
323  Polar_Point(const Geom_Number & __r, const Geom_Number & __theta)
324  : r(__r), theta(__theta)
325  {
326  // empty
327  }
328 
330  Polar_Point(const Point & p) : Geom_Object(p)
331  {
332  const Geom_Number & x = p.x;
333  const Geom_Number & y = p.y;
334 
335  r = pitag(x, y); // radio se determima por Pitágoras
336 
337  // ahora determinamos el angulo según signos
338 
339  if (x == 0) // ¿ningún angulo?
340  {
341  theta = y >= 0 ? PI/2 : 3*PI/2;
342 
343  return;
344  }
345 
346  if (y == 0) // ¡PI/2 (90 grados)?
347  {
348  theta = x >= 0 ? 0 : PI;
349 
350  return;
351  }
352 
353  theta = arctan(y/x);
354 
355  if (x > 0 and y > 0) // ¿1er cuadrante?
356  return;
357 
358  if (x < 0) // ¿2do o 3er cuadrante?
359  r = -r;
360  }
361 
363  enum Quadrant { First, Second, Third, Fourth };
364 
367  {
368  if (r > 0 and theta > 0)
369  return First;
370 
371  if (r > 0)
372  return Fourth;
373 
374  if (theta > 0)
375  return Third;
376 
377  return Second;
378  }
379 
381  std::string to_string() const
382  {
383  return "[" + std::to_string(geom_number_to_double(r)) + "," +
384  std::to_string(geom_number_to_double(theta)) + "]";
385  }
386 
387  Polar_Point() : r(0), theta(0) { /* empty */ }
388 };
389 
390 
391  inline
392 Point::Point(const Polar_Point & pp)
393  : x(pp.r * cosinus(pp.theta)), y(pp.r * sinus(pp.theta))
394 {
395  // empty
396 }
397 
398 
403 class Segment : public Geom_Object
404 {
405  friend class Point;
406  friend class Triangle;
407 
408  Point src, tgt;
409 
410  double compute_slope() const
411  {
412  if (tgt.x == src.x)
413  {
414  if (src.y < tgt.y )
415  return std::numeric_limits<double>::max();
416  else
417  return - std::numeric_limits<double>::max();
418  }
419 
420  const Geom_Number __slope = (tgt.y - src.y) / (tgt.x - src.x);
421 
422  return __slope.get_d();
423  }
424 
425 public:
426 
427  bool operator == (const Segment & s) const
428  {
429  return src == s.src and tgt == s.tgt;
430  }
431 
432  bool operator != (const Segment & s) const
433  {
434  return not (*this == s);
435  }
436 
437  const Point & highest_point() const
438  {
439  return src.y > tgt.y ? src : tgt;
440  }
441 
442  const Point & lowest_point() const
443  {
444  return src.y < tgt.y ? src : tgt;
445  }
446 
447  const Point & leftmost_point() const
448  {
449  return src.x < tgt.x ? src : tgt;
450  }
451 
452  const Point & rightmost_point() const
453  {
454  return src.x > tgt.x ? src : tgt;
455  }
456 
457  const Point & get_src_point() const { return src; }
458 
459  const Point & get_tgt_point() const { return tgt; }
460 
461  Segment() { /* empty */ }
462 
463  Segment(const Segment & s)
464  : Geom_Object(), src(s.src), tgt(s.tgt)
465  {
466  // empty
467  }
468 
469  Segment(const Point & __src, const Point & __tgt)
470  : Geom_Object(), src(__src), tgt(__tgt)
471  {
472  // empty
473  }
474 
475 private:
476 
488  static
489  Point compute_tgt_point(const Point & __src, // punto de origen
490  const Geom_Number & m, // pendiente
491  const Geom_Number & d) // longitud segmento
492  {
493  const Geom_Number den2 = 1 + m*m;
494 
495  const Geom_Number den = square_root(den2);
496 
497  const Geom_Number x = __src.x + d/den;
498 
499  const Geom_Number y = __src.y + d*m/den;
500 
501  return Point(x, y);
502  }
503 
504 public:
505 
517  Segment(const Point & __src, // punto de origen
518  const Geom_Number & m, // pendiente
519  const Geom_Number & l) // longitud de la recta
520  : Geom_Object(), src(__src), tgt(compute_tgt_point(src, m, l))
521  {
522  // empty
523  }
524 
526  Segment(const Segment & sg, const Geom_Number & dist)
527  {
528  const Segment perp = sg.mid_perpendicular(dist);
529 
530  const Point mid_point = sg.mid_point();
531 
532  const Point diff_point = mid_point - perp.get_src_point();
533 
534  src = sg.get_src_point() + diff_point;
535  tgt = sg.get_tgt_point() + diff_point;
536  }
537 
538  double slope() const
539  {
540  return compute_slope();
541  }
542 
544  double counterclockwise_angle_with(const Segment & s) const
545  {
546  Geom_Number x1 = tgt.x - src.x;
547  Geom_Number x2 = s.tgt.x - s.src.x;
548  Geom_Number y1 = tgt.y - src.y;
549  Geom_Number y2 = s.tgt.y - s.src.y;
550  Geom_Number dot = x1 * x2 + y1 * y2;
551  Geom_Number det = x1 * y2 - y1 * x2;
552 
553  Geom_Number angle = arctan2(det, dot);
554 
555  if (angle == 0)
556  return 0;
557 
558  if (angle < 0)
559  return -angle.get_d();
560 
561  return 2 * PI - angle.get_d();
562  }
563 
565  double counterclockwise_angle() const
566  {
567  Segment x_axis(Point(0, 0), Point(1, 0));
568  return counterclockwise_angle_with(x_axis);
569  }
570 
571  // retorna la longitud del segmento; es decir la distancia
572  // euclidiana entre los puntos origen y destino
573  Geom_Number size() const
574  {
575  return pitag(tgt.x - src.x, tgt.y - src.y);
576  }
577 
578  // retorna true si p es colineal al segmento this
579  bool is_colinear_with(const Point & p) const
580  {
581  return p.is_colinear_with(src, tgt);
582  }
583 
584  // retorna true si segmento this está a la izquierda de punto p
585  bool is_to_left_from(const Point & p) const
586  {
587  return p.is_to_right_from(*this);
588  }
589 
590  // retorna true si segmento this está a la derecha del punto p
591  bool is_to_right_from(const Point & p) const
592  {
593  return p.is_to_left_from(*this);
594  }
595 
596  // retorna el punto medio del segmento this
597  Point mid_point() const
598  {
599  const Geom_Number x = (src.get_x() + tgt.get_x()) / 2;
600  const Geom_Number y = (src.get_y() + tgt.get_y()) / 2;
601 
602  return Point(x, y);
603  }
604 
605 
606  // retorna el punto más cercano al punto p entre y los extremos del
607  // segmento this
608  const Point & nearest_point(const Point & p) const
609  {
610  return p.nearest_point(get_src_point(), get_tgt_point());
611  }
612 
613  // Construye un segmento perpendicular a this que pase por el punto p.
614  Segment get_perpendicular(const Point & p) const
615  {
616  if (src == tgt)
617  return *this;
618 
619  /* Si la pendiente es cero, construyo un segmento vertical que comience
620  en la componente x de p y componente y de cualquier extremo del segmento
621  y que termine en p.
622  */
623  if (src.get_y() == tgt.get_y())
624  return Segment(Point(p.get_x(), src.get_y()), p);
625 
626  // Si this es vertical, entonces construyo un segmento horizontal.
627  if (src.get_x() == tgt.get_x())
628  return Segment(Point(src.get_x(), p.get_y()), p);
629 
630  Geom_Number m1 = Geom_Number(slope());
631 
632  // Calculo la pendiente del nuevo segmento
633  Geom_Number m2 = -Geom_Number(1.0) / m1;
634 
635  /* Con esta información calculo el punto de intersección de las rectas
636  formadas por ambos segmentos.
637  */
638  const Geom_Number & x1 = src.get_x();
639  const Geom_Number & y1 = src.get_y();
640  const Geom_Number & x2 = p.get_x();
641  const Geom_Number & y2 = p.get_y();
642 
643  Geom_Number x = (y2 - y1 + m1 * x1 - m2 * x2) / (m1 - m2);
644  Geom_Number y = m1 * (x - x1) + y1;
645 
646  // El nuevo segmento comienza en la intersección y termina en p
647  return Segment(Point(x, y), p);
648  }
649 
650  // retorna el segmento perpendicular que cruza por el punto medio
651  // del segmento this de longitud 2*dist. Los puntos origen y
652  // destino del segmento resultante conforman los punto
653  // perpendiculares a distancia dist del centro del segmento this
654  Segment mid_perpendicular(const Geom_Number & dist) const
655  {
656  // llevamos punto destino del segmento al origen y luego lo
657  // transformamos a coordenadas polares
658  const Polar_Point tgt_polar(tgt - src);
659 
660  // arco del segmento this respecto a la horizontal
661  const Geom_Number arc_tgt_src = tgt_polar.get_theta();
662 
663  // arco del punto perpendicular entre segmentos this y
664  // src--perp, donde perp es el punto resultado
665  Geom_Number arc_perp_pt = arctan(dist/(tgt_polar.get_r()/2));
666 
667  const Geom_Number mperp = dist/(tgt_polar.get_r()/2);
668 
669  // distancia entre src y perp
670  Geom_Number perp_r = pitag(dist, tgt_polar.get_r()/2);
671 
672  if (tgt_polar.get_r() < 0)
673  perp_r = - perp_r; // si el radio es negativo ==> el radio del
674  // punto medio también lo es
675 
676  if (tgt_polar.get_theta() < 0)
677  arc_perp_pt = - arc_perp_pt; // si el angulo es negativo ==> el
678  // radio del punto medio también lo es
679 
680  // punto perpendicular a la izquierda del segmento this y
681  // respecto a src (en coordenada polar)
682  const Polar_Point polar_perp_pt_l(perp_r, arc_tgt_src + arc_perp_pt);
683 
684  // punto perpendicular a la derecha del segmento this y respecto
685  // a src (en coordenada polar)
686  const Polar_Point polar_perp_pt_r(perp_r, arc_tgt_src - arc_perp_pt);
687 
688  // determine los puntos en coordenadas rectangulares
689  const Point p1(Point(polar_perp_pt_l) + src);
690  const Point p2(Point(polar_perp_pt_r) + src);
691 
692  // segmento resultado debe ir en sentido antihorario respecto al
693  // segmento this
694  if (p1.is_to_right_from(*this))
695  return Segment(p1, p2);
696  else
697  return Segment(p2, p1);
698  }
699 
700  // retorna true si hay intersección propia entre los segmentos.
701  //
702  // Una intersección propia es cuando el punto de intersección está
703  // contenido en los segmentos
704  bool intersects_properly_with(const Segment & s) const
705  {
706  // verifica las 4 combinaciones posibles de colinealidad
707  if (src.is_colinear_with(s) or tgt.is_colinear_with(s) or
708  s.src.is_colinear_with(*this) or s.tgt.is_colinear_with(*this))
709  return false;
710 
711  // Hay intersección si, para cada segmento, un punto está a la
712  // izquierda y el otro a la derecha
713  return ((src.is_to_left_from(s) xor tgt.is_to_left_from(s)) and
714  (s.src.is_to_left_from(*this) xor s.tgt.is_to_left_from(*this)));
715  }
716 
717  // retorna true si p está contenido en el segmento this
718  bool contains_to(const Point & p) const
719  {
720  return p.is_between(src, tgt);
721  }
722 
723  // retorna true si s está contenido en el segmento this
724  bool contains_to(const Segment & s) const
725  {
726  return (s.get_src_point().is_between(src, tgt) and
727  s.get_tgt_point().is_between(src, tgt));
728  }
729 
730  // retorna true si s intersecta con segmento this
731  bool intersects_with(const Segment & s) const
732  {
733  if (this->intersects_properly_with(s))
734  return true;
735 
736  // si no hay intersección propia ==> verificamos si alguno de los
737  // puntos del segmento está contenido en el otro
738 
739  return (this->contains_to(s.src) or this->contains_to(s.tgt) or
740  s.contains_to(this->src) or s.contains_to(this->tgt));
741  }
742 
743  // retorna true si segmento this intersecta con triangulo t
744  inline bool intersects_with(const Triangle & t) const;
745 
746  // retorna true si segmento this intersecta con elipse e
747  inline bool intersects_with(const Ellipse & e) const;
748 
749  // retorna true si segmento this es paralelo a segmento s
750  bool is_parallel_with(const Segment & s) const
751  {
752  return slope() == s.slope();
753  }
754 
755  /*
756  Calcula la intersección de dos segmentos
757 
758  Se se sirve de las ecuaciones punto y pendiente
759 
760  y - y1 = m1 (x - x1) ((x1,y1) = this->src , m1 = this->slope())
761  y - y2 = m2 (x - x2) ((x1,y1) = s->src , m2 = s_slope())
762  */
763  Point intersection_with(const Segment & s) const
764  {
765  if (this->is_parallel_with(s))
766  throw std::domain_error("Segments are parallels");
767 
768  const Geom_Number & x1 = this->src.x;
769  const Geom_Number & y1 = this->src.y;
770 
771  const Geom_Number & x2 = s.src.x;
772  const Geom_Number & y2 = s.src.y;
773 
774  const Geom_Number & m1 = this->slope();
775  const Geom_Number & m2 = s.slope();
776 
777  const Geom_Number x = (y2 - y1 + m1*x1 - m2*x2) / (m1 - m2);
778 
779  const Geom_Number y = m1*(x - x1) + y1;
780 
781  return Point(x, y);
782  }
783 
784  // TODO: este cálculo debe pasar a coordenadas polares
785 
786  // sentidos cardinales de dirección de un segmento
787  enum Sense { E, NE, N, NW, W, S, SW, SE };
788 
789  Sense sense() const
790  {
791  if (src.x < tgt.x) // ¿está hacia el este?
792  {
793  if (src.y < tgt.y) // ¿está al norte?
794  return NE;
795  else if (src.y > tgt.y) // ¿está al sur?
796  return SE;
797  else
798  return E;
799  }
800 
801  if (src.x > tgt.x) // ¿está hacia el oeste?
802  {
803  if (src.y < tgt.y) // ¿está al norte?
804  return NW;
805  else if (src.y > tgt.y) // ¿está al sur?
806  return SW;
807  else return W;
808  }
809 
810  // en este punto el segmento es con certitud vertical
811 
812  return src.y > tgt.y ? N : S;
813  }
814 
815  // aumenta la distancia del segmento en __dist desde el punto origen
816  void enlarge_src(const Geom_Number & __dist)
817  {
818  const double m = slope();
819 
820  Point p = compute_tgt_point(src, m, - __dist);
821 
822  const Segment s(p, src);
823 
824  if (s.size() < __dist)
825  p = compute_tgt_point(src, m, __dist);
826 
827  src = p;
828  }
829 
830  // aumenta la distancia del segmento en __dist desde el punto destino
831  void enlarge_tgt(const Geom_Number & __dist)
832  {
833  const double m = slope();
834 
835  Point p = compute_tgt_point(tgt, m, __dist);
836 
837  Segment s(tgt, p);
838 
839  if (s.size() < __dist)
840  p = compute_tgt_point(tgt, m, - __dist);
841 
842  tgt = p;
843  }
844 
845  // construye un string de la forma "(src)(tgt)"
846  std::string to_string() const
847  {
848  return src.to_string() + tgt.to_string();
849  }
850 
851  // convierte el segmento a un string de la forma "(src)(tgt)"
852  operator std::string () const
853  {
854  return to_string();
855  }
856 
857  // gira el segmento en ángulo angle alrededor del punto origen
858  // manteniendo la misma longitud del segmento; lo que implica que
859  // el punto destino tgt cambia
860  /*
861  Procedimiento
862 
863  1) Normalizar el segmento al origen ==> tgt - src
864 
865  2) Tranformar tgt a coordenada polar ptgt
866 
867  3) El nuevo ptgt es la coordenada polar del punto con angulo sumado
868  en angle; es decir ptgt Polar_Point(r, theta + angle)
869 
870  4) Llevar ptgt a coordenadas rectangulares tgt
871 
872  5) El resultado es tgt + src
873  */
874  void rotate(const double & angle)
875  {
876  if (angle == 0)
877  return;
878 
879  const Polar_Point ptgt(tgt - src); // tgt en coordenadas polares
880 
881  // lo desplazamos en angle radianes
882  tgt = Polar_Point(ptgt.get_r(), ptgt.get_theta() + angle);
883 
884  tgt = tgt + src; // lo regresamos al punto de referencia src (el polo)
885  }
886 
887  // retorna el segmento intersección con el triangulo t (si existe)
888  inline Segment intersection_with(const Triangle & t) const;
889 
890  // retorna el segmento intersección con la elipse e (si existe)
891  inline Segment intersection_with(const Ellipse & e) const;
892 };
893 
894  // retorna true si this está contenido en el segmento this
895 inline bool Point::is_inside(const Segment & s) const
896 {
897  return s.contains_to(*this);
898 }
899 
900  // retorna true si el punto this es colineal con el segmento s
901 inline bool Point::is_colinear_with(const Segment & s) const
902 {
903  return this->is_colinear_with(s.src, s.tgt);
904 }
905 
906  // retorna true si el punto this está a la izquierda del segmento s
907 inline bool Point::is_to_left_from(const Segment & s) const
908 {
909  return this->is_to_left_from(s.src, s.tgt);
910 }
911 
912  // retorna true si el punto this está a la derecha del segmento s
913 inline bool Point::is_to_right_from(const Segment & s) const
914 {
915  return this->is_to_right_from(s.src, s.tgt);
916 }
917 
918  // retorna true si la secuencia this--s está en sentido horario
919 inline bool Point::is_clockwise_with(const Segment & s) const
920 {
921  return this->is_clockwise_with(s.src, s.tgt);
922 }
923 
924 
925 
926  // retorna la distancia euclidiana entre el punto this y el punto p
927 inline Geom_Number Point::distance_squared_to(const Point & that) const
928 {
929  Geom_Number dx = this->x - that.x;
930  Geom_Number dy = this->y - that.y;
931  return dx*dx + dy*dy;
932 }
933 
934 
935  // retorna la distancia euclidiana entre el punto this y el punto p
936 inline Geom_Number Point::distance_with(const Point & p) const
937 {
938  const Segment seg(*this, p);
939 
940  return seg.size();
941 }
942 
943 
944 /*****************************************************************
945 
946  Clase fundamental triangulo
947 
948  La idea de esta clase es servir como objeto de uso básico en los
949  algoritmos de triangulización de polígonos
950  */
951 class Triangle : public Geom_Object
952 {
953  friend class Point;
954  friend class Segment;
955 
956  Point p1, p2, p3;
957 
958  Geom_Number __area;
959 
960 public:
961 
962  Triangle(const Point & __p1, const Point & __p2, const Point & __p3)
963  : p1(__p1), p2(__p2), p3(__p3)
964  {
965  __area = area_of_parallelogram(p1, p2, p3)/2;
966 
967  if (__area == 0)
968  throw std::domain_error("The three points of triangle are colinears");
969  }
970 
971  Triangle(const Point & p, const Segment & s)
972  : p1(p), p2(s.src), p3(s.tgt)
973  {
974  __area = area_of_parallelogram(p1, p2, p3)/2;
975 
976  if (__area == 0)
977  throw std::domain_error("The three points of triangle are colinears");
978  }
979 
980  Triangle(const Segment & s, const Point & p)
981  : p1(s.src), p2(s.tgt), p3(p)
982  {
983  __area = area_of_parallelogram(p1, p2, p3)/2;
984 
985  if (__area == 0)
986  throw std::domain_error("The three points of triangle are colinears");
987  }
988 
989  Geom_Number area() const
990  {
991  return abs(__area);
992  }
993 
994  // retorna true si los vértices del triangulo están en sentido horario
995  bool is_clockwise() const
996  {
997  return __area >= 0;
998  }
999 
1000  const Point & highest_point() const
1001  {
1002  const Point & max = p1.y > p2.y ? p1 : p2;
1003 
1004  return p3.y > max.y ? p3 : max;
1005  }
1006 
1007  const Point & lowest_point() const
1008  {
1009  const Point & min = p1.y < p2.y ? p1 : p2;
1010 
1011  return p3.y < min.y ? p3 : min;
1012  }
1013 
1014  const Point & leftmost_point() const
1015  {
1016  const Point & min = p1.x < p2.x ? p1 : p2;
1017 
1018  return p3.x < min.x ? p3 : min;
1019  }
1020 
1021  const Point & rightmost_point() const
1022  {
1023  const Point & max = p1.x > p2.x ? p1 : p2;
1024 
1025  return p3.x > max.x ? p3 : max;
1026  }
1027 
1028  const Point & get_p1() const { return p1; }
1029 
1030  const Point & get_p2() const { return p2; }
1031 
1032  const Point & get_p3() const { return p3; }
1033 
1034  // retorna true si el punto p está contenido dentro del triángulo
1035  bool contains_to(const Point & p) const
1036  {
1037  const bool s = p.is_to_left_from(p1, p2);
1038 
1039  if (p.is_to_left_from(p2, p3) != s)
1040  return false;
1041 
1042  if (p.is_to_left_from(p3, p1) != s)
1043  return false;
1044 
1045  return true;
1046  }
1047 
1048  // retorna el segmento "intersección" del triangulo con el segmento s
1049  Segment intersection_wih(const Segment & s) const
1050  {
1051  return s.intersection_with(*this);
1052  }
1053 };
1054 
1055 class Rectangle
1056 {
1057  Geom_Number xmin, ymin;
1058  Geom_Number xmax, ymax;
1059 
1060 public:
1061 
1062  const Geom_Number & get_xmin() const { return xmin; }
1063 
1064  const Geom_Number & get_ymin() const { return ymin; }
1065 
1066  const Geom_Number & get_xmax() const { return xmax; }
1067 
1068  const Geom_Number & get_ymax() const { return ymax; }
1069 
1070  Rectangle() : xmin(0), ymin(0), xmax(0), ymax(0)
1071  {
1072  // empty
1073  }
1074 
1075  Rectangle(const Geom_Number & __xmin, const Geom_Number & __ymin,
1076  const Geom_Number & __xmax, const Geom_Number & __ymax)
1077  : xmin(__xmin), ymin(__ymin), xmax(__xmax), ymax(__ymax)
1078  {
1079  if (xmax < xmin || ymax < ymin)
1080  throw std::range_error("Invalid rectangle");
1081  }
1082 
1083  void set_rect(const Geom_Number & xmin, const Geom_Number & ymin,
1084  const Geom_Number & xmax, const Geom_Number & ymax)
1085  {
1086  new (this) Rectangle(xmin, ymin, xmax, ymax);
1087  }
1088 
1089  Geom_Number width() { return xmax - xmin; }
1090 
1091  Geom_Number height() { return ymax - ymin; }
1092 
1093  // does this axis-aligned rectangle intersect that one?
1094  bool intersects(const Rectangle & that)
1095  {
1096  return this->xmax >= that.xmin and this->ymax >= that.ymin and
1097  that.xmax >= this->xmin and that.ymax >= this->ymin;
1098  }
1099 
1100  Geom_Number distance_squared_to(const Point & p)
1101  {
1102  Geom_Number dx = 0.0, dy = 0.0;
1103  if (p.get_x() < xmin)
1104  dx = p.get_x() - xmin;
1105  else if (p.get_x() > xmax)
1106  dx = p.get_x() - xmax;
1107 
1108  if (p.get_y() < ymin)
1109  dy = p.get_y() - ymin;
1110  else if (p.get_y() > ymax)
1111  dy = p.get_y() - ymax;
1112 
1113  return dx*dx + dy*dy;
1114  }
1115 
1116  // distance from p to closest point on this axis-aligned rectangle
1117  Geom_Number distance_to(const Point & p)
1118  {
1119  return sqrt(mpfr_class(distance_squared_to(p)));
1120  }
1121 
1122  // does this axis-aligned rectangle contain p?
1123  bool contains(const Point & p) const
1124  {
1125  return p.get_x() >= xmin and p.get_x() <= xmax and
1126  p.get_y() >= ymin and p.get_y() <= ymax;
1127  }
1128 
1129 
1130 };
1131 
1132  // retorna true si el segmento this intersecta con uno o dos lados del
1133  // triangulo t
1134 inline bool Segment::intersects_with(const Triangle & t) const
1135 {
1136  return (this->intersects_with(Segment(t.get_p1(), t.get_p2())) or
1137  this->intersects_with(Segment(t.get_p2(), t.get_p3())) or
1138  this->intersects_with(Segment(t.get_p3(), t.get_p1())));
1139 }
1140 
1141 
1142  // retotrna el segmento resultante de la intersección del segmento this
1143  // con el triangulo t. Note que si un punto del segmento this está
1144  // dentro del triangulo, entonces la intersección es un punto ==>
1145  // este método podría usarse para determinar si un punto está o no
1146  // dentro del triangulo
1147 inline Segment Segment::intersection_with(const Triangle & t) const
1148 {
1149  if (not this->intersects_with(t))
1150  throw std::domain_error("segment does not intersects with triangle");
1151 
1152  Point p[2];
1153 
1154  int i = 0;
1155 
1156  try
1157  { // revisa si hay intersección con el lado p1-p2
1158  p[i] = this->intersection_with(Segment(t.get_p1(), t.get_p2()));
1159 
1160  if (t.contains_to(p[i]))
1161  ++i; // intersección detectada
1162  }
1163  catch (std::domain_error)
1164  {
1165  // No hay intersección con el segmento anterior. Proseguimos ...
1166  }
1167 
1168  try
1169  { // revisa si hay intersección con el lado p2-p3
1170  p[i] = this->intersection_with(Segment(t.get_p2(), t.get_p3()));
1171 
1172  if (t.contains_to(p[i]))
1173  ++i;// intersección detectada
1174  }
1175  catch (std::domain_error)
1176  {
1177  // No hay intersección con el segmento anterior. Proseguimos ...
1178  }
1179 
1180  if (i == 2) // si ya tenemos dos puntos de intersección ==> ya no
1181  // queda más que hacer sino retornar el segmento
1182  return Segment(p[0], p[1]);
1183 
1184  try
1185  { // revisa si hay intersección con el lado p3-p1
1186  p[i] = this->intersection_with(Segment(t.get_p3(), t.get_p1()));
1187  }
1188  catch (std::domain_error)
1189  {
1190  throw; // algo serio debe ocurrir si hay excepción aquí. Esto es
1191  // un bug pues previamente se preguntó
1192  }
1193 
1194  // el resultado depende de la cantidad de puntos de intersección que
1195  // tengamos
1196  return i == 1 ? Segment(p[0], p[0]) : Segment(p[0], p[1]);
1197 }
1198 
1199 
1200 /*****************************************************************
1201 
1202  Clase fundamental Elipse
1203 
1204  */
1205 class Ellipse : public Geom_Object
1206 {
1207  friend class Point;
1208 
1209  /*
1210  Se asume la siguiente ecuación en el centro (xc, yc):
1211 
1212  2 2
1213  (y - yc) (x - xc)
1214  --------- + --------- = 1
1215  2 2
1216  vr hr
1217 
1218  */
1219 
1220  Point center; // punto centro
1221 
1222  Geom_Number hr; // radio horizontal (parámetro a)
1223  Geom_Number vr; // radio vertical (parámetro b)
1224 
1225 public:
1226 
1227  Ellipse(const Point & __center,
1228  const Geom_Number & __hr,
1229  const Geom_Number & __vr)
1230  : center(__center), hr(__hr), vr(__vr)
1231  {
1232  // empty
1233  }
1234 
1235  Ellipse(const Ellipse & e)
1236  : Geom_Object(e), center(e.center), hr(e.hr), vr(e.vr)
1237  {
1238  // empty
1239  }
1240 
1241  Ellipse() { /* empty */ }
1242 
1243  const Point & get_center() const { return center; }
1244 
1245  const Geom_Number & get_hradius() const { return hr; }
1246 
1247  const Geom_Number & get_vradius() const { return vr; }
1248 
1249  bool is_clockwise() const { return false; }
1250 
1251  Point highest_point() const
1252  {
1253  return Point(center.get_x(), center.get_y() + vr);
1254  }
1255 
1256  Point lowest_point() const
1257  {
1258  return Point(center.get_x(), center.get_y() - vr);
1259  }
1260 
1261  Point leftmost_point() const
1262  {
1263  return Point(center.get_x() - hr, center.get_y());
1264  }
1265 
1266  Point rightmost_point() const
1267  {
1268  return Point(center.get_x() + hr, center.get_y());
1269  }
1270 
1271  /* Calcula las tagentes a la elipse this con pendiente m
1272 
1273  Se calcula según ecuación;
1274 
1275  y = m x + sqrt(a^2 m^2 + b^2)
1276 
1277  que es la ecuación de las tangentes de la elipse con centro (0,0).
1278 
1279  La ecuacióon anterior es resultante de igualar la ecuación
1280  simplificada de la elipse en (0,0) y la recta con tangente m. Es
1281  decir, substituir y = mx + y0 en
1282 
1283  2 2
1284  y x
1285  --- + --- = 1
1286  2 2
1287  vr hr
1288 
1289  ATENCIÓN: posibles errores de precisión debido a la irracionalidad
1290 
1291  s1 y s2 son las tangente y m es la pendiente
1292  */
1293  void
1294  compute_tangents(Segment & s1, Segment & s2, const Geom_Number & m) const
1295  {
1296  if (m == 0)
1297  {
1298  s1 = Segment(center + Point(-hr, vr), center + Point(hr, vr));
1299  s2 = Segment(center + Point(-hr, -vr), center + Point(hr, -vr));
1300 
1301  return;
1302  }
1303 
1304  const Geom_Number product = hr*hr*m*m + vr*vr;
1305 
1306  // este es corte de la tangente con la abscisa si la elipse
1307  // estuviese centrada en (0,0)
1308  const Geom_Number y1= square_root(product);
1309 
1310  const Geom_Number x1 = -y1/m;
1311 
1312  // si la elipse está centrada en (0,0) entonces los puntos de las
1313  // tangentes son (0, y1) y (0, -y1). Los puntos reales, respecto a
1314  // la elipse centrada en center se calculan según la recta
1315  // conformada por (0,0)--center
1316 
1317  Segment t1 = Segment(center + Point(x1, 0), center + Point(0, y1));
1318 
1319  Segment t2 = Segment(center + Point(-x1, 0), center + Point(0, -y1));
1320 
1321  // estos segmentos son tangentes a la elipse, pero, según su
1322  // pendiente, éstos podrían ser demasiado grandes. Por tanto,
1323  // para cada segmento, escogeremos el punto que está más cercano
1324  // al centro de la elipse
1325 
1326  // decide el tamaño de la tangente en función del mayor radio
1327  const Geom_Number tangent_size = hr > vr ? hr : vr;
1328 
1329  { // calcula distancias desde el centro hasta los puntos extremo
1330  // de la tangente t1
1331  const Geom_Number dsrc = center.distance_with(t1.get_src_point());
1332  const Geom_Number dtgt = center.distance_with(t1.get_tgt_point());
1333 
1334  if (dsrc < dtgt) // selecciona el punto más cercano al centro
1335  {
1336  s1 = Segment(t1.get_src_point(), m, tangent_size);
1337  s1.enlarge_src(tangent_size);
1338  }
1339  else
1340  {
1341  s1 = Segment(t1.get_tgt_point(), m, tangent_size);
1342  s1.enlarge_tgt(tangent_size);
1343  }
1344  }
1345 
1346  { // calcula distancias desde el centro hasta los puntos extremo
1347  // de la tangente t1
1348  const Geom_Number dsrc = center.distance_with(t2.get_src_point());
1349  const Geom_Number dtgt = center.distance_with(t2.get_tgt_point());
1350 
1351  if (dsrc < dtgt) // selecciona el punto más cercano al centro
1352  {
1353  s2 = Segment(t2.get_src_point(), m, tangent_size);
1354  s2.enlarge_src(tangent_size);
1355  }
1356  else
1357  {
1358  s2 = Segment(t2.get_tgt_point(), m, tangent_size);
1359  s2.enlarge_tgt(tangent_size);
1360  }
1361  }
1362  }
1363 
1364  // retorna true si s intersecta con la elipse
1365  bool intersects_with(const Segment & s) const
1366  {
1367  Segment tg1;
1368  Segment tg2;
1369 
1370  compute_tangents(tg1, tg2, s.slope()); // calcula las dos tangentes
1371 
1372  // existe intersección si s está entre las tangentes de la
1373  // elipse que son paralelas a s
1374  return (s.is_to_left_from(tg1.get_src_point()) xor
1375  s.is_to_left_from(tg2.get_tgt_point()));
1376  }
1377 
1378 private:
1379 
1380  // Calcula el valor de:
1381  //
1382  // (p.x - xc)^2 + (p.y - yc)^2
1383  // ------------ ------------ = 1
1384  // a^2 b^2
1385  //
1386  // lo que permitirá determinar si un punto está o no circunscrito
1387  // por la elipse
1388  Geom_Number compute_radius(const Point & p) const
1389  {
1390  Geom_Number x2 = (p.get_x() - center.get_x());
1391  x2 = x2*x2;
1392 
1393  Geom_Number y2 = (p.get_y() - center.get_y());
1394  y2 = y2*y2;
1395 
1396  return x2/(hr*hr) + y2/(vr*vr);
1397  }
1398 
1399 public:
1400 
1401  // retotrna true si el punto p está contenido dentro de la elipse this
1402  bool contains_to(const Point & p) const
1403  {
1404  return compute_radius(p) <= 1;
1405  }
1406 
1407  // retotrna true si el punto p pertenece exactamente a la curvade
1408  // la elipse this
1409  bool intersects_with(const Point & p) const
1410  {
1411  return compute_radius(p) == 1;
1412  }
1413 
1414  /*
1415  Rutinas de intersección con segmento. Para ello, se resuelve el
1416  sistema de ecuaciones planteado por la ecuación de la elipse
1417 
1418  2 2
1419  y x
1420  eq1 -- + -- = 1
1421  2 2
1422  b a
1423 
1424  y la ecuación de la recta del segmento:
1425 
1426  eq2 y - yr = m*(x - xr)
1427 
1428  Donde (xr,yr) es un punto de la recta transformada al plano del centro
1429  de la elipse
1430 
1431  Lo cual arroja los siguientes puntos (segun maxima
1432  solve([eq1,eq2],[x,y]);)
1433 
1434  2 2 2 2 2 2 2 2 2
1435  a b sqrt(- yr + 2 m xr yr - m xr + a m + b ) + a m yr - a m xr
1436 x1 = - ----------------------------------------------------------------------
1437  2 2 2
1438  a m + b
1439 
1440  2 2 2 2 2 2 2 2
1441  a b m sqrt(- yr + 2 m xr yr - m xr + a m + b ) - b yr + b m xr
1442 y1 = - ----------------------------------------------------------------------
1443  2 2 2
1444  a m + b
1445 
1446  2 2 2 2 2 2 2 2 2
1447  a b sqrt(- yr + 2 m xr yr - m xr + a m + b ) - a m yr + a m xr
1448 x2 = ----------------------------------------------------------------------
1449  2 2 2
1450  a m + b
1451 
1452  2 2 2 2 2 2 2 2
1453  a b m sqrt(- yr + 2 m xr yr - m xr + a m + b ) + b yr - b m xr
1454 y2 = ----------------------------------------------------------------------
1455  2 2 2
1456  a m + b
1457 
1458  Nótese que se presume que el centro de la elipse está en (0,0)
1459 
1460  Para calcular la intersección, la recta se desplaza
1461  proporcionalmente con la distancia del centro de la elipse. Luego
1462  se calculan los puntos de intersección según las ecuaciones
1463  anteriores. Finalmente, el segmento resultante se desplaza a la
1464  posición real de la elipse
1465 
1466  BUG: hay un error. estudiar código generado por graphpic para.
1467  el detalle parece aparecer cuando la recta pasa por centro de
1468  la elipse
1469 
1470  Los puntos intersección con diferentes puntos de la recta, dan
1471  diferentes y deberían dar iguales ¿por qué?
1472  */
1473  Segment intersection_with(const Segment & sg) const
1474  {
1475 
1476  if (not intersects_with(sg))
1477  throw std::domain_error("there is no intersection");
1478 
1479  const Geom_Number & a = hr;
1480  const Geom_Number & b = vr;
1481 
1482  const Geom_Number a2 = a*a;
1483  const Geom_Number b2 = b*b;
1484 
1485  const Geom_Number ab = a*b;
1486 
1487  // segmento desplazado al eje de coordenadas con origen en (xc, yc)
1488  const Segment sg_new(sg.get_src_point() - center,
1489  sg.get_tgt_point() - center);
1490 
1491  const Point pr = sg_new.get_tgt_point();
1492 
1493  const Geom_Number & xr = pr.get_x();
1494  const Geom_Number & yr = pr.get_y();
1495 
1496  const Geom_Number m = sg_new.slope();
1497 
1498  assert(m == sg.slope());
1499 
1500  const Geom_Number m2 = m*m;
1501 
1502  const Geom_Number yr2 = yr*yr;
1503 
1504  const Geom_Number xr2 = xr*xr;
1505 
1506  assert(m2 >= 0 and yr2 >= 0 and xr2 >= 0);
1507 
1508  const Geom_Number a2m2_plus_b2 = a2*m2 + b2;
1509 
1510  Geom_Number ab_root = -yr2 + 2*m*xr*yr -m2*xr2 + a2m2_plus_b2;
1511  ab_root = ab*square_root(ab_root);
1512 
1513  const Geom_Number ab_m_root = m*ab_root;
1514 
1515  const Geom_Number yr_minus_m_xr = yr - m*xr;
1516 
1517  const Geom_Number sumx = a2*m*yr_minus_m_xr;
1518 
1519  const Geom_Number sumy = b2*yr_minus_m_xr;
1520 
1521  // hechas la cuentas principales, calculamos los valores
1522 
1523  const Geom_Number x1 = - (ab_root + sumx) / a2m2_plus_b2;
1524 
1525  const Geom_Number y1 = - (ab_m_root - sumy) / a2m2_plus_b2;
1526 
1527  const Geom_Number x2 = (ab_root - sumx) / a2m2_plus_b2;
1528 
1529  const Geom_Number y2 = (ab_m_root + sumy) / a2m2_plus_b2;
1530 
1531  // como los resultados son para la elipse en (0,0), reajustamos los
1532  // puntos de intersección al centro real de la elipse
1533 
1534  const Point src = Point(x1, y1) + center;
1535  const Point tgt = Point(x2, y2) + center;
1536 
1537  return Segment(src, tgt);
1538  }
1539 };
1540 
1541  // retorna true si el punto this está contenido dentro de la elipse e
1542 inline bool Point::is_inside(const Ellipse & e) const
1543 {
1544  return e.contains_to(*this);
1545 }
1546 
1547  // retorna true si el punto this intersecta exactamente con la elipse e
1548 inline bool Point::intersects_with(const Ellipse & e) const
1549 {
1550  return e.intersects_with(*this);
1551 }
1552 
1553  // retorna true si el segmento this intersecta a la elipse
1554 inline bool Segment::intersects_with(const Ellipse & e) const
1555 {
1556  return e.intersects_with(*this);
1557 }
1558 
1559  // retorna el segmento resultante de los dos puntos de intersección del
1560  // segmento this con la elipse e
1561 inline Segment Segment::intersection_with(const Ellipse & e) const
1562 {
1563  return e.intersection_with(*this);
1564 }
1565 
1566 /*****************************************************************
1567 
1568  Clase fundamental cadena de texto
1569 
1570  Utilizada para escribir cadenas en el plano.
1571 
1572  No usamos offsets porque, en apariencia, desde este primer estadio de
1573  diseño, un offset puede especificarse por el invocante desplazando el
1574  punto
1575 */
1576 
1577  /* Esta rutina calcula un estimado en cantidad de caracteres imprimibles
1578  según que la cadena sea para LateX. Por ejemplo, no se contabilizan '\'
1579  '$' '{' '}' etc.
1580  */
1581 inline size_t aproximate_string_size(const std::string & str)
1582 {
1583  const char * ptr = str.c_str();
1584 
1585  size_t __len = 0;
1586  for (int i = 0; true; /* empty */)
1587  {
1588  switch (ptr[i])
1589  {
1590  case '\\':
1591  // salte todos los caracteres que conforman el comando LateX
1592  for (++i; isalnum(ptr[i]) and ptr[i] != '\0'; /* nothing */)
1593  ++i;
1594  ++__len;
1595  break;
1596 
1597  case '$': case '{': case '}': case '\n':
1598  ++i;
1599  break;
1600 
1601  case '\0':
1602  return __len;
1603 
1604  default:
1605  ++__len; ++i;
1606  break;
1607  }
1608  }
1609 }
1610 
1611 class Text : public Geom_Object
1612 {
1613  Point p;
1614 
1615  std::string str;
1616 
1617  size_t __len;
1618 
1619 public:
1620 
1621  static const double font_width_in_points;
1622 
1623  static const double font_height_in_points;
1624 
1625  Text(const Point & __p, const std::string & __str)
1626  : p(__p), str(__str), __len(aproximate_string_size(__str))
1627  {
1628  // empty
1629  }
1630 
1631  Text() { /* empty */ }
1632 
1633  const size_t & len() const { return __len; }
1634 
1635  const Point & get_point() const
1636  {
1637  return p;
1638  }
1639 
1640  const std::string & get_str() const { return str; }
1641 
1642  Point highest_point() const
1643  {
1644  return p;
1645  }
1646 
1647  Point lowest_point() const
1648  {
1649  return p;
1650  }
1651 
1652  Point leftmost_point() const
1653  {
1654  return p;
1655  }
1656 
1657  Point rightmost_point() const
1658  {
1659  return p;
1660  }
1661 };
1662 
1663  inline Geom_Number
1664 area_of_parallelogram(const Point & a, const Point & b, const Point & c)
1665 {
1666  return ((b.get_x() - a.get_x()) * (c.get_y() - a.get_y()) -
1667  (c.get_x() - a.get_x()) * (b.get_y() - a.get_y()));
1668 }
1669 
1670 
1671 # endif // POINT_H
Geom_Number distance_with(const Point &p) const
Returns the euclidean distance between this and p.
Definition: point.H:936
double counterclockwise_angle() const
Compute the counterclock angle of this respect x-axis.
Definition: point.H:565
const Geom_Number & get_theta() const
Returns the angle.
Definition: point.H:321
bool is_clockwise_with(const Point &p1, const Point &p2) const
Returns true if the sequence this-p1-p2 is clockwise.
Definition: point.H:233
Point(const Geom_Number &__x, const Geom_Number &__y)
Builds a new point in coordinates (__x, __y)
Definition: point.H:138
Geom_Number distance_squared_to(const Point &that) const
Returns the square distance between this y that.
Definition: point.H:927
std::string to_string() const
Convierte a string.
Definition: point.H:381
Definition: point.H:308
Quadrant get_quadrant() const
Retorna el cuadrante donde se encuentra el punto.
Definition: point.H:366
Polar_Point(const Point &p)
Constructor a partir de un punto cartesiano. El origen es (0,0)
Definition: point.H:330
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:227
bool is_inside(const Segment &s) const
Returns true if this is inside of segment s.
Definition: point.H:895
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:221
Definition: point.H:124
Segment(const Segment &sg, const Geom_Number &dist)
Builds a new segment parallel to sg and with a distance dist.
Definition: point.H:526
const Point & nearest_point(const Point &p1, const Point &p2) const
Return the nearest point (to this) between p1 and p2.
Definition: point.H:259
Segment(const Point &__src, const Geom_Number &m, const Geom_Number &l)
Definition: point.H:517
bool is_colinear_with(const Point &p1, const Point &p2) const
Returns true if this is colinear with p1 and p2.
Definition: point.H:200
std::string to_string() const
Return a string representation of this.
Definition: point.H:274
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:215
double counterclockwise_angle_with(const Segment &s) const
Compute the counterclock wise angle respect another segment s.
Definition: point.H:544
Definition: point.H:403
Quadrant
Cuadrantes.
Definition: point.H:363
const Geom_Number & get_x() const
Returns x value.
Definition: point.H:189
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:209
bool intersects_with(const Ellipse &e) const
retorna true si this intercepta con la elipse e
Definition: point.H:1548
Point(const Point &p)
Builds a copy of p.
Definition: point.H:145
bool is_between(const Point &p1, const Point &p2) const
Returns true if this is between p1 and p2.
Definition: point.H:245
const Geom_Number & get_y() const
Returns y value.
Definition: point.H:194
const Geom_Number & get_r() const
Returns the magnitude.
Definition: point.H:318

Leandro Rabindranath León