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);
101 std::vector<Point> res;
102 for(unsigned i = 0; i <= n; i++) {
103 res.push_back(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 template <typename T>
325 inline T
326 cross(D2<T> const & a, D2<T> const & b) {
327 boost::function_requires<ScalableConcept<T> >();
328 boost::function_requires<MultiplicableConcept<T> >();
330 return a[1] * b[0] - a[0] * b[1];
331 }
334 //equivalent to cw/ccw, for use in situations where rotation direction doesn't matter.
335 template <typename T>
336 inline D2<T>
337 rot90(D2<T> const & a) {
338 boost::function_requires<ScalableConcept<T> >();
339 return D2<T>(-a[Y], a[X]);
340 }
342 //TODO: concepterize the following functions
343 template <typename T>
344 inline D2<T>
345 compose(D2<T> const & a, T const & b) {
346 D2<T> r;
347 for(unsigned i = 0; i < 2; i++)
348 r[i] = compose(a[i],b);
349 return r;
350 }
352 template <typename T>
353 inline D2<T>
354 compose_each(D2<T> const & a, D2<T> const & b) {
355 D2<T> r;
356 for(unsigned i = 0; i < 2; i++)
357 r[i] = compose(a[i],b[i]);
358 return r;
359 }
361 template <typename T>
362 inline D2<T>
363 compose_each(T const & a, D2<T> const & b) {
364 D2<T> r;
365 for(unsigned i = 0; i < 2; i++)
366 r[i] = compose(a,b[i]);
367 return r;
368 }
371 template<typename T>
372 inline Point
373 D2<T>::operator()(double t) const {
374 Point p;
375 for(unsigned i = 0; i < 2; i++)
376 p[i] = (*this)[i](t);
377 return p;
378 }
380 //TODO: we might want to have this take a Point as the parameter.
381 template<typename T>
382 inline Point
383 D2<T>::operator()(double x, double y) const {
384 Point p;
385 for(unsigned i = 0; i < 2; i++)
386 p[i] = (*this)[i](x, y);
387 return p;
388 }
391 template<typename T>
392 D2<T> derivative(D2<T> const & a) {
393 return D2<T>(derivative(a[X]), derivative(a[Y]));
394 }
395 template<typename T>
396 D2<T> integral(D2<T> const & a) {
397 return D2<T>(integral(a[X]), integral(a[Y]));
398 }
400 } //end namespace Geom
402 #include <2geom/rect.h>
403 #include <2geom/d2-sbasis.h>
405 namespace Geom{
407 //Some D2 Fragment implementation which requires rect:
408 template <typename T>
409 OptRect bounds_fast(const D2<T> &a) {
410 boost::function_requires<FragmentConcept<T> >();
411 return OptRect(bounds_fast(a[X]), bounds_fast(a[Y]));
412 }
413 template <typename T>
414 OptRect bounds_exact(const D2<T> &a) {
415 boost::function_requires<FragmentConcept<T> >();
416 return OptRect(bounds_exact(a[X]), bounds_exact(a[Y]));
417 }
418 template <typename T>
419 OptRect bounds_local(const D2<T> &a, const OptInterval &t) {
420 boost::function_requires<FragmentConcept<T> >();
421 return OptRect(bounds_local(a[X], t), bounds_local(a[Y], t));
422 }
423 };
425 /*
426 Local Variables:
427 mode:c++
428 c-file-style:"stroustrup"
429 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
430 indent-tabs-mode:nil
431 fill-column:99
432 End:
433 */
434 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
435 #endif