Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
aa.cpp
Go to the documentation of this file.
1#include <2geom/convex-hull.h>
2#include <2geom/d2.h>
3#include <2geom/geom.h>
5
6#include <toys/path-cairo.h>
8
9#include <aa.h>
10#include <complex>
11#include <algorithm>
12#include <optional>
13
14using std::vector;
15using namespace Geom;
16using namespace std;
17
18//Geom::Rect zoom(Geom::Rect r, Geom::Point p, double s) {
19// return p + (r - p)*s;
20//}
21
22typedef std::complex<AAF> CAAF;
23
24struct PtLexCmp{
25 bool operator()(const Point &a, const Point &b) {
26 return (a[0] < b[0]) || ((a[0] == b[0]) and (a[1] < b[1]));
27 }
28};
29
30void draw_line_in_rect(cairo_t*cr, Rect &r, Point n, double c) {
31 std::optional<Geom::LineSegment> ls =
32 rect_line_intersect(r, Line::fromNormalDistance(n, c));
33
34 if(ls) {
35 cairo_move_to(cr, (*ls)[0]);
36 cairo_line_to(cr, (*ls)[1]);
37 cairo_stroke(cr);
38
39 }
40}
41
43 vector<Geom::Point> result;
44 Point resultp;
45 for(int i = 0; i < 4; i++) {
46 Point cnr = r.corner(i);
47 double z = dot(cnr, n);
48 if((z > lu[0]) and (z < lu[1]))
49 result.push_back(cnr);
50 }
51 for(int i = 0; i < 2; i++) {
52 double c = lu[i];
53
54 std::optional<Geom::LineSegment> ls =
55 rect_line_intersect(r, Line::fromNormalDistance(n, c));
56
57 if(ls) {
58 result.push_back((*ls)[0]);
59 result.push_back((*ls)[1]);
60 }
61 }
62 if(result.size() < 2)
63 return OptRect();
64 Rect nr(result[0], result[1]);
65 for(size_t i = 2; i < result.size(); i++) {
66 nr.expandTo(result[i]);
67 }
68 return intersect(nr, r);
69}
70
71AAF ls_sample_based(AAF x, vector<Point> pts) {
72 NL::Matrix m(pts.size(), 2);
73 NL::Vector v(pts.size());
74 NL::LinearSystem ls(m, v);
75
76 m.set_all(0);
77 v.set_all(0);
78 for (unsigned int k = 0; k < pts.size(); ++k)
79 {
80 m(k,0) += pts[k][0];
81 m(k,1) += 1;
82 //std::cout << pts[k] << " ";
83
84 v[k] += pts[k][1];
85 //v[1] += pts[k][1];
86 //v[2] += y2;
87 }
88
89 ls.SV_solve();
90
91 double A = ls.solution()[0];
92 double B = ls.solution()[1];
93 // Ax + B = y
94 Interval bnd(0,0);
95 for (unsigned int k = 0; k < pts.size(); ++k)
96 {
97 bnd.extendTo(A*pts[k][0]+B - pts[k][1]);
98 }
99 //std::cout << A << "," << B << std::endl;
100 return AAF(x, A, B, bnd.extent(),
101 x.special);
102}
103
104AAF md_sample_based(AAF x, vector<Point> pts) {
105 Geom::ConvexHull ch1(pts);
106 Point a, b, c;
107 double dia = ch1.narrowest_diameter(a, b, c);
108 Point db = c-b;
109 double A = db[1]/db[0];
110 Point aa = db*(dot(db, a-b)/dot(db,db))+b;
111 Point mid = (a+aa)/2;
112 double B = mid[1] - A*mid[0];
113 double dB = (a[1] - A*a[0]) - B;
114 // Ax + B = y
115 std::cout << A << "," << B << std::endl;
116 return AAF(x, A, B, dB,
117 x.special);
118}
119
121 interval ab(x);
122 const double a = ab.min(); // [a,b] is our interval
123 const double b = ab.max();
124
125 const double ea = atan(a);
126 const double eb = atan(b);
127 vector<Point> pts;
128 pts.push_back(Point(a,ea));
129 pts.push_back(Point(b,eb));
130 const double alpha = (eb-ea)/(b-a);
131 double xs = sqrt(1/alpha-1);
132 if((a < xs) and (xs < b))
133 pts.push_back(Point(xs,atan(xs)));
134 xs = -xs;
135 if((a < xs) and (xs < b))
136 pts.push_back(Point(xs,atan(xs)));
137
138 return md_sample_based(x, pts);
139}
140
142 interval ab(x);
143 const double a = ab.min(); // [a,b] is our interval
144 const double b = ab.max();
145 AAF_TYPE type;
146 if(a > 0)
147 type = AAF_TYPE_AFFINE;
148 else if(b < 0) { // no point in continuing
149 type = AAF_TYPE_NAN;
150 return AAF(type);
151 }
152 else if(a <= 0) { // undefined, can we do better?
153 type = (AAF_TYPE)(AAF_TYPE_AFFINE | AAF_TYPE_NAN);
154 return AAF(type);
155 // perhaps we should make a = 0+eps and try to continue?
156 }
157
158 const double ea = log(a);
159 const double eb = log(b);
160 vector<Point> pts;
161 pts.push_back(Point(a,ea));
162 pts.push_back(Point(b,eb));
163 const double alpha = (eb-ea)/(b-a);
164 // dlog(xs) = alpha
165 double xs = 1/(alpha);
166 if((a < xs) and (xs < b))
167 pts.push_back(Point(xs,log(xs)));
168
169 return md_sample_based(x, pts);
170}
171
173 interval ab(x);
174 const double a = ab.min(); // [a,b] is our interval
175 const double b = ab.max();
176
177 const double ea = exp(a);
178 const double eb = exp(b);
179 vector<Point> pts;
180 pts.push_back(Point(a,ea));
181 pts.push_back(Point(b,eb));
182 const double alpha = (eb-ea)/(b-a);
183 // dexp(xs) = alpha
184 double xs = log(alpha);
185 if((a < xs) and (xs < b))
186 pts.push_back(Point(xs,exp(xs)));
187
188 return md_sample_based(x, pts);
189}
190
191AAF pow_sample_based(AAF x, double p) {
192 interval ab(x);
193 const double a = ab.min(); // [a,b] is our interval
194 const double b = ab.max();
195 AAF_TYPE type;
196 if(a >= 0)
197 type = AAF_TYPE_AFFINE;
198 else if(b < 0) { // no point in continuing
199 type = AAF_TYPE_NAN;
200 return AAF(type);
201 }
202 else if(a <= 0) { // undefined, can we do better?
203 type = (AAF_TYPE)(AAF_TYPE_AFFINE | AAF_TYPE_NAN);
204 return AAF(type);
205 // perhaps we should make a = 0+eps and try to continue?
206 }
207
208 const double ea = pow(a, p);
209 const double eb = pow(b, p);
210 vector<Point> pts;
211 pts.push_back(Point(a,ea));
212 pts.push_back(Point(b,eb));
213 const double alpha = (eb-ea)/(b-a);
214 // d(xs^p) = alpha
215 // p xs^(p-1) = alpha
216 // xs = (alpha/p)^(1-p)
217 double xs = pow(alpha/p, 1./(p-1));
218 if((a < xs) and (xs < b))
219 pts.push_back(Point(xs,pow(xs, p)));
220 xs = -xs;
221 if((a < xs) and (xs < b))
222 pts.push_back(Point(xs,pow(xs, p)));
223
224 return md_sample_based(x, pts);
225}
226
228double scale=100;
229
230AAF trial_eval(AAF x, AAF y) {
231 x = x-origin[0];
232 y = y-origin[1];
233
234 x = x/scale;
235 y = y/scale;
236
237 return x*x -y*y + -6*x +10*y-16;
238 return -y + log(sqrt(x))/log(x);
239 return y*y - x*(x-1)*(x+1);
240
241 //return x*x - 1;
242 //return y - pow(x,3);
243 //return y - pow_sample_based(x,2.5);
244 //return y - log_sample_based(x);
245 //return y - log(x);
246 //return y - exp_sample_based(x*log(x));
247 //return y - sqrt(sin(x));
248 //return sqrt(y)*x - sqrt(x) - y - 1;
249 //return y-1/x;
250 //return exp(x)-y;
251 //return sin(x)-y;
252 //return exp_sample_based(x)-y;
253 //return atan(x)-y;
254 //return atan_sample_based(x)-y;
255 //return atanh(x)-y;
256 //return x*y;
257 //return 4*x+3*y-1;
258 //return x*x + y*y - 1;
259 //return sin(x*y) + cos(pow(x, 3)) - atan(x);
260 //return pow((x*x + y*y), 2) - (x*x-y*y);
261 return 4*(2*y-4*x)*(2*y+4*x-16)-16*y*y;
262 return pow((x*x + y*y), 2) - (x*x-y*y);
263 //return pow(x,3) - 3*x*x - 3*y*y;
264 return (x*x + y*y-1)*((x-1)*(x-1)+y*y-1);
265 //return x*x-y;
266 //return (x*x*x-y*x)*sin(x) + (x-y*y)*cos(y)-0.5;
267}
268
269AAF xaxis(AAF x, AAF y) {
270 y = y-origin[1];
271 y = y/scale;
272 return y;
273}
274
275AAF xaxis2(AAF x, AAF y) {
276 y = y-origin[1];
277 y = y/scale;
278 return y-4;
279}
280
281AAF yaxis(AAF x, AAF y) {
282 x = x-origin[0];
283 x = x/scale;
284 return x;
285}
286
287class ConvexTest: public Toy {
288public:
289 PointSetHandle test_window;
290 PointSetHandle samples;
291 PointHandle orig_handle;
292 ConvexTest () {
293 toggles.push_back(Toggle("Show trials", false));
294 handles.push_back(&test_window);
295 handles.push_back(&samples);
296 handles.push_back(&orig_handle);
297 orig_handle.pos = Point(300,300);
298 test_window.push_back(Point(100,100));
299 test_window.push_back(Point(200,200));
300 for(int i = 0; i < 0; i++) {
301 samples.push_back(Point(i*100, i*100+25));
302 }
303 }
304 int iters;
305 int splits[4];
306 bool show_splits;
307 std::vector<Toggle> toggles;
308 AAF (*eval)(AAF, AAF);
309 Geom::Rect view;
310 void recursive_implicit(Rect r, cairo_t*cr, double w) {
311 if(show_splits) {
312 cairo_save(cr);
313 cairo_set_line_width(cr, 0.3);
314 /*if(f.is_partial())
315 cairo_set_source_rgba(cr, 1, 0, 1, 0.25);
316 else*/
317 cairo_set_source_rgba(cr, 0, 1, 0, 0.25);
318 cairo_rectangle(cr, r);
319 cairo_stroke(cr);
320 cairo_restore(cr);
321 }
322 iters++;
323 AAF x(interval(r.left(), r.right()));
324 AAF y(interval(r.top(), r.bottom()));
325 //assert(x.rad() > 0);
326 //assert(y.rad() > 0);
327 AAF f = (*eval)(x, y);
328 // pivot
329 double a = f.index_coeff(x.get_index(0))/x.index_coeff(x.get_index(0));
330 double b = f.index_coeff(y.get_index(0))/y.index_coeff(y.get_index(0));
331 AAF d = a*x + b*y - f;
332 interval ivl(d);
333 Point n(a,b);
334 OptRect out = tighten(r, n, Interval(ivl.min(), ivl.max()));
335 if(ivl.extent() < 0.5*L2(n)) {
336 draw_line_in_rect(cr, r, n, ivl.middle());
337 return;
338 }
339 if(!f.is_partial() and f.is_indeterminate()) {
340 cairo_save(cr);
341 cairo_set_line_width(cr, 0.3);
342 if(f.is_infinite()) {
343 cairo_set_source_rgb(cr, 1, 0.5, 0.5);
344 } else if(f.is_nan()) {
345 cairo_set_source_rgb(cr, 1, 1, 0);
346 } else {
347 cairo_set_source_rgb(cr, 1, 0, 0);
348 }
349 cairo_rectangle(cr, r);
350 if(show_splits) {
351 cairo_stroke(cr);
352 } else {
353 cairo_fill(cr);
354 }
355 cairo_restore(cr);
356 return;
357 }
358
359 if((r.width() > w) or (r.height()>w)) {
360 if(f.straddles_zero()) {
361 // Three possibilities:
362 // 1) the trim operation buys us enough that we should just iterate
363 Point c = r.midpoint();
364 Rect oldr = r;
365 if(out)
366 r = *out;
367 if(1 && out && (r.area() < oldr.area()*0.25)) {
368 splits[0] ++;
369 recursive_implicit(r, cr, w);
370 // 2) one dimension is significantly smaller
371 } else if(1 && (r[1].extent() < oldr[1].extent()*0.5)) {
372 splits[1]++;
373 recursive_implicit(Rect(Interval(r.left(), r.right()),
374 Interval(r.top(), c[1])), cr,w);
375 recursive_implicit(Rect(Interval(r.left(), r.right()),
376 Interval(c[1], r.bottom())), cr,w);
377 } else if(1 && (r[0].extent() < oldr[0].extent()*0.5)) {
378 splits[2]++;
379 recursive_implicit(Rect(Interval(r.left(), c[0]),
380 Interval(r.top(), r.bottom())), cr,w);
381 recursive_implicit(Rect(Interval(c[0], r.right()),
382 Interval(r.top(), r.bottom())), cr,w);
383 // 3) to ensure progress we must do a four way split
384 } else {
385 splits[3]++;
386 recursive_implicit(Rect(Interval(r.left(), c[0]),
387 Interval(r.top(), c[1])), cr,w);
388 recursive_implicit(Rect(Interval(c[0], r.right()),
389 Interval(r.top(), c[1])), cr,w);
390 recursive_implicit(Rect(Interval(r.left(), c[0]),
391 Interval(c[1], r.bottom())), cr,w);
392 recursive_implicit(Rect(Interval(c[0], r.right()),
393 Interval(c[1], r.bottom())), cr,w);
394 }
395 }
396 } else {
397 }
398 }
399
400 void key_hit(unsigned keyval, unsigned modifiers) override {
401 if(keyval == 'w') toggles[0].toggle(); else
402 if(keyval == 'a') toggles[1].toggle(); else
403 if(keyval == 'q') toggles[2].toggle(); else
404 if(keyval == 's') toggles[3].toggle();
405 redraw();
406 }
407 void mouse_pressed(Geom::Point const &pos, unsigned button, unsigned modifiers) override {
408 toggle_events(toggles, pos, button);
409 Toy::mouse_pressed(pos, button, modifiers);
410 }
411 void scroll(GdkScrollDirection dir, Geom::Point const &delta) override {
412 if (dir == GDK_SCROLL_UP) {
413 scale /= 1.2;
414 } else if (dir == GDK_SCROLL_DOWN) {
415 scale *= 1.2;
416 }
417 redraw();
418 }
419 void draw(cairo_t *cr, std::ostringstream *notify, int width, int height, bool save, std::ostringstream *timer_stream) override {
420 cairo_set_source_rgba (cr, 0., 0., 0, 1);
421 cairo_set_line_width (cr, 1);
422 origin = orig_handle.pos;
423 if(1) {
424 cairo_save(cr);
425 cairo_set_line_width(cr, 0.3);
426 cairo_set_source_rgb(cr, 0.5, 0.5, 1);
427 eval = xaxis;
428 recursive_implicit(Rect(Interval(0,width), Interval(0, height)), cr, 3);
429 eval = xaxis2;
430 recursive_implicit(Rect(Interval(0,width), Interval(0, height)), cr, 3);
431 eval = yaxis;
432 recursive_implicit(Rect(Interval(0,width), Interval(0, height)), cr, 3);
433 cairo_restore(cr);
434 iters = 0;
435 for(int & split : splits)
436 split = 0;
437 show_splits = toggles[0].on;
438 eval = trial_eval;
439 recursive_implicit(Rect(Interval(0,width), Interval(0, height)), cr, 3);
440 for(int split : splits)
441 *notify << split << " + ";
442 *notify << " = " << iters;
443 }
444 if(1) {
445 Rect r(test_window.pts[0], test_window.pts[1]);
446 AAF x(interval(r.left(), r.right()));
447 AAF y(interval(r.top(), r.bottom()));
448 //AAF f = md_sample_based(x, samples.pts)-y;
449 if(0) {
450 x = x-500;
451 y = y-300;
452 x = x/200;
453 y = y/200;
454 AAF f = atan_sample_based(x)-y;
455 cout << f << endl;
456 }
457 AAF f = (*eval)(x, y);
458 double a = f.index_coeff(x.get_index(0))/x.index_coeff(x.get_index(0));
459 double b = f.index_coeff(y.get_index(0))/y.index_coeff(y.get_index(0));
460 AAF d = a*x + b*y - f;
461 //cout << d << endl;
462 interval ivl(d);
463 Point n(a,b);
464 OptRect out = tighten(r, n, Interval(ivl.min(), ivl.max()));
465 if(out)
466 cairo_rectangle(cr, *out);
467 cairo_rectangle(cr, r);
468 draw_line_in_rect(cr, r, n, ivl.min());
469 cairo_stroke(cr);
470 cairo_save(cr);
471 cairo_set_line_width(cr, 0.3);
472 cairo_set_source_rgb(cr, 0.5, 0.5, 0);
473 draw_line_in_rect(cr, r, n, ivl.middle());
474 cairo_restore(cr);
475 draw_line_in_rect(cr, r, n, ivl.max());
476 cairo_stroke(cr);
477 }
478 if(0) {
479 Geom::ConvexHull gm(samples.pts);
480 cairo_convex_hull(cr, gm);
481 cairo_stroke(cr);
482 Point a, b, c;
483 double dia = gm.narrowest_diameter(a, b, c);
484 cairo_save(cr);
485 cairo_set_line_width(cr, 2);
486 cairo_set_source_rgba(cr, 1, 0, 0, 0.5);
487 cairo_move_to(cr, b);
488 cairo_line_to(cr, c);
489 cairo_move_to(cr, a);
490 cairo_line_to(cr, (c-b)*dot(a-b, c-b)/dot(c-b,c-b)+b);
491 cairo_stroke(cr);
492 //std::cout << a << ", " << b << ", " << c << ": " << dia << "\n";
493 cairo_restore(cr);
494 }
495 Toy::draw(cr, notify, width, height, save,timer_stream);
496 Point d(25,25);
497 toggles[0].bounds = Rect(Point(10, height-80)+d,
498 Point(10+120, height-80+d[1])+d);
499
500 draw_toggles(cr, toggles);
501 }
502
503};
504
505int main(int argc, char **argv) {
506 init(argc, argv, new ConvexTest());
507
508 return 0;
509}
510
511/*
512 Local Variables:
513 mode:c++
514 c-file-style:"stroustrup"
515 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
516 indent-tabs-mode:nil
517 fill-column:99
518 End:
519*/
520// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Various geometrical calculations.
AAF md_sample_based(AAF x, vector< Point > pts)
Definition aa.cpp:104
AAF log_sample_based(AAF x)
Definition aa.cpp:141
AAF exp_sample_based(AAF x)
Definition aa.cpp:172
void draw_line_in_rect(cairo_t *cr, Rect &r, Point n, double c)
Definition aa.cpp:30
AAF trial_eval(AAF x, AAF y)
Definition aa.cpp:230
AAF yaxis(AAF x, AAF y)
Definition aa.cpp:281
double scale
Definition aa.cpp:228
Point origin
Definition aa.cpp:227
AAF pow_sample_based(AAF x, double p)
Definition aa.cpp:191
AAF atan_sample_based(AAF x)
Definition aa.cpp:120
std::complex< AAF > CAAF
Definition aa.cpp:22
AAF xaxis(AAF x, AAF y)
Definition aa.cpp:269
AAF ls_sample_based(AAF x, vector< Point > pts)
Definition aa.cpp:71
OptRect tighten(Rect &r, Point n, Interval lu)
Definition aa.cpp:42
AAF xaxis2(AAF x, AAF y)
Definition aa.cpp:275
int main()
Convex hull based on the Andrew's monotone chain algorithm.
constexpr C extent() const
C right() const
Return rightmost coordinate of the rectangle (+X is to the right).
C area() const
Compute the rectangle's area.
C top() const
Return top coordinate of the rectangle (+Y is downwards).
CPoint midpoint() const
Get the point in the geometric center of the rectangle.
C left() const
Return leftmost coordinate of the rectangle (+X is to the right).
void expandTo(CPoint const &p)
Enlarge the rectangle to contain the given point.
C height() const
Get the vertical extent of the rectangle.
C width() const
Get the horizontal extent of the rectangle.
C bottom() const
Return bottom coordinate of the rectangle (+Y is downwards).
CPoint corner(unsigned i) const
Return the n-th corner of the rectangle.
Range of real numbers that is never empty.
Definition interval.h:59
const Vector & SV_solve()
const Vector & solution() const
void set_all(double x)
Definition matrix.h:225
Axis-aligned rectangle that can be empty.
Definition rect.h:203
Two-dimensional point that doubles as a vector.
Definition point.h:66
Axis aligned, non-empty rectangle.
Definition rect.h:92
Geom::Point pos
void push_back(double x, double y)
std::vector< Geom::Point > pts
virtual void mouse_pressed(Geom::Point const &pos, unsigned button, unsigned modifiers)
vector< Handle * > handles
virtual void save(FILE *f)
virtual void key_hit(unsigned keyval, unsigned modifiers)
virtual void draw(cairo_t *cr, std::ostringstream *notify, int w, int h, bool save, std::ostringstream *timing_stream)
virtual void scroll(GdkScrollDirection dir, Geom::Point const &delta)
const double w
Definition conic-4.cpp:19
Convex hull data structures.
Css & result
double c[8][4]
Lifts one dimensional objects into 2D.
T pow(T const &t, int n)
Integer exponentiation for transforms.
Definition transforms.h:98
Point origin
Definition ineaa.cpp:358
Various utility functions.
Definition affine.h:22
SBasisN< n > sqrt(SBasisN< n > const &a, int k)
std::optional< Geom::LineSegment > rect_line_intersect(Geom::Rect &r, Geom::LineSegment ls)
Determine whether & where an (infinite) line intersects a rectangle.
Definition geom.cpp:333
void split(vector< Point > const &p, double t, vector< Point > &left, vector< Point > &right)
Piecewise< SBasis > log(SBasis const &f, double tol=1e-3, int order=3)
SBasis L2(D2< SBasis > const &a, unsigned k)
Definition d2-sbasis.cpp:42
T dot(D2< T > const &a, D2< T > const &b)
Definition d2.h:355
std::vector< Point > intersect(const xAx &C1, const xAx &C2)
Definition conicsec.cpp:361
int n
Definition spiro.cpp:66
STL namespace.
void cairo_rectangle(cairo_t *cr, Geom::Rect const &r)
void cairo_line_to(cairo_t *cr, Geom::Point p1)
struct _cairo cairo_t
Definition path-cairo.h:16
void cairo_convex_hull(cairo_t *cr, Geom::ConvexHull const &r)
void cairo_move_to(cairo_t *cr, Geom::Point p1)
int delta
double height
double width
void toggle_events(std::vector< Toggle > &ts, Geom::Point const &pos, unsigned button)
void cairo_set_source_rgba(cairo_t *cr, colour c)
void draw_toggles(cairo_t *cr, std::vector< Toggle > &ts)
void redraw()
void init(int argc, char **argv, Toy *t, int width=600, int height=600)