conrod_core/widget/primitive/shape/
triangles.rs

1//! A primitive widget that allows for drawing using a list of triangles.
2
3use color;
4use graph;
5use std;
6use utils::{vec2_add, vec2_sub};
7use widget;
8use {Point, Positionable, Rect, Scalar, Sizeable, Theme, Widget};
9
10/// A widget that allows for drawing a list of triangles.
11#[derive(Copy, Clone, Debug, WidgetCommon_)]
12pub struct Triangles<S, I> {
13    /// Data necessary and common for all widget builder types.
14    #[conrod(common_builder)]
15    pub common: widget::CommonBuilder,
16    /// Unique styling for the **Triangles**.
17    pub style: S,
18    /// All the point in the triangle list.
19    pub triangles: I,
20    /// Whether or not the triangles should be automatically centred to the widget position.
21    pub maybe_shift_to_centre_from: Option<Point>,
22}
23
24/// Types used as vertices that make up a list of triangles.
25pub trait Vertex: Clone + Copy + PartialEq {
26    /// The x y location of the vertex.
27    fn point(&self) -> Point;
28    /// Add the given vector onto the position of self and return the result.
29    fn add(self, p: Point) -> Self;
30}
31
32/// Unique styling types for `Triangles`.
33pub trait Style: widget::Style + Clone + Send {
34    /// The type of vertices that make up the list of triangles for this style.
35    type Vertex: Vertex + Send;
36}
37
38/// All triangles colored with a single `Color`.
39#[derive(Copy, Clone, Debug, PartialEq)]
40pub struct SingleColor(pub color::Rgba);
41
42/// Each triangle is colored per vertex.
43#[derive(Copy, Clone, Debug, PartialEq)]
44pub struct MultiColor;
45
46/// A single triangle described by three vertices.
47#[derive(Copy, Clone, Debug, PartialEq)]
48pub struct Triangle<V>(pub [V; 3])
49where
50    V: Vertex;
51
52/// A point with an associated color.
53pub type ColoredPoint = (Point, color::Rgba);
54
55/// Unique state stored between updates for a `Triangles`.
56#[derive(Clone, Debug, PartialEq)]
57pub struct State<T> {
58    /// The triangles that make up the triangles.
59    pub triangles: T,
60}
61
62impl Vertex for Point {
63    fn point(&self) -> Point {
64        *self
65    }
66    fn add(self, add: Point) -> Self {
67        vec2_add(self, add)
68    }
69}
70
71impl Vertex for ColoredPoint {
72    fn point(&self) -> Point {
73        self.0
74    }
75    fn add(self, add: Point) -> Self {
76        let (p, c) = self;
77        (vec2_add(p, add), c)
78    }
79}
80
81impl Style for SingleColor {
82    type Vertex = Point;
83}
84
85impl Style for MultiColor {
86    type Vertex = ColoredPoint;
87}
88
89/// When beginning to build `Triangles` they are initially unpositioned.
90///
91/// This is an intemediary type which allows the user to choose how to position the bounding
92/// rectangle relative to the points.
93#[derive(Copy, Clone, Debug)]
94pub struct TrianglesUnpositioned<S, I> {
95    triangles: Triangles<S, I>,
96}
97
98impl<V> Triangle<V>
99where
100    V: Vertex,
101{
102    /// Shift the triangle by the given amount by adding it onto the position of each point.
103    pub fn add(self, amount: Point) -> Self {
104        let a = self[0].add(amount);
105        let b = self[1].add(amount);
106        let c = self[2].add(amount);
107        Triangle([a, b, c])
108    }
109
110    /// The three points that make up the triangle.
111    pub fn points(self) -> [Point; 3] {
112        [self[0].point(), self[1].point(), self[2].point()]
113    }
114}
115
116impl Triangle<Point> {
117    /// Convert the `Triangle<Point>` to a `Triangle<ColoredPoint>`.
118    pub fn color(self, a: color::Rgba, b: color::Rgba, c: color::Rgba) -> Triangle<ColoredPoint> {
119        Triangle([(self[0], a), (self[1], b), (self[2], c)])
120    }
121
122    /// Convert the `Triangle<Point>` to a `Triangle<ColoredPoint>` using the given color.
123    pub fn color_all(self, color: color::Rgba) -> Triangle<ColoredPoint> {
124        Triangle([(self[0], color), (self[1], color), (self[2], color)])
125    }
126}
127
128impl<V> std::ops::Deref for Triangle<V>
129where
130    V: Vertex,
131{
132    type Target = [V; 3];
133    fn deref(&self) -> &Self::Target {
134        &self.0
135    }
136}
137
138impl<V> From<[V; 3]> for Triangle<V>
139where
140    V: Vertex,
141{
142    fn from(points: [V; 3]) -> Self {
143        Triangle(points)
144    }
145}
146
147impl<V> From<(V, V, V)> for Triangle<V>
148where
149    V: Vertex,
150{
151    fn from((a, b, c): (V, V, V)) -> Self {
152        Triangle([a, b, c])
153    }
154}
155
156impl<V> Into<[V; 3]> for Triangle<V>
157where
158    V: Vertex,
159{
160    fn into(self) -> [V; 3] {
161        self.0
162    }
163}
164
165impl<V> Into<(V, V, V)> for Triangle<V>
166where
167    V: Vertex,
168{
169    fn into(self) -> (V, V, V) {
170        (self[0], self[1], self[2])
171    }
172}
173
174impl<S, I> Triangles<S, I> {
175    fn new(style: S, triangles: I) -> Self {
176        Triangles {
177            common: widget::CommonBuilder::default(),
178            style: style,
179            triangles: triangles,
180            maybe_shift_to_centre_from: None,
181        }
182    }
183}
184
185impl<I> Triangles<SingleColor, I>
186where
187    I: IntoIterator<Item = Triangle<<SingleColor as Style>::Vertex>>,
188{
189    /// A list of triangles described by the given points.
190    ///
191    /// All triangles are colored with the given `Color`.
192    pub fn single_color<C>(color: C, points: I) -> TrianglesUnpositioned<SingleColor, I>
193    where
194        C: Into<color::Rgba>,
195    {
196        let style = SingleColor(color.into());
197        TrianglesUnpositioned::new(Triangles::new(style, points))
198    }
199}
200
201impl<I> Triangles<MultiColor, I>
202where
203    I: IntoIterator<Item = Triangle<<MultiColor as Style>::Vertex>>,
204{
205    /// A list of triangles described by the given points.
206    ///
207    /// Every vertex specifies its own unique color.
208    pub fn multi_color(points: I) -> TrianglesUnpositioned<MultiColor, I> {
209        TrianglesUnpositioned::new(Triangles::new(MultiColor, points))
210    }
211}
212
213fn bounding_rect_for_triangles<I, V>(triangles: I) -> Rect
214where
215    I: IntoIterator<Item = Triangle<V>>,
216    V: Vertex,
217{
218    struct TriangleVertices<V>
219    where
220        V: Vertex,
221    {
222        index: usize,
223        triangle: Triangle<V>,
224    }
225
226    impl<V> Iterator for TriangleVertices<V>
227    where
228        V: Vertex,
229    {
230        type Item = V;
231        fn next(&mut self) -> Option<Self::Item> {
232            let v = self.triangle.get(self.index).map(|&v| v);
233            self.index += 1;
234            v
235        }
236    }
237
238    let points = triangles.into_iter().flat_map(|t| {
239        let vs = TriangleVertices {
240            index: 0,
241            triangle: t,
242        };
243        vs.map(|v| v.point())
244    });
245    super::super::bounding_box_for_points(points)
246}
247
248impl<S, I> TrianglesUnpositioned<S, I>
249where
250    S: Style,
251    I: IntoIterator<Item = Triangle<S::Vertex>>,
252    Triangles<S, I>: Widget,
253{
254    fn new(triangles: Triangles<S, I>) -> Self {
255        TrianglesUnpositioned {
256            triangles: triangles,
257        }
258    }
259
260    /// Specify the bounding rectangle for the **Triangles**.
261    ///
262    /// Typically, the given `Rect` bounds should be the min and max positions along both axes that
263    /// are touched by the **Triangles**' points.
264    ///
265    /// This method is significantly more efficient than `calc_bounding_rect` and
266    /// `centre_points_to_bounding_rect` as the bounding rectangle does not have to be calculated
267    /// from the **Triangles**' points.
268    pub fn with_bounding_rect(self, rect: Rect) -> Triangles<S, I> {
269        let TrianglesUnpositioned { triangles } = self;
270        let (xy, dim) = rect.xy_dim();
271        triangles.wh(dim).xy(xy)
272    }
273
274    /// Calculate the position and size of the bounding rectangle from the `Triangles` points. The
275    /// resulting bounding rectangle will fit to the absolute co-ordinates of all points.
276    ///
277    /// In other words, this method will automatically call `Sizeable::wh` and `Positionable::xy`
278    /// after calculating the size and position from the given points.
279    ///
280    /// This requires that the `points` iterator is `Clone` so that we may iterate through and
281    /// determine the bounding box of the `points`. If you know the bounds of the rectangle ahead
282    /// of time, we recommend calling `with_bounding_rect` instead as it will be significantly
283    /// cheaper.
284    ///
285    /// If you would rather centre the points to the middle of the bounding box, use
286    /// [**TrianglesUnpositioned::centre_points_to_bounding_rect**](./struct.TrianglesUnpositioned#method.centre_points_to_bounding_rect)
287    /// instead.
288    pub fn calc_bounding_rect(self) -> Triangles<S, I>
289    where
290        I: Clone,
291    {
292        let TrianglesUnpositioned { triangles } = self;
293        let (xy, dim) = bounding_rect_for_triangles(triangles.triangles.clone()).xy_dim();
294        triangles.wh(dim).xy(xy)
295    }
296
297    /// Shift the location of the **Triangles** points so that the centre of their bounding
298    /// rectangle lies at the position determined for the **Triangles** widget.
299    ///
300    /// This is useful if your points simply describe a shape and you want to position them using
301    /// conrod's auto-layout or **Positionable** and **Sizeable** methods.
302    ///
303    /// This requires that the `points` iterator is `Clone` so that we may iterate through and
304    /// determine the bounding box of the `points`. If you know the bounds of the rectangle ahead
305    /// of time, we recommend calling `with_bounding_rect` instead as it will be significantly
306    /// cheaper.
307    ///
308    /// If you would rather calculate the bounding box *from* the given absolute points, use the
309    /// [**TrianglesUnpositioned::calc_bounding_rect**](./struct.TrianglesUnpositioned#method.calc_bounding_rect)
310    /// instead.
311    pub fn centre_points_to_bounding_rect(self) -> Triangles<S, I>
312    where
313        I: Clone,
314    {
315        let TrianglesUnpositioned { mut triangles } = self;
316        let (xy, dim) = bounding_rect_for_triangles(triangles.triangles.clone()).xy_dim();
317        triangles.maybe_shift_to_centre_from = Some(xy);
318        triangles.wh(dim)
319    }
320}
321
322impl<S, I> Widget for Triangles<S, I>
323where
324    S: Style,
325    I: IntoIterator<Item = Triangle<S::Vertex>>,
326{
327    type State = State<Vec<Triangle<S::Vertex>>>;
328    type Style = S;
329    type Event = ();
330
331    fn init_state(&self, _: widget::id::Generator) -> Self::State {
332        State {
333            triangles: Vec::new(),
334        }
335    }
336
337    fn style(&self) -> Self::Style {
338        self.style.clone()
339    }
340
341    fn is_over(&self) -> widget::IsOverFn {
342        is_over_widget::<S>
343    }
344
345    fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
346        use utils::{iter_diff, IterDiff};
347        let widget::UpdateArgs { rect, state, .. } = args;
348        let Triangles {
349            triangles,
350            maybe_shift_to_centre_from,
351            ..
352        } = self;
353
354        // A function that compares the given triangles iterator to the triangles currently owned by
355        // `State` and updates only if necessary.
356        fn update_triangles<I>(state: &mut widget::State<State<Vec<I::Item>>>, triangles: I)
357        where
358            I: IntoIterator,
359            I::Item: PartialEq,
360        {
361            match iter_diff(&state.triangles, triangles) {
362                Some(IterDiff::FirstMismatch(i, mismatch)) => state.update(|state| {
363                    state.triangles.truncate(i);
364                    state.triangles.extend(mismatch);
365                }),
366                Some(IterDiff::Longer(remaining)) => {
367                    state.update(|state| state.triangles.extend(remaining))
368                }
369                Some(IterDiff::Shorter(total)) => {
370                    state.update(|state| state.triangles.truncate(total))
371                }
372                None => (),
373            }
374        }
375
376        match maybe_shift_to_centre_from {
377            Some(original) => {
378                let xy = rect.xy();
379                let difference = vec2_sub(xy, original);
380                let triangles = triangles.into_iter().map(|tri| tri.add(difference));
381                update_triangles(state, triangles)
382            }
383            None => update_triangles(state, triangles),
384        }
385    }
386}
387
388/// Triangulates the given quad, represented by four points that describe its edges in either
389/// clockwise or anti-clockwise order.
390///
391/// # Example
392///
393/// The following rectangle
394///
395/// ```ignore
396///
397///  a        b
398///   --------
399///   |      |
400///   |      |
401///   |      |
402///   --------
403///  d        c
404///
405/// ```
406///
407/// given as
408///
409/// ```ignore
410/// from_quad([a, b, c, d])
411/// ```
412///
413/// returns
414///
415/// ```ignore
416/// (Triangle([a, b, c]), Triangle([a, c, d]))
417/// ```
418///
419/// Here's a basic code example:
420///
421/// ```
422/// extern crate conrod_core;
423///
424/// use conrod_core::widget::triangles::{from_quad, Triangle};
425///
426/// fn main() {
427///     let a = [0.0, 1.0];
428///     let b = [1.0, 1.0];
429///     let c = [1.0, 0.0];
430///     let d = [0.0, 0.0];
431///     let quad = [a, b, c, d];
432///     let triangles = from_quad(quad);
433///     assert_eq!(triangles, (Triangle([a, b, c]), Triangle([a, c, d])));
434/// }
435/// ```
436#[inline]
437pub fn from_quad(points: [Point; 4]) -> (Triangle<Point>, Triangle<Point>) {
438    let (a, b, c, d) = (points[0], points[1], points[2], points[3]);
439    (Triangle([a, b, c]), Triangle([a, c, d]))
440}
441
442impl<V> AsRef<Triangle<V>> for Triangle<V>
443where
444    V: Vertex,
445{
446    fn as_ref(&self) -> &Triangle<V> {
447        self
448    }
449}
450
451/// Returns `true` if the given `Point` is over the given `Triangle`.
452pub fn is_over_triangle<V>(t: &Triangle<V>, p: Point) -> bool
453where
454    V: Vertex,
455{
456    let ps = t.points();
457    let (a, b, c) = (ps[0], ps[1], ps[2]);
458
459    fn sign(a: Point, b: Point, c: Point) -> Scalar {
460        (a[0] - c[0]) * (b[1] - c[1]) - (b[0] - c[0]) * (a[1] - c[1])
461    }
462
463    let b1 = sign(p, a, b) < 0.0;
464    let b2 = sign(p, b, c) < 0.0;
465    let b3 = sign(p, c, a) < 0.0;
466
467    (b1 == b2) && (b2 == b3)
468}
469
470/// Returns `true` if the given `Point` is over any of the given `Triangle`s.
471pub fn is_over<V, I, T>(ts: I, p: Point) -> bool
472where
473    V: Vertex,
474    T: AsRef<Triangle<V>>,
475    I: IntoIterator<Item = T>,
476{
477    ts.into_iter().any(|t| is_over_triangle(t.as_ref(), p))
478}
479
480/// The function to use for picking whether a given point is over the line.
481pub fn is_over_widget<S>(widget: &graph::Container, point: Point, _: &Theme) -> widget::IsOver
482where
483    S: Style,
484{
485    widget
486        .state_and_style::<State<Vec<Triangle<S::Vertex>>>, S>()
487        .map(|widget| is_over(widget.state.triangles.iter().cloned(), point))
488        .unwrap_or_else(|| widget.rect.is_over(point))
489        .into()
490}