Inkscape
Vector Graphics Editor
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages Concepts
sb-of-sb.cpp
Go to the documentation of this file.
1#include <time.h>
2#include <vector>
3#include <toys/path-cairo.h>
5
6#include <2geom/sbasis.h>
9
11
12using namespace Geom;
13using namespace std;
14
16 SBasis result(f.size(), Linear());
17 for (unsigned i=0; i<f.size(); i++){
18 result[i] = Linear(f[i][0],f[i][1]);
19 }
20 return result;
21}
24 for (auto i : f){
25 result.push_back(LinearOf<double>(i[0],i[1]));
26 }
27 return result;
28}
29
30
31#if 0
32template<unsigned dim>
33class LinearDim;
34template<unsigned dim>
35class SBasisDim;
36
37template<unsigned dim>
38class LinearDim : public LinearOf<SBasisDim<dim-1> >{
39public:
40 LinearDim() : LinearOf<SBasisDim<dim-1> >() {};
41 LinearDim(SBasisDim <dim-1> const &a, SBasisDim<dim-1> const &b ) : LinearOf<SBasisDim<dim-1> >(a,b) {};
42 LinearDim(LinearDim <dim-1> const &a, LinearDim<dim-1> const &b ) :
43 LinearOf<SBasisDim<dim-1> >(SBasisDim<dim-1>(a),SBasisDim<dim-1>(b)) {};
44};
45
46template<>
47class LinearDim<1> : public LinearOf<double>{
48public:
49 LinearDim() : LinearOf<double>() {};
50 LinearDim(double const &a, double const &b ) : LinearOf<double>(a,b) {};
51};
52
53
54template<unsigned dim>
55class SBasisDim : public SBasisOf<SBasisDim<dim-1> >{
56public:
57 SBasisDim() : SBasisOf<SBasisDim<dim-1> >() {};
58 SBasisDim(LinearDim<dim> const &lin) :
59 SBasisOf<SBasisDim<dim-1> >(LinearOf<SBasisDim<dim-1> >(lin[0],lin[1])) {};
60};
61
62template<>
63class SBasisDim<1> : public SBasisOf<double>{
64/*
65public:
66 SBasisDim<1>() : SBasisOf<double>() {};
67 SBasisDim(SBasisOf<double> other) : SBasisOf<double>(other) {};
68 SBasisDim(LinearOf<double> other) : SBasisOf<double>(other) {};
69*/
70};
71
72SBasis toSBasis(SBasisDim<1> f){
73 SBasis result(f.size(), Linear());
74 for (unsigned i=0; i<f.size(); i++){
75 result[i] = Linear(f[i][0],f[i][1]);
76 }
77 return result;
78}
79
80template<unsigned dim_f,unsigned dim_g>
81SBasisDim<dim_g> compose(SBasisDim<dim_f> const &f, std::vector<SBasisDim<dim_g> > const &g ){
82
83 assert( dim_f <= g.size() );
84
85 SBasisDim<dim_g> u0 = g[dim_f-1];
86 SBasisDim<dim_g> u1 = -u0 + 1;
87 SBasisDim<dim_g> s = multiply(u0,u1);
88 SBasisDim<dim_g> r;
89
90 for(int i = f.size()-1; i >= 0; i--) {
91 if ( dim_f>1 ){
92 r = s*r + compose(f[i][0],g)*u0 + compose(f[i][1],g)*u1;
93 }else{
94 r = s*r + f[i][0]*u0 + f[i][1]*u1;
95 }
96 }
97 return r;
98}
99
100#endif
101
102template <typename T>
104
105 //assert( f.input_dim() <= g.size() );
106
107 SBasisOf<T> u0 = g;
109 SBasisOf<T> s = multiply(u0,u1);
110 SBasisOf<T> r;
111
112 for(int i = f.size()-1; i >= 0; i--) {
113 r = s*r + f[i][0]*u0 + f[i][1]*u1;
114 }
115 return r;
116}
118 SBasisOf<double> const &x,
119 SBasisOf<double> const &y){
120 SBasisOf<double> y0 = -y + LinearOf<double>(1,1);
121 SBasisOf<double> s = multiply(y0,y);
123
124 for(int i = f.size()-1; i >= 0; i--) {
125 r = s*r + compose(f[i][0],x)*y0 + compose(f[i][1],x)*y;
126 }
127 return r;
128}
129
131 D2<SBasisOf<double> > const &X){
132 return compose(f, X[0], X[1]);
133}
134
139
140/*
141static
142SBasis eval_v(SBasisOf<SBasis> const &f, double v){
143 SBasis result(f.size(), Linear());
144 for (unsigned i=0; i<f.size(); i++){
145 result[i] = Linear(f[i][0].valueAt(v),f[i][1].valueAt(v));
146 }
147 return result;
148}
149static
150SBasis eval_v(SBasisOf<SBasisOf<double> > const &f, double v){
151 SBasis result(f.size(), Linear());
152 for (unsigned i=0; i<f.size(); i++){
153 result[i] = Linear(f[i][0].valueAt(v),f[i][1].valueAt(v));
154 }
155 return result;
156}*/
157static
158SBasisOf<double> eval_dim(SBasisOf<SBasisOf<double> > const &f, double t, unsigned dim){
159 if (dim == 1) return f.valueAt(t);
161 for (unsigned i=0; i<f.size(); i++){
162 result.push_back(LinearOf<double>(f[i][0].valueAt(t),f[i][1].valueAt(t)));
163 }
164 return result;
165}
166
167/*
168static
169SBasis eval_v(SBasisDim<2> const &f, double v){
170 SBasis result;
171 for (unsigned i=0; i<f.size(); i++){
172 result.push_back(Linear(f[i][0].valueAt(v),f[i][1].valueAt(v)));
173 }
174 return result;
175}
176*/
177
178struct Frame
179{
180 Geom::Point O;
181 Geom::Point x;
182 Geom::Point y;
183 Geom::Point z;
184 // find the point on the x,y plane that projects to P
185 Point unproject(Point P) {
186 return P * from_basis(x, y, O).inverse();
187 }
188};
189
190void
191plot3d(cairo_t *cr, SBasis const &x, SBasis const &y, SBasis const &z, Frame frame){
193 for (unsigned dim=0; dim<2; dim++){
194 curve[dim] = x*frame.x[dim] + y*frame.y[dim] + z*frame.z[dim];
195 curve[dim] += frame.O[dim];
196 }
197 cairo_d2_sb(cr, curve);
198}
199void
200plot3d(cairo_t *cr, SBasis const &x, SBasis const &y, SBasisOf<double> const &z, Frame frame){
202 for (unsigned dim=0; dim<2; dim++){
203 curve[dim] = x*frame.x[dim] + y*frame.y[dim] + toSBasis(z)*frame.z[dim];
204 curve[dim] += frame.O[dim];
205 }
206 cairo_d2_sb(cr, curve);
207}
208
209void
211 Piecewise<SBasis> const &x,
212 Piecewise<SBasis> const &y,
213 Piecewise<SBasis> const &z, Frame frame){
214
215 Piecewise<SBasis> xx = partition(x,y.cuts);
216 Piecewise<SBasis> xxx = partition(xx,z.cuts);
217 Piecewise<SBasis> yyy = partition(y,xxx.cuts);
218 Piecewise<SBasis> zzz = partition(z,xxx.cuts);
219
220 for (unsigned i=0; i<xxx.size(); i++){
221 plot3d(cr, xxx[i], yyy[i], zzz[i], frame);
222 }
223}
224
225void
226plot3d(cairo_t *cr, SBasisOf<SBasisOf<double> > const &f, Frame frame){
227 int iMax = 5;
228 for (int i=0; i<iMax; i++){
229 plot3d(cr, Linear(0,1), Linear(i/(iMax-1.)), eval_dim(f, i/(iMax-1.), 0), frame);
230 plot3d(cr, Linear(i/(iMax-1.)), Linear(0,1), eval_dim(f, i/(iMax-1.), 1), frame);
231 }
232}
233
235 //variable of f = 1, variable of f's coefficients = 0.
236 if (var == 1) return Geom::integral(f);
238 for(unsigned i = 0; i< f.size(); i++) {
239 result.push_back(LinearOf<SBasisOf<double> >(Geom::integral(f[i][0]), Geom::integral(f[i][1])));
240 }
241 return result;
242}
243
245 SBasisOf<double> const &g, Interval dom_g){
246
247 if ( dom_f.extent() < dom_g.extent() ) return convole(g, dom_g, f, dom_f);
248
250 u.push_back(LinearOf<SBasisOf<double> >(LinearOf<double>(0,1),
251 LinearOf<double>(0,1)));
252 v.push_back(LinearOf<SBasisOf<double> >(LinearOf<double>(0,0),
253 LinearOf<double>(1,1)));
254 SBasisOf<SBasisOf<double> > v_u = v - u*(dom_f.extent()/dom_g.extent());
255 v_u += SBasisOf<SBasisOf<double> >(SBasisOf<double>(dom_f.min()/dom_g.extent()));
256 SBasisOf<SBasisOf<double> > gg = multi_compose(g,(v - u*(dom_f.extent()/dom_g.extent())));
259
261 result.cuts.push_back(dom_f.min()+dom_g.min());
262 //Note: we know dom_f.extent() >= dom_g.extent()!!
263 double rho = dom_f.extent()/dom_g.extent();
264 SBasisOf<double> a,b,t;
265 SBasis seg;
267 b = SBasisOf<double>(LinearOf<double>(0.,1/rho));
268 t = SBasisOf<double>(LinearOf<double>(dom_f.min()/dom_g.extent(),dom_f.min()/dom_g.extent()+1));
269 seg = toSBasis(compose(hh,b,t)-compose(hh,a,t));
270 result.push(seg,dom_f.min() + dom_g.max());
271 if (dom_f.extent() > dom_g.extent()){
272 a = SBasisOf<double>(LinearOf<double>(0.,1-1/rho));
273 b = SBasisOf<double>(LinearOf<double>(1/rho,1.));
274 t = SBasisOf<double>(LinearOf<double>(dom_f.min()/dom_g.extent()+1, dom_f.max()/dom_g.extent() ));
275 seg = toSBasis(compose(hh,b,t)-compose(hh,a,t));
276 result.push(seg,dom_f.max() + dom_g.min());
277 }
278 a = SBasisOf<double>(LinearOf<double>(1.-1/rho,1.));
280 t = SBasisOf<double>(LinearOf<double>(dom_f.max()/dom_g.extent(), dom_f.max()/dom_g.extent()+1 ));
281 seg = toSBasis(compose(hh,b,t)-compose(hh,a,t));
282 result.push(seg,dom_f.max() + dom_g.max());
283 return result;
284}
285
286template <typename T>
288 SBasisOf<T> res;
289 for(unsigned i = 0; i < f.size(); i++) {
290 res.push_back(LinearOf<T>(derivative(f[i][0]), derivative(f[i][1])));
291 }
292 return res;
293}
294
298
303//TODO: handle the case when B is "behind" A for the natural orientation of the level set.
304//TODO: more generally, there might be up to 4 solutions. Choose the best one!
307 D2<SBasis>result;//(Linear(A[X],B[X]),Linear(A[Y],B[Y]));
308 //g_warning("check 0 = %f = %f!", f.apply(A[X],A[Y]), f.apply(B[X],B[Y]));
309
315
316 Geom::Point dfA(f_u.valueAt(A[X]).valueAt(A[Y]),f_v.valueAt(A[X]).valueAt(A[Y]));
317 Geom::Point dfB(f_u.valueAt(B[X]).valueAt(B[Y]),f_v.valueAt(B[X]).valueAt(B[Y]));
318
319 Geom::Point V0 = rot90(dfA);
320 Geom::Point V1 = rot90(dfB);
321
322 double D2fVV0 = f_uu.valueAt(A[X]).valueAt(A[Y])*V0[X]*V0[X]+
323 2*f_uv.valueAt(A[X]).valueAt(A[Y])*V0[X]*V0[Y]+
324 f_vv.valueAt(A[X]).valueAt(A[Y])*V0[Y]*V0[Y];
325 double D2fVV1 = f_uu.valueAt(B[X]).valueAt(B[Y])*V1[X]*V1[X]+
326 2*f_uv.valueAt(B[X]).valueAt(B[Y])*V1[X]*V1[Y]+
327 f_vv.valueAt(B[X]).valueAt(B[Y])*V1[Y]*V1[Y];
328
329 std::vector<D2<SBasis> > candidates = cubics_fitting_curvature(A,B,V0,V1,D2fVV0,D2fVV1);
330 if (candidates.size()==0) {
331 return D2<SBasis>(SBasis(A[X],B[X]),SBasis(A[Y],B[Y]));
332 }
333 //TODO: I'm sure std algorithm could do that for me...
334 double error = -1;
335 unsigned best = 0;
336 for (unsigned i=0; i<candidates.size(); i++){
337 Interval bounds = *bounds_fast(compose(f,candidates[i]));
338 double new_error = (fabs(bounds.max())>fabs(bounds.min()) ? fabs(bounds.max()) : fabs(bounds.min()) );
339 if ( new_error < error || error < 0 ){
340 error = new_error;
341 best = i;
342 }
343 }
344 return candidates[best];
345}
346
347class SBasis0fSBasisToy: public Toy {
348 PointSetHandle hand;
349 PointSetHandle cut_hand;
350 void draw(cairo_t *cr, std::ostringstream *notify, int width, int height, bool save, std::ostringstream *timer_stream) override {
351
352 double slider_top = width/4.;
353 double slider_bot = width*3./4.;
354 double slider_margin = width/8.;
355 if(hand.pts.empty()) {
356 hand.pts.emplace_back(width*3./16., 3*width/4.);
357 hand.pts.push_back(hand.pts[0] + Geom::Point(width/2., 0));
358 hand.pts.push_back(hand.pts[0] + Geom::Point(width/8., -width/12.));
359 hand.pts.push_back(hand.pts[0] + Geom::Point(0,-width/4.));
360 hand.pts.emplace_back(slider_margin,slider_bot);
361 hand.pts.emplace_back(width-slider_margin,slider_top);
362 }
363
364 hand.pts[4][X] = slider_margin;
365 if (hand.pts[4][Y]<slider_top) hand.pts[4][Y] = slider_top;
366 if (hand.pts[4][Y]>slider_bot) hand.pts[4][Y] = slider_bot;
367 hand.pts[5][X] = width-slider_margin;
368 if (hand.pts[5][Y]<slider_top) hand.pts[5][Y] = slider_top;
369 if (hand.pts[5][Y]>slider_bot) hand.pts[5][Y] = slider_bot;
370
371 //double tA = (slider_bot-hand.pts[4][Y])/(slider_bot-slider_top);
372 //double tB = (slider_bot-hand.pts[5][Y])/(slider_bot-slider_top);
373
374 cairo_move_to(cr,Geom::Point(slider_margin,slider_bot));
375 cairo_line_to(cr,Geom::Point(slider_margin,slider_top));
376 cairo_move_to(cr,Geom::Point(width-slider_margin,slider_bot));
377 cairo_line_to(cr,Geom::Point(width-slider_margin,slider_top));
378 cairo_set_line_width(cr,.5);
379 cairo_set_source_rgba (cr, 0., 0.3, 0., 1.);
380 cairo_stroke(cr);
381
382 Frame frame;
383 frame.O = hand.pts[0];//
384 frame.x = hand.pts[1]-hand.pts[0];//
385 frame.y = hand.pts[2]-hand.pts[0];//
386 frame.z = hand.pts[3]-hand.pts[0];//
387
388 plot3d(cr,Linear(0,1),Linear(0,0),Linear(0,0),frame);
389 plot3d(cr,Linear(0,1),Linear(1,1),Linear(0,0),frame);
390 plot3d(cr,Linear(0,0),Linear(0,1),Linear(0,0),frame);
391 plot3d(cr,Linear(1,1),Linear(0,1),Linear(0,0),frame);
392 cairo_set_line_width(cr,.2);
393 cairo_set_source_rgba (cr, 0., 0., 0., 1.);
394 cairo_stroke(cr);
395
396
397
401#if 1
403 //*notify << "input dim = " << f.input_dim() <<"\n";
404 plot3d(cr,f,frame);
405 cairo_set_line_width(cr,1);
406 cairo_set_source_rgba (cr, .5, 0.5, 0.5, 1.);
407 cairo_stroke(cr);
408
409 LineSegment ls(frame.unproject(cut_hand.pts[0]),
410 frame.unproject(cut_hand.pts[1]));
411 SBasis cutting = toSBasis(compose(f, ls.toSBasis()));
412 //cairo_sb(cr, cutting);
413 //cairo_stroke(cr);
414 plot3d(cr, ls.toSBasis()[0], ls.toSBasis()[1], SBasis(0.0), frame);
415 vector<double> rts = roots(cutting);
416 if(rts.size() >= 2) {
417 Geom::Point A = ls.pointAt(rts[0]);
418 Geom::Point B = ls.pointAt(rts[1]);
419
420 //Geom::Point A(1,0.5);
421 //Geom::Point B(0.5,1);
422 D2<SBasis> zeroset = sbofsb_cubic_solve(f,A,B);
423 plot3d(cr, zeroset[X], zeroset[Y], SBasis(Linear(0.)),frame);
424 cairo_set_line_width(cr,1);
425 cairo_set_source_rgba (cr, 0.9, 0., 0., 1.);
426 cairo_stroke(cr);
427 }
428#else
429
430 SBasisOf<SBasisOf<double> > g = u - v ;
433 h.push_back(LinearOf<double>(0,0));
434 h.push_back(LinearOf<double>(0,0));
435 h.push_back(LinearOf<double>(1,1));
436
437 f = multi_compose(h,g);
438 plot3d(cr,f,frame);
439 cairo_set_line_width(cr,1);
440 cairo_set_source_rgba (cr, .75, 0.25, 0.25, 1.);
441 cairo_stroke(cr);
442/*
443 SBasisDim<1> g = SBasisOf<double>(LinearOf<double>(0,1));
444 g.push_back(LinearOf<double>(-1,-1));
445 std::vector<SBasisDim<2> > vars;
446 vars.push_back(ff);
447 plot3d(cr,compose(g,vars),frame);
448 cairo_set_source_rgba (cr, .5, 0.9, 0.5, 1.);
449 cairo_stroke(cr);
450*/
451#endif
452 Toy::draw(cr, notify, width, height, save,timer_stream);
453 }
454
455public:
456 SBasis0fSBasisToy(){
457 handles.push_back(&hand);
458 handles.push_back(&cut_hand);
459 cut_hand.push_back(100,100);
460 cut_hand.push_back(500,500);
461 }
462};
463
464int main(int argc, char **argv) {
465 init(argc, argv, new SBasis0fSBasisToy);
466 return 0;
467}
468
469/*
470 Local Variables:
471 mode:c++
472 c-file-style:"stroustrup"
473 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
474 indent-tabs-mode:nil
475 fill-column:99
476 End:
477*/
478// vim: filetype = cpp:expandtab:shiftwidth = 4:tabstop = 8:softtabstop = 4:encoding = utf-8:textwidth = 99 :
int main()
Conversion between Bezier control points and SBasis curves.
Geom::IntRect bounds
Definition canvas.cpp:182
Affine inverse() const
Compute the inverse matrix.
Definition affine.cpp:388
Adaptor that creates 2D functions from 1D ones.
Definition d2.h:55
constexpr C extent() const
constexpr C min() const
constexpr C max() const
CPoint min() const
Get the corner of the rectangle with smallest coordinate values.
CPoint max() const
Get the corner of the rectangle with largest coordinate values.
Range of real numbers that is never empty.
Definition interval.h:59
Function that interpolates linearly between two values.
Definition linear.h:55
Range of real numbers that can be empty.
Definition interval.h:199
Function defined as discrete pieces.
Definition piecewise.h:71
unsigned size() const
Definition piecewise.h:131
std::vector< double > cuts
Definition piecewise.h:75
Two-dimensional point that doubles as a vector.
Definition point.h:66
T valueAt(double t) const
Definition sbasis-of.h:103
Polynomial in symmetric power basis.
Definition sbasis.h:70
void push_back(double x, double y)
std::vector< Geom::Point > pts
vector< Handle * > handles
virtual void save(FILE *f)
virtual void draw(cairo_t *cr, std::ostringstream *notify, int w, int h, bool save, std::ostringstream *timing_stream)
SBasisOf< T > multi_compose(SBasisOf< double > const &f, SBasisOf< T > const &g)
Definition convole.cpp:82
void plot3d(cairo_t *cr, SBasis const &x, SBasis const &y, SBasis const &z, Frame frame)
Definition convole.cpp:203
Css & result
@ Y
Definition coord.h:48
@ X
Definition coord.h:48
size_t v
Various utility functions.
Definition affine.h:22
Affine from_basis(const Point &x_basis, const Point &y_basis, const Point &offset=Point(0, 0))
Creates a Affine given an axis and origin point.
Definition affine.cpp:26
Bezier multiply(Bezier const &f, Bezier const &g)
Definition bezier.h:337
D2< T > compose(D2< T > const &a, T const &b)
Definition d2.h:405
std::vector< double > roots(SBasis const &s)
Bezier integral(Bezier const &a)
Definition bezier.cpp:294
Bezier derivative(Bezier const &a)
Definition bezier.cpp:282
SBasis toSBasis(SBasisN< 1 > f)
Definition sbasisN.h:640
std::vector< D2< SBasis > > cubics_fitting_curvature(Point const &M0, Point const &M1, Point const &dM0, Point const &dM1, double d2M0xdM0, double d2M1xdM1, int insist_on_speed_signs=1, double epsilon=1e-5)
OptInterval bounds_fast(Bezier const &b)
Definition bezier.cpp:305
D2< T > rot90(D2< T > const &a)
Definition d2.h:397
STL namespace.
void cairo_line_to(cairo_t *cr, Geom::Point p1)
struct _cairo cairo_t
Definition path-cairo.h:16
void cairo_move_to(cairo_t *cr, Geom::Point p1)
void cairo_d2_sb(cairo_t *cr, Geom::D2< Geom::SBasis > const &p)
D2< SBasis > sbofsb_cubic_solve(SBasisOf< SBasisOf< double > > const &f, Geom::Point const &A, Geom::Point const &B)
Finds a path which traces the 0 contour of f, traversing from A to B as a single cubic d2<sbasis>.
Definition sb-of-sb.cpp:306
Piecewise< SBasis > convole(SBasisOf< double > const &f, Interval dom_f, SBasisOf< double > const &g, Interval dom_g)
Definition sb-of-sb.cpp:244
SBasisOf< T > multi_compose(SBasisOf< double > const &f, SBasisOf< T > const &g)
Definition sb-of-sb.cpp:103
SBasisOf< double > toSBasisOfDouble(SBasis const &f)
Definition sb-of-sb.cpp:22
static SBasisOf< double > eval_dim(SBasisOf< SBasisOf< double > > const &f, double t, unsigned dim)
Definition sb-of-sb.cpp:158
void plot3d(cairo_t *cr, SBasis const &x, SBasis const &y, SBasis const &z, Frame frame)
Definition sb-of-sb.cpp:191
SBasisOf< T > subderivative(SBasisOf< T > const &f)
Definition sb-of-sb.cpp:287
two-dimensional geometric operators.
Defines S-power basis function class with coefficient in arbitrary ring.
Polynomial in symmetric power basis (S-basis)
Definition curve.h:24
double height
double width
void cairo_set_source_rgba(cairo_t *cr, colour c)
void init(int argc, char **argv, Toy *t, int width=600, int height=600)