at artful, screen stabilizes
[feisty_meow.git] / graphiq / library / geometric / point.h
1 #ifndef POINT_CLASS
2 #define POINT_CLASS
3
4 /*****************************************************************************\
5 *                                                                             *
6 *  Name   : point                                                             *
7 *  Author : Chris Koeritz                                                     *
8 *                                                                             *
9 *******************************************************************************
10 * Copyright (c) 1992-$now By Author.  This program is free software; you can  *
11 * redistribute it and/or modify it under the terms of the GNU General Public  *
12 * License as published by the Free Software Foundation; either version 2 of   *
13 * the License or (at your option) any later version.  This is online at:      *
14 *     http://www.fsf.org/copyleft/gpl.html                                    *
15 * Please send any updates to: fred@gruntose.com                               *
16 \*****************************************************************************/
17
18 #include "angle.h"
19 #include "math_bits.h"
20 #include "point.h"
21
22 #include <basis/astring.h>
23 #include <basis/contracts.h>
24 #include <basis/functions.h>
25 #include <structures/object_packers.h>
26
27 #include <math.h>
28
29 //! Contains all of our objects for geometry and avoids name clashes.
30
31 namespace geometric {
32
33 //! Represents a geometric point.
34
35 template <class numeric_type>
36 class point : public basis::packable, public virtual basis::root_object
37 {
38 public:
39   point(numeric_type x = 0, numeric_type y = 0);
40   point(numeric_type r, double_angle theta);
41
42   DEFINE_CLASS_NAME("point");
43
44   void set(numeric_type x, numeric_type y);
45   void set(numeric_type r, double_angle theta);
46
47   numeric_type x() const { return _x; }
48   numeric_type y() const { return _y; }
49
50   numeric_type r() const;
51   double_angle theta() const;
52
53   point rotate(const double_angle &theta) const;
54     //!< Rotates the point by the angle "theta".
55     /*!< This rotates the position of the point around the origin in the
56     trigonometric standard manner; zero degrees is at the right, increasing
57     degree angles are counterclockwise from the x axis to the y to the
58     -x to the -y .... */
59
60   numeric_type distance(const point &p2) const;
61     //!< Returns the distance between `this' and the second point `p2'.
62
63   point operator - () const { return point<numeric_type>(-_x, -_y); }
64     //!< return the additive inverse of the vector
65
66   numeric_type magnitude() const;
67     //!< return the distance from the origin to this point.
68
69   point operator + (const point &arg2) const;
70   point operator - (const point &arg2) const;
71   point &operator += (const point &arg2);
72   point &operator -= (const point &arg2);
73   bool operator == (const point &arg2) const;
74
75   basis::astring text_form() const;
76     //!< Prints out the two values (x and y) held in the point.
77
78   bool from_text(const basis::astring &text);
79     //!< returns true if the "text" is successfully pulled into this point.
80
81   virtual void pack(basis::byte_array &packed_form) const;
82   virtual bool unpack(basis::byte_array &packed_form);
83   int packed_size() const;
84
85 private:
86   numeric_type _x;
87   numeric_type _y;
88 };
89
90 //////////////
91
92 // implementations below...
93
94 // notes:
95 //
96 // - there is an odd breaking up of the expressions where we're taking a
97 //   square root because ms visual studio 7 has a bug of some sort that
98 //   convinces it that angle<int> is being used in there, although it's not.
99 //   these lines use a temporary named "sumsquar" to deconfuse the compiler. 
100
101 template <class numeric_type>
102 point<numeric_type>::point(numeric_type x, numeric_type y) { set(x, y); }
103
104 template <class numeric_type>
105 point<numeric_type>::point(numeric_type r, double_angle theta)
106 { set(r, theta); }
107
108 template <class numeric_type>
109 basis::astring point<numeric_type>::text_form() const
110 {
111   numeric_type temp = 0;
112   basis::astring specifier(numeric_specifier(temp));
113   basis::astring sprintf_template(basis::astring::SPRINTF, "(%s, %s)", specifier.s(), specifier.s());
114   return basis::astring(basis::astring::SPRINTF, sprintf_template.s(), x(), y());
115 }
116
117 template <class numeric_type>
118 void point<numeric_type>::set(numeric_type x, numeric_type y)
119 { _x = x; _y = y; }
120
121 template <class numeric_type>
122 numeric_type point<numeric_type>::r() const
123 {
124   const double sumsquar = basis::square(x()) + basis::square(y());
125   return numeric_type(sqrt(sumsquar)); 
126 }
127
128 template <class numeric_type>
129 void point<numeric_type>::set(numeric_type r, double_angle theta)
130 { set(numeric_type(r * theta.cosine()), numeric_type(r * theta.sine())); }
131
132 template <class numeric_type>
133 numeric_type point<numeric_type>::distance(const point &p2) const
134 {
135   const double sumsquar = basis::square(p2.x() - x()) + basis::square(p2.y() - y());
136   return numeric_type(sqrt(sumsquar));
137 }
138
139 template <class numeric_type>
140 double_angle point<numeric_type>::theta() const
141 {
142   basis::outcome retval;
143   return double_angle::arctangent(y(), x(), retval);
144 }
145
146 template <class contents>
147 int point<contents>::packed_size() const
148 {
149   basis::byte_array temp;
150 //hmmm: inefficient!
151   pack(temp);
152   return temp.length();
153 }
154
155 template <class contents>
156 void point<contents>::pack(basis::byte_array &packed_form) const
157 {
158   structures::attach(packed_form, _x);
159   structures::attach(packed_form, _y);
160 }
161
162 template <class contents>
163 bool point<contents>::unpack(basis::byte_array &packed_form)
164 {
165   if (!structures::detach(packed_form, _x)) return false;
166   if (!structures::detach(packed_form, _y)) return false;
167   return true;
168 }
169
170 template <class numeric_type>
171 numeric_type point<numeric_type>::magnitude() const
172 {
173   const double sumsquar = basis::square(x()) + basis::square(y());
174   return numeric_type(sqrt(sumsquar)); 
175 }
176
177 template <class numeric_type>
178 point<numeric_type> point<numeric_type>::operator + (const point &arg2) const
179 { return point<numeric_type>(x() + arg2.x(), y() + arg2.y()); }
180
181 template <class numeric_type>
182 point<numeric_type> point<numeric_type>::operator - (const point &arg2) const
183 { return point<numeric_type>(x() - arg2.x(), y() - arg2.y()); }
184
185 template <class numeric_type>
186 point<numeric_type> &point<numeric_type>::operator += (const point &arg2)
187 { _x += arg2.x(); _y += arg2.y(); return *this; }
188
189 template <class numeric_type>
190 point<numeric_type> &point<numeric_type>::operator -= (const point &arg2)
191 { _x -= arg2.x(); _y -= arg2.y(); return *this; }
192
193 template <class numeric_type>
194 bool point<numeric_type>::operator == (const point &arg2) const
195 {
196 // this bit should be part of the floating point stuff...
197   double epsilon = 1e-10;
198   return (basis::absolute_value(x() - arg2.x()) <= epsilon)
199       && (basis::absolute_value(y() - arg2.y()) <= epsilon);
200 }
201
202 template <class numeric_type>
203 point<numeric_type> point<numeric_type>::rotate
204     (const double_angle &theta) const
205 {
206   numeric_type tempX = x();
207   numeric_type tempY = y();
208   numeric_type temp1 = numeric_type(tempX * theta.cosine()
209       - tempY * theta.sine());
210   numeric_type temp2 = numeric_type(tempX * theta.sine() 
211       + tempY * theta.cosine());
212   return point<numeric_type>(temp1, temp2);
213 }
214
215 template <class numeric_type>
216 bool point<numeric_type>::from_text(const basis::astring &_text)
217 {
218   numeric_type x = 0, y = 0;
219   basis::astring text(_text);
220   // chop junk off the front.
221   text = crop_non_numeric(text);
222   // scan the string for values.
223   x = text.convert(x);
224   // remove the number.
225   text = crop_numeric(text);
226   // chop off more junk.
227   text = crop_non_numeric(text);
228   // get the next number.
229   y = text.convert(y);
230   set(x, y);
231   return true;
232 }
233
234 } // namespace.
235
236 #endif
237