1 /*
2 * Conic Section Toy
3 *
4 * Authors:
5 * Marco Cecchetti <mrcekets at gmail.com>
6 *
7 * Copyright 2009 authors
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it either under the terms of the GNU Lesser General Public
11 * License version 2.1 as published by the Free Software Foundation
12 * (the "LGPL") or, at your option, under the terms of the Mozilla
13 * Public License Version 1.1 (the "MPL"). If you do not alter this
14 * notice, a recipient may use your version of this file under either
15 * the MPL or the LGPL.
16 *
17 * You should have received a copy of the LGPL along with this library
18 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * You should have received a copy of the MPL along with this library
21 * in the file COPYING-MPL-1.1
22 *
23 * The contents of this file are subject to the Mozilla Public License
24 * Version 1.1 (the "License"); you may not use this file except in
25 * compliance with the License. You may obtain a copy of the License at
26 * http://www.mozilla.org/MPL/
27 *
28 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
29 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
30 * the specific language governing rights and limitations.
31 */
32
33
34 #include <toys/path-cairo.h>
35 #include <toys/toy-framework-2.h>
36
37 //#define CLIP_WITH_CAIRO_SUPPORT
38 #ifdef CLIP_WITH_CAIRO_SUPPORT
39 #include <2geom/conic_section_clipper_cr.h>
40 #endif
41
42
43 #include <2geom/conicsec.h>
44 #include <2geom/line.h>
45
46 //#include <iomanip>
47 #include <optional>
48
49
50 using namespace Geom;
51
52
53 class ConicSectionToy : public Toy
54 {
55 enum menu_item_t
56 {
57 SHOW_MENU = 0,
58 TEST_VERTEX_FOCI,
59 TEST_FITTING,
60 TEST_ECCENTRICITY,
61 TEST_DEGENERATE,
62 TEST_ROOTS,
63 TEST_NEAREST_POINT,
64 TEST_BOUND,
65 TEST_CLIP,
66 TEST_TANGENT,
67 TEST_DUAL,
68 TOTAL_ITEMS // this one must be the last item
69 };
70
71 static const char* menu_items[TOTAL_ITEMS];
72 static const char keys[TOTAL_ITEMS];
73
first_time(int,char **)74 void first_time(int /*argc*/, char** /*argv*/) override
75 {
76 draw_f = &ConicSectionToy::draw_menu;
77 }
78
79
init_common()80 void init_common()
81 {
82 init_vertex_foci();
83 set_control_geometry = true;
84 }
85
draw_common(cairo_t * cr,std::ostringstream * notify,int width,int height,bool save,std::ostringstream * timer_stream)86 void draw_common (cairo_t *cr, std::ostringstream *notify,
87 int width, int height, bool save,
88 std::ostringstream * timer_stream)
89 {
90 draw_vertex_foci(cr, notify, width, height, save, timer_stream);
91 }
92
93
94 /*
95 * TEST VERTEX FOCI
96 */
init_vertex_foci()97 void init_vertex_foci()
98 {
99 set_common_control_geometry = true;
100 handles.clear();
101
102 focus1.pos = Point(300, 300);
103 focus2.pos = Point(500, 300);
104 vertex.pos = Point(200, 300);
105
106 parabola_toggle = Toggle("set/unset F2 to infinity", false);
107
108 handles.push_back (&vertex);
109 handles.push_back (&focus1);
110 handles.push_back (&focus2);
111 handles.push_back (¶bola_toggle);
112 }
113
draw_vertex_foci(cairo_t * cr,std::ostringstream * notify,int width,int height,bool,std::ostringstream *)114 void draw_vertex_foci (cairo_t *cr, std::ostringstream *notify,
115 int width, int height, bool /*save*/,
116 std::ostringstream * /*timer_stream*/)
117 {
118 init_vertex_foci_ctrl_geom(cr, notify, width, height);
119
120
121 if (!parabola_toggle.on )
122 {
123 if (focus2.pos == Point(infinity(),infinity()))
124 focus2.pos = Point(m_width/2, m_height/2);
125 double df1f2 = distance (focus1.pos, focus2.pos);
126 if (df1f2 > 20 )
127 {
128 Line axis(focus1.pos,focus2.pos);
129 vertex.pos = projection (vertex.pos, axis);
130 }
131 else if (df1f2 > 1)
132 {
133 Line axis(focus1.pos,vertex.pos);
134 focus2.pos = projection (focus2.pos, axis);
135 }
136 else
137 {
138 Line axis(focus1.pos,vertex.pos);
139 focus2.pos = focus1.pos;
140 }
141 }
142 else
143 {
144 focus2.pos = Point(infinity(),infinity());
145 }
146
147 cs.set (vertex.pos, focus1.pos, focus2.pos);
148 cairo_set_source_rgba(cr, 0.3, 0.3, 0.3, 1.0);
149 cairo_set_line_width (cr, 0.5);
150 draw (cr, cs, m_window);
151 cairo_stroke(cr);
152
153 draw_label(cr, focus1, "F1");
154 if (!parabola_toggle.on) draw_label(cr, focus2, "F2");
155 draw_label(cr, vertex, "V");
156 cairo_stroke(cr);
157
158 *notify << cs.categorise() << ": " << cs << std::endl;
159 }
160
init_vertex_foci_ctrl_geom(cairo_t *,std::ostringstream *,int width,int)161 void init_vertex_foci_ctrl_geom (cairo_t* /*cr*/,
162 std::ostringstream* /*notify*/,
163 int width, int /*height*/)
164 {
165 if ( set_common_control_geometry )
166 {
167 set_common_control_geometry = false;
168
169 Point toggle_sp( width - 200, 10);
170 parabola_toggle.bounds = Rect (toggle_sp, toggle_sp + Point(190,30));
171 }
172 }
173
174
175 /*
176 * TEST FITTING
177 */
init_fitting()178 void init_fitting()
179 {
180 set_common_control_geometry = true;
181 handles.clear();
182
183 psh.pts.resize(5);
184 psh.pts[0] = Point(450, 250);
185 psh.pts[1] = Point(250, 100);
186 psh.pts[2] = Point(250, 400);
187 psh.pts[3] = Point(400, 320);
188 psh.pts[4] = Point(50, 250);
189
190 fitting_slider.set (0, 5, 1, 0, "more handles");
191
192 handles.push_back(&psh);
193 handles.push_back(&fitting_slider);
194 }
195
draw_fitting(cairo_t * cr,std::ostringstream * notify,int width,int height,bool,std::ostringstream *)196 void draw_fitting (cairo_t *cr, std::ostringstream *notify,
197 int width, int height, bool /*save*/,
198 std::ostringstream * /*timer_stream*/)
199 {
200 init_fitting_ctrl_geom(cr, notify, width, height);
201
202 size_t n = (size_t)(fitting_slider.value()) + 5;
203 if (n < psh.pts.size())
204 {
205 psh.pts.resize(n);
206 }
207 else if (n > psh.pts.size())
208 {
209 psh.push_back (std::fabs (width - 100) * uniform() + 50,
210 std::fabs (height - 100) * uniform() + 50);
211 }
212
213 cs.set (psh.pts);
214
215 cairo_set_source_rgba(cr, 0.3, 0.3, 0.3, 1.0);
216 cairo_set_line_width (cr, 0.5);
217 draw (cr, cs, m_window);
218 cairo_stroke(cr);
219 *notify << cs.categorise() << ": " << cs << std::endl;
220 }
221
init_fitting_ctrl_geom(cairo_t *,std::ostringstream *,int,int height)222 void init_fitting_ctrl_geom (cairo_t* /*cr*/,
223 std::ostringstream* /*notify*/,
224 int /*width*/, int height)
225 {
226 if ( set_common_control_geometry )
227 {
228 set_common_control_geometry = false;
229 fitting_slider.geometry (Point(50, height - 50), 100);
230 }
231 }
232
233
234 /*
235 * TEST ECCENTRICITY
236 */
init_eccentricity()237 void init_eccentricity()
238 {
239 set_common_control_geometry = true;
240 handles.clear();
241
242 p1 = Point (100, 100);
243 p2 = Point (100, 400);
244 focus1 = Point (300, 250);
245
246 eccentricity_slider.set (0, 3, 0, 1, "eccentricity");
247
248 handles.push_back (&p1);
249 handles.push_back (&p2);
250 handles.push_back (&focus1);
251 handles.push_back (&eccentricity_slider);
252 }
253
draw_eccentricity(cairo_t * cr,std::ostringstream * notify,int width,int height,bool,std::ostringstream *)254 void draw_eccentricity (cairo_t *cr, std::ostringstream *notify,
255 int width, int height, bool /*save*/,
256 std::ostringstream * /*timer_stream*/)
257 {
258 init_eccentricity_ctrl_geom(cr, notify, width, height);
259
260 Line directrix (p1.pos, p2.pos);
261
262 cs.set (focus1.pos, directrix, eccentricity_slider.value());
263
264 cairo_set_source_rgba(cr, 0.3, 0.3, 0.3, 1.0);
265 cairo_set_line_width (cr, 0.5);
266 draw (cr, cs, m_window);
267 cairo_stroke(cr);
268
269 draw_label (cr, focus1, "F");
270 draw_line (cr, directrix, m_window);
271 draw_label(cr, p1, "directrix");
272 cairo_stroke(cr);
273
274 *notify << cs.categorise() << ": " << cs << std::endl;
275 }
276
init_eccentricity_ctrl_geom(cairo_t *,std::ostringstream *,int,int height)277 void init_eccentricity_ctrl_geom (cairo_t* /*cr*/,
278 std::ostringstream* /*notify*/,
279 int /*width*/, int height)
280 {
281 if ( set_common_control_geometry )
282 {
283 set_common_control_geometry = false;
284 eccentricity_slider.geometry (Point (10, height - 50), 300);
285 }
286 }
287
288
289
290 /*
291 * TEST DEGENERATE
292 */
init_degenerate()293 void init_degenerate()
294 {
295 set_common_control_geometry = true;
296 handles.clear();
297
298 psh.pts.resize(4);
299 psh.pts[0] = Point(450, 250);
300 psh.pts[1] = Point(250, 100);
301 psh.pts[2] = Point(250, 400);
302 psh.pts[3] = Point(400, 320);
303
304
305
306 handles.push_back(&psh);
307 }
308
draw_degenerate(cairo_t * cr,std::ostringstream * notify,int width,int height,bool,std::ostringstream *)309 void draw_degenerate (cairo_t *cr, std::ostringstream *notify,
310 int width, int height, bool /*save*/,
311 std::ostringstream * /*timer_stream*/)
312 {
313 init_degenerate_ctrl_geom(cr, notify, width, height);
314
315 Line l1 (psh.pts[0], psh.pts[1]);
316 Line l2 (psh.pts[2], psh.pts[3]);
317 cs.set (l1, l2);
318 cairo_set_source_rgba(cr, 0.3, 0.3, 0.3, 1.0);
319 cairo_set_line_width (cr, 0.5);
320 draw (cr, cs, m_window);
321 cairo_stroke(cr);
322
323 *notify << cs.categorise() << ": " << cs << std::endl;
324 }
325
init_degenerate_ctrl_geom(cairo_t *,std::ostringstream *,int,int)326 void init_degenerate_ctrl_geom (cairo_t* /*cr*/,
327 std::ostringstream* /*notify*/,
328 int /*width*/, int /*height*/)
329 {
330 if ( set_common_control_geometry )
331 {
332 set_common_control_geometry = false;
333 }
334 }
335
336
337 /*
338 * TEST ROOTS
339 */
init_roots()340 void init_roots()
341 {
342 init_common();
343
344 p1.pos = Point(180, 50);
345
346 x_y_toggle = Toggle("X/Y roots", true);
347
348 handles.push_back(&p1);
349 handles.push_back(&x_y_toggle);
350 }
351
draw_roots(cairo_t * cr,std::ostringstream * notify,int width,int height,bool save,std::ostringstream * timer_stream)352 void draw_roots (cairo_t *cr, std::ostringstream *notify,
353 int width, int height, bool save,
354 std::ostringstream * timer_stream)
355 {
356 draw_common(cr, notify, width, height, save, timer_stream);
357 init_roots_ctrl_geom(cr, notify, width, height);
358
359
360 Dim2 DIM = x_y_toggle.on ? X : Y;
361 Line l(p1.pos, DIM * (-M_PI/2) + M_PI/2);
362
363 cairo_set_line_width(cr, 0.2);
364 cairo_set_source_rgba(cr, 0.3, 0.3, 0.3, 1.0);
365 draw_line(cr, l, m_window);
366 cairo_stroke(cr);
367
368 cairo_set_source_rgba(cr, 0.8, 0.0, 0.0, 1.0);
369 std::vector<double> values;
370 try
371 {
372 cs.roots(values, p1.pos[DIM], DIM);
373 }
374 catch(Geom::Exception e)
375 {
376 std::cerr << e.what() << std::endl;
377 }
378 for (double value : values)
379 {
380 Point p(value, value);
381 p[DIM] = p1.pos[DIM];
382 draw_handle(cr, p);
383 }
384 cairo_stroke(cr);
385
386 *notify << " ";
387 for ( unsigned int i = 0; i < values.size(); ++i )
388 {
389 *notify << "v" << i << " = " << values[i] << " ";
390 }
391 }
392
init_roots_ctrl_geom(cairo_t *,std::ostringstream *,int width,int height)393 void init_roots_ctrl_geom (cairo_t* /*cr*/, std::ostringstream* /*notify*/,
394 int width, int height)
395 {
396 if ( set_control_geometry )
397 {
398 set_control_geometry = false;
399
400 Point T(width - 120, height - 60);
401 x_y_toggle.bounds = Rect( T, T + Point(100,25) );
402 }
403 }
404
405 /*
406 * TEST NEAREST POINT
407 */
408
init_nearest_time()409 void init_nearest_time()
410 {
411 init_common();
412 p1.pos = Point(180, 50);
413 handles.push_back(&p1);
414 }
415
draw_nearest_time(cairo_t * cr,std::ostringstream * notify,int width,int height,bool save,std::ostringstream * timer_stream)416 void draw_nearest_time (cairo_t *cr, std::ostringstream *notify,
417 int width, int height, bool save,
418 std::ostringstream * timer_stream)
419 {
420 draw_common(cr, notify, width, height, save, timer_stream);
421
422 Point P;
423 try
424 {
425 P = cs.nearestTime (p1.pos);
426 }
427 catch (LogicalError e)
428 {
429 std::cerr << e.what() << std::endl;
430 }
431
432
433 cairo_set_source_rgba(cr, 0.8, 0.1, 0.1, 1.0);
434 draw_line_seg(cr, p1.pos, P);
435 cairo_stroke(cr);
436
437 cairo_set_source_rgba(cr, 0.1, 0.1, 0.9, 1.0);
438 draw_handle(cr, P);
439 cairo_stroke(cr);
440 cairo_set_source_rgba(cr, 0.1, 0.1, 0.1, 1.0);
441 draw_label(cr, p1, "Q");
442 draw_text(cr, P + Point(5, 5), "P");
443 cairo_stroke(cr);
444 }
445
446 /*
447 * TEST BOUND
448 */
init_bound()449 void init_bound()
450 {
451 init_common();
452 p1.pos = Point(50, 200);
453 p2.pos = Point(50, 400);
454 p3.pos = Point(50, 500);
455 handles.push_back(&p1);
456 handles.push_back(&p2);
457 handles.push_back(&p3);
458 }
459
draw_bound(cairo_t * cr,std::ostringstream * notify,int width,int height,bool save,std::ostringstream * timer_stream)460 void draw_bound (cairo_t *cr, std::ostringstream *notify,
461 int width, int height, bool save,
462 std::ostringstream * timer_stream)
463 {
464 draw_common(cr, notify, width, height, save, timer_stream);
465
466 try
467 {
468 p1.pos = cs.nearestTime (p1.pos);
469 p2.pos = cs.nearestTime (p2.pos);
470 p3.pos = cs.nearestTime (p3.pos);
471 }
472 catch (LogicalError e)
473 {
474 std::cerr << e.what() << std::endl;
475 }
476
477 Rect bound = cs.arc_bound (p1.pos, p2.pos, p3.pos);
478 cairo_set_source_rgba(cr, 0.8, 0.1, 0.1, 1.0);
479 cairo_set_line_width (cr, 0.5);
480 cairo_rectangle (cr, bound);
481 cairo_stroke(cr);
482
483 cairo_set_source_rgba(cr, 0.1, 0.1, 0.1, 1.0);
484 draw_label (cr, p1, "initial");
485 draw_label (cr, p2, "inner");
486 draw_label (cr, p3, "final");
487 cairo_stroke(cr);
488
489 }
490
491 /*
492 * TEST CLIP
493 */
init_clip()494 void init_clip()
495 {
496 init_common();
497 }
498
draw_clip(cairo_t * cr,std::ostringstream * notify,int width,int height,bool save,std::ostringstream * timer_stream)499 void draw_clip (cairo_t *cr, std::ostringstream *notify,
500 int width, int height, bool save,
501 std::ostringstream * timer_stream)
502 {
503 draw_common(cr, notify, width, height, save, timer_stream);
504 //init_clip_ctrl_geom(cr, notify, width, height);
505
506
507 Rect R(Point (100, 100),Point (width-100, height-100));
508 std::vector<RatQuad> rq;
509 #ifdef CLIP_WITH_CAIRO_SUPPORT
510 clipper_cr aclipper(cr, cs, R);
511 aclipper.clip (rq);
512 #else
513 clip (rq, cs, R);
514 #endif
515 cairo_set_source_rgba(cr, 0.8, 0.1, 0.1, 1.0);
516 cairo_set_line_width (cr, 0.5);
517 cairo_rectangle (cr, Rect (Point (100, 100),Point (width-100, height-100)));
518 for (auto & i : rq)
519 {
520 cairo_d2_sb (cr, i.toCubic().toSBasis());
521 }
522 cairo_stroke(cr);
523 }
524
525 /*
526 * TEST TANGENT
527 */
init_tangent()528 void init_tangent()
529 {
530 init_common();
531
532 p1.pos = Point(180, 50);
533
534 handles.push_back(&p1);
535 }
536
draw_tangent(cairo_t * cr,std::ostringstream * notify,int width,int height,bool save,std::ostringstream * timer_stream)537 void draw_tangent (cairo_t *cr, std::ostringstream *notify,
538 int width, int height, bool save,
539 std::ostringstream * timer_stream)
540 {
541 draw_common(cr, notify, width, height, save, timer_stream);
542
543 p1.pos = cs.nearestTime (p1.pos);
544 Line l = cs.tangent(p1.pos);
545
546 draw_label (cr, p1, "P");
547 cairo_set_source_rgba(cr, 0.8, 0.0, 0.0, 1.0);
548 draw_line(cr, l, m_window);
549 cairo_stroke(cr);
550 }
551
552 /*
553 * TEST DUAL
554 */
init_dual()555 void init_dual()
556 {
557 init_common();
558 }
559
draw_dual(cairo_t * cr,std::ostringstream * notify,int width,int height,bool save,std::ostringstream * timer_stream)560 void draw_dual (cairo_t *cr, std::ostringstream *notify,
561 int width, int height, bool save,
562 std::ostringstream * timer_stream)
563 {
564 draw_common(cr, notify, width, height, save, timer_stream);
565
566 cairo_set_source_rgba(cr, 0.8, 0.0, 0.0, 1.0);
567 xAx dc = cs.dual();
568 // we need some trick to make the dual visible in the window
569 std::string dckind = dc.categorise();
570 std::optional<Point> T = dc.centre();
571 if (T) dc = dc.translate (-*T);
572 dc = dc.scale (1e-5, 1e-5);
573 dc = dc.translate (Point(width/2, height/2));
574 draw (cr, dc, m_window);
575 cairo_stroke(cr);
576 *notify << "\n dual: " << dckind << ": " << dc;
577 }
578
579
draw_segment(cairo_t * cr,Point const & p1,Point const & p2)580 void draw_segment (cairo_t* cr, Point const& p1, Point const& p2)
581 {
582 cairo_move_to(cr, p1);
583 cairo_line_to(cr, p2);
584 }
585
draw(cairo_t * cr,xAx const & cs,const Rect & _window)586 void draw (cairo_t* cr, xAx const& cs, const Rect& _window)
587 {
588
589 // offset
590 //Point O(400, 300);
591 Point O(0, 0);
592 std::vector<double> r1, r2;
593
594 size_t N = (size_t)(2 *_window.width());
595 double dx = 0.5;//width / N;
596 //std::cout << "dx = " << dx << std::endl;
597 double x = _window.left() - O[X];
598 for (size_t i = 0; i < N; ++i, x += dx)
599 {
600 if (r1.empty())
601 {
602 cs.roots(r1, x, X);
603 if (r1.size() == 1)
604 {
605 r1.push_back(r1.front());
606 }
607 if (i != 0 && r1.size() == 2)
608 {
609 Point p1(x-dx, r1[0]);
610 Point p2(x-dx, r1[1]);
611 p1 += O; p2 += O;
612 if (_window.contains(p1) && _window.contains(p2))
613 draw_segment(cr, p1, p2);
614 }
615 continue;
616 }
617 cs.roots(r2, x, X);
618 if (r2.empty())
619 {
620 Point p1(x-dx, r1[0]);
621 Point p2(x-dx, r1[1]);
622 p1 += O; p2 += O;
623 if (_window.contains(p1) && _window.contains(p2))
624 draw_segment(cr, p1, p2);
625 r1.clear();
626 continue;
627 }
628 if (r2.size() == 1)
629 {
630 r2.push_back(r2.front());
631 }
632
633 Point p1(x-dx, r1[0]);
634 Point p2(x, r2[0]);
635 p1 += O; p2 += O;
636 if (_window.contains(p1) && _window.contains(p2))
637 draw_segment(cr, p1, p2);
638
639 p1 = Point(x-dx, r1[1]) + O;
640 p2 = Point(x, r2[1]) + O;
641 if (_window.contains(p1) && _window.contains(p2))
642 draw_segment(cr, p1, p2);
643
644 using std::swap;
645 swap(r1, r2);
646 }
647 }
648
draw_label(cairo_t * cr,PointHandle const & ph,const char * label)649 void draw_label(cairo_t* cr, PointHandle const& ph, const char* label)
650 {
651 draw_text(cr, ph.pos+op, label);
652 }
653
654 // void draw_label(cairo_t* cr, Line const& l, const char* label)
655 // {
656 // draw_text(cr, projection(Point(m_width/2-30, m_height/2-30), l)+op, label);
657 // }
658
init_menu()659 void init_menu()
660 {
661 handles.clear();
662 }
663
draw_menu(cairo_t *,std::ostringstream * notify,int,int,bool,std::ostringstream *)664 void draw_menu( cairo_t * /*cr*/, std::ostringstream *notify,
665 int /*width*/, int /*height*/, bool /*save*/,
666 std::ostringstream */*timer_stream*/ )
667 {
668 *notify << std::endl;
669 for (int i = SHOW_MENU; i < TOTAL_ITEMS; ++i)
670 {
671 *notify << " " << keys[i] << " - " << menu_items[i] << std::endl;
672 }
673 }
674
675
key_hit(GdkEventKey * e)676 void key_hit(GdkEventKey *e) override
677 {
678 char choice = std::toupper(e->keyval);
679 switch ( choice )
680 {
681 case 'A':
682 init_menu();
683 draw_f = &ConicSectionToy::draw_menu;
684 break;
685 case 'B':
686 init_common();
687 draw_f = &ConicSectionToy::draw_vertex_foci;
688 break;
689 case 'C':
690 init_fitting();
691 draw_f = &ConicSectionToy::draw_fitting;
692 break;
693 case 'D':
694 init_eccentricity();
695 draw_f = &ConicSectionToy::draw_eccentricity;
696 break;
697 case 'E':
698 init_degenerate();
699 draw_f = &ConicSectionToy::draw_degenerate;
700 break;
701 case 'F':
702 init_roots();
703 draw_f = &ConicSectionToy::draw_roots;
704 break;
705 case 'G':
706 init_nearest_time();
707 draw_f = &ConicSectionToy::draw_nearest_time;
708 break;
709 case 'H':
710 init_bound();
711 draw_f = &ConicSectionToy::draw_bound;
712 break;
713 case 'K':
714 init_clip();
715 draw_f = &ConicSectionToy::draw_clip;
716 break;
717 case 'J':
718 init_tangent();
719 draw_f = &ConicSectionToy::draw_tangent;
720 break;
721 case 'I':
722 init_dual();
723 draw_f = &ConicSectionToy::draw_dual;
724 break;
725
726 }
727 redraw();
728 }
729
draw(cairo_t * cr,std::ostringstream * notify,int width,int height,bool save,std::ostringstream * timer_stream)730 void draw( cairo_t *cr, std::ostringstream *notify,
731 int width, int height, bool save,
732 std::ostringstream *timer_stream ) override
733 {
734 if (timer_stream == 0) timer_stream = notify;
735 m_width = width;
736 m_height = height;
737 m_length = (m_width > m_height) ? m_width : m_height;
738 m_length *= 2;
739 m_window = Rect (Point (0, 0), Point (m_width, m_height));
740 (this->*draw_f)(cr, notify, width, height, save, timer_stream);
741 Toy::draw(cr, notify, width, height, save, timer_stream);
742 }
743
744 public:
ConicSectionToy()745 ConicSectionToy()
746 {
747 op = Point(5,5);
748 }
749
750 private:
751 typedef void (ConicSectionToy::* draw_func_t) (cairo_t*, std::ostringstream*, int, int, bool, std::ostringstream*);
752 draw_func_t draw_f;
753 bool set_common_control_geometry;
754 bool set_control_geometry;
755 Point op;
756 double m_width, m_height, m_length;
757 Rect m_window;
758
759 xAx cs;
760 PointHandle vertex, focus1, focus2;
761 Toggle parabola_toggle;
762
763 PointSetHandle psh;
764 Slider fitting_slider;
765
766 PointHandle p1, p2, p3;
767 Toggle x_y_toggle;
768
769 Slider eccentricity_slider;
770 };
771
772
773 const char* ConicSectionToy::menu_items[] =
774 {
775 "show this menu",
776 "vertex and foci",
777 "fitting",
778 "eccentricity",
779 "degenerate",
780 "roots",
781 "nearest point",
782 "bound",
783 "clip",
784 "tangent",
785 "dual"
786 };
787
788 const char ConicSectionToy::keys[] =
789 {
790 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'K', 'J', 'I'
791 };
792
793
main(int argc,char ** argv)794 int main(int argc, char **argv)
795 {
796 //std::cout.precision(20);
797 init( argc, argv, new ConicSectionToy(), 800, 600 );
798 return 0;
799 }
800
801
802
803
804 /*
805 Local Variables:
806 mode:c++
807 c-file-style:"stroustrup"
808 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
809 indent-tabs-mode:nil
810 fill-column:99
811 End:
812 */
813 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
814