1 /**
2 * \file
3 * \brief Lifts one dimensional objects into 2d
4 *
5 * Copyright 2007 Michael Sloan <mgsloan@gmail.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it either under the terms of the GNU Lesser General Public
9 * License version 2.1 as published by the Free Software Foundation
10 * (the "LGPL") or, at your option, under the terms of the Mozilla
11 * Public License Version 1.1 (the "MPL"). If you do not alter this
12 * notice, a recipient may use your version of this file under either
13 * the MPL or the LGPL.
14 *
15 * You should have received a copy of the LGPL along with this library
16 * in the file COPYING-LGPL-2.1; if not, output to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * You should have received a copy of the MPL along with this library
19 * in the file COPYING-MPL-1.1
20 *
21 * The contents of this file are subject to the Mozilla Public License
22 * Version 1.1 (the "License"); you may not use this file except in
23 * compliance with the License. You may obtain a copy of the License at
24 * http://www.mozilla.org/MPL/
25 *
26 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28 * the specific language governing rights and limitations.
29 *
30 */
32 #ifndef _2GEOM_D2 //If this is change, change the guard in rect.h as well.
33 #define _2GEOM_D2
35 #include <2geom/point.h>
36 #include <2geom/interval.h>
37 #include <2geom/matrix.h>
39 #include <boost/concept_check.hpp>
40 #include <2geom/concepts.h>
42 namespace Geom{
43 /**
44 * The D2 class takes two instances of a scalar data type and treats them
45 * like a point. All operations which make sense on a point are deļ¬ned for D2.
46 * A D2<double> is a Point. A D2<Interval> is a standard axis aligned rectangle.
47 * D2<SBasis> provides a 2d parametric function which maps t to a point
48 * x(t), y(t)
49 */
50 template <class T>
51 class D2{
52 //BOOST_CLASS_REQUIRE(T, boost, AssignableConcept);
53 private:
54 T f[2];
56 public:
57 D2() {f[X] = f[Y] = T();}
58 explicit D2(Point const &a) {
59 f[X] = T(a[X]); f[Y] = T(a[Y]);
60 }
62 D2(T const &a, T const &b) {
63 f[X] = a;
64 f[Y] = b;
65 }
67 //TODO: ask mental about operator= as seen in Point
69 T& operator[](unsigned i) { return f[i]; }
70 T const & operator[](unsigned i) const { return f[i]; }
72 //IMPL: FragmentConcept
73 typedef Point output_type;
74 bool isZero() const {
75 boost::function_requires<FragmentConcept<T> >();
76 return f[X].isZero() && f[Y].isZero();
77 }
78 bool isConstant() const {
79 boost::function_requires<FragmentConcept<T> >();
80 return f[X].isConstant() && f[Y].isConstant();
81 }
82 bool isFinite() const {
83 boost::function_requires<FragmentConcept<T> >();
84 return f[X].isFinite() && f[Y].isFinite();
85 }
86 Point at0() const {
87 boost::function_requires<FragmentConcept<T> >();
88 return Point(f[X].at0(), f[Y].at0());
89 }
90 Point at1() const {
91 boost::function_requires<FragmentConcept<T> >();
92 return Point(f[X].at1(), f[Y].at1());
93 }
94 Point valueAt(double t) const {
95 boost::function_requires<FragmentConcept<T> >();
96 return (*this)(t);
97 }
98 std::vector<Point > valueAndDerivatives(double t, unsigned n) const {
99 std::vector<Coord> x = f[X].valueAndDerivatives(t, n),
100 y = f[Y].valueAndDerivatives(t, n); // always returns a vector of size n+1
101 std::vector<Point> res(n+1);
102 for(unsigned i = 0; i <= n; i++) {
103 res[i] = Point(x[i], y[i]);
104 }
105 return res;
106 }
107 D2<SBasis> toSBasis() const {
108 boost::function_requires<FragmentConcept<T> >();
109 return D2<SBasis>(f[X].toSBasis(), f[Y].toSBasis());
110 }
112 Point operator()(double t) const;
113 Point operator()(double x, double y) const;
114 };
115 template <typename T>
116 inline D2<T> reverse(const D2<T> &a) {
117 boost::function_requires<FragmentConcept<T> >();
118 return D2<T>(reverse(a[X]), reverse(a[Y]));
119 }
121 template <typename T>
122 inline D2<T> portion(const D2<T> &a, Coord f, Coord t) {
123 boost::function_requires<FragmentConcept<T> >();
124 return D2<T>(portion(a[X], f, t), portion(a[Y], f, t));
125 }
127 template <typename T>
128 inline D2<T> portion(const D2<T> &a, Interval i) {
129 boost::function_requires<FragmentConcept<T> >();
130 return D2<T>(portion(a[X], i), portion(a[Y], i));
131 }
133 //IMPL: boost::EqualityComparableConcept
134 template <typename T>
135 inline bool
136 operator==(D2<T> const &a, D2<T> const &b) {
137 boost::function_requires<boost::EqualityComparableConcept<T> >();
138 return a[0]==b[0] && a[1]==b[1];
139 }
140 template <typename T>
141 inline bool
142 operator!=(D2<T> const &a, D2<T> const &b) {
143 boost::function_requires<boost::EqualityComparableConcept<T> >();
144 return a[0]!=b[0] || a[1]!=b[1];
145 }
147 //IMPL: NearConcept
148 template <typename T>
149 inline bool
150 are_near(D2<T> const &a, D2<T> const &b, double tol) {
151 boost::function_requires<NearConcept<T> >();
152 return are_near(a[0], b[0]) && are_near(a[1], b[1]);
153 }
155 //IMPL: AddableConcept
156 template <typename T>
157 inline D2<T>
158 operator+(D2<T> const &a, D2<T> const &b) {
159 boost::function_requires<AddableConcept<T> >();
161 D2<T> r;
162 for(unsigned i = 0; i < 2; i++)
163 r[i] = a[i] + b[i];
164 return r;
165 }
166 template <typename T>
167 inline D2<T>
168 operator-(D2<T> const &a, D2<T> const &b) {
169 boost::function_requires<AddableConcept<T> >();
171 D2<T> r;
172 for(unsigned i = 0; i < 2; i++)
173 r[i] = a[i] - b[i];
174 return r;
175 }
176 template <typename T>
177 inline D2<T>
178 operator+=(D2<T> &a, D2<T> const &b) {
179 boost::function_requires<AddableConcept<T> >();
181 for(unsigned i = 0; i < 2; i++)
182 a[i] += b[i];
183 return a;
184 }
185 template <typename T>
186 inline D2<T>
187 operator-=(D2<T> &a, D2<T> const & b) {
188 boost::function_requires<AddableConcept<T> >();
190 for(unsigned i = 0; i < 2; i++)
191 a[i] -= b[i];
192 return a;
193 }
195 //IMPL: ScalableConcept
196 template <typename T>
197 inline D2<T>
198 operator-(D2<T> const & a) {
199 boost::function_requires<ScalableConcept<T> >();
200 D2<T> r;
201 for(unsigned i = 0; i < 2; i++)
202 r[i] = -a[i];
203 return r;
204 }
205 template <typename T>
206 inline D2<T>
207 operator*(D2<T> const & a, Point const & b) {
208 boost::function_requires<ScalableConcept<T> >();
210 D2<T> r;
211 for(unsigned i = 0; i < 2; i++)
212 r[i] = a[i] * b[i];
213 return r;
214 }
215 template <typename T>
216 inline D2<T>
217 operator/(D2<T> const & a, Point const & b) {
218 boost::function_requires<ScalableConcept<T> >();
219 //TODO: b==0?
220 D2<T> r;
221 for(unsigned i = 0; i < 2; i++)
222 r[i] = a[i] / b[i];
223 return r;
224 }
225 template <typename T>
226 inline D2<T>
227 operator*=(D2<T> &a, Point const & b) {
228 boost::function_requires<ScalableConcept<T> >();
230 for(unsigned i = 0; i < 2; i++)
231 a[i] *= b[i];
232 return a;
233 }
234 template <typename T>
235 inline D2<T>
236 operator/=(D2<T> &a, Point const & b) {
237 boost::function_requires<ScalableConcept<T> >();
238 //TODO: b==0?
239 for(unsigned i = 0; i < 2; i++)
240 a[i] /= b[i];
241 return a;
242 }
244 template <typename T>
245 inline D2<T> operator*(D2<T> const & a, double b) { return D2<T>(a[0]*b, a[1]*b); }
246 template <typename T>
247 inline D2<T> operator*=(D2<T> & a, double b) { a[0] *= b; a[1] *= b; return a; }
248 template <typename T>
249 inline D2<T> operator/(D2<T> const & a, double b) { return D2<T>(a[0]/b, a[1]/b); }
250 template <typename T>
251 inline D2<T> operator/=(D2<T> & a, double b) { a[0] /= b; a[1] /= b; return a; }
253 template<typename T>
254 D2<T> operator*(D2<T> const &v, Matrix const &m) {
255 boost::function_requires<AddableConcept<T> >();
256 boost::function_requires<ScalableConcept<T> >();
257 D2<T> ret;
258 for(unsigned i = 0; i < 2; i++)
259 ret[i] = v[X] * m[i] + v[Y] * m[i + 2] + m[i + 4];
260 return ret;
261 }
263 //IMPL: MultiplicableConcept
264 template <typename T>
265 inline D2<T>
266 operator*(D2<T> const & a, T const & b) {
267 boost::function_requires<MultiplicableConcept<T> >();
268 D2<T> ret;
269 for(unsigned i = 0; i < 2; i++)
270 ret[i] = a[i] * b;
271 return ret;
272 }
274 //IMPL:
276 //IMPL: OffsetableConcept
277 template <typename T>
278 inline D2<T>
279 operator+(D2<T> const & a, Point b) {
280 boost::function_requires<OffsetableConcept<T> >();
281 D2<T> r;
282 for(unsigned i = 0; i < 2; i++)
283 r[i] = a[i] + b[i];
284 return r;
285 }
286 template <typename T>
287 inline D2<T>
288 operator-(D2<T> const & a, Point b) {
289 boost::function_requires<OffsetableConcept<T> >();
290 D2<T> r;
291 for(unsigned i = 0; i < 2; i++)
292 r[i] = a[i] - b[i];
293 return r;
294 }
295 template <typename T>
296 inline D2<T>
297 operator+=(D2<T> & a, Point b) {
298 boost::function_requires<OffsetableConcept<T> >();
299 for(unsigned i = 0; i < 2; i++)
300 a[i] += b[i];
301 return a;
302 }
303 template <typename T>
304 inline D2<T>
305 operator-=(D2<T> & a, Point b) {
306 boost::function_requires<OffsetableConcept<T> >();
307 for(unsigned i = 0; i < 2; i++)
308 a[i] -= b[i];
309 return a;
310 }
312 template <typename T>
313 inline T
314 dot(D2<T> const & a, D2<T> const & b) {
315 boost::function_requires<AddableConcept<T> >();
316 boost::function_requires<MultiplicableConcept<T> >();
318 T r;
319 for(unsigned i = 0; i < 2; i++)
320 r += a[i] * b[i];
321 return r;
322 }
324 /** @brief Calculates the 'dot product' or 'inner product' of \c a and \c b
325 * @return \f$a \bullet b = a_X b_X + a_Y b_Y\f$.
326 * @relates D2 */
327 template <typename T>
328 inline T
329 dot(D2<T> const & a, Point const & b) {
330 boost::function_requires<AddableConcept<T> >();
331 boost::function_requires<ScalableConcept<T> >();
333 T r;
334 for(unsigned i = 0; i < 2; i++) {
335 r += a[i] * b[i];
336 }
337 return r;
338 }
340 /** @brief Calculates the 'cross product' or 'outer product' of \c a and \c b
341 * @return \f$a \times b = a_Y b_X - a_X b_Y\f$.
342 * @relates D2 */
343 template <typename T>
344 inline T
345 cross(D2<T> const & a, D2<T> const & b) {
346 boost::function_requires<ScalableConcept<T> >();
347 boost::function_requires<MultiplicableConcept<T> >();
349 return a[1] * b[0] - a[0] * b[1];
350 }
353 //equivalent to cw/ccw, for use in situations where rotation direction doesn't matter.
354 template <typename T>
355 inline D2<T>
356 rot90(D2<T> const & a) {
357 boost::function_requires<ScalableConcept<T> >();
358 return D2<T>(-a[Y], a[X]);
359 }
361 //TODO: concepterize the following functions
362 template <typename T>
363 inline D2<T>
364 compose(D2<T> const & a, T const & b) {
365 D2<T> r;
366 for(unsigned i = 0; i < 2; i++)
367 r[i] = compose(a[i],b);
368 return r;
369 }
371 template <typename T>
372 inline D2<T>
373 compose_each(D2<T> const & a, D2<T> const & b) {
374 D2<T> r;
375 for(unsigned i = 0; i < 2; i++)
376 r[i] = compose(a[i],b[i]);
377 return r;
378 }
380 template <typename T>
381 inline D2<T>
382 compose_each(T const & a, D2<T> const & b) {
383 D2<T> r;
384 for(unsigned i = 0; i < 2; i++)
385 r[i] = compose(a,b[i]);
386 return r;
387 }
390 template<typename T>
391 inline Point
392 D2<T>::operator()(double t) const {
393 Point p;
394 for(unsigned i = 0; i < 2; i++)
395 p[i] = (*this)[i](t);
396 return p;
397 }
399 //TODO: we might want to have this take a Point as the parameter.
400 template<typename T>
401 inline Point
402 D2<T>::operator()(double x, double y) const {
403 Point p;
404 for(unsigned i = 0; i < 2; i++)
405 p[i] = (*this)[i](x, y);
406 return p;
407 }
410 template<typename T>
411 D2<T> derivative(D2<T> const & a) {
412 return D2<T>(derivative(a[X]), derivative(a[Y]));
413 }
414 template<typename T>
415 D2<T> integral(D2<T> const & a) {
416 return D2<T>(integral(a[X]), integral(a[Y]));
417 }
419 /** A function to print out the Point. It just prints out the coords
420 on the given output stream */
421 template <typename T>
422 inline std::ostream &operator<< (std::ostream &out_file, const Geom::D2<T> &in_d2) {
423 out_file << "X: " << in_d2[X] << " Y: " << in_d2[Y];
424 return out_file;
425 }
427 } //end namespace Geom
429 #include <2geom/rect.h>
430 #include <2geom/d2-sbasis.h>
432 namespace Geom{
434 //Some D2 Fragment implementation which requires rect:
435 template <typename T>
436 OptRect bounds_fast(const D2<T> &a) {
437 boost::function_requires<FragmentConcept<T> >();
438 return OptRect(bounds_fast(a[X]), bounds_fast(a[Y]));
439 }
440 template <typename T>
441 OptRect bounds_exact(const D2<T> &a) {
442 boost::function_requires<FragmentConcept<T> >();
443 return OptRect(bounds_exact(a[X]), bounds_exact(a[Y]));
444 }
445 template <typename T>
446 OptRect bounds_local(const D2<T> &a, const OptInterval &t) {
447 boost::function_requires<FragmentConcept<T> >();
448 return OptRect(bounds_local(a[X], t), bounds_local(a[Y], t));
449 }
450 };
452 /*
453 Local Variables:
454 mode:c++
455 c-file-style:"stroustrup"
456 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
457 indent-tabs-mode:nil
458 fill-column:99
459 End:
460 */
461 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
462 #endif