use window-based coordinates when picking current item so that we get per-item (per...
[ardour.git] / libs / canvas / poly_line.cc
1 /*
2     Copyright (C) 2011-2013 Paul Davis
3     Author: Carl Hetherington <cth@carlh.net>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <algorithm>
21
22 #include "canvas/poly_line.h"
23 #include "canvas/canvas.h"
24 #include "canvas/utils.h"
25
26 using namespace ArdourCanvas;
27
28 PolyLine::PolyLine (Group* parent)
29         : Item (parent)
30         , PolyItem (parent)
31         , _threshold (1.0)
32 {
33
34 }
35
36 void
37 PolyLine::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
38 {
39         if (_outline) {
40                 setup_outline_context (context);
41                 render_path (area, context);
42                 context->stroke ();
43         }
44 }
45
46 bool
47 PolyLine::covers (Duple const & point) const
48 {
49         Duple p = window_to_item (point);
50
51         const Points::size_type npoints = _points.size();
52         
53         if (npoints < 2) {
54                 return false;
55         }
56
57         Points::size_type i;
58         Points::size_type j;
59
60         /* repeat for each line segment */
61
62         const Rect visible (window_to_item (_canvas->visible_area()));
63
64         for (i = 1, j = 0; i < npoints; ++i, ++j) {
65
66                 Duple at;
67                 double t;
68                 Duple a (_points[j]);
69                 Duple b (_points[i]);
70                 
71                 /*
72                   Clamp the line endpoints to the visible area of the canvas. If we do
73                   not do this, we may have a line segment extending to COORD_MAX and our
74                   math goes wrong.
75                 */
76                 
77                 a.x = std::min (a.x, visible.x1);
78                 a.y = std::min (a.y, visible.y1);
79                 b.x = std::min (b.x, visible.x1);
80                 b.y = std::min (b.y, visible.y1);
81                 
82                 double d = distance_to_segment_squared (p, a, b, t, at);
83                 
84                 if (t < 0.0 || t > 1.0) {
85                         continue;
86                 }
87                 
88                 if (d < _threshold + _outline_width) {
89                         return true;
90                 }
91                 
92         }
93         
94         return false;
95 }
96
97 void
98 PolyLine::set_covers_threshold (double t)
99 {
100         _threshold = t;
101 }