60bca6bccf87011de9afbc28f6a12d679d49184f
[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 (Canvas* c)
29         : PolyItem (c)
30         , _threshold (1.0)
31 {
32 }
33
34 PolyLine::PolyLine (Item* parent)
35         : PolyItem (parent)
36         , _threshold (1.0)
37 {
38 }
39
40 void
41 PolyLine::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
42 {
43         if (_outline) {
44                 setup_outline_context (context);
45                 render_path (area, context);
46                 context->stroke ();
47         }
48 }
49
50 bool
51 PolyLine::covers (Duple const & point) const
52 {
53         Duple p = window_to_item (point);
54
55         const Points::size_type npoints = _points.size();
56         
57         if (npoints < 2) {
58                 return false;
59         }
60
61         Points::size_type i;
62         Points::size_type j;
63
64         /* repeat for each line segment */
65
66         const Rect visible (window_to_item (_canvas->visible_area()));
67
68         for (i = 1, j = 0; i < npoints; ++i, ++j) {
69
70                 Duple at;
71                 double t;
72                 Duple a (_points[j]);
73                 Duple b (_points[i]);
74                 
75                 /*
76                   Clamp the line endpoints to the visible area of the canvas. If we do
77                   not do this, we may have a line segment extending to COORD_MAX and our
78                   math goes wrong.
79                 */
80                 
81                 a.x = std::min (a.x, visible.x1);
82                 a.y = std::min (a.y, visible.y1);
83                 b.x = std::min (b.x, visible.x1);
84                 b.y = std::min (b.y, visible.y1);
85                 
86                 double d = distance_to_segment_squared (p, a, b, t, at);
87                 
88                 if (t < 0.0 || t > 1.0) {
89                         continue;
90                 }
91                 
92                 if (d < _threshold + _outline_width) {
93                         return true;
94                 }
95                 
96         }
97         
98         return false;
99 }
100
101 void
102 PolyLine::set_covers_threshold (double t)
103 {
104         _threshold = t;
105 }