1 /*
2  * Rect Toy
3  *
4  * Copyright 2008  njh <>
5  * multitoy approach
6  * Copyright 2008  Marco <>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it either under the terms of the GNU Lesser General Public
10  * License version 2.1 as published by the Free Software Foundation
11  * (the "LGPL") or, at your option, under the terms of the Mozilla
12  * Public License Version 1.1 (the "MPL"). If you do not alter this
13  * notice, a recipient may use your version of this file under either
14  * the MPL or the LGPL.
15  *
16  * You should have received a copy of the LGPL along with this library
17  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  * You should have received a copy of the MPL along with this library
20  * in the file COPYING-MPL-1.1
21  *
22  * The contents of this file are subject to the Mozilla Public License
23  * Version 1.1 (the "License"); you may not use this file except in
24  * compliance with the License. You may obtain a copy of the License at
25  * http://www.mozilla.org/MPL/
26  *
27  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29  * the specific language governing rights and limitations.
30  */
31 
32 
33 #include <2geom/line.h>
34 #include <toys/path-cairo.h>
35 #include <toys/toy-framework-2.h>
36 #include <2geom/transforms.h>
37 
38 #include <2geom/angle.h>
39 
40 #include <vector>
41 #include <string>
42 #include <optional>
43 
44 using namespace Geom;
45 
46 
47 
angle_formatter(double angle)48 std::string angle_formatter(double angle)
49 {
50     return default_formatter(decimal_round(deg_from_rad(angle),2));
51 }
52 
53 class LineToy : public Toy
54 {
55     enum menu_item_t
56     {
57         SHOW_MENU = 0,
58         TEST_CREATE,
59         TEST_PROJECTION,
60         TEST_ORTHO,
61         TEST_DISTANCE,
62         TEST_POSITION,
63         TEST_SEG_BISEC,
64         TEST_ANGLE_BISEC,
65         TEST_COLLINEAR,
66         TEST_INTERSECTIONS,
67         TOTAL_ITEMS // this one must be the last item
68     };
69 
70     enum handle_label_t
71     {
72     };
73 
74     enum toggle_label_t
75     {
76     };
77 
78     enum slider_label_t
79     {
80         ANGLE_SLIDER = 0,
81     };
82 
83     static const char* menu_items[TOTAL_ITEMS];
84     static const char keys[TOTAL_ITEMS];
85 
first_time(int,char **)86     virtual void first_time(int /*argc*/, char** /*argv*/)
87     {
88         draw_f = &LineToy::draw_menu;
89     }
90 
init_common()91     void init_common()
92     {
93         set_common_control_geometry = true;
94         set_control_geometry = true;
95 
96         sliders.clear();
97         toggles.clear();
98         handles.clear();
99     }
100 
101 
draw_common(cairo_t * cr,std::ostringstream * notify,int width,int height,bool)102     virtual void draw_common( cairo_t *cr, std::ostringstream *notify,
103                               int width, int height, bool /*save*/ )
104     {
105         init_common_ctrl_geom(cr, width, height, notify);
106     }
107 
108 
init_create()109     void init_create()
110     {
111         init_common();
112 
113         p1.pos = Point(400, 50);
114         p2.pos = Point(450, 450);
115 
116         sliders.push_back(Slider(0, 2*M_PI, 0, 0, "angle"));
117         sliders[ANGLE_SLIDER].formatter(&angle_formatter);
118 
119         handles.push_back(&p1);
120         handles.push_back(&p2);
121         handles.push_back(&(sliders[ANGLE_SLIDER]));
122     }
123 
draw_create(cairo_t * cr,std::ostringstream * notify,int width,int height,bool save,std::ostringstream *)124     void draw_create(cairo_t *cr, std::ostringstream *notify,
125                       int width, int height, bool save, std::ostringstream */*timer_stream*/)
126     {
127         draw_common(cr, notify, width, height, save);
128         init_create_ctrl_geom(cr, notify, width, height);
129 
130         Rect r1(p1.pos, p2.pos);
131 
132         cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
133         cairo_set_line_width(cr, 0.3);
134         cairo_rectangle(cr, r1);
135 
136 	Affine  rot = Translate(-r1.midpoint())*Rotate(sliders[ANGLE_SLIDER].value())*Translate(r1.midpoint());
137         cairo_rectangle(cr, r1*rot);
138 	cairo_move_to(cr, r1.corner(3)*rot);
139 	for(int i = 0; i < 4; i++) {
140 	  cairo_line_to(cr, r1.corner(i)*rot);
141 	}
142 
143         cairo_stroke(cr);
144 
145         draw_label(cr, p1, "P1");
146         draw_label(cr, p2, "P2");
147     }
148 
149 
150 
init_intersections()151     void init_intersections()
152     {
153         init_common();
154         p1.pos = Point(400, 50);
155         p2.pos = Point(450, 450);
156         p3.pos = Point(100, 250);
157         p4.pos = Point(200, 450);
158         p5.pos = Point(50, 150);
159         p6.pos = Point(480, 60);
160 
161         handles.push_back(&p1);
162         handles.push_back(&p2);
163         handles.push_back(&p3);
164         handles.push_back(&p4);
165         handles.push_back(&p5);
166         handles.push_back(&p6);
167     }
168 
draw_intersections(cairo_t * cr,std::ostringstream * notify,int width,int height,bool save,std::ostringstream *)169     void draw_intersections(cairo_t *cr, std::ostringstream *notify,
170                             int width, int height, bool save,
171                             std::ostringstream */*timer_stream*/)
172     {
173         draw_common(cr, notify, width, height, save);
174 
175         Rect r1(p1.pos, p2.pos);
176         Rect r2(p3.pos, p4.pos);
177         Line l1(p5.pos, p6.pos);
178 
179         cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
180         cairo_set_line_width(cr, 0.3);
181         cairo_rectangle(cr, r1);
182         cairo_stroke(cr);
183 
184         cairo_set_source_rgba(cr, 0.0, 0.3, 0.0, 1.0);
185         cairo_rectangle(cr, r2);
186         cairo_stroke(cr);
187 
188         OptRect r1xr2 = intersect(r1, r2);
189         if(r1xr2) {
190             cairo_set_source_rgba(cr, 1.0, 0.7, 0.7, 1.0);
191             cairo_rectangle(cr, *r1xr2);
192             cairo_fill(cr);
193         }
194 
195         cairo_set_source_rgba(cr, 0.2, 0.2, 0.2, 1.0);
196         cairo_set_line_width(cr, 0.3);
197         draw_line(cr, l1);
198         cairo_stroke(cr);
199 
200 
201         std::optional<LineSegment> ls = rect_line_intersect(r1, LineSegment(p5.pos, p6.pos));
202         *notify << "intersects: " << ((ls)?"true":"false") << std::endl;
203         if(ls) {
204             draw_handle(cr, (*ls)[0]);
205             draw_handle(cr, (*ls)[1]);
206             cairo_save(cr);
207             cairo_set_line_width(cr, 2);
208             cairo_move_to(cr, (*ls)[0]);
209             cairo_line_to(cr, (*ls)[1]);
210             cairo_stroke(cr);
211             cairo_restore(cr);
212         }
213 
214 
215     }
216 
init_common_ctrl_geom(cairo_t *,int,int,std::ostringstream *)217     void init_common_ctrl_geom(cairo_t* /*cr*/, int /*width*/, int /*height*/, std::ostringstream* /*notify*/)
218     {
219         if ( set_common_control_geometry )
220         {
221             set_common_control_geometry = false;
222         }
223     }
224 
init_create_ctrl_geom(cairo_t *,std::ostringstream *,int,int height)225     void init_create_ctrl_geom(cairo_t* /*cr*/, std::ostringstream* /*notify*/, int /*width*/, int height)
226     {
227         if ( set_control_geometry )
228         {
229             set_control_geometry = false;
230 
231             sliders[ANGLE_SLIDER].geometry(Point(50, height - 50), 180);
232         }
233     }
234 
235 
236 
draw_segment(cairo_t * cr,Point const & p1,Point const & p2)237     void draw_segment(cairo_t* cr, Point const& p1, Point const&  p2)
238     {
239         cairo_move_to(cr, p1);
240         cairo_line_to(cr, p2);
241     }
242 
draw_segment(cairo_t * cr,Point const & p1,double angle,double length)243     void draw_segment(cairo_t* cr, Point const& p1, double angle, double length)
244     {
245         Point p2;
246         p2[X] = length * std::cos(angle);
247         p2[Y] = length * std::sin(angle);
248         p2 += p1;
249         draw_segment(cr, p1, p2);
250     }
251 
draw_segment(cairo_t * cr,LineSegment const & ls)252     void draw_segment(cairo_t* cr, LineSegment const& ls)
253     {
254         draw_segment(cr, ls[0], ls[1]);
255     }
256 
draw_ray(cairo_t * cr,Ray const & r)257     void draw_ray(cairo_t* cr, Ray const& r)
258     {
259         double angle = r.angle();
260         draw_segment(cr, r.origin(), angle, m_length);
261     }
262 
draw_line(cairo_t * cr,Line const & l)263     void draw_line(cairo_t* cr, Line const& l)
264     {
265         double angle = l.angle();
266         draw_segment(cr, l.origin(), angle, m_length);
267         draw_segment(cr, l.origin(), angle, -m_length);
268     }
269 
draw_label(cairo_t * cr,PointHandle const & ph,const char * label)270     void draw_label(cairo_t* cr, PointHandle const& ph, const char* label)
271     {
272         draw_text(cr, ph.pos+op, label);
273     }
274 
draw_label(cairo_t * cr,Line const & l,const char * label)275     void draw_label(cairo_t* cr, Line const& l, const char* label)
276     {
277         draw_text(cr, projection(Point(m_width/2-30, m_height/2-30), l)+op, label);
278     }
279 
draw_label(cairo_t * cr,LineSegment const & ls,const char * label)280     void draw_label(cairo_t* cr, LineSegment const& ls, const char* label)
281     {
282         draw_text(cr, middle_point(ls[0], ls[1])+op, label);
283     }
284 
draw_label(cairo_t * cr,Ray const & r,const char * label)285     void draw_label(cairo_t* cr, Ray const& r, const char* label)
286     {
287         Point prj = r.pointAt(r.nearestTime(Point(m_width/2-30, m_height/2-30)));
288         if (L2(r.origin() - prj) < 100)
289         {
290             prj = r.origin() + 100*r.vector();
291         }
292         draw_text(cr, prj+op, label);
293     }
294 
init_menu()295     void init_menu()
296     {
297         handles.clear();
298         sliders.clear();
299         toggles.clear();
300     }
301 
draw_menu(cairo_t *,std::ostringstream * notify,int,int,bool,std::ostringstream *)302     void draw_menu( cairo_t * /*cr*/, std::ostringstream *notify,
303                     int /*width*/, int /*height*/, bool /*save*/,
304                     std::ostringstream */*timer_stream*/)
305     {
306         *notify << std::endl;
307         for (int i = SHOW_MENU; i < TOTAL_ITEMS; ++i)
308         {
309             *notify << "   " << keys[i] << " -  " <<  menu_items[i] << std::endl;
310         }
311     }
312 
key_hit(GdkEventKey * e)313     void key_hit(GdkEventKey *e)
314     {
315         char choice = std::toupper(e->keyval);
316         switch ( choice )
317         {
318             case 'A':
319                 init_menu();
320                 draw_f = &LineToy::draw_menu;
321                 break;
322             case 'B':
323                 init_create();
324                 draw_f = &LineToy::draw_create;
325                 break;
326             case 'C':
327                 init_intersections();
328                 draw_f = &LineToy::draw_intersections;
329                 break;
330         }
331         redraw();
332     }
333 
draw(cairo_t * cr,std::ostringstream * notify,int width,int height,bool save,std::ostringstream * timer_stream)334     virtual void draw( cairo_t *cr, std::ostringstream *notify,
335                        int width, int height, bool save, std::ostringstream *timer_stream)
336     {
337         m_width = width;
338         m_height = height;
339         m_length = (m_width > m_height) ? m_width : m_height;
340         m_length *= 2;
341         (this->*draw_f)(cr, notify, width, height, save, timer_stream);
342         Toy::draw(cr, notify, width, height, save, timer_stream);
343     }
344 
345   public:
LineToy()346     LineToy()
347     {
348         op = Point(5,5);
349     }
350 
351   private:
352     typedef void (LineToy::* draw_func_t) (cairo_t*, std::ostringstream*, int, int, bool, std::ostringstream*);
353     draw_func_t draw_f;
354     bool set_common_control_geometry;
355     bool set_control_geometry;
356     PointHandle p1, p2, p3, p4, p5, p6, O;
357     std::vector<Toggle> toggles;
358     std::vector<Slider> sliders;
359     Point op;
360     double m_width, m_height, m_length;
361 
362 }; // end class LineToy
363 
364 
365 const char* LineToy::menu_items[] =
366 {
367     "show this menu",
368     "rect generation",
369     "intersection with a line"
370 };
371 
372 const char LineToy::keys[] =
373 {
374      'A', 'B', 'C'
375 };
376 
377 
378 
main(int argc,char ** argv)379 int main(int argc, char **argv)
380 {
381     init( argc, argv, new LineToy());
382     return 0;
383 }
384 
385 
386 /*
387   Local Variables:
388   mode:c++
389   c-file-style:"stroustrup"
390   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
391   indent-tabs-mode:nil
392   fill-column:99
393   End:
394 */
395 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
396