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