<commit_before>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use imgui_sys::{self, ImVec4};

use model::{Color, FieldCoord, HexCoord};
use vec2::Vec2;

const SQRT_3: f32 = 1.732_050_807_568_877_f32;

// #f3e4cf
const FIELD_WHITE: [f32; 4] = [0.9529, 0.8941, 0.8118, 1.0];
// #998578
const FIELD_BLACK: [f32; 4] = [0.6, 0.5216, 0.4706, 1.0];
// #ffffff
const PIECE_WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
// #000000
const PIECE_OUTLINE: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
// #757575
const PIECE_BLACK: [f32; 4] = [0.4588, 0.4588, 0.4588, 1.0];

macro_rules! im_color {
    ($v:expr) => (imgui_sys::igColorConvertFloat4ToU32(ImVec4::from($v)))
}

pub fn draw_hex(coord: &HexCoord, origin: Vec2, size: f32) {
    for i in 0..6 {
        draw_field(&coord.to_field(i), origin, size);
    }
}

fn draw_field(coord: &FieldCoord, origin: Vec2, size: f32) {
    let (v1, v2, v3) = field_vertexes(coord, origin, size);
    unsafe {
        let color = match coord.color() {
            Color::White => im_color!(FIELD_WHITE),
            Color::Black => im_color!(FIELD_BLACK),
        };

        let draw_list = imgui_sys::igGetWindowDrawList();
        imgui_sys::ImDrawList_AddTriangleFilled(draw_list, v1.into(), v2.into(), v3.into(), color);
    }
}

pub fn highlight_field(color: [f32; 4], coord: &FieldCoord, origin: Vec2, size: f32) {
    let (v1, v2, v3) = field_vertexes(coord, origin, size);
    unsafe {
        let highlight = im_color!(color);

        let draw_list = imgui_sys::igGetWindowDrawList();
        imgui_sys::ImDrawList_AddTriangleFilled(
            draw_list,
            v1.into(),
            v2.into(),
            v3.into(),
            highlight,
        );
    }
}

pub fn highlight_field_dot(color: [f32; 4], coord: &FieldCoord, origin: Vec2, size: f32) {
    let center = field_center(coord, origin, size);
    unsafe {
        let highlight = im_color!(color);

        let draw_list = imgui_sys::igGetWindowDrawList();
        imgui_sys::ImDrawList_AddCircleFilled(
            draw_list,
            center.into(),
            size / (4.0 * SQRT_3),
            highlight,
            15,
        );
    }
}

pub fn draw_piece(coord: &FieldCoord, origin: Vec2, size: f32) {
    let (v1, v2, v3) = field_vertexes(coord, origin, size);
    let center = field_center(coord, origin, size);

    const SCALE: f32 = 0.7;

    let v1 = center + (v1 - center) * SCALE;
    let v2 = center + (v2 - center) * SCALE;
    let v3 = center + (v3 - center) * SCALE;

    // Linear equation derived by human testing and regression
    let outline_size = 0.032 * size - 0.335;

    unsafe {
        let color = match coord.color() {
            Color::White => im_color!(PIECE_WHITE),
            Color::Black => im_color!(PIECE_BLACK),
        };

        let draw_list = imgui_sys::igGetWindowDrawList();
        imgui_sys::ImDrawList_AddTriangleFilled(draw_list, v1.into(), v2.into(), v3.into(), color);
        imgui_sys::ImDrawList_AddTriangle(
            draw_list,
            v1.into(),
            v2.into(),
            v3.into(),
            im_color!(PIECE_OUTLINE),
            outline_size,
        );
    }
}

fn field_center(coord: &FieldCoord, origin: Vec2, size: f32) -> Vec2 {
    let (v1, v2, v3) = field_vertexes(coord, origin, size);
    let center_x = (v1.x + v2.x + v3.x) / 3.0;
    let min_y = (v1.y).min(v2.y).min(v3.y);
    let center_y = match coord.color() {
        Color::White => min_y + size / SQRT_3,
        Color::Black => min_y + size / (2.0 * SQRT_3),
    };

    Vec2::new(center_x, center_y)
}

fn field_vertexes(coord: &FieldCoord, origin: Vec2, size: f32) -> (Vec2, Vec2, Vec2) {
    let center = hex_to_pixel(&coord.to_hex(), origin, size);
    let height = size * SQRT_3 / 2.0;

    let west = Vec2::new(-size, 0.0);
    let east = Vec2::new(size, 0.0);

    let northwest = Vec2::new(-size / 2.0, -height);
    let southwest = Vec2::new(-size / 2.0, height);
    let northeast = Vec2::new(size / 2.0, -height);
    let southeast = Vec2::new(size / 2.0, height);

    let v1;
    let v2;
    match coord.f() {
        0 => {
            v1 = center + northwest;
            v2 = center + northeast;
        }
        1 => {
            v1 = center + northeast;
            v2 = center + east;
        }
        2 => {
            v1 = center + east;
            v2 = center + southeast;
        }
        3 => {
            v1 = center + southeast;
            v2 = center + southwest;
        }
        4 => {
            v1 = center + southwest;
            v2 = center + west;
        }
        5 => {
            v1 = center + west;
            v2 = center + northwest;
        }
        _ => unreachable!(),
    };

    (center, v1, v2)
}

// Algorithm based on http://www.redblobgames.com/grids/hexagons/#hex-to-pixel
fn hex_to_pixel(coord: &HexCoord, origin: Vec2, size: f32) -> Vec2 {
    let x = f32::from(coord.x());
    let y = f32::from(coord.y());

    let p = Vec2::new(size * (3.0 / 2.0) * x, size * -SQRT_3 * (x / 2.0 + y));

    origin + p
}

// Algorithm based on http://www.redblobgames.com/grids/hexagons/#pixel-to-hex
pub fn pixel_to_field(p: Vec2, origin: Vec2, size: f32) -> Option<FieldCoord> {
    let v = p - origin;

    let q = v.x * (2.0 / 3.0) / size;
    let r = (-v.x - SQRT_3 * v.y) / (size * 3.0);

    round_hex_coord(q, r).and_then(|hex| {
        /*
           To find the field, we subtract the converted hex coordinates (q, r) from the rounded hex
           coordinates (hex) to get the fractional part of the coordinates. Here is a diagram of a
           single hex, with the fractional coordinates of each of its vertexes in the hex coordinate
           system:

                (-1/3, 2/3) _______ (1/3, 1/3)
                           /\     /\
                          /  \   /  \
                         /    \ /    \
            (-2/3, 1/3) (----(0,0)----) (2/3, -1/3)
                         \    / \    /
                          \  /   \  /
              (-1/3, -1/3) \/_____\/ (1/3, -2/3)

           Suppose our converted coordinates were (q, r) = (1.333, 0.583). Our rounded coordinates
           are hex = (1, 1), and so our fractional coordinates are (0.333, -0.417).

           We now define three linear equations that will split this hexagon into its six fields:

                            _______ y = x (/)
                           /\     /\
                          /  \   /  \
                         /    \ /    \
                        (------X------) y = -x/2 (-)
                         \    / \    /
                          \  /   \  /
                           \/_____\/ y = -2x (\)

           Using these three equations as linear inequalities, we can check any pair of fractional
           coordinates and find which field it is in. (As a reminder, fields are numbered clockwise
           starting from 0 at the top.)

           For our example (0.333, -0.417), we see that:
               y + x/2 >= 0, so our field is above (-), and is either 5, 0, or 1.
               y +  2x >= 0, so our field is to the right of (\), and is either 0 or 1.
               y -   x <  0, so our field is to the right of (/), and is 1.
        */
        let x_diff = q - f32::from(hex.x());
        let y_diff = r - f32::from(hex.y());
        let mut i = 0;

        if y_diff + x_diff / 2.0 >= 0.0 {
            i |= 0b100;
        }
        if y_diff + x_diff * 2.0 >= 0.0 {
            i |= 0b010;
        }
        if y_diff - x_diff >= 0.0 {
            i |= 0b001;
        }

        Some(hex.to_field(match i {
            0 => 3,
            1 => 4,
            2 => 2,
            5 => 5,
            6 => 1,
            7 => 0,
            _ => unreachable!(),
        }))
    })
}

// Algorithm from http://www.redblobgames.com/grids/hexagons/#rounding
fn round_hex_coord(x: f32, y: f32) -> Option<HexCoord> {
    let z = -x - y;

    let mut rx = x.round();
    let mut ry = y.round();
    let rz = z.round();

    let x_diff = (rx - x).abs();
    let y_diff = (ry - y).abs();
    let z_diff = (rz - z).abs();

    if x_diff > y_diff && x_diff > z_diff {
        rx = -ry - rz;
    } else if y_diff > z_diff {
        ry = -rx - rz;
    }

    HexCoord::try_new(rx as i8, ry as i8)
}
<commit_msg>Apply rustfmt v0.4.1<commit_after>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use imgui_sys::{self, ImVec4};

use model::{Color, FieldCoord, HexCoord};
use vec2::Vec2;

const SQRT_3: f32 = 1.732_050_807_568_877_f32;

// #f3e4cf
const FIELD_WHITE: [f32; 4] = [0.9529, 0.8941, 0.8118, 1.0];
// #998578
const FIELD_BLACK: [f32; 4] = [0.6, 0.5216, 0.4706, 1.0];
// #ffffff
const PIECE_WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
// #000000
const PIECE_OUTLINE: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
// #757575
const PIECE_BLACK: [f32; 4] = [0.4588, 0.4588, 0.4588, 1.0];

macro_rules! im_color {
    ($v: expr) => {
        imgui_sys::igColorConvertFloat4ToU32(ImVec4::from($v))
    };
}

pub fn draw_hex(coord: &HexCoord, origin: Vec2, size: f32) {
    for i in 0..6 {
        draw_field(&coord.to_field(i), origin, size);
    }
}

fn draw_field(coord: &FieldCoord, origin: Vec2, size: f32) {
    let (v1, v2, v3) = field_vertexes(coord, origin, size);
    unsafe {
        let color = match coord.color() {
            Color::White => im_color!(FIELD_WHITE),
            Color::Black => im_color!(FIELD_BLACK),
        };

        let draw_list = imgui_sys::igGetWindowDrawList();
        imgui_sys::ImDrawList_AddTriangleFilled(draw_list, v1.into(), v2.into(), v3.into(), color);
    }
}

pub fn highlight_field(color: [f32; 4], coord: &FieldCoord, origin: Vec2, size: f32) {
    let (v1, v2, v3) = field_vertexes(coord, origin, size);
    unsafe {
        let highlight = im_color!(color);

        let draw_list = imgui_sys::igGetWindowDrawList();
        imgui_sys::ImDrawList_AddTriangleFilled(
            draw_list,
            v1.into(),
            v2.into(),
            v3.into(),
            highlight,
        );
    }
}

pub fn highlight_field_dot(color: [f32; 4], coord: &FieldCoord, origin: Vec2, size: f32) {
    let center = field_center(coord, origin, size);
    unsafe {
        let highlight = im_color!(color);

        let draw_list = imgui_sys::igGetWindowDrawList();
        imgui_sys::ImDrawList_AddCircleFilled(
            draw_list,
            center.into(),
            size / (4.0 * SQRT_3),
            highlight,
            15,
        );
    }
}

pub fn draw_piece(coord: &FieldCoord, origin: Vec2, size: f32) {
    let (v1, v2, v3) = field_vertexes(coord, origin, size);
    let center = field_center(coord, origin, size);

    const SCALE: f32 = 0.7;

    let v1 = center + (v1 - center) * SCALE;
    let v2 = center + (v2 - center) * SCALE;
    let v3 = center + (v3 - center) * SCALE;

    // Linear equation derived by human testing and regression
    let outline_size = 0.032 * size - 0.335;

    unsafe {
        let color = match coord.color() {
            Color::White => im_color!(PIECE_WHITE),
            Color::Black => im_color!(PIECE_BLACK),
        };

        let draw_list = imgui_sys::igGetWindowDrawList();
        imgui_sys::ImDrawList_AddTriangleFilled(draw_list, v1.into(), v2.into(), v3.into(), color);
        imgui_sys::ImDrawList_AddTriangle(
            draw_list,
            v1.into(),
            v2.into(),
            v3.into(),
            im_color!(PIECE_OUTLINE),
            outline_size,
        );
    }
}

fn field_center(coord: &FieldCoord, origin: Vec2, size: f32) -> Vec2 {
    let (v1, v2, v3) = field_vertexes(coord, origin, size);
    let center_x = (v1.x + v2.x + v3.x) / 3.0;
    let min_y = (v1.y).min(v2.y).min(v3.y);
    let center_y = match coord.color() {
        Color::White => min_y + size / SQRT_3,
        Color::Black => min_y + size / (2.0 * SQRT_3),
    };

    Vec2::new(center_x, center_y)
}

fn field_vertexes(coord: &FieldCoord, origin: Vec2, size: f32) -> (Vec2, Vec2, Vec2) {
    let center = hex_to_pixel(&coord.to_hex(), origin, size);
    let height = size * SQRT_3 / 2.0;

    let west = Vec2::new(-size, 0.0);
    let east = Vec2::new(size, 0.0);

    let northwest = Vec2::new(-size / 2.0, -height);
    let southwest = Vec2::new(-size / 2.0, height);
    let northeast = Vec2::new(size / 2.0, -height);
    let southeast = Vec2::new(size / 2.0, height);

    let v1;
    let v2;
    match coord.f() {
        0 => {
            v1 = center + northwest;
            v2 = center + northeast;
        }
        1 => {
            v1 = center + northeast;
            v2 = center + east;
        }
        2 => {
            v1 = center + east;
            v2 = center + southeast;
        }
        3 => {
            v1 = center + southeast;
            v2 = center + southwest;
        }
        4 => {
            v1 = center + southwest;
            v2 = center + west;
        }
        5 => {
            v1 = center + west;
            v2 = center + northwest;
        }
        _ => unreachable!(),
    };

    (center, v1, v2)
}

// Algorithm based on http://www.redblobgames.com/grids/hexagons/#hex-to-pixel
fn hex_to_pixel(coord: &HexCoord, origin: Vec2, size: f32) -> Vec2 {
    let x = f32::from(coord.x());
    let y = f32::from(coord.y());

    let p = Vec2::new(size * (3.0 / 2.0) * x, size * -SQRT_3 * (x / 2.0 + y));

    origin + p
}

// Algorithm based on http://www.redblobgames.com/grids/hexagons/#pixel-to-hex
pub fn pixel_to_field(p: Vec2, origin: Vec2, size: f32) -> Option<FieldCoord> {
    let v = p - origin;

    let q = v.x * (2.0 / 3.0) / size;
    let r = (-v.x - SQRT_3 * v.y) / (size * 3.0);

    round_hex_coord(q, r).and_then(|hex| {
        /*
           To find the field, we subtract the converted hex coordinates (q, r) from the rounded hex
           coordinates (hex) to get the fractional part of the coordinates. Here is a diagram of a
           single hex, with the fractional coordinates of each of its vertexes in the hex coordinate
           system:

                (-1/3, 2/3) _______ (1/3, 1/3)
                           /\     /\
                          /  \   /  \
                         /    \ /    \
            (-2/3, 1/3) (----(0,0)----) (2/3, -1/3)
                         \    / \    /
                          \  /   \  /
              (-1/3, -1/3) \/_____\/ (1/3, -2/3)

           Suppose our converted coordinates were (q, r) = (1.333, 0.583). Our rounded coordinates
           are hex = (1, 1), and so our fractional coordinates are (0.333, -0.417).

           We now define three linear equations that will split this hexagon into its six fields:

                            _______ y = x (/)
                           /\     /\
                          /  \   /  \
                         /    \ /    \
                        (------X------) y = -x/2 (-)
                         \    / \    /
                          \  /   \  /
                           \/_____\/ y = -2x (\)

           Using these three equations as linear inequalities, we can check any pair of fractional
           coordinates and find which field it is in. (As a reminder, fields are numbered clockwise
           starting from 0 at the top.)

           For our example (0.333, -0.417), we see that:
               y + x/2 >= 0, so our field is above (-), and is either 5, 0, or 1.
               y +  2x >= 0, so our field is to the right of (\), and is either 0 or 1.
               y -   x <  0, so our field is to the right of (/), and is 1.
        */
        let x_diff = q - f32::from(hex.x());
        let y_diff = r - f32::from(hex.y());
        let mut i = 0;

        if y_diff + x_diff / 2.0 >= 0.0 {
            i |= 0b100;
        }
        if y_diff + x_diff * 2.0 >= 0.0 {
            i |= 0b010;
        }
        if y_diff - x_diff >= 0.0 {
            i |= 0b001;
        }

        Some(hex.to_field(match i {
            0 => 3,
            1 => 4,
            2 => 2,
            5 => 5,
            6 => 1,
            7 => 0,
            _ => unreachable!(),
        }))
    })
}

// Algorithm from http://www.redblobgames.com/grids/hexagons/#rounding
fn round_hex_coord(x: f32, y: f32) -> Option<HexCoord> {
    let z = -x - y;

    let mut rx = x.round();
    let mut ry = y.round();
    let rz = z.round();

    let x_diff = (rx - x).abs();
    let y_diff = (ry - y).abs();
    let z_diff = (rz - z).abs();

    if x_diff > y_diff && x_diff > z_diff {
        rx = -ry - rz;
    } else if y_diff > z_diff {
        ry = -rx - rz;
    }

    HexCoord::try_new(rx as i8, ry as i8)
}
<|endoftext|>


<commit_before>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-pass

// Bastion of the Turbofish
// ------------------------
// Beware travellers, lest you venture into waters callous and unforgiving,
// where hope must be abandoned, ere it is cruelly torn from you. For here
// stands the bastion of the Turbofish: an impenetrable fortress holding
// unshaking against those who would dare suggest the supererogation of the
// Turbofish.
//
// Once I was young and foolish and had the impudence to imagine that I could
// shake free from the coils by which that creature had us tightly bound. I
// dared to suggest that there was a better way: a brighter future, in which
// Rustaceans both new and old could be rid of that vile beast. But alas! In
// my foolhardiness my ignorance was unveiled and my dreams were dashed
// unforgivingly against the rock of syntactic ambiguity.
//
// This humble program, small and insignificant though it might seem,
// demonstrates that to which we had previously cast a blind eye: an ambiguity
// in permitting generic arguments to be provided without the consent of the
// Great Turbofish. Should you be so naïve as to try to revolt against its
// mighty clutches, here shall its wrath be indomitably displayed. This
// program must pass for all eternity, fundamentally at odds with an impetuous
// rebellion against the Turbofish.
//
// My heart aches in sorrow, for I know I am defeated. Let this be a warning
// to all those who come after. Here stands the bastion of the Turbofish.

fn main() {
    let (oh, woe, is, me) = ("the", "Turbofish", "remains", "undefeated");
    let _: (bool, bool) = (oh<woe, is>(me));
}
<commit_msg>Lament the invincibility of the Turbofish<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-pass

// Bastion of the Turbofish
// ------------------------
// Beware travellers, lest you venture into waters callous and unforgiving,
// where hope must be abandoned, ere it is cruelly torn from you. For here
// stands the bastion of the Turbofish: an impenetrable fortress holding
// unshaking against those who would dare suggest the supererogation of the
// Turbofish.
//
// Once I was young and foolish and had the impudence to imagine that I could
// shake free from the coils by which that creature had us tightly bound. I
// dared to suggest that there was a better way: a brighter future, in which
// Rustaceans both new and old could be rid of that vile beast. But alas! In
// my foolhardiness my ignorance was unveiled and my dreams were dashed
// unforgivingly against the rock of syntactic ambiguity.
//
// This humble program, small and insignificant though it might seem,
// demonstrates that to which we had previously cast a blind eye: an ambiguity
// in permitting generic arguments to be provided without the consent of the
// Great Turbofish. Should you be so naïve as to try to revolt against its
// mighty clutches, here shall its wrath be indomitably displayed. This
// program must pass for all eternity, fundamentally at odds with an impetuous
// rebellion against the Turbofish.
//
// My heart aches in sorrow, for I know I am defeated. Let this be a warning
// to all those who come after. Here stands the bastion of the Turbofish.

// See https://github.com/rust-lang/rust/pull/53562
// and https://github.com/rust-lang/rfcs/pull/2527
// for context.

fn main() {
    let (oh, woe, is, me) = ("the", "Turbofish", "remains", "undefeated");
    let _: (bool, bool) = (oh<woe, is>(me));
}
<|endoftext|>


<commit_before>#![allow(deprecated)]
use std::path::PathBuf;
use std::{io, fs, slice};
use curl::easy::Easy;
use memmap::{Mmap, Protection};
use flate2::{Flush, Decompress};
use std::io::{Read, Write};
use utils::data::{DatasetIntfRef, DatasetIntf};
use std::rc::Rc;
use tensor::{Tensor, TensorKind, NumLimits};
use torch;
use std::marker::PhantomData;

type Sample<T> = (Tensor<T>, i64);
type CollatedSample<T> = (Tensor<T>, Tensor<i64>);

static URLS: [&str; 4] = ["http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz",
                          "http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz",
                          "http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz",
                          "http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz"];
static RAW_FOLDER: &str = "raw";
static PROCESSED_FOLDER: &str = "processed";
static TRAINING_FILE: &str = "training.pt";
static TEST_FILE: &str = "test.pt";

fn create_dir_f(arg: PathBuf) -> io::Result<()> {
    let result = fs::create_dir(arg);
    if let Some(err) = result.err() {
        match err.kind() {
            io::ErrorKind::AlreadyExists => Ok(()),
            _ => Err(err),
        }
    } else {
        Ok(())
    }
}

fn check_exists(arg: &PathBuf) -> io::Result<bool> {
    let train = fs::metadata(arg.join(TRAINING_FILE))?;
    let test = fs::metadata(arg.join(TEST_FILE))?;

    return Ok(train.is_file() && test.is_file());
}

fn download(root: &String) -> io::Result<()> {
    let raw_path = PathBuf::from(root).join(RAW_FOLDER);
    let processed_path = PathBuf::from(root).join(PROCESSED_FOLDER);
    create_dir_f(raw_path.clone())?;
    create_dir_f(processed_path.clone())?;

    for url in URLS.iter() {
        println!("downloading {}", url);
        let paths: Vec<_> = url.split("/").collect();
        let mut fname: Vec<_> = paths[5].split("/").collect();
        fname = fname[0].split(".").collect();
        let file_path = raw_path.join(fname[0]);
        let mut file = fs::OpenOptions::new()
            .write(true)
            .create(true)
            .open(file_path)?;
        let mut data = Vec::new();
        let mut handle = Easy::new();
        handle.url(url).unwrap();
        {
            let mut transfer = handle.transfer();
            transfer
                .write_function(|new_data| {
                                    data.extend_from_slice(new_data);
                                    Ok(new_data.len())
                                })
                .unwrap();
            transfer.perform().unwrap();
        }
        let mut output = Vec::with_capacity(data.len() + 1100000);
        let mut gz = ::flate2::read::GzDecoder::new(data.as_slice())?;
        gz.read_to_end(&mut output)?;

        file.write_all(output.as_slice())?;
    }
    println!("Proceeding");

    let training_set =
        vec![read_image_file(raw_path.join("train-images-idx3-ubyte"))?,
                            read_label_file(raw_path.join("train-labels-idx1-ubyte"))?];
    let test_set = vec![read_image_file(raw_path.join("t10k-images-idx3-ubyte"))?,
                        read_label_file(raw_path.join("t10k-labels-idx1-ubyte"))?];

    torch::save(processed_path.join(TRAINING_FILE), &training_set)?;
    torch::save(processed_path.join(TEST_FILE), &test_set)?;

    Ok(())
}

fn read_image_file(path: PathBuf) -> io::Result<TensorKind> {
    let fp = Mmap::open_path(path, Protection::Read)?;
    let (length, nrows, ncols);
    {
        let data = unsafe { slice::from_raw_parts(fp.ptr() as *const i32, fp.len()) };
        assert_eq!(i32::from_be(data[0]), 2051);
        length = i32::from_be(data[1]) as usize;
        nrows = i32::from_be(data[2]) as usize;
        ncols = i32::from_be(data[3]) as usize;
    }
    let data = unsafe { fp.as_slice() };
    let mut images: Vec<Vec<u8>> = Vec::with_capacity(length);
    let mut idx = 16;
    for _ in 0..length {
        let mut img = Vec::with_capacity(nrows * ncols);
        for _ in 0..nrows * ncols {
            img.push(data[idx]);
            idx += 1;
        }
        images.push(img)
    }
    Ok(torch::byte_tensor(images).view(&[-1, 28, 28]).into())
}

fn read_label_file(path: PathBuf) -> io::Result<TensorKind> {
    let fp = Mmap::open_path(path, Protection::Read)?;
    let length;
    {
        let data = unsafe { slice::from_raw_parts(fp.ptr() as *const u32, fp.len()) };
        assert_eq!(data[0], 2049);
        length = data[1] as usize;
    }
    let data = unsafe { fp.as_slice() };
    let mut labels: Vec<u8> = Vec::with_capacity(length);
    for i in 0..length {
        labels.push(data[8 + i])
    }
    Ok(torch::byte_tensor(labels).into())
}

pub struct MNIST<T: NumLimits> {
    pub root: String,
    pub train: bool,
    pub data: Tensor<u8>,
    pub labels: Tensor<u8>,
    pub transform: Option<Xfrm>,
    phantom: PhantomData<T>,
}

#[builder(pattern="owned")]
#[derive(Builder)]
pub struct MNISTArgs {
    root: String,
    #[builder(default="true")]
    train: bool,
    #[builder(default="false")]
    download: bool,
}

type Xfrm = Box<fn(&TensorKind) -> TensorKind>;
impl MNISTArgsBuilder {
    pub fn done<T: NumLimits + 'static>(self,
                                        xfrm: Option<Xfrm>)
                                        -> DatasetIntfRef<CollatedSample<T>> {
        let args = self.build().unwrap();
        Rc::new(MNIST::new(args, xfrm))
    }
}

impl<T: NumLimits> MNIST<T> {
    pub fn build(root: &str) -> MNISTArgsBuilder {
        MNISTArgsBuilder::default().root(root.into())
    }
    pub fn new(args: MNISTArgs, xfrm: Option<Xfrm>) -> Self {
        if args.download {
            download(&args.root).expect("download failed");
        }
        let processed_path = PathBuf::from(&args.root).join(PROCESSED_FOLDER);
        if !check_exists(&processed_path).expect("Dataset not found, try downloading") {
            panic!("Dataset not found, use download=true to download it");
        }
        let mut v: Vec<TensorKind> = if args.train {
            torch::load(processed_path.join(TRAINING_FILE)).expect("torch load failed")
        } else {
            torch::load(processed_path.join(TEST_FILE)).expect("torch load failed")
        };
        let (data, labels) = (v.remove(0), v.remove(0));

        MNIST {
            root: args.root.clone(),
            train: args.train,
            data: data.into(),
            labels: labels.into(),
            transform: xfrm,
            phantom: PhantomData,
        }
    }
    fn index(&self, idx: usize) -> Sample<T> {
        let img = self.data.s(idx);
        let img = if let Some(ref transform) = self.transform {
            transform(&img.into()).into()
        } else {
            img.copy().cast::<T>()
        };
        (img, self.labels[idx].clone() as i64)
    }
}

impl<T: NumLimits> DatasetIntf for MNIST<T> {
    type Batch = CollatedSample<T>;
    fn len(&self) -> usize {
        if self.train { 60000 } else { 10000 }
    }
    fn collate(&self, sample: Vec<usize>) -> Self::Batch {
        let v: Vec<Sample<T>> = sample.into_iter().map(|i| self.index(i)).collect();
        let labels: Vec<i64> = v.iter().map(|&(_, ref t)| *t).collect();
        let imgs: Vec<Tensor<T>> = v.into_iter().map(|(d, _)| d).collect();
        // XXX should check for case of double
        let img_batch = torch::tensor(imgs);
        let label_batch = torch::long_tensor(labels);
        (img_batch, label_batch)
    }
}
<commit_msg>handle BE data<commit_after>#![allow(deprecated)]
use std::path::PathBuf;
use std::{io, fs, slice};
use curl::easy::Easy;
use memmap::{Mmap, Protection};
use flate2::{Flush, Decompress};
use std::io::{Read, Write};
use utils::data::{DatasetIntfRef, DatasetIntf};
use std::rc::Rc;
use tensor::{Tensor, TensorKind, NumLimits};
use torch;
use std::marker::PhantomData;

type Sample<T> = (Tensor<T>, i64);
type CollatedSample<T> = (Tensor<T>, Tensor<i64>);

static URLS: [&str; 4] = ["http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz",
                          "http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz",
                          "http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz",
                          "http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz"];
static RAW_FOLDER: &str = "raw";
static PROCESSED_FOLDER: &str = "processed";
static TRAINING_FILE: &str = "training.pt";
static TEST_FILE: &str = "test.pt";

fn create_dir_f(arg: PathBuf) -> io::Result<()> {
    let result = fs::create_dir(arg);
    if let Some(err) = result.err() {
        match err.kind() {
            io::ErrorKind::AlreadyExists => Ok(()),
            _ => Err(err),
        }
    } else {
        Ok(())
    }
}

fn check_exists(arg: &PathBuf) -> io::Result<bool> {
    let train = fs::metadata(arg.join(TRAINING_FILE))?;
    let test = fs::metadata(arg.join(TEST_FILE))?;

    return Ok(train.is_file() && test.is_file());
}

fn download(root: &String) -> io::Result<()> {
    let raw_path = PathBuf::from(root).join(RAW_FOLDER);
    let processed_path = PathBuf::from(root).join(PROCESSED_FOLDER);
    create_dir_f(raw_path.clone())?;
    create_dir_f(processed_path.clone())?;

    for url in URLS.iter() {
        println!("downloading {}", url);
        let paths: Vec<_> = url.split("/").collect();
        let mut fname: Vec<_> = paths[5].split("/").collect();
        fname = fname[0].split(".").collect();
        let file_path = raw_path.join(fname[0]);
        let mut file = fs::OpenOptions::new()
            .write(true)
            .create(true)
            .open(file_path)?;
        let mut data = Vec::new();
        let mut handle = Easy::new();
        handle.url(url).unwrap();
        {
            let mut transfer = handle.transfer();
            transfer
                .write_function(|new_data| {
                                    data.extend_from_slice(new_data);
                                    Ok(new_data.len())
                                })
                .unwrap();
            transfer.perform().unwrap();
        }
        let mut output = Vec::with_capacity(data.len() + 1100000);
        let mut gz = ::flate2::read::GzDecoder::new(data.as_slice())?;
        gz.read_to_end(&mut output)?;

        file.write_all(output.as_slice())?;
    }
    println!("Proceeding");

    let training_set =
        vec![read_image_file(raw_path.join("train-images-idx3-ubyte"))?,
                            read_label_file(raw_path.join("train-labels-idx1-ubyte"))?];
    let test_set = vec![read_image_file(raw_path.join("t10k-images-idx3-ubyte"))?,
                        read_label_file(raw_path.join("t10k-labels-idx1-ubyte"))?];

    torch::save(processed_path.join(TRAINING_FILE), &training_set)?;
    torch::save(processed_path.join(TEST_FILE), &test_set)?;

    Ok(())
}

fn read_image_file(path: PathBuf) -> io::Result<TensorKind> {
    let fp = Mmap::open_path(path, Protection::Read)?;
    let (length, nrows, ncols);
    {
        let data = unsafe { slice::from_raw_parts(fp.ptr() as *const i32, fp.len()) };
        assert_eq!(i32::from_be(data[0]), 2051);
        length = i32::from_be(data[1]) as usize;
        nrows = i32::from_be(data[2]) as usize;
        ncols = i32::from_be(data[3]) as usize;
    }
    let data = unsafe { fp.as_slice() };
    let mut images: Vec<Vec<u8>> = Vec::with_capacity(length);
    let mut idx = 16;
    for _ in 0..length {
        let mut img = Vec::with_capacity(nrows * ncols);
        for _ in 0..nrows * ncols {
            img.push(data[idx]);
            idx += 1;
        }
        images.push(img)
    }
    Ok(torch::byte_tensor(images).view(&[-1, 28, 28]).into())
}

fn read_label_file(path: PathBuf) -> io::Result<TensorKind> {
    let fp = Mmap::open_path(path, Protection::Read)?;
    let length;
    {
        let data = unsafe { slice::from_raw_parts(fp.ptr() as *const i32, fp.len()) };
        assert_eq!(i32::from_be(data[0]), 2049);
        length = i32::from_be(data[1]) as usize;
    }
    let data = unsafe { fp.as_slice() };
    let mut labels: Vec<u8> = Vec::with_capacity(length);
    for i in 0..length {
        labels.push(data[8 + i])
    }
    Ok(torch::byte_tensor(labels).into())
}

pub struct MNIST<T: NumLimits> {
    pub root: String,
    pub train: bool,
    pub data: Tensor<u8>,
    pub labels: Tensor<u8>,
    pub transform: Option<Xfrm>,
    phantom: PhantomData<T>,
}

#[builder(pattern="owned")]
#[derive(Builder)]
pub struct MNISTArgs {
    root: String,
    #[builder(default="true")]
    train: bool,
    #[builder(default="false")]
    download: bool,
}

type Xfrm = Box<fn(&TensorKind) -> TensorKind>;
impl MNISTArgsBuilder {
    pub fn done<T: NumLimits + 'static>(self,
                                        xfrm: Option<Xfrm>)
                                        -> DatasetIntfRef<CollatedSample<T>> {
        let args = self.build().unwrap();
        Rc::new(MNIST::new(args, xfrm))
    }
}

impl<T: NumLimits> MNIST<T> {
    pub fn build(root: &str) -> MNISTArgsBuilder {
        MNISTArgsBuilder::default().root(root.into())
    }
    pub fn new(args: MNISTArgs, xfrm: Option<Xfrm>) -> Self {
        if args.download {
            download(&args.root).expect("download failed");
        }
        let processed_path = PathBuf::from(&args.root).join(PROCESSED_FOLDER);
        if !check_exists(&processed_path).expect("Dataset not found, try downloading") {
            panic!("Dataset not found, use download=true to download it");
        }
        let mut v: Vec<TensorKind> = if args.train {
            torch::load(processed_path.join(TRAINING_FILE)).expect("torch load failed")
        } else {
            torch::load(processed_path.join(TEST_FILE)).expect("torch load failed")
        };
        let (data, labels) = (v.remove(0), v.remove(0));

        MNIST {
            root: args.root.clone(),
            train: args.train,
            data: data.into(),
            labels: labels.into(),
            transform: xfrm,
            phantom: PhantomData,
        }
    }
    fn index(&self, idx: usize) -> Sample<T> {
        let img = self.data.s(idx);
        let img = if let Some(ref transform) = self.transform {
            transform(&img.into()).into()
        } else {
            img.copy().cast::<T>()
        };
        (img, self.labels[idx].clone() as i64)
    }
}

impl<T: NumLimits> DatasetIntf for MNIST<T> {
    type Batch = CollatedSample<T>;
    fn len(&self) -> usize {
        if self.train { 60000 } else { 10000 }
    }
    fn collate(&self, sample: Vec<usize>) -> Self::Batch {
        let v: Vec<Sample<T>> = sample.into_iter().map(|i| self.index(i)).collect();
        let labels: Vec<i64> = v.iter().map(|&(_, ref t)| *t).collect();
        let imgs: Vec<Tensor<T>> = v.into_iter().map(|(d, _)| d).collect();
        // XXX should check for case of double
        let img_batch = torch::tensor(imgs);
        let label_batch = torch::long_tensor(labels);
        (img_batch, label_batch)
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate direct_composition;
extern crate euclid;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate winit;

use direct_composition::DirectComposition;
use std::sync::mpsc;
use webrender::api;
use winit::os::windows::WindowExt;
use glutin::dpi::LogicalSize;

fn main() {
    let mut events_loop = winit::EventsLoop::new();

    let (tx, rx) = mpsc::channel();
    let notifier = Box::new(Notifier { events_proxy: events_loop.create_proxy(), tx });

    let window = winit::WindowBuilder::new()
        .with_title("WebRender + ANGLE + DirectComposition")
        .with_dimensions(LogicalSize::new(1024., 768.))
        .build(&events_loop)
        .unwrap();

    let composition = direct_composition_from_window(&window);
    let factor = window.get_hidpi_factor() as f32;

    let mut clicks: usize = 0;
    let mut offset_y = 100.;
    let size = api::DeviceUintSize::new;
    let mut rects = [
        Rectangle::new(&composition, &notifier, factor, size(300, 200), 0., 0.2, 0.4, 1.),
        Rectangle::new(&composition, &notifier, factor, size(400, 300), 0., 0.5, 0., 0.5),
    ];
    rects[0].render(factor, &rx);
    rects[1].render(factor, &rx);

    rects[0].visual.set_offset_x(100.);
    rects[0].visual.set_offset_y(50.);

    rects[1].visual.set_offset_x(200.);
    rects[1].visual.set_offset_y(offset_y);

    composition.commit();

    events_loop.run_forever(|event| {
        if let winit::Event::WindowEvent { event, .. } = event {
            match event {
                winit::WindowEvent::CloseRequested => {
                    return winit::ControlFlow::Break
                }
                winit::WindowEvent::MouseWheel { delta, .. } => {
                    let dy = match delta {
                        winit::MouseScrollDelta::LineDelta(_, dy) => dy,
                        winit::MouseScrollDelta::PixelDelta(pos) => pos.y as f32,
                    };
                    offset_y = (offset_y - 10. * dy).max(0.).min(468.);

                    rects[1].visual.set_offset_y(offset_y);
                    composition.commit();
                }
                winit::WindowEvent::MouseInput {
                    button: winit::MouseButton::Left,
                    state: winit::ElementState::Pressed,
                    ..
                } => {
                    clicks += 1;
                    let rect = &mut rects[clicks % 2];
                    rect.color.g += 0.1;
                    rect.color.g %= 1.;
                    rect.render(factor, &rx)
                }
                _ => {}
            }
        }
        winit::ControlFlow::Continue
    });
}

fn direct_composition_from_window(window: &winit::Window) -> DirectComposition {
    unsafe {
        DirectComposition::new(window.get_hwnd() as _)
    }
}

struct Rectangle {
    visual: direct_composition::AngleVisual,
    renderer: Option<webrender::Renderer>,
    api: api::RenderApi,
    document_id: api::DocumentId,
    size: api::DeviceUintSize,
    color: api::ColorF,
}

impl Rectangle {
    fn new(composition: &DirectComposition, notifier: &Box<Notifier>,
           device_pixel_ratio: f32, size: api::DeviceUintSize, r: f32, g: f32, b: f32, a: f32)
           -> Self {
        let visual = composition.create_angle_visual(size.width, size.height);
        visual.make_current();

        let (renderer, sender) = webrender::Renderer::new(
            composition.gleam.clone(),
            notifier.clone(),
            webrender::RendererOptions {
                clear_color: Some(api::ColorF::new(0., 0., 0., 0.)),
                device_pixel_ratio,
                ..webrender::RendererOptions::default()
            },
        ).unwrap();
        let api = sender.create_api();

       Rectangle {
            visual,
            renderer: Some(renderer),
            document_id: api.add_document(size, 0),
            api,
            size,
            color: api::ColorF { r, g, b, a },
        }
    }

    fn render(&mut self, device_pixel_ratio: f32, rx: &mpsc::Receiver<()>) {
        self.visual.make_current();

        let pipeline_id = api::PipelineId(0, 0);
        let layout_size = self.size.to_f32() / euclid::TypedScale::new(device_pixel_ratio);
        let mut builder = api::DisplayListBuilder::new(pipeline_id, layout_size);

        let rect = euclid::TypedRect::new(euclid::TypedPoint2D::zero(), layout_size);

        let region = api::ComplexClipRegion::new(
            rect,
            api::BorderRadius::uniform(20.),
            api::ClipMode::Clip
        );
        let clip_id = builder.define_clip(rect, vec![region], None);
        builder.push_clip_id(clip_id);

        builder.push_rect(&api::PrimitiveInfo::new(rect), self.color);

        builder.pop_clip_id();

        let mut transaction = api::Transaction::new();
        transaction.set_display_list(
            api::Epoch(0),
            None,
            layout_size,
            builder.finalize(),
            true,
        );
        transaction.set_root_pipeline(pipeline_id);
        transaction.generate_frame();
        self.api.send_transaction(self.document_id, transaction);
        rx.recv().unwrap();
        let renderer = self.renderer.as_mut().unwrap();
        renderer.update();
        renderer.render(self.size).unwrap();
        let _ = renderer.flush_pipeline_info();
        self.visual.present();
    }
}

impl Drop for Rectangle {
    fn drop(&mut self) {
        self.renderer.take().unwrap().deinit()
    }
}

#[derive(Clone)]
struct Notifier {
    events_proxy: winit::EventsLoopProxy,
    tx: mpsc::Sender<()>,
}

impl api::RenderNotifier for Notifier {
    fn clone(&self) -> Box<api::RenderNotifier> {
        Box::new(Clone::clone(self))
    }

    fn wake_up(&self) {
        self.tx.send(()).unwrap();
        let _ = self.events_proxy.wakeup();
    }

    fn new_frame_ready(&self,
                       _: api::DocumentId,
                       _: bool,
                       _: bool,
                       _: Option<u64>) {
        self.wake_up();
    }
}
<commit_msg>Auto merge of #2886 - ekicyou:feature/WS_EX_NOREDIRECTIONBITMAP, r=SimonSapin<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate direct_composition;
extern crate euclid;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate winit;

use direct_composition::DirectComposition;
use std::sync::mpsc;
use webrender::api;
use winit::os::windows::{WindowExt, WindowBuilderExt};
use glutin::dpi::LogicalSize;

fn main() {
    let mut events_loop = winit::EventsLoop::new();

    let (tx, rx) = mpsc::channel();
    let notifier = Box::new(Notifier { events_proxy: events_loop.create_proxy(), tx });

    let window = winit::WindowBuilder::new()
        .with_title("WebRender + ANGLE + DirectComposition")
        .with_dimensions(LogicalSize::new(1024., 768.))
        .with_decorations(true)
        .with_transparency(true)
        .with_no_redirection_bitmap(true)
        .build(&events_loop)
        .unwrap();

    let composition = direct_composition_from_window(&window);
    let factor = window.get_hidpi_factor() as f32;

    let mut clicks: usize = 0;
    let mut offset_y = 100.;
    let size = api::DeviceUintSize::new;
    let mut rects = [
        Rectangle::new(&composition, &notifier, factor, size(300, 200), 0., 0.2, 0.4, 1.),
        Rectangle::new(&composition, &notifier, factor, size(400, 300), 0., 0.5, 0., 0.5),
    ];
    rects[0].render(factor, &rx);
    rects[1].render(factor, &rx);

    rects[0].visual.set_offset_x(100.);
    rects[0].visual.set_offset_y(50.);

    rects[1].visual.set_offset_x(200.);
    rects[1].visual.set_offset_y(offset_y);

    composition.commit();

    events_loop.run_forever(|event| {
        if let winit::Event::WindowEvent { event, .. } = event {
            match event {
                winit::WindowEvent::CloseRequested => {
                    return winit::ControlFlow::Break
                }
                winit::WindowEvent::MouseWheel { delta, .. } => {
                    let dy = match delta {
                        winit::MouseScrollDelta::LineDelta(_, dy) => dy,
                        winit::MouseScrollDelta::PixelDelta(pos) => pos.y as f32,
                    };
                    offset_y = (offset_y - 10. * dy).max(0.).min(468.);

                    rects[1].visual.set_offset_y(offset_y);
                    composition.commit();
                }
                winit::WindowEvent::MouseInput {
                    button: winit::MouseButton::Left,
                    state: winit::ElementState::Pressed,
                    ..
                } => {
                    clicks += 1;
                    let rect = &mut rects[clicks % 2];
                    rect.color.g += 0.1;
                    rect.color.g %= 1.;
                    rect.render(factor, &rx)
                }
                _ => {}
            }
        }
        winit::ControlFlow::Continue
    });
}

fn direct_composition_from_window(window: &winit::Window) -> DirectComposition {
    unsafe {
        DirectComposition::new(window.get_hwnd() as _)
    }
}

struct Rectangle {
    visual: direct_composition::AngleVisual,
    renderer: Option<webrender::Renderer>,
    api: api::RenderApi,
    document_id: api::DocumentId,
    size: api::DeviceUintSize,
    color: api::ColorF,
}

impl Rectangle {
    fn new(composition: &DirectComposition, notifier: &Box<Notifier>,
           device_pixel_ratio: f32, size: api::DeviceUintSize, r: f32, g: f32, b: f32, a: f32)
           -> Self {
        let visual = composition.create_angle_visual(size.width, size.height);
        visual.make_current();

        let (renderer, sender) = webrender::Renderer::new(
            composition.gleam.clone(),
            notifier.clone(),
            webrender::RendererOptions {
                clear_color: Some(api::ColorF::new(0., 0., 0., 0.)),
                device_pixel_ratio,
                ..webrender::RendererOptions::default()
            },
        ).unwrap();
        let api = sender.create_api();

       Rectangle {
            visual,
            renderer: Some(renderer),
            document_id: api.add_document(size, 0),
            api,
            size,
            color: api::ColorF { r, g, b, a },
        }
    }

    fn render(&mut self, device_pixel_ratio: f32, rx: &mpsc::Receiver<()>) {
        self.visual.make_current();

        let pipeline_id = api::PipelineId(0, 0);
        let layout_size = self.size.to_f32() / euclid::TypedScale::new(device_pixel_ratio);
        let mut builder = api::DisplayListBuilder::new(pipeline_id, layout_size);

        let rect = euclid::TypedRect::new(euclid::TypedPoint2D::zero(), layout_size);

        let region = api::ComplexClipRegion::new(
            rect,
            api::BorderRadius::uniform(20.),
            api::ClipMode::Clip
        );
        let clip_id = builder.define_clip(rect, vec![region], None);
        builder.push_clip_id(clip_id);

        builder.push_rect(&api::PrimitiveInfo::new(rect), self.color);

        builder.pop_clip_id();

        let mut transaction = api::Transaction::new();
        transaction.set_display_list(
            api::Epoch(0),
            None,
            layout_size,
            builder.finalize(),
            true,
        );
        transaction.set_root_pipeline(pipeline_id);
        transaction.generate_frame();
        self.api.send_transaction(self.document_id, transaction);
        rx.recv().unwrap();
        let renderer = self.renderer.as_mut().unwrap();
        renderer.update();
        renderer.render(self.size).unwrap();
        let _ = renderer.flush_pipeline_info();
        self.visual.present();
    }
}

impl Drop for Rectangle {
    fn drop(&mut self) {
        self.renderer.take().unwrap().deinit()
    }
}

#[derive(Clone)]
struct Notifier {
    events_proxy: winit::EventsLoopProxy,
    tx: mpsc::Sender<()>,
}

impl api::RenderNotifier for Notifier {
    fn clone(&self) -> Box<api::RenderNotifier> {
        Box::new(Clone::clone(self))
    }

    fn wake_up(&self) {
        self.tx.send(()).unwrap();
        let _ = self.events_proxy.wakeup();
    }

    fn new_frame_ready(&self,
                       _: api::DocumentId,
                       _: bool,
                       _: bool,
                       _: Option<u64>) {
        self.wake_up();
    }
}
<|endoftext|>


<commit_before>use descartes::{P2, V2, Path, Segment, Band, Intersect, convex_hull, FiniteCurve, N, RoughlyComparable};
use kay::{CVec, Swarm, Recipient, CreateWith, ActorSystem, Individual, Fate};
use monet::{Instance, Thing, Norm};
use core::geometry::{CPath, band_to_thing};
use ordered_float::OrderedFloat;

mod road_stroke_node_interactable;
mod road_stroke_canvas;

pub use self::road_stroke_node_interactable::RoadStrokeNodeInteractable;
pub use self::road_stroke_canvas::RoadStrokeCanvas;

#[derive(Copy, Clone)]
pub struct PlanRef(usize, usize);

#[derive(Compact, Clone)]
pub struct Plan {
    strokes: CVec<RoadStroke>,
    intersections: CVec<Intersection>,
    strokes_after_cutting: CVec<RoadStroke>,
    ui_state: PlanUIState
}
impl Individual for Plan{}

impl Plan{
    fn create_interactables(&self) {
        Swarm::<RoadStrokeCanvas>::all() << CreateWith(RoadStrokeCanvas::new(), AddToUI);
        for (i, stroke) in self.strokes.iter().enumerate() {
            stroke.create_interactables(PlanRef(i, 0));
        }
    }

    fn find_intersections(&self) -> CVec<Intersection> {
        let mut all_intersection_points = Vec::new();

        for i in 0..self.strokes.len() {
            let stroke1 = &self.strokes[i];
            if stroke1.nodes.len() > 1 {
                let band1 = Band::new(stroke1.path(), 8.0).outline();
                for j in (i + 1)..self.strokes.len() {
                    let stroke2 = &self.strokes[j];
                    if stroke2.nodes.len() > 1 {
                        let band2 = Band::new(stroke2.path(), 8.0).outline();

                        let intersections = (&band1, &band2).intersect();
                        all_intersection_points.extend(intersections.iter().map(|i| i.position));
                    }
                }
            }
        }

        let mut intersection_point_groups = Vec::<Vec<P2>>::new();

        const INTERSECTION_GROUPING_RADIUS : f32 = 20.0;

        for point in all_intersection_points.drain(..) {
            let create_new_group = match intersection_point_groups.iter_mut().find(|group| {
                let max_distance = group.iter().map(|other_point| OrderedFloat((*other_point - point).norm())).max().unwrap();
                *max_distance < INTERSECTION_GROUPING_RADIUS
            }) {
                Some(exisiting_group) => {exisiting_group.push(point); false},
                None => true
            };

            if create_new_group {
                intersection_point_groups.push(vec![point]);
            }
        }

        let mut merging_ongoing = true;

        while merging_ongoing {
            merging_ongoing = false;
            #[allow(needless_range_loop)]
            for i in 0..intersection_point_groups.len() {
                for j in ((i + 1)..intersection_point_groups.len()).rev() {
                    let merge_groups = {
                        let group_i = &intersection_point_groups[i];
                        let group_j = &intersection_point_groups[j];
                        group_i.iter().any(|point_i|
                            group_j.iter().any(|point_j| (*point_i - *point_j).norm() < INTERSECTION_GROUPING_RADIUS)
                        )
                    };
                    if merge_groups {
                        let group_to_be_merged = intersection_point_groups[j].clone();
                        intersection_point_groups[i].extend_from_slice(&group_to_be_merged);
                        intersection_point_groups[j].clear();
                        merging_ongoing = true;
                    }
                }
            }
        }

        intersection_point_groups.iter().filter_map(|group|
            if group.len() >= 2 {
                Some(Intersection{
                    shape: convex_hull::<CPath>(group),
                    connecting_strokes: CVec::new()
                })
            } else {None}
        ).collect()
    }

    fn cut_strokes_at_intersections(&self) -> CVec<RoadStroke> {
        let mut strokes_todo : Vec<_> = self.strokes.iter().cloned().collect();

        let mut cutting_ongoing = true;
        let mut iters = 0;
        while cutting_ongoing {
            cutting_ongoing = false;
            let mut new_strokes = Vec::new();

            for stroke in &strokes_todo {
                let mut was_cut = false;

                for intersection in self.intersections.iter() {
                    let intersection_points = (&stroke.path(), &intersection.shape).intersect();
                    if intersection_points.len() >= 2 {
                        let entry_distance = intersection_points.iter().map(|p| OrderedFloat(p.along_a)).min().unwrap();
                        let exit_distance = intersection_points.iter().map(|p| OrderedFloat(p.along_a)).max().unwrap();
                        new_strokes.push(stroke.cut_before(*entry_distance - 1.0));
                        new_strokes.push(stroke.cut_after(*exit_distance + 1.0));
                        cutting_ongoing = true;
                        was_cut = true;
                        break;
                    }
                }

                if !was_cut {new_strokes.push(stroke.clone())};
            }

            strokes_todo = new_strokes;
            iters += 1;
            if iters > 30 {
                panic!("STuck!!!")
            }
        }

        strokes_todo.into()
    }
}

#[derive(Copy, Clone)]
enum PlanControl{
    AddRoadStrokeNode(P2),
    MoveRoadStrokeNodeTo(PlanRef, P2)
}

impl Recipient<PlanControl> for Plan {
    fn receive(&mut self, msg: &PlanControl) -> Fate {match *msg{
        PlanControl::AddRoadStrokeNode(at) => {
            let new_node = RoadStrokeNode{position: at, direction: None};

            if let Some(PlanRef(stroke_idx, node_idx)) = self.ui_state.current_node {
                let stroke = &mut self.strokes[stroke_idx];
                let current_node = stroke.nodes[node_idx];

                if (current_node.position - new_node.position).norm() < 5.0 {
                    // finish stroke
                    self.ui_state.current_node = None;
                } else if node_idx == stroke.nodes.len() - 1 {
                    // append
                    stroke.nodes.push(new_node);
                    self.ui_state.current_node = Some(PlanRef(stroke_idx, stroke.nodes.len() - 1));
                } else if node_idx == 0 {
                    // prepend
                    stroke.nodes.insert(0, new_node);
                } else {unreachable!()}
            } else {
                self.strokes.push(RoadStroke{
                    nodes: vec![new_node].into()
                });
                self.ui_state.current_node = Some(PlanRef(self.strokes.len() - 1, 0))
            }

            self.ui_state.dirty = true;
            self.intersections = self.find_intersections();
            self.strokes_after_cutting = self.cut_strokes_at_intersections();
            Fate::Live
        },
        PlanControl::MoveRoadStrokeNodeTo(PlanRef(stroke, node), position) => {
            self.strokes[stroke].nodes[node].position = position;
            self.ui_state.dirty = true;
            self.intersections = self.find_intersections();
            self.strokes_after_cutting = self.cut_strokes_at_intersections();
            Fate::Live
        }
    }}
}

#[derive(Copy, Clone)]
struct RecreateInteractables;
#[derive(Copy, Clone)]
struct ClearAll;

impl Recipient<RecreateInteractables> for Plan {
    fn receive(&mut self, _msg: &RecreateInteractables) -> Fate {
        Swarm::<RoadStrokeNodeInteractable>::all() << ClearAll;
        self.create_interactables();
        Fate::Live
    }
}

use monet::SetupInScene;

impl Recipient<SetupInScene> for Plan {
    fn receive(&mut self, _msg: &SetupInScene) -> Fate {
        self.create_interactables();
        Fate::Live
    }
}

use monet::RenderToScene;
use monet::UpdateThing;

impl Recipient<RenderToScene> for Plan {
    fn receive(&mut self, msg: &RenderToScene) -> Fate {match *msg{
        RenderToScene{renderer_id, scene_id} => {
            if self.ui_state.dirty {
                let thing : Thing = self.strokes_after_cutting.iter()
                    .filter(|stroke| stroke.nodes.len() > 1)
                    .map(RoadStroke::preview_thing)
                    .sum();
                renderer_id << UpdateThing{
                    scene_id: scene_id,
                    thing_id: 13,
                    thing: thing,
                    instance: Instance{
                        instance_position: [0.0, 0.0, 0.0],
                        instance_direction: [1.0, 0.0],
                        instance_color: [0.5, 0.5, 0.5]
                    }
                };
                let intersections_thing : Thing = self.intersections.iter()
                    .filter(|i| i.shape.segments().len() > 0)
                    .map(|i| band_to_thing(&Band::new(i.shape.clone(), 0.4), 0.5))
                    .sum();
                renderer_id << UpdateThing{
                    scene_id: scene_id,
                    thing_id: 14,
                    thing: intersections_thing,
                    instance: Instance{
                        instance_position: [0.0, 0.0, 0.0],
                        instance_direction: [1.0, 0.0],
                        instance_color: [0.0, 0.0, 1.0]
                    }
                };
                self.ui_state.dirty = false;
            }
            Fate::Live
        }
    }}
}

#[derive(Compact, Clone)]
struct RoadStroke{
    nodes: CVec<RoadStrokeNode>
}

impl RoadStroke {
    fn path(&self) -> CPath {
        CPath::new(self.nodes.windows(2).map(|window|
            Segment::line(window[0].position, window[1].position)
        ).collect::<Vec<_>>())
    }

    fn preview_thing(&self) -> Thing {
        band_to_thing(&Band::new(self.path(), 3.0), 0.0)
    }

    fn create_interactables(&self, self_ref: PlanRef) {
        for (i, node) in self.nodes.iter().enumerate() {
            let child_ref = match self_ref {
                PlanRef(stroke_idx, _) => PlanRef(stroke_idx, i)
            };
            node.create_interactables(child_ref);
        }
    }

    // TODO: this is really ugly
    fn cut_before(&self, offset: N) -> Self {
        let path = self.path();
        let cut_path = path.subsection(0.0, offset);
        RoadStroke{nodes: self.nodes.iter().filter(|node|
            cut_path.segments().iter().any(|segment|
                segment.start().is_roughly_within(node.position, 0.1) || segment.end().is_roughly_within(node.position, 0.1)
            )
        ).chain(&[RoadStrokeNode{
            position: path.along(offset), direction: None
        }]).cloned().collect()}
    }

    fn cut_after(&self, offset: N) -> Self {
        let path = self.path();
        let cut_path = path.subsection(offset, path.length());
        RoadStroke{nodes: (&[RoadStrokeNode{
            position: path.along(offset), direction: None
        }]).iter().chain(self.nodes.iter().filter(|node|
            cut_path.segments().iter().any(|segment|
                segment.start().is_roughly_within(node.position, 0.1) || segment.end().is_roughly_within(node.position, 0.1)
            )
        )).cloned().collect()}
    }
}

#[derive(Copy, Clone)]
struct RoadStrokeNode {
    position: P2,
    direction: Option<V2>
}
#[derive(Copy, Clone)]
struct AddToUI;

impl RoadStrokeNode {
    fn create_interactables(&self, self_ref: PlanRef) {
        Swarm::<RoadStrokeNodeInteractable>::all() << CreateWith(
            RoadStrokeNodeInteractable::new(self.position, self_ref),
            AddToUI
        );
    }
}

#[derive(Compact, Clone)]
struct Intersection{
    shape: CPath,
    connecting_strokes: CVec<RoadStroke>
}

#[derive(Compact, Clone)]
struct PlanUIState{
    current_node: Option<PlanRef>,
    dirty: bool
}

pub fn setup(system: &mut ActorSystem) {
    let plan = Plan{
        strokes: CVec::new(),
        strokes_after_cutting: CVec::new(),
        intersections: CVec::new(),
        ui_state: PlanUIState{
            current_node: None,
            dirty: true
        }
    };

    system.add_individual(plan);
    system.add_inbox::<SetupInScene, Plan>();
    system.add_inbox::<RenderToScene, Plan>();
    system.add_inbox::<PlanControl, Plan>();
    system.add_inbox::<RecreateInteractables, Plan>();

    road_stroke_canvas::setup(system);
    road_stroke_node_interactable::setup(system);
}<commit_msg>Create connecting road strokes on intersections #6<commit_after>use descartes::{P2, V2, Path, Segment, Band, Intersect, convex_hull, FiniteCurve, N, RoughlyComparable};
use kay::{CVec, Swarm, Recipient, CreateWith, ActorSystem, Individual, Fate};
use monet::{Instance, Thing, Norm};
use core::geometry::{CPath, band_to_thing};
use ordered_float::OrderedFloat;

mod road_stroke_node_interactable;
mod road_stroke_canvas;

pub use self::road_stroke_node_interactable::RoadStrokeNodeInteractable;
pub use self::road_stroke_canvas::RoadStrokeCanvas;

#[derive(Copy, Clone)]
pub struct PlanRef(usize, usize);

#[derive(Compact, Clone)]
pub struct Plan {
    strokes: CVec<RoadStroke>,
    intersections: CVec<Intersection>,
    strokes_after_cutting: CVec<RoadStroke>,
    ui_state: PlanUIState
}
impl Individual for Plan{}

impl Plan{
    fn create_interactables(&self) {
        Swarm::<RoadStrokeCanvas>::all() << CreateWith(RoadStrokeCanvas::new(), AddToUI);
        for (i, stroke) in self.strokes.iter().enumerate() {
            stroke.create_interactables(PlanRef(i, 0));
        }
    }

    fn create_intersections(&mut self) {
        let mut all_intersection_points = Vec::new();

        for i in 0..self.strokes.len() {
            let stroke1 = &self.strokes[i];
            if stroke1.nodes.len() > 1 {
                let band1 = Band::new(stroke1.path(), 8.0).outline();
                for j in (i + 1)..self.strokes.len() {
                    let stroke2 = &self.strokes[j];
                    if stroke2.nodes.len() > 1 {
                        let band2 = Band::new(stroke2.path(), 8.0).outline();

                        let intersections = (&band1, &band2).intersect();
                        all_intersection_points.extend(intersections.iter().map(|i| i.position));
                    }
                }
            }
        }

        let mut intersection_point_groups = Vec::<Vec<P2>>::new();

        const INTERSECTION_GROUPING_RADIUS : f32 = 20.0;

        for point in all_intersection_points.drain(..) {
            let create_new_group = match intersection_point_groups.iter_mut().find(|group| {
                let max_distance = group.iter().map(|other_point| OrderedFloat((*other_point - point).norm())).max().unwrap();
                *max_distance < INTERSECTION_GROUPING_RADIUS
            }) {
                Some(exisiting_group) => {exisiting_group.push(point); false},
                None => true
            };

            if create_new_group {
                intersection_point_groups.push(vec![point]);
            }
        }

        let mut merging_ongoing = true;

        while merging_ongoing {
            merging_ongoing = false;
            #[allow(needless_range_loop)]
            for i in 0..intersection_point_groups.len() {
                for j in ((i + 1)..intersection_point_groups.len()).rev() {
                    let merge_groups = {
                        let group_i = &intersection_point_groups[i];
                        let group_j = &intersection_point_groups[j];
                        group_i.iter().any(|point_i|
                            group_j.iter().any(|point_j| (*point_i - *point_j).norm() < INTERSECTION_GROUPING_RADIUS)
                        )
                    };
                    if merge_groups {
                        let group_to_be_merged = intersection_point_groups[j].clone();
                        intersection_point_groups[i].extend_from_slice(&group_to_be_merged);
                        intersection_point_groups[j].clear();
                        merging_ongoing = true;
                    }
                }
            }
        }

        self.intersections = intersection_point_groups.iter().filter_map(|group|
            if group.len() >= 2 {
                Some(Intersection{
                    shape: convex_hull::<CPath>(group),
                    incoming: CVec::new(),
                    outgoing: CVec::new(),
                    connecting_strokes: CVec::new()
                })
            } else {None}
        ).collect()
    }

    fn cut_strokes_at_intersections(&mut self) {
        let mut strokes_todo : Vec<_> = self.strokes.iter().cloned().collect();

        let mut cutting_ongoing = true;
        let mut iters = 0;
        while cutting_ongoing {
            cutting_ongoing = false;
            let mut new_strokes = Vec::new();

            for stroke in &strokes_todo {
                let mut was_cut = false;

                for intersection in self.intersections.iter_mut() {
                    let intersection_points = (&stroke.path(), &intersection.shape).intersect();
                    if intersection_points.len() >= 2 {
                        let entry_distance = intersection_points.iter().map(|p| OrderedFloat(p.along_a)).min().unwrap();
                        let exit_distance = intersection_points.iter().map(|p| OrderedFloat(p.along_a)).max().unwrap();
                        let before_intersection = stroke.cut_before(*entry_distance - 1.0);
                        let after_intersection = stroke.cut_after(*exit_distance + 1.0);

                        intersection.incoming.push(*before_intersection.nodes.last().unwrap());
                        intersection.outgoing.push(after_intersection.nodes[0]);
                        new_strokes.push(before_intersection);
                        new_strokes.push(after_intersection);

                        cutting_ongoing = true;
                        was_cut = true;
                        break;
                    }
                }

                if !was_cut {new_strokes.push(stroke.clone())};
            }

            strokes_todo = new_strokes;
            iters += 1;
            if iters > 30 {
                panic!("STuck!!!")
            }
        }

        self.strokes_after_cutting = strokes_todo.into();
    }

    fn create_connecting_strokes_on_intersections(&mut self) {
        for intersection in self.intersections.iter_mut() {
            let mut connecting_strokes = CVec::new();
            for incoming in intersection.incoming.iter() {
                for outgoing in intersection.outgoing.iter() {
                    connecting_strokes.push(RoadStroke{
                        nodes: vec![*incoming, *outgoing].into()
                    });
                }
            }
            intersection.connecting_strokes = connecting_strokes;
        }

    }
}

#[derive(Copy, Clone)]
enum PlanControl{
    AddRoadStrokeNode(P2),
    MoveRoadStrokeNodeTo(PlanRef, P2)
}

impl Recipient<PlanControl> for Plan {
    fn receive(&mut self, msg: &PlanControl) -> Fate {match *msg{
        PlanControl::AddRoadStrokeNode(at) => {
            let new_node = RoadStrokeNode{position: at, direction: None};

            if let Some(PlanRef(stroke_idx, node_idx)) = self.ui_state.current_node {
                let stroke = &mut self.strokes[stroke_idx];
                let current_node = stroke.nodes[node_idx];

                if (current_node.position - new_node.position).norm() < 5.0 {
                    // finish stroke
                    self.ui_state.current_node = None;
                } else if node_idx == stroke.nodes.len() - 1 {
                    // append
                    stroke.nodes.push(new_node);
                    self.ui_state.current_node = Some(PlanRef(stroke_idx, stroke.nodes.len() - 1));
                } else if node_idx == 0 {
                    // prepend
                    stroke.nodes.insert(0, new_node);
                } else {unreachable!()}
            } else {
                self.strokes.push(RoadStroke{
                    nodes: vec![new_node].into()
                });
                self.ui_state.current_node = Some(PlanRef(self.strokes.len() - 1, 0))
            }

            self.ui_state.dirty = true;
            self.create_intersections();
            self.cut_strokes_at_intersections();
            self.create_connecting_strokes_on_intersections();
            Fate::Live
        },
        PlanControl::MoveRoadStrokeNodeTo(PlanRef(stroke, node), position) => {
            self.strokes[stroke].nodes[node].position = position;
            self.ui_state.dirty = true;
            self.create_intersections();
            self.cut_strokes_at_intersections();
            self.create_connecting_strokes_on_intersections();
            Fate::Live
        }
    }}
}

#[derive(Copy, Clone)]
struct RecreateInteractables;
#[derive(Copy, Clone)]
struct ClearAll;

impl Recipient<RecreateInteractables> for Plan {
    fn receive(&mut self, _msg: &RecreateInteractables) -> Fate {
        Swarm::<RoadStrokeNodeInteractable>::all() << ClearAll;
        self.create_interactables();
        Fate::Live
    }
}

use monet::SetupInScene;

impl Recipient<SetupInScene> for Plan {
    fn receive(&mut self, _msg: &SetupInScene) -> Fate {
        self.create_interactables();
        Fate::Live
    }
}

use monet::RenderToScene;
use monet::UpdateThing;

impl Recipient<RenderToScene> for Plan {
    fn receive(&mut self, msg: &RenderToScene) -> Fate {match *msg{
        RenderToScene{renderer_id, scene_id} => {
            if self.ui_state.dirty {
                let thing : Thing = self.strokes_after_cutting.iter()
                    .filter(|stroke| stroke.nodes.len() > 1)
                    .map(RoadStroke::preview_thing)
                    .sum();
                renderer_id << UpdateThing{
                    scene_id: scene_id,
                    thing_id: 13,
                    thing: thing,
                    instance: Instance{
                        instance_position: [0.0, 0.0, 0.0],
                        instance_direction: [1.0, 0.0],
                        instance_color: [0.3, 0.3, 0.5]
                    }
                };
                let intersections_thing : Thing = self.intersections.iter()
                    .filter(|i| i.shape.segments().len() > 0)
                    .map(|i| band_to_thing(&Band::new(i.shape.clone(), 0.4), 0.5))
                    .sum();
                renderer_id << UpdateThing{
                    scene_id: scene_id,
                    thing_id: 14,
                    thing: intersections_thing,
                    instance: Instance{
                        instance_position: [0.0, 0.0, 0.0],
                        instance_direction: [1.0, 0.0],
                        instance_color: [0.0, 0.0, 1.0]
                    }
                };
                let connecting_strokes_thing : Thing = self.intersections.iter()
                    .filter(|i| !i.connecting_strokes.is_empty())
                    .map(|i| i.connecting_strokes.iter().map(RoadStroke::preview_thing).sum())
                    .sum();
                renderer_id << UpdateThing{
                    scene_id: scene_id,
                    thing_id: 15,
                    thing: connecting_strokes_thing,
                    instance: Instance{
                        instance_position: [0.0, 0.0, 0.0],
                        instance_direction: [1.0, 0.0],
                        instance_color: [0.5, 0.5, 1.0]
                    }
                };
                self.ui_state.dirty = false;
            }
            Fate::Live
        }
    }}
}

#[derive(Compact, Clone)]
struct RoadStroke{
    nodes: CVec<RoadStrokeNode>
}

impl RoadStroke {
    fn path(&self) -> CPath {
        CPath::new(self.nodes.windows(2).map(|window|
            Segment::line(window[0].position, window[1].position)
        ).collect::<Vec<_>>())
    }

    fn preview_thing(&self) -> Thing {
        band_to_thing(&Band::new(Band::new(self.path(), 3.0).outline(), 0.3), 0.0)
    }

    fn create_interactables(&self, self_ref: PlanRef) {
        for (i, node) in self.nodes.iter().enumerate() {
            let child_ref = match self_ref {
                PlanRef(stroke_idx, _) => PlanRef(stroke_idx, i)
            };
            node.create_interactables(child_ref);
        }
    }

    // TODO: this is really ugly
    fn cut_before(&self, offset: N) -> Self {
        let path = self.path();
        let cut_path = path.subsection(0.0, offset);
        RoadStroke{nodes: self.nodes.iter().filter(|node|
            cut_path.segments().iter().any(|segment|
                segment.start().is_roughly_within(node.position, 0.1) || segment.end().is_roughly_within(node.position, 0.1)
            )
        ).chain(&[RoadStrokeNode{
            position: path.along(offset), direction: None
        }]).cloned().collect()}
    }

    fn cut_after(&self, offset: N) -> Self {
        let path = self.path();
        let cut_path = path.subsection(offset, path.length());
        RoadStroke{nodes: (&[RoadStrokeNode{
            position: path.along(offset), direction: None
        }]).iter().chain(self.nodes.iter().filter(|node|
            cut_path.segments().iter().any(|segment|
                segment.start().is_roughly_within(node.position, 0.1) || segment.end().is_roughly_within(node.position, 0.1)
            )
        )).cloned().collect()}
    }
}

#[derive(Copy, Clone)]
struct RoadStrokeNode {
    position: P2,
    direction: Option<V2>
}
#[derive(Copy, Clone)]
struct AddToUI;

impl RoadStrokeNode {
    fn create_interactables(&self, self_ref: PlanRef) {
        Swarm::<RoadStrokeNodeInteractable>::all() << CreateWith(
            RoadStrokeNodeInteractable::new(self.position, self_ref),
            AddToUI
        );
    }
}

#[derive(Compact, Clone)]
struct Intersection{
    shape: CPath,
    incoming: CVec<RoadStrokeNode>,
    outgoing: CVec<RoadStrokeNode>,
    connecting_strokes: CVec<RoadStroke>
}

#[derive(Compact, Clone)]
struct PlanUIState{
    current_node: Option<PlanRef>,
    dirty: bool
}

pub fn setup(system: &mut ActorSystem) {
    let plan = Plan{
        strokes: CVec::new(),
        strokes_after_cutting: CVec::new(),
        intersections: CVec::new(),
        ui_state: PlanUIState{
            current_node: None,
            dirty: true
        }
    };

    system.add_individual(plan);
    system.add_inbox::<SetupInScene, Plan>();
    system.add_inbox::<RenderToScene, Plan>();
    system.add_inbox::<PlanControl, Plan>();
    system.add_inbox::<RecreateInteractables, Plan>();

    road_stroke_canvas::setup(system);
    road_stroke_node_interactable::setup(system);
}<|endoftext|>


<commit_before>use std::collections::LinkedList;
use std::borrow::Borrow;

use token::Token;

use std::cell::Cell;
use std::rc::Rc;
use regex::Regex;
use context::Context;
use token::Posn;

pub trait ESCharExt {
    fn is_es_newline(self) -> bool;
    fn is_es_whitespace(self) -> bool;
}

impl ESCharExt for char {
    fn is_es_newline(self) -> bool {
        match self {
            '\u{000a}' | '\u{000d}' | '\u{2028}' | '\u{2029}' => true,
            _ => false
        }
    }

    fn is_es_whitespace(self) -> bool {
        match self {
              '\u{0009}' | '\u{000b}' | '\u{000c}' | '\u{0020}' | '\u{00a0}'
            | '\u{1680}' | '\u{2000}' | '\u{2001}' | '\u{2002}' | '\u{2003}' | '\u{2004}'
            | '\u{2005}' | '\u{2006}' | '\u{2009}' | '\u{200a}' | '\u{202f}' | '\u{205f}'
            | '\u{3000}' | '\u{feff}' => true,
            _ => false
        }
    }
}

struct LineOrientedReader<I> {
    chars: I,
    curr_char: Option<char>,
    next_char: Option<char>,
    curr_posn: Posn
}

impl<I> LineOrientedReader<I> where I: Iterator<Item=char> {
    pub fn new(mut chars: I) -> LineOrientedReader<I> {
        let curr_char = chars.next();
        let next_char = if curr_char.is_some() { chars.next() } else { None };
        LineOrientedReader {
            chars: chars,
            curr_char: curr_char,
            next_char: next_char,
            curr_posn: Posn {
                offset: 0,
                line: 0,
                column: 0
            }
        }
    }

    pub fn curr_char(&mut self) -> Option<char> { self.curr_char }
    pub fn curr_posn(&mut self) -> Posn { self.curr_posn }
    pub fn next_char(&mut self) -> Option<char> { self.next_char }

    pub fn bump(&mut self) {
        let curr_char = self.next_char;
        let next_char = if curr_char.is_some() { self.chars.next() } else { None };

        self.curr_char = curr_char;
        self.next_char = next_char;

        if (curr_char == Some('\r') && next_char != Some('\n')) ||
           curr_char == Some('\n') ||
           curr_char == Some('\u{2028}') ||
           curr_char == Some('\u{2029}') {
            self.curr_posn.line += 1;
            self.curr_posn.column = 0;
        } else {
            self.curr_posn.column += 1;
        }

        self.curr_posn.offset += 1;
    }
}

struct TokenBuffer {
    tokens: LinkedList<Token>
}

impl TokenBuffer {
    fn new() -> TokenBuffer {
        TokenBuffer {
            tokens: LinkedList::new()
        }
    }

    fn is_empty(&mut self) -> bool {
        self.tokens.len() == 0
    }

    fn push_token(&mut self, token: Token) {
        assert!(self.tokens.len() == 0);
        self.tokens.push_back(token);
    }

    fn read_token(&mut self) -> Token {
        assert!(self.tokens.len() > 0);
        self.tokens.pop_front().unwrap()
    }

    fn peek_token(&mut self) -> &Token {
        assert!(self.tokens.len() > 0);
        self.tokens.front().unwrap()
    }

    fn unread_token(&mut self, token: Token) {
        assert!(self.tokens.len() >= 0);
        assert!(self.tokens.len() < 3);
        self.tokens.push_front(token);
    }
}

pub struct Lexer<I> {
    reader: LineOrientedReader<I>,
    cx: Rc<Cell<Context>>,
    lookahead: TokenBuffer
}

impl<I> Lexer<I> where I: Iterator<Item=char> {
    // constructor

    pub fn new(chars: I, cx: Rc<Cell<Context>>) -> Lexer<I> {
        Lexer {
            reader: LineOrientedReader::new(chars),
            cx: cx,
            lookahead: TokenBuffer::new()
        }
    }

    // public methods

    pub fn is_eof(&mut self) -> bool {
        match *self.peek_token() {
            Token::EOF => true,
            _ => false
        }
    }

    pub fn peek_token(&mut self) -> &Token {
        if self.lookahead.is_empty() {
            let token = self.read_next_token();
            self.lookahead.push_token(token);
        }
        self.lookahead.peek_token()
    }

    pub fn read_token(&mut self) -> Token {
        if self.lookahead.is_empty() {
            self.read_next_token()
        } else {
            self.lookahead.read_token()
        }
    }

    pub fn unread_token(&mut self, token: Token) {
        self.lookahead.unread_token(token);
    }

    // private methods

    fn skip_line_comment(&mut self) {
    }

    fn skip_block_comment(&mut self) {
    }

    fn div_or_regexp(&mut self) -> Token {
        if self.cx.get().operator {
            unimplemented!()
        } else {
            unimplemented!()
        }
    }

    fn read_next_token(&mut self) -> Token {
        self.skip_whitespace();
        loop {
            match self.reader.curr_char() {
                None => return Token::EOF,
                Some(ch) => {
                    if ch == '/' {
                        match self.reader.next_char() {
                            Some('/') => self.skip_line_comment(),
                            Some('*') => self.skip_block_comment(),
                            _ => return self.div_or_regexp()
                        }
                    }
                    unimplemented!()
                }
            }
        }
    }

    fn is_whitespace(&mut self) -> bool {
        match self.reader.curr_char() {
            Some(ch) => ch.is_es_whitespace(),
            None => false
        }
    }

    fn eat(&mut self) -> Option<char> {
        let ch = self.reader.curr_char();
        self.reader.bump();
        ch
    }

    fn skip_whitespace(&mut self) {
        while self.is_whitespace() {
            self.reader.bump();
        }
    }
}

impl<I> Iterator for Lexer<I> where I: Iterator<Item=char> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        self.skip_whitespace();
        self.eat()
            .map(|ch| {
                match ch {
                    '1' => Token::DecimalInt(String::from_str("1")),
                    '+' => Token::Plus,
                    _ => Token::Error(ch)
                }
            })
    }
}
<commit_msg>replace private field access with public method, we're good now<commit_after>use std::collections::LinkedList;
use std::borrow::Borrow;

use token::Token;

use std::cell::Cell;
use std::rc::Rc;
use regex::Regex;
use context::Context;
use token::Posn;

pub trait ESCharExt {
    fn is_es_newline(self) -> bool;
    fn is_es_whitespace(self) -> bool;
}

impl ESCharExt for char {
    fn is_es_newline(self) -> bool {
        match self {
            '\u{000a}' | '\u{000d}' | '\u{2028}' | '\u{2029}' => true,
            _ => false
        }
    }

    fn is_es_whitespace(self) -> bool {
        match self {
              '\u{0009}' | '\u{000b}' | '\u{000c}' | '\u{0020}' | '\u{00a0}'
            | '\u{1680}' | '\u{2000}' | '\u{2001}' | '\u{2002}' | '\u{2003}' | '\u{2004}'
            | '\u{2005}' | '\u{2006}' | '\u{2009}' | '\u{200a}' | '\u{202f}' | '\u{205f}'
            | '\u{3000}' | '\u{feff}' => true,
            _ => false
        }
    }
}

struct LineOrientedReader<I> {
    chars: I,
    curr_char: Option<char>,
    next_char: Option<char>,
    curr_posn: Posn
}

impl<I> LineOrientedReader<I> where I: Iterator<Item=char> {
    pub fn new(mut chars: I) -> LineOrientedReader<I> {
        let curr_char = chars.next();
        let next_char = if curr_char.is_some() { chars.next() } else { None };
        LineOrientedReader {
            chars: chars,
            curr_char: curr_char,
            next_char: next_char,
            curr_posn: Posn {
                offset: 0,
                line: 0,
                column: 0
            }
        }
    }

    pub fn curr_char(&mut self) -> Option<char> { self.curr_char }
    pub fn curr_posn(&mut self) -> Posn { self.curr_posn }
    pub fn next_char(&mut self) -> Option<char> { self.next_char }

    pub fn bump(&mut self) {
        let curr_char = self.next_char;
        let next_char = if curr_char.is_some() { self.chars.next() } else { None };

        self.curr_char = curr_char;
        self.next_char = next_char;

        if (curr_char == Some('\r') && next_char != Some('\n')) ||
           curr_char == Some('\n') ||
           curr_char == Some('\u{2028}') ||
           curr_char == Some('\u{2029}') {
            self.curr_posn.line += 1;
            self.curr_posn.column = 0;
        } else {
            self.curr_posn.column += 1;
        }

        self.curr_posn.offset += 1;
    }
}

struct TokenBuffer {
    tokens: LinkedList<Token>
}

impl TokenBuffer {
    fn new() -> TokenBuffer {
        TokenBuffer {
            tokens: LinkedList::new()
        }
    }

    fn is_empty(&mut self) -> bool {
        self.tokens.len() == 0
    }

    fn push_token(&mut self, token: Token) {
        assert!(self.tokens.len() == 0);
        self.tokens.push_back(token);
    }

    fn read_token(&mut self) -> Token {
        assert!(self.tokens.len() > 0);
        self.tokens.pop_front().unwrap()
    }

    fn peek_token(&mut self) -> &Token {
        assert!(self.tokens.len() > 0);
        self.tokens.front().unwrap()
    }

    fn unread_token(&mut self, token: Token) {
        assert!(self.tokens.len() >= 0);
        assert!(self.tokens.len() < 3);
        self.tokens.push_front(token);
    }
}

pub struct Lexer<I> {
    reader: LineOrientedReader<I>,
    cx: Rc<Cell<Context>>,
    lookahead: TokenBuffer
}

impl<I> Lexer<I> where I: Iterator<Item=char> {
    // constructor

    pub fn new(chars: I, cx: Rc<Cell<Context>>) -> Lexer<I> {
        Lexer {
            reader: LineOrientedReader::new(chars),
            cx: cx,
            lookahead: TokenBuffer::new()
        }
    }

    // public methods

    pub fn is_eof(&mut self) -> bool {
        match *self.peek_token() {
            Token::EOF => true,
            _ => false
        }
    }

    pub fn peek_token(&mut self) -> &Token {
        if self.lookahead.is_empty() {
            let token = self.read_next_token();
            self.lookahead.push_token(token);
        }
        self.lookahead.peek_token()
    }

    pub fn read_token(&mut self) -> Token {
        if self.lookahead.is_empty() {
            self.read_next_token()
        } else {
            self.lookahead.read_token()
        }
    }

    pub fn unread_token(&mut self, token: Token) {
        self.lookahead.unread_token(token);
    }

    // private methods

    fn skip_line_comment(&mut self) {
    }

    fn skip_block_comment(&mut self) {
    }

    fn div_or_regexp(&mut self) -> Token {
        if self.cx.get().is_operator() {
            unimplemented!()
        } else {
            unimplemented!()
        }
    }

    fn read_next_token(&mut self) -> Token {
        self.skip_whitespace();
        loop {
            match self.reader.curr_char() {
                None => return Token::EOF,
                Some(ch) => {
                    if ch == '/' {
                        match self.reader.next_char() {
                            Some('/') => self.skip_line_comment(),
                            Some('*') => self.skip_block_comment(),
                            _ => return self.div_or_regexp()
                        }
                    }
                    unimplemented!()
                }
            }
        }
    }

    fn is_whitespace(&mut self) -> bool {
        match self.reader.curr_char() {
            Some(ch) => ch.is_es_whitespace(),
            None => false
        }
    }

    fn eat(&mut self) -> Option<char> {
        let ch = self.reader.curr_char();
        self.reader.bump();
        ch
    }

    fn skip_whitespace(&mut self) {
        while self.is_whitespace() {
            self.reader.bump();
        }
    }
}

impl<I> Iterator for Lexer<I> where I: Iterator<Item=char> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        self.skip_whitespace();
        self.eat()
            .map(|ch| {
                match ch {
                    '1' => Token::DecimalInt(String::from_str("1")),
                    '+' => Token::Plus,
                    _ => Token::Error(ch)
                }
            })
    }
}
<|endoftext|>