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

Leandro Rabindranath León