<commit_before>#[cfg(test)]
#[path="../../../../tests/collisions/detection/gjkepa/gjk_epa_detection_test.rs"]
mod tests;

use {ID, INFINITY, Scalar, TOLERANCE};
use maths::{Approximations, Vec3D};
use utils::Handle;
use algorithms::{Execute, IterativeAlgorithm, PanicOnIteration};
use collisions::{CollisionBody, CollisionData, Contact, Detection};
use collisions::geometry::shapes::Shape;
use collisions::detection::gjkepa::{ContactTracker, EPA, GJKSimplex, MinkowskiDifference};

pub struct GJKEPADetection { }

impl GJKEPADetection {
    pub fn new() -> GJKEPADetection {
        GJKEPADetection { }
    }

    // TODO return Option<&mut ContactTracker> instead
    fn find_tracker_mut(&mut self, _id_0: ID, _id_1: ID) -> Option<ContactTracker> {
        None
    }

    fn create_tracker<B>(&mut self, body_0: &B, body_1: &B) -> ContactTracker where B: CollisionBody {
        ContactTracker::new(body_0.collision_data(), body_1.collision_data())
    }
}

impl<B> Detection<B> for GJKEPADetection where B: CollisionBody {
    fn update(&mut self) {
        // do nothing
    }

    fn compute_contacts(&mut self, handle_0: &Handle<B>, handle_1: &Handle<B>) -> Option<Contact<B>> {
        let body_0 = handle_0.borrow();
        let body_1 = handle_1.borrow();

        let mut tracker = self.find_tracker_mut(body_0.id(), body_1.id())
            .unwrap_or_else(|| self.create_tracker(&*body_0, &*body_1));

        GJK::using_simplex(tracker.simplex_mut(), body_0.collision_data(), body_1.collision_data())
            .panic_on_iteration(1000, "GJK failed to complete")
            .execute()
            .map(|simplex| {
                // TODO pass the MinkowskiDifference around
                EPA::new(simplex, body_0.collision_data(), body_1.collision_data())
                    .panic_on_iteration(1000, "EPA failed to complete")
                    .execute()
                    .compute_contact_set()
            })
            .map(|contact_set| {
                Contact::new(contact_set, Handle::clone(handle_0), Handle::clone(handle_1))
            })
    }
}

pub struct GJK<'a> {
    diff: MinkowskiDifference<'a>,
    simplex: &'a mut GJKSimplex,
    last_max_distance: Scalar,
    intersection_tolerance: Scalar,
    converged_success_result: Option<bool>,
}

impl<'a> GJK<'a> {
    pub fn using_simplex(simplex: &'a mut GJKSimplex, data_0: &'a CollisionData, data_1: &'a CollisionData) -> GJK<'a> {
        let diff = MinkowskiDifference(data_0, data_1);
        let intersection_tolerance = diff.0.shape().surface_radius() +
            diff.1.shape().surface_radius();

        GJK {
            diff: diff,
            simplex: simplex,
            last_max_distance: INFINITY,
            intersection_tolerance: intersection_tolerance,
            converged_success_result: None,
        }
    }
}

impl<'a> IterativeAlgorithm for GJK<'a> {
    type Result = Option<&'a GJKSimplex>;

    fn result(self) -> Self::Result {
        self.converged_success_result.and_then(move |success| {
            if success {
                Some(self.simplex as &GJKSimplex)
            } else {
                None
            }
        })
    }

    fn has_converged(&self) -> bool {
        self.converged_success_result.is_some()
    }

    fn next_iteration(&mut self) {
        if let Some(_result) = self.converged_success_result {
            return;
        }

        let next_guess = self.simplex.separating_planes_with_index_of_out_of_plane_point_iter()
            .map(|(not_on_plane_index, plane)| {
                let projection = plane.normal_projection_of_origin();

                (not_on_plane_index, plane, projection)
            })
            .filter(|&(_not_on_plane_index, ref _plane, projection)| projection > self.intersection_tolerance + TOLERANCE && projection < self.last_max_distance)
            // TODO find out if this would have issues with precision
            .min_by_key(|&(_not_on_plane_index, ref _plane, projection)| (projection / TOLERANCE) as i32)
            .map(|(not_on_plane_index, plane, _projection)| (not_on_plane_index, plane));

        let (not_on_plane_index, plane) = match next_guess {
            Some(data) => data,

            None => {
                self.converged_success_result = Some(true);
                return;
            },
        };

        let new_support_point = self.diff.support_point(Vec3D::from(plane.normal()));

        if !plane.normal_projection_of(new_support_point).is_strictly_positive() {
            self.converged_success_result = Some(false);
            return;
        }

        *self.simplex.vertex_mut(not_on_plane_index) = new_support_point;
    }
}
<commit_msg>Fix a bug in the GJK algorithm<commit_after>#[cfg(test)]
#[path="../../../../tests/collisions/detection/gjkepa/gjk_epa_detection_test.rs"]
mod tests;

use {ID, Scalar, TOLERANCE};
use maths::{Approximations, Vec3D};
use utils::Handle;
use algorithms::{Execute, IterativeAlgorithm, PanicOnIteration};
use collisions::{CollisionBody, CollisionData, Contact, Detection};
use collisions::geometry::shapes::Shape;
use collisions::detection::gjkepa::{ContactTracker, EPA, GJKSimplex, MinkowskiDifference};

pub struct GJKEPADetection { }

impl GJKEPADetection {
    pub fn new() -> GJKEPADetection {
        GJKEPADetection { }
    }

    // TODO return Option<&mut ContactTracker> instead
    fn find_tracker_mut(&mut self, _id_0: ID, _id_1: ID) -> Option<ContactTracker> {
        None
    }

    fn create_tracker<B>(&mut self, body_0: &B, body_1: &B) -> ContactTracker where B: CollisionBody {
        ContactTracker::new(body_0.collision_data(), body_1.collision_data())
    }
}

impl<B> Detection<B> for GJKEPADetection where B: CollisionBody {
    fn update(&mut self) {
        // do nothing
    }

    fn compute_contacts(&mut self, handle_0: &Handle<B>, handle_1: &Handle<B>) -> Option<Contact<B>> {
        let body_0 = handle_0.borrow();
        let body_1 = handle_1.borrow();

        let mut tracker = self.find_tracker_mut(body_0.id(), body_1.id())
            .unwrap_or_else(|| self.create_tracker(&*body_0, &*body_1));

        GJK::using_simplex(tracker.simplex_mut(), body_0.collision_data(), body_1.collision_data())
            .panic_on_iteration(1000, "GJK failed to complete")
            .execute()
            .map(|simplex| {
                // TODO pass the MinkowskiDifference around
                EPA::new(simplex, body_0.collision_data(), body_1.collision_data())
                    .panic_on_iteration(1000, "EPA failed to complete")
                    .execute()
                    .compute_contact_set()
            })
            .map(|contact_set| {
                Contact::new(contact_set, Handle::clone(handle_0), Handle::clone(handle_1))
            })
    }
}

pub struct GJK<'a> {
    diff: MinkowskiDifference<'a>,
    simplex: &'a mut GJKSimplex,
    intersection_tolerance: Scalar,
    converged_success_result: Option<bool>,
}

impl<'a> GJK<'a> {
    pub fn using_simplex(simplex: &'a mut GJKSimplex, data_0: &'a CollisionData, data_1: &'a CollisionData) -> GJK<'a> {
        let diff = MinkowskiDifference(data_0, data_1);
        let intersection_tolerance = diff.0.shape().surface_radius() +
            diff.1.shape().surface_radius();

        GJK {
            diff: diff,
            simplex: simplex,
            intersection_tolerance: intersection_tolerance,
            converged_success_result: None,
        }
    }
}

impl<'a> IterativeAlgorithm for GJK<'a> {
    type Result = Option<&'a GJKSimplex>;

    fn result(self) -> Self::Result {
        self.converged_success_result.and_then(move |success| {
            if success {
                Some(self.simplex as &GJKSimplex)
            } else {
                None
            }
        })
    }

    fn has_converged(&self) -> bool {
        self.converged_success_result.is_some()
    }

    fn next_iteration(&mut self) {
        if let Some(_result) = self.converged_success_result {
            return;
        }

        let next_guess = self.simplex.separating_planes_with_index_of_out_of_plane_point_iter()
            .map(|(not_on_plane_index, plane)| {
                let projection = plane.normal_projection_of_origin();

                (not_on_plane_index, plane, projection)
            })
            .filter(|&(_not_on_plane_index, ref _plane, projection)| {
                projection > self.intersection_tolerance + TOLERANCE
            })
            // TODO find out if this would have issues with precision
            .max_by_key(|&(_not_on_plane_index, ref _plane, projection)| (projection / TOLERANCE) as i32);

        let (not_on_plane_index, plane) = match next_guess {
            Some((not_on_plane_index, plane, _projection)) => {
                (not_on_plane_index, plane)
            },

            None => {
                self.converged_success_result = Some(true);
                return;
            },
        };

        let new_support_point = self.diff.support_point(Vec3D::from(plane.normal()));

        if !plane.normal_projection_of(new_support_point).is_strictly_positive() {
            self.converged_success_result = Some(false);
            return;
        }

        *self.simplex.vertex_mut(not_on_plane_index) = new_support_point;
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;

// https://leetcode.com/problems/reverse-odd-levels-of-binary-tree/
#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
    pub val: i32,
    pub left: Option<Rc<RefCell<TreeNode>>>,
    pub right: Option<Rc<RefCell<TreeNode>>>,
}

impl TreeNode {
    #[inline]
    pub fn new(val: i32) -> Self {
        TreeNode {
            val,
            left: None,
            right: None,
        }
    }
}

pub fn reverse_odd_levels(root: Option<Rc<RefCell<TreeNode>>>) -> Option<Rc<RefCell<TreeNode>>> {
    todo!()
}

fn main() {
    fn create_node(value: i32) -> Option<Rc<RefCell<TreeNode>>> {
        Some(Rc::new(RefCell::new(TreeNode::new(value))))
    }

    fn add_left(
        parent: &Option<Rc<RefCell<TreeNode>>>,
        value: i32,
    ) -> Option<Rc<RefCell<TreeNode>>> {
        parent.as_ref().unwrap().as_ref().borrow_mut().left = create_node(value);
        parent.as_ref().unwrap().as_ref().borrow().left.clone()
    }

    fn add_right(
        parent: &Option<Rc<RefCell<TreeNode>>>,
        value: i32,
    ) -> Option<Rc<RefCell<TreeNode>>> {
        parent.as_ref().unwrap().as_ref().borrow_mut().right = create_node(value);
        parent.as_ref().unwrap().as_ref().borrow().right.clone()
    }

    fn to_tree(nodes: Vec<i32>) -> Option<Rc<RefCell<TreeNode>>> {
        let mut deque: VecDeque<Option<Rc<RefCell<TreeNode>>>> = VecDeque::new();
        let mut root: Option<Rc<RefCell<TreeNode>>> = None;
        deque.push_back(create_node(nodes[0]));
        let mut i = 1;
        while i < nodes.len() {
            let parent = deque.pop_front().unwrap();
            deque.push_back(add_left(&parent, nodes[i]));
            deque.push_back(add_right(&parent, nodes[i + 1]));
            i += 2;
            if root == None {
                root = parent;
            }
        }
        root
    }

    let root = to_tree(vec![2, 3, 5, 8, 13, 21, 34]);
    println!("{:?}", reverse_odd_levels(root)); // [2,5,3,8,13,21,34]

    let root = to_tree(vec![7, 13, 11]);
    println!("{:?}", reverse_odd_levels(root)); // [7,11,13]

    let root = to_tree(vec![0, 1, 2, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2]);
    println!("{:?}", reverse_odd_levels(root)); // [0,2,1,0,0,0,0,2,2,2,2,1,1,1,1]

    let root = to_tree(vec![0, 1, 2, 0, 0, 0, 0, 6, 7, 8, 9, 1, 2, 3, 4]);
    println!("{:?}", reverse_odd_levels(root)); // [0,2,1,0,0,0,0,4,3,2,1,9,8,7,6]
}
<commit_msg>Update problem 2415<commit_after>use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;

// https://leetcode.com/problems/reverse-odd-levels-of-binary-tree/
#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
    pub val: i32,
    pub left: Option<Rc<RefCell<TreeNode>>>,
    pub right: Option<Rc<RefCell<TreeNode>>>,
}

impl TreeNode {
    #[inline]
    pub fn new(val: i32) -> Self {
        TreeNode {
            val,
            left: None,
            right: None,
        }
    }
}

pub fn reverse_odd_levels(root: Option<Rc<RefCell<TreeNode>>>) -> Option<Rc<RefCell<TreeNode>>> {
    let mut deque: VecDeque<&Option<Rc<RefCell<TreeNode>>>> = VecDeque::new();
    deque.push_back(&root);
    while !deque.is_empty() {
        let node = deque.pop_front().unwrap();
        let size = deque.len();
        for _ in 0..size {
            if let Some(n) = node {
                let left = &n.as_ref().borrow().left;
                let right = &n.as_ref().borrow().right;
            }
        }
    }
    root
}

fn main() {
    fn create_node(value: i32) -> Option<Rc<RefCell<TreeNode>>> {
        Some(Rc::new(RefCell::new(TreeNode::new(value))))
    }

    fn add_left(
        parent: &Option<Rc<RefCell<TreeNode>>>,
        value: i32,
    ) -> Option<Rc<RefCell<TreeNode>>> {
        parent.as_ref().unwrap().as_ref().borrow_mut().left = create_node(value);
        parent.as_ref().unwrap().as_ref().borrow().left.clone()
    }

    fn add_right(
        parent: &Option<Rc<RefCell<TreeNode>>>,
        value: i32,
    ) -> Option<Rc<RefCell<TreeNode>>> {
        parent.as_ref().unwrap().as_ref().borrow_mut().right = create_node(value);
        parent.as_ref().unwrap().as_ref().borrow().right.clone()
    }

    fn to_tree(nodes: Vec<i32>) -> Option<Rc<RefCell<TreeNode>>> {
        let mut deque: VecDeque<Option<Rc<RefCell<TreeNode>>>> = VecDeque::new();
        let mut root: Option<Rc<RefCell<TreeNode>>> = None;
        deque.push_back(create_node(nodes[0]));
        let mut i = 1;
        while i < nodes.len() {
            let parent = deque.pop_front().unwrap();
            deque.push_back(add_left(&parent, nodes[i]));
            deque.push_back(add_right(&parent, nodes[i + 1]));
            i += 2;
            if root == None {
                root = parent;
            }
        }
        root
    }

    let root = to_tree(vec![2, 3, 5, 8, 13, 21, 34]);
    println!("{:?}", reverse_odd_levels(root)); // [2,5,3,8,13,21,34]

    let root = to_tree(vec![7, 13, 11]);
    println!("{:?}", reverse_odd_levels(root)); // [7,11,13]

    let root = to_tree(vec![0, 1, 2, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2]);
    println!("{:?}", reverse_odd_levels(root)); // [0,2,1,0,0,0,0,2,2,2,2,1,1,1,1]

    let root = to_tree(vec![0, 1, 2, 0, 0, 0, 0, 6, 7, 8, 9, 1, 2, 3, 4]);
    println!("{:?}", reverse_odd_levels(root)); // [0,2,1,0,0,0,0,4,3,2,1,9,8,7,6]
}
<|endoftext|>


<commit_before>use std::env;
use std::ffi::OsStr;
use std::path::PathBuf;
use std::process::Command;

use flate2::read::GzDecoder;
use tar::Archive;

fn main() {
	// TODO: Replace with is_some_with once stabilized
	// https://github.com/rust-lang/rust/issues/93050
	let targets_hermit =
		matches!(env::var_os("CARGO_CFG_TARGET_OS"), Some(os) if os == OsStr::new("hermit"));
	let runs_clippy =
		matches!(env::var_os("CARGO_CFG_FEATURE"), Some(os) if os == OsStr::new("cargo-clippy"));
	if !targets_hermit || runs_clippy {
		return;
	}

	let kernel_src = KernelSrc::local().unwrap_or_else(KernelSrc::download);

	kernel_src.build();
}

struct KernelSrc {
	src_dir: PathBuf,
}

impl KernelSrc {
	fn local() -> Option<Self> {
		let mut src_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
		src_dir.set_file_name("libhermit-rs");
		src_dir.exists().then(|| Self { src_dir })
	}

	fn download() -> Self {
		let version = "0.3.54";
		let out_dir = out_dir();
		let src_dir = out_dir.join(format!("libhermit-rs-{version}"));

		if !src_dir.exists() {
			let url = format!(
				"https://github.com/hermitcore/libhermit-rs/archive/refs/tags/v{version}.tar.gz"
			);
			let response = ureq::get(url.as_str()).call().unwrap().into_reader();
			let tar = GzDecoder::new(response);
			let mut archive = Archive::new(tar);
			archive.unpack(src_dir.parent().unwrap()).unwrap();
		}

		Self { src_dir }
	}

	fn build(self) {
		let target_dir = target_dir();
		let manifest_path = self.src_dir.join("Cargo.toml");
		assert!(
			manifest_path.exists(),
			"kernel manifest path `{}` does not exist",
			manifest_path.display()
		);
		let arch = env::var_os("CARGO_CFG_TARGET_ARCH").unwrap();
		let profile = env::var("PROFILE").expect("PROFILE was not set");

		let mut cmd = Command::new("cargo");

		// Remove rust-toolchain-specific environment variables from kernel cargo
		cmd.env_remove("LD_LIBRARY_PATH");
		env::vars()
			.filter(|(key, _value)| key.starts_with("CARGO") || key.starts_with("RUST"))
			.for_each(|(key, _value)| {
				cmd.env_remove(&key);
			});

		cmd.current_dir(&self.src_dir)
			.arg("run")
			.arg("--package=xtask")
			.arg("--target-dir")
			.arg(&target_dir)
			.arg("--")
			.arg("build")
			.arg("--arch")
			.arg(&arch)
			.args(&[
				"--profile",
				match profile.as_str() {
					"debug" => "dev",
					profile => profile,
				},
			])
			.arg("--target-dir")
			.arg(&target_dir);

		if has_feature("instrument") {
			cmd.arg("--instrument-mcount");
		}

		// Control enabled features via this crate's features
		cmd.arg("--no-default-features");
		forward_features(
			&mut cmd,
			["acpi", "fsgsbase", "pci", "pci-ids", "smp", "vga"].into_iter(),
		);

		let status = cmd.status().expect("failed to start kernel build");
		assert!(status.success());

		let lib_location = target_dir
			.join(&arch)
			.join(&profile)
			.canonicalize()
			.unwrap();

		println!("cargo:rustc-link-search=native={}", lib_location.display());
		println!("cargo:rustc-link-lib=static=hermit");

		println!("cargo:rerun-if-changed={}", self.src_dir.display());
		// HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time
		println!("cargo:rerun-if-env-changed=HERMIT_LOG_LEVEL_FILTER");
	}
}

fn out_dir() -> PathBuf {
	env::var_os("OUT_DIR").unwrap().into()
}

fn target_dir() -> PathBuf {
	let mut target_dir = out_dir();
	target_dir.push("target");
	target_dir
}

fn has_feature(feature: &str) -> bool {
	let mut var = "CARGO_FEATURE_".to_string();

	var.extend(feature.chars().map(|c| match c {
		'-' => '_',
		c => c.to_ascii_uppercase(),
	}));

	env::var_os(&var).is_some()
}

fn forward_features<'a>(cmd: &mut Command, features: impl Iterator<Item = &'a str>) {
	let features = features.filter(|f| has_feature(f)).collect::<Vec<_>>();
	if !features.is_empty() {
		cmd.args(&["--features", &features.join(" ")]);
	}
}
<commit_msg>build.rs: Don't build kernel on docs.rs<commit_after>use std::env;
use std::ffi::OsStr;
use std::path::PathBuf;
use std::process::Command;

use flate2::read::GzDecoder;
use tar::Archive;

fn main() {
	// TODO: Replace with is_some_with once stabilized
	// https://github.com/rust-lang/rust/issues/93050
	let targets_hermit =
		matches!(env::var_os("CARGO_CFG_TARGET_OS"), Some(os) if os == OsStr::new("hermit"));
	let runs_clippy =
		matches!(env::var_os("CARGO_CFG_FEATURE"), Some(os) if os == OsStr::new("cargo-clippy"));
	let is_docs_rs = env::var_os("DOCS_RS").is_some();
	if !targets_hermit || runs_clippy || is_docs_rs {
		return;
	}

	let kernel_src = KernelSrc::local().unwrap_or_else(KernelSrc::download);

	kernel_src.build();
}

struct KernelSrc {
	src_dir: PathBuf,
}

impl KernelSrc {
	fn local() -> Option<Self> {
		let mut src_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
		src_dir.set_file_name("libhermit-rs");
		src_dir.exists().then(|| Self { src_dir })
	}

	fn download() -> Self {
		let version = "0.3.54";
		let out_dir = out_dir();
		let src_dir = out_dir.join(format!("libhermit-rs-{version}"));

		if !src_dir.exists() {
			let url = format!(
				"https://github.com/hermitcore/libhermit-rs/archive/refs/tags/v{version}.tar.gz"
			);
			let response = ureq::get(url.as_str()).call().unwrap().into_reader();
			let tar = GzDecoder::new(response);
			let mut archive = Archive::new(tar);
			archive.unpack(src_dir.parent().unwrap()).unwrap();
		}

		Self { src_dir }
	}

	fn build(self) {
		let target_dir = target_dir();
		let manifest_path = self.src_dir.join("Cargo.toml");
		assert!(
			manifest_path.exists(),
			"kernel manifest path `{}` does not exist",
			manifest_path.display()
		);
		let arch = env::var_os("CARGO_CFG_TARGET_ARCH").unwrap();
		let profile = env::var("PROFILE").expect("PROFILE was not set");

		let mut cmd = Command::new("cargo");

		// Remove rust-toolchain-specific environment variables from kernel cargo
		cmd.env_remove("LD_LIBRARY_PATH");
		env::vars()
			.filter(|(key, _value)| key.starts_with("CARGO") || key.starts_with("RUST"))
			.for_each(|(key, _value)| {
				cmd.env_remove(&key);
			});

		cmd.current_dir(&self.src_dir)
			.arg("run")
			.arg("--package=xtask")
			.arg("--target-dir")
			.arg(&target_dir)
			.arg("--")
			.arg("build")
			.arg("--arch")
			.arg(&arch)
			.args(&[
				"--profile",
				match profile.as_str() {
					"debug" => "dev",
					profile => profile,
				},
			])
			.arg("--target-dir")
			.arg(&target_dir);

		if has_feature("instrument") {
			cmd.arg("--instrument-mcount");
		}

		// Control enabled features via this crate's features
		cmd.arg("--no-default-features");
		forward_features(
			&mut cmd,
			["acpi", "fsgsbase", "pci", "pci-ids", "smp", "vga"].into_iter(),
		);

		let status = cmd.status().expect("failed to start kernel build");
		assert!(status.success());

		let lib_location = target_dir
			.join(&arch)
			.join(&profile)
			.canonicalize()
			.unwrap();

		println!("cargo:rustc-link-search=native={}", lib_location.display());
		println!("cargo:rustc-link-lib=static=hermit");

		println!("cargo:rerun-if-changed={}", self.src_dir.display());
		// HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time
		println!("cargo:rerun-if-env-changed=HERMIT_LOG_LEVEL_FILTER");
	}
}

fn out_dir() -> PathBuf {
	env::var_os("OUT_DIR").unwrap().into()
}

fn target_dir() -> PathBuf {
	let mut target_dir = out_dir();
	target_dir.push("target");
	target_dir
}

fn has_feature(feature: &str) -> bool {
	let mut var = "CARGO_FEATURE_".to_string();

	var.extend(feature.chars().map(|c| match c {
		'-' => '_',
		c => c.to_ascii_uppercase(),
	}));

	env::var_os(&var).is_some()
}

fn forward_features<'a>(cmd: &mut Command, features: impl Iterator<Item = &'a str>) {
	let features = features.filter(|f| has_feature(f)).collect::<Vec<_>>();
	if !features.is_empty() {
		cmd.args(&["--features", &features.join(" ")]);
	}
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate petgraph;
extern crate test;

use test::Bencher;

#[allow(dead_code)]
mod common;
use common::*;

use petgraph::algo::is_isomorphic;

#[bench]
fn petersen_iso_bench(bench: &mut Bencher) {
    let a = digraph().petersen_a();
    let b = digraph().petersen_b();

    bench.iter(|| is_isomorphic(&a, &b));
}

#[bench]
fn petersen_undir_iso_bench(bench: &mut Bencher) {
    let a = ungraph().petersen_a();
    let b = ungraph().petersen_b();

    bench.iter(|| is_isomorphic(&a, &b));
}

#[bench]
fn full_iso_bench(bench: &mut Bencher) {
    let a = ungraph().full_a();
    let b = ungraph().full_b();

    bench.iter(|| is_isomorphic(&a, &b));
}

#[bench]
fn praust_dir_no_iso_bench(bench: &mut Bencher) {
    let a = digraph().praust_a();
    let b = digraph().praust_b();

    bench.iter(|| is_isomorphic(&a, &b));
}

#[bench]
fn praust_undir_no_iso_bench(bench: &mut Bencher) {
    let a = ungraph().praust_a();
    let b = ungraph().praust_b();

    bench.iter(|| is_isomorphic(&a, &b));
}
<commit_msg>Add assertions to `benches/iso.rs` to check for correctness<commit_after>#![feature(test)]

extern crate petgraph;
extern crate test;

use test::Bencher;

#[allow(dead_code)]
mod common;
use common::*;

use petgraph::algo::is_isomorphic;

#[bench]
fn petersen_iso_bench(bench: &mut Bencher) {
    let a = digraph().petersen_a();
    let b = digraph().petersen_b();

    bench.iter(|| is_isomorphic(&a, &b));
    assert!(is_isomorphic(&a, &b));
}

#[bench]
fn petersen_undir_iso_bench(bench: &mut Bencher) {
    let a = ungraph().petersen_a();
    let b = ungraph().petersen_b();

    bench.iter(|| is_isomorphic(&a, &b));
    assert!(is_isomorphic(&a, &b));
}

#[bench]
fn full_iso_bench(bench: &mut Bencher) {
    let a = ungraph().full_a();
    let b = ungraph().full_b();

    bench.iter(|| is_isomorphic(&a, &b));
    assert!(is_isomorphic(&a, &b));
}

#[bench]
fn praust_dir_no_iso_bench(bench: &mut Bencher) {
    let a = digraph().praust_a();
    let b = digraph().praust_b();

    bench.iter(|| is_isomorphic(&a, &b));
    assert!(!is_isomorphic(&a, &b));
}

#[bench]
fn praust_undir_no_iso_bench(bench: &mut Bencher) {
    let a = ungraph().praust_a();
    let b = ungraph().praust_b();

    bench.iter(|| is_isomorphic(&a, &b));
    assert!(!is_isomorphic(&a, &b));
}
<|endoftext|>


<commit_before>#![feature(test)]
extern crate test;

use std::collections::VecDeque;

#[macro_use]
extern crate sliding_window;
use sliding_window::SliceRing;
use sliding_window::OptimizedSliceRing;
use sliding_window::SlidingWindow;

#[bench]
fn bench_empty_to_probe_for_release_mode(b: &mut test::Bencher) {
    b.iter(|| 1)
}

macro_rules! bench_push_many_back {
    ($bencher:expr, $new:expr) => {{
        let vec = (0..1000).collect::<Vec<i32>>();
        $bencher.iter(|| {
            let mut testable = $new;
            testable.push_many_back(&vec[..]);
            testable
        });
    }}
}
#[bench]
fn bench_push_many_back_unoptimized(b: &mut test::Bencher) {
    bench_push_many_back!(b, VecDeque::new());
}
#[bench]
fn bench_push_many_back_optimized(b: &mut test::Bencher) {
    bench_push_many_back!(b, OptimizedSliceRing::new());
}

macro_rules! bench_push_many_back_drop_many_front {
    ($bencher:expr, $new:expr) => {{
        let vec = (0..1000).collect::<Vec<i32>>();
        $bencher.iter(|| {
            let mut testable = $new;
            testable.push_many_back(&vec[..]);
            testable.drop_many_front(1000)
        });
    }}
}

#[bench]
fn bench_push_many_back_drop_many_front_unoptimized(b: &mut test::Bencher) {
    bench_push_many_back!(b, VecDeque::new());
}
#[bench]
fn bench_push_many_back_drop_many_front_optimized(b: &mut test::Bencher) {
    bench_push_many_back!(b, OptimizedSliceRing::new());
}

macro_rules! bench_read_many_front {
    ($bencher:expr, $new:expr) => {{
        let mut output: Vec<i32> = std::iter::repeat(0).take(1000).collect();
        let vec = (0..1000).collect::<Vec<i32>>();
        let mut testable = $new;
        testable.push_many_back(&vec[..]);
        $bencher.iter(|| {
            testable.read_many_front(&mut output[..])
        });
    }}
}
#[bench]
fn bench_read_many_front_unoptimized(b: &mut test::Bencher) {
    bench_read_many_front!(b, VecDeque::new());
}
#[bench]
fn bench_read_many_front_optimized(b: &mut test::Bencher) {
    bench_read_many_front!(b, OptimizedSliceRing::new());
}

#[bench]
fn bench_test_slice_ring_unoptimized(b: &mut test::Bencher) {
    b.iter(|| {
        test_slice_ring!(VecDeque::<i32>::new());
    });
}
#[bench]
fn bench_test_slice_ring_optimized(b: &mut test::Bencher) {
    b.iter(|| {
        test_slice_ring!(OptimizedSliceRing::<i32>::new())
    });
}

#[bench]
fn bench_test_sliding_window_unoptimized(b: &mut test::Bencher) {
    b.iter(|| {
    // TODO this type declaration is soo ugly
        test_sliding_window!(SlidingWindow::<i32, VecDeque<i32>>::new_unoptimized(
            4096, 512));
    });
}
#[bench]
fn bench_test_sliding_window_optimized(b: &mut test::Bencher) {
    b.iter(|| {
        // TODO this type declaration is soo ugly
        test_sliding_window!(SlidingWindow::<i32, OptimizedSliceRing<i32>>::new(
            4096, 512));
    });
}
<commit_msg>benchmark with_capacity to remove allocations overhead from benchmark<commit_after>#![feature(test)]
extern crate test;

use std::collections::VecDeque;

#[macro_use]
extern crate sliding_window;
use sliding_window::SliceRing;
use sliding_window::OptimizedSliceRing;
use sliding_window::SlidingWindow;

#[bench]
fn bench_empty_to_probe_for_release_mode(b: &mut test::Bencher) {
    b.iter(|| 1)
}

macro_rules! bench_push_many_back {
    ($bencher:expr, $new:expr) => {{
        let vec = (0..1000).collect::<Vec<i32>>();
        $bencher.iter(|| {
            let mut testable = $new;
            testable.push_many_back(&vec[..]);
            testable
        });
    }}
}
#[bench]
fn bench_push_many_back_deque(b: &mut test::Bencher) {
    bench_push_many_back!(b, VecDeque::new());
}
#[bench]
fn bench_push_many_back_deque_with_capacity(b: &mut test::Bencher) {
    bench_push_many_back!(b, VecDeque::with_capacity(1000));
}
#[bench]
fn bench_push_many_back_optimized(b: &mut test::Bencher) {
    bench_push_many_back!(b, OptimizedSliceRing::new());
}
#[bench]
fn bench_push_many_back_optimized_with_capacity(b: &mut test::Bencher) {
    bench_push_many_back!(b, OptimizedSliceRing::with_capacity(1000));
}

macro_rules! bench_drop_many_front {
    ($bencher:expr, $new:expr) => {{
        let vec = (0..1000).collect::<Vec<i32>>();
        $bencher.iter(|| {
            let mut testable = $new;
            testable.push_many_back(&vec[..]);
            testable.drop_many_front(1000)
        });
    }}
}

#[bench]
fn bench_drop_many_front_deque(b: &mut test::Bencher) {
    bench_drop_many_front!(b, VecDeque::new());
}
#[bench]
fn bench_drop_many_front_deque_with_capacity(b: &mut test::Bencher) {
    bench_drop_many_front!(b, VecDeque::with_capacity(1000));
}
#[bench]
fn bench_drop_many_front_optimized(b: &mut test::Bencher) {
    bench_drop_many_front!(b, OptimizedSliceRing::new());
}
#[bench]
fn bench_drop_many_front_optimized_with_capacity(b: &mut test::Bencher) {
    bench_drop_many_front!(b, OptimizedSliceRing::with_capacity(1000));
}

macro_rules! bench_read_many_front {
    ($bencher:expr, $new:expr) => {{
        let mut output: Vec<i32> = std::iter::repeat(0).take(1000).collect();
        let vec = (0..1000).collect::<Vec<i32>>();
        let mut testable = $new;
        testable.push_many_back(&vec[..]);
        $bencher.iter(|| {
            testable.read_many_front(&mut output[..])
        });
    }}
}
#[bench]
fn bench_read_many_front_deque(b: &mut test::Bencher) {
    bench_read_many_front!(b, VecDeque::new());
}
#[bench]
fn bench_read_many_front_deque_with_capacity(b: &mut test::Bencher) {
    bench_read_many_front!(b, VecDeque::with_capacity(1000));
}
#[bench]
fn bench_read_many_front_optimized(b: &mut test::Bencher) {
    bench_read_many_front!(b, OptimizedSliceRing::new());
}
#[bench]
fn bench_read_many_front_optimized_with_capacity(b: &mut test::Bencher) {
    bench_read_many_front!(b, OptimizedSliceRing::with_capacity(1000));
}

#[bench]
fn bench_test_slice_ring_deque(b: &mut test::Bencher) {
    b.iter(|| {
        test_slice_ring!(VecDeque::<i32>::new());
    });
}
#[bench]
fn bench_test_slice_ring_optimized(b: &mut test::Bencher) {
    b.iter(|| {
        test_slice_ring!(OptimizedSliceRing::<i32>::new())
    });
}
#[macro_export]
macro_rules! bench_slice_ring_windowing {
    ($new:expr) => {{
        let window_size = 4096;
        let step_size = 512;
        let mut testable = $new;
        let input: Vec<i32> = std::iter::repeat(0).take(6000).collect();
        let mut output: Vec<i32> = std::iter::repeat(0).take(window_size).collect();
        for _ in 0..100 {
            testable.push_many_back(&input[..]);
            while testable.len() >= window_size {
                testable.read_many_front(&mut output[..]);
                testable.drop_many_front(step_size);
            }
        }
        testable
    }};
}
#[bench]
fn bench_slice_ring_windowing_deque(b: &mut test::Bencher) {
    b.iter(|| {
        bench_slice_ring_windowing!(VecDeque::<i32>::new());
    });
}
#[bench]
fn bench_slice_ring_windowing_optimized(b: &mut test::Bencher) {
    b.iter(|| {
        bench_slice_ring_windowing!(OptimizedSliceRing::<i32>::new())
    });
}

#[bench]
fn bench_test_sliding_window_deque(b: &mut test::Bencher) {
    b.iter(|| {
    // TODO this type declaration is soo ugly
        test_sliding_window!(SlidingWindow::<i32, VecDeque<i32>>::new_unoptimized(
            4096, 512));
    });
}
#[bench]
fn bench_test_sliding_window_optimized(b: &mut test::Bencher) {
    b.iter(|| {
        // TODO this type declaration is soo ugly
        test_sliding_window!(SlidingWindow::<i32, OptimizedSliceRing<i32>>::new(
            4096, 512));
    });
}
<|endoftext|>


<commit_before>extern crate cairo;

#[derive(Debug)]
#[derive(PartialEq)]
pub enum Segment {
    Degenerate {            // A single lone point
        x: f64,
        y: f64
    },

    LineOrCurve {
        x1: f64, y1: f64,
        x2: f64, y2: f64,
        x3: f64, y3: f64,
        x4: f64, y4: f64
    },
}

enum SegmentState {
    Initial,
    NewSubpath,
    InSubpath,
    ClosedSubpath
}

/* This converts a cairo_path_t into a list of curveto-like segments.  Each segment can be:
 *
 * 1. Segment::Degenerate => the segment is actually a single point (x, y)
 *
 * 2. Segment::LineOrCurve => either a lineto or a curveto (or the effective lineto that results from a closepath).
 *    We have the following points:
 *       P1 = (x1, y1)
 *       P2 = (x2, y2)
 *       P3 = (x3, y3)
 *       P4 = (x4, y4)
 *
 *    The start and end points are P1 and P4, respectively.
 *    The tangent at the start point is given by the vector (P2 - P1).
 *    The tangent at the end point is given by the vector (P4 - P3).
 *    The tangents also work if the segment refers to a lineto (they will both just point in the same direction).
 */

const EPSILON: f64 = 1e-10;

fn double_equals (a: f64, b: f64) -> bool {
    (a - b).abs () < EPSILON
}

fn make_degenerate (x: f64, y: f64) -> Segment {
    Segment::Degenerate { x: x, y: y}
}

fn make_curve (x1: f64, y1: f64,
               mut x2: f64, mut y2: f64,
               mut x3: f64, mut y3: f64,
               x4: f64, y4: f64) -> Segment {
    /* Fix the tangents for when the middle control points coincide with their respective endpoints */

    if double_equals (x2, x1) && double_equals (y2, y1) {
        x2 = x3;
        y2 = y3;
    }

    if double_equals (x3, x4) && double_equals (y3, y4) {
        x3 = x2;
        y3 = y2;
    }

    Segment::LineOrCurve {
        x1: x1, y1: y1,
        x2: x2, y2: y2,
        x3: x3, y3: y3,
        x4: x4, y4: y4
    }
}

fn make_line (x1: f64, y1: f64, x2: f64, y2: f64) -> Segment {
    make_curve (x1, y1, x2, y2, x1, y1, x2, y2)
}

pub fn path_to_segments (path: cairo::Path) -> Vec<Segment> {
    let mut last_x: f64;
    let mut last_y: f64;
    let mut cur_x: f64;
    let mut cur_y: f64;
    let mut subpath_start_x: f64;
    let mut subpath_start_y: f64;
    let mut segments: Vec<Segment>;
    let mut state: SegmentState;

    cur_x = 0.0;
    cur_y = 0.0;
    subpath_start_x = 0.0;
    subpath_start_y = 0.0;

    segments = Vec::new ();
    state = SegmentState::Initial;

    for cairo_segment in path.iter () {
        last_x = cur_x;
        last_y = cur_y;

        let seg: Segment;

        match cairo_segment {
            cairo::PathSegment::MoveTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                subpath_start_x = cur_x;
                subpath_start_y = cur_y;

                match state {
                    SegmentState::Initial |
                    SegmentState::InSubpath => {
                        /* Ignore the very first moveto in a sequence (Initial state), or if we were
                         * already drawing within a subpath, start a new subpath.
                         */
                        state = SegmentState::NewSubpath;
                    },

                    SegmentState::NewSubpath => {
                        /* We had just begun a new subpath (i.e. from a moveto) and we got another
                         * moveto?  Output a stray point for the previous moveto.
                         */
                        segments.push (make_degenerate (last_x, last_y));
                        state = SegmentState::NewSubpath;
                    }

                    SegmentState::ClosedSubpath => {
                        /* Cairo outputs a moveto after every closepath, so that subsequent
                         * lineto/curveto commands will start at the closed vertex.
                         *
                         * We don't want to actually emit a point (a degenerate segment) in that
                         * artificial-moveto case.
                         *
                         * We'll reset to the Initial state so that a subsequent "real" moveto will
                         * be handled as the beginning of a new subpath, or a degenerate point, as
                         * usual.
                         */
                        state = SegmentState::Initial;
                    }
                }
            },

            cairo::PathSegment::LineTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                seg = make_line (last_x, last_y, cur_x, cur_y);

                state = SegmentState::InSubpath;
                segments.push (seg);
            },

            cairo::PathSegment::CurveTo ((x2, y2), (x3, y3), (x4, y4)) => {
                cur_x = x4;
                cur_y = y4;

                seg = make_curve (last_x, last_y, x2, y2, x3, y3, cur_x, cur_y);

                state = SegmentState::InSubpath;
                segments.push (seg);
            },

            cairo::PathSegment::ClosePath => {
                cur_x = subpath_start_x;
                cur_y = subpath_start_y;

                seg = make_line (last_x, last_y, cur_x, cur_y);

                state = SegmentState::ClosedSubpath;
                segments.push (seg);
            }
        }
    }

    match state {
        SegmentState::NewSubpath => {
            /* Output a lone point if we started a subpath with a
             * moveto command, but there are no subsequent commands.
             */
            let seg = make_degenerate (cur_x, cur_y);
            segments.push (seg);
        },

        _ => {
        }
    }

    segments
}

#[cfg(test)]
mod tests {
    use super::*;
    extern crate cairo;

    fn create_cr () -> cairo::Context {
        let surf = cairo::ImageSurface::create (cairo::Format::Rgb24, 1, 1);
        let cr = cairo::Context::new (&surf);

        cr
    }

    fn degenerate (x: f64, y: f64) -> Segment {
        Segment::Degenerate { x: x, y: y }
    }

    fn curve (x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64, x4: f64, y4: f64) -> Segment {
        Segment::LineOrCurve {
            x1: x1, y1: y1, x2: x2, y2: y2, x3: x3, y3: y3, x4: x4, y4: y4
        }
    }

    fn line (x1: f64, y1: f64, x2: f64, y2: f64) -> Segment {
        curve (x1, y1, x2, y2, x1, y1, x2, y2)
    }

    fn test_path_to_segments (path: cairo::Path, expected_segments: Vec<Segment>) {
        let segments = path_to_segments (path);
        assert_eq! (expected_segments, segments);
    }

    /* Single open path; the easy case */

    fn setup_open_path () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);

        cr.copy_path ()
    }

    #[test]
    fn path_to_segments_handles_open_path () {
        let expected_segments: Vec<Segment> = vec![
            line (10.0, 10.0, 20.0, 10.0),
            line (20.0, 10.0, 20.0, 20.0)
        ];

        test_path_to_segments (setup_open_path(), expected_segments);
    }

    /* Multiple open subpaths */

    fn setup_multiple_open_subpaths () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);

        cr.move_to (30.0, 30.0);
        cr.line_to (40.0, 30.0);
        cr.curve_to (50.0, 35.0, 60.0, 60.0, 70.0, 70.0);
        cr.line_to (80.0, 90.0);

        cr.copy_path ()
    }

    #[test]
    fn path_to_segments_handles_multiple_open_subpaths () {
        let expected_segments: Vec<Segment> = vec![
            line  (10.0, 10.0, 20.0, 10.0),
            line  (20.0, 10.0, 20.0, 20.0),

            line  (30.0, 30.0, 40.0, 30.0),
            curve (40.0, 30.0, 50.0, 35.0, 60.0, 60.0, 70.0, 70.0),
            line  (70.0, 70.0, 80.0, 90.0)
        ];

        test_path_to_segments (setup_multiple_open_subpaths (), expected_segments);
    }

    /* Closed subpath; must have a line segment back to the first point */

    fn setup_closed_subpath () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);
        cr.close_path ();

        cr.copy_path ()
    }

    #[test]
    fn path_to_segments_handles_closed_subpath () {
        let expected_segments: Vec<Segment> = vec![
            line (10.0, 10.0, 20.0, 10.0),
            line (20.0, 10.0, 20.0, 20.0),
            line (20.0, 20.0, 10.0, 10.0)
        ];

        test_path_to_segments (setup_closed_subpath (), expected_segments);
    }

    /* Multiple closed subpaths; each must have a line segment back to their
     * initial points, with no degenerate segments between subpaths.
     */

    fn setup_multiple_closed_subpaths () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);
        cr.close_path ();

        cr.move_to (30.0, 30.0);
        cr.line_to (40.0, 30.0);
        cr.curve_to (50.0, 35.0, 60.0, 60.0, 70.0, 70.0);
        cr.line_to (80.0, 90.0);
        cr.close_path ();

        cr.copy_path ()
    }

    #[test]
    fn path_to_segments_handles_multiple_closed_subpaths () {
        let expected_segments: Vec<Segment> = vec![
            line  (10.0, 10.0, 20.0, 10.0),
            line  (20.0, 10.0, 20.0, 20.0),
            line  (20.0, 20.0, 10.0, 10.0),

            line  (30.0, 30.0, 40.0, 30.0),
            curve (40.0, 30.0, 50.0, 35.0, 60.0, 60.0, 70.0, 70.0),
            line  (70.0, 70.0, 80.0, 90.0),
            line  (80.0, 90.0, 30.0, 30.0)
        ];

        test_path_to_segments (setup_multiple_closed_subpaths (), expected_segments);
    }

    /* A lineto follows the first closed subpath, with no moveto to start the second subpath.  The
     * lineto must start at the first point of the first subpath.
     */

    fn setup_no_moveto_after_closepath () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);
        cr.close_path ();

        cr.line_to (40.0, 30.0);

        cr.copy_path ()
    }

    #[test]
    fn path_to_segments_handles_no_moveto_after_closepath () {
        let expected_segments: Vec<Segment> = vec![
            line  (10.0, 10.0, 20.0, 10.0),
            line  (20.0, 10.0, 20.0, 20.0),
            line  (20.0, 20.0, 10.0, 10.0),

            line  (10.0, 10.0, 40.0, 30.0)
        ];

        test_path_to_segments (setup_no_moveto_after_closepath (), expected_segments);
    }

    /* Sequence of moveto; should generate degenerate points.
     *
     * This test is not enabled right now!  We create the
     * path fixtures with Cairo, and Cairo compresses
     * sequences of moveto into a single one.  So, we can't
     * really test this, as we don't get the fixture we want.
     *
     * Eventually we'll probably have to switch librsvg to
     * its own internal path representation which should
     * allow for unelided path commands, and which should
     * only build a cairo_path_t for the final rendering step.

    fn setup_sequence_of_moveto () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.move_to (20.0, 20.0);
        cr.move_to (30.0, 30.0);
        cr.move_to (40.0, 40.0);

        let path = cr.copy_path ();
        path
    }

    #[test]
    fn path_to_segments_handles_sequence_of_moveto () {
        let expected_segments: Vec<Segment> = vec! [
            degenerate (10.0, 10.0),
            degenerate (20.0, 20.0),
            degenerate (30.0, 30.0),
            degenerate (40.0, 40.0)
        ];

        test_path_to_segments (setup_sequence_of_moveto (), expected_segments);
    }
     */
}
<commit_msg>marker.rs: Create segments without an auxiliary variable<commit_after>extern crate cairo;

#[derive(Debug)]
#[derive(PartialEq)]
pub enum Segment {
    Degenerate {            // A single lone point
        x: f64,
        y: f64
    },

    LineOrCurve {
        x1: f64, y1: f64,
        x2: f64, y2: f64,
        x3: f64, y3: f64,
        x4: f64, y4: f64
    },
}

enum SegmentState {
    Initial,
    NewSubpath,
    InSubpath,
    ClosedSubpath
}

/* This converts a cairo_path_t into a list of curveto-like segments.  Each segment can be:
 *
 * 1. Segment::Degenerate => the segment is actually a single point (x, y)
 *
 * 2. Segment::LineOrCurve => either a lineto or a curveto (or the effective lineto that results from a closepath).
 *    We have the following points:
 *       P1 = (x1, y1)
 *       P2 = (x2, y2)
 *       P3 = (x3, y3)
 *       P4 = (x4, y4)
 *
 *    The start and end points are P1 and P4, respectively.
 *    The tangent at the start point is given by the vector (P2 - P1).
 *    The tangent at the end point is given by the vector (P4 - P3).
 *    The tangents also work if the segment refers to a lineto (they will both just point in the same direction).
 */

const EPSILON: f64 = 1e-10;

fn double_equals (a: f64, b: f64) -> bool {
    (a - b).abs () < EPSILON
}

fn make_degenerate (x: f64, y: f64) -> Segment {
    Segment::Degenerate { x: x, y: y}
}

fn make_curve (x1: f64, y1: f64,
               mut x2: f64, mut y2: f64,
               mut x3: f64, mut y3: f64,
               x4: f64, y4: f64) -> Segment {
    /* Fix the tangents for when the middle control points coincide with their respective endpoints */

    if double_equals (x2, x1) && double_equals (y2, y1) {
        x2 = x3;
        y2 = y3;
    }

    if double_equals (x3, x4) && double_equals (y3, y4) {
        x3 = x2;
        y3 = y2;
    }

    Segment::LineOrCurve {
        x1: x1, y1: y1,
        x2: x2, y2: y2,
        x3: x3, y3: y3,
        x4: x4, y4: y4
    }
}

fn make_line (x1: f64, y1: f64, x2: f64, y2: f64) -> Segment {
    make_curve (x1, y1, x2, y2, x1, y1, x2, y2)
}

pub fn path_to_segments (path: cairo::Path) -> Vec<Segment> {
    let mut last_x: f64;
    let mut last_y: f64;
    let mut cur_x: f64;
    let mut cur_y: f64;
    let mut subpath_start_x: f64;
    let mut subpath_start_y: f64;
    let mut segments: Vec<Segment>;
    let mut state: SegmentState;

    cur_x = 0.0;
    cur_y = 0.0;
    subpath_start_x = 0.0;
    subpath_start_y = 0.0;

    segments = Vec::new ();
    state = SegmentState::Initial;

    for cairo_segment in path.iter () {
        last_x = cur_x;
        last_y = cur_y;

        match cairo_segment {
            cairo::PathSegment::MoveTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                subpath_start_x = cur_x;
                subpath_start_y = cur_y;

                match state {
                    SegmentState::Initial |
                    SegmentState::InSubpath => {
                        /* Ignore the very first moveto in a sequence (Initial state), or if we were
                         * already drawing within a subpath, start a new subpath.
                         */
                        state = SegmentState::NewSubpath;
                    },

                    SegmentState::NewSubpath => {
                        /* We had just begun a new subpath (i.e. from a moveto) and we got another
                         * moveto?  Output a stray point for the previous moveto.
                         */
                        segments.push (make_degenerate (last_x, last_y));
                        state = SegmentState::NewSubpath;
                    }

                    SegmentState::ClosedSubpath => {
                        /* Cairo outputs a moveto after every closepath, so that subsequent
                         * lineto/curveto commands will start at the closed vertex.
                         *
                         * We don't want to actually emit a point (a degenerate segment) in that
                         * artificial-moveto case.
                         *
                         * We'll reset to the Initial state so that a subsequent "real" moveto will
                         * be handled as the beginning of a new subpath, or a degenerate point, as
                         * usual.
                         */
                        state = SegmentState::Initial;
                    }
                }
            },

            cairo::PathSegment::LineTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                segments.push (make_line (last_x, last_y, cur_x, cur_y));

                state = SegmentState::InSubpath;
            },

            cairo::PathSegment::CurveTo ((x2, y2), (x3, y3), (x4, y4)) => {
                cur_x = x4;
                cur_y = y4;

                segments.push (make_curve (last_x, last_y, x2, y2, x3, y3, cur_x, cur_y));

                state = SegmentState::InSubpath;
            },

            cairo::PathSegment::ClosePath => {
                cur_x = subpath_start_x;
                cur_y = subpath_start_y;

                segments.push (make_line (last_x, last_y, cur_x, cur_y));

                state = SegmentState::ClosedSubpath;
            }
        }
    }

    match state {
        SegmentState::NewSubpath => {
            /* Output a lone point if we started a subpath with a
             * moveto command, but there are no subsequent commands.
             */
            segments.push (make_degenerate (cur_x, cur_y));
        },

        _ => {
        }
    }

    segments
}

#[cfg(test)]
mod tests {
    use super::*;
    extern crate cairo;

    fn create_cr () -> cairo::Context {
        let surf = cairo::ImageSurface::create (cairo::Format::Rgb24, 1, 1);
        let cr = cairo::Context::new (&surf);

        cr
    }

    fn degenerate (x: f64, y: f64) -> Segment {
        Segment::Degenerate { x: x, y: y }
    }

    fn curve (x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64, x4: f64, y4: f64) -> Segment {
        Segment::LineOrCurve {
            x1: x1, y1: y1, x2: x2, y2: y2, x3: x3, y3: y3, x4: x4, y4: y4
        }
    }

    fn line (x1: f64, y1: f64, x2: f64, y2: f64) -> Segment {
        curve (x1, y1, x2, y2, x1, y1, x2, y2)
    }

    fn test_path_to_segments (path: cairo::Path, expected_segments: Vec<Segment>) {
        let segments = path_to_segments (path);
        assert_eq! (expected_segments, segments);
    }

    /* Single open path; the easy case */

    fn setup_open_path () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);

        cr.copy_path ()
    }

    #[test]
    fn path_to_segments_handles_open_path () {
        let expected_segments: Vec<Segment> = vec![
            line (10.0, 10.0, 20.0, 10.0),
            line (20.0, 10.0, 20.0, 20.0)
        ];

        test_path_to_segments (setup_open_path(), expected_segments);
    }

    /* Multiple open subpaths */

    fn setup_multiple_open_subpaths () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);

        cr.move_to (30.0, 30.0);
        cr.line_to (40.0, 30.0);
        cr.curve_to (50.0, 35.0, 60.0, 60.0, 70.0, 70.0);
        cr.line_to (80.0, 90.0);

        cr.copy_path ()
    }

    #[test]
    fn path_to_segments_handles_multiple_open_subpaths () {
        let expected_segments: Vec<Segment> = vec![
            line  (10.0, 10.0, 20.0, 10.0),
            line  (20.0, 10.0, 20.0, 20.0),

            line  (30.0, 30.0, 40.0, 30.0),
            curve (40.0, 30.0, 50.0, 35.0, 60.0, 60.0, 70.0, 70.0),
            line  (70.0, 70.0, 80.0, 90.0)
        ];

        test_path_to_segments (setup_multiple_open_subpaths (), expected_segments);
    }

    /* Closed subpath; must have a line segment back to the first point */

    fn setup_closed_subpath () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);
        cr.close_path ();

        cr.copy_path ()
    }

    #[test]
    fn path_to_segments_handles_closed_subpath () {
        let expected_segments: Vec<Segment> = vec![
            line (10.0, 10.0, 20.0, 10.0),
            line (20.0, 10.0, 20.0, 20.0),
            line (20.0, 20.0, 10.0, 10.0)
        ];

        test_path_to_segments (setup_closed_subpath (), expected_segments);
    }

    /* Multiple closed subpaths; each must have a line segment back to their
     * initial points, with no degenerate segments between subpaths.
     */

    fn setup_multiple_closed_subpaths () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);
        cr.close_path ();

        cr.move_to (30.0, 30.0);
        cr.line_to (40.0, 30.0);
        cr.curve_to (50.0, 35.0, 60.0, 60.0, 70.0, 70.0);
        cr.line_to (80.0, 90.0);
        cr.close_path ();

        cr.copy_path ()
    }

    #[test]
    fn path_to_segments_handles_multiple_closed_subpaths () {
        let expected_segments: Vec<Segment> = vec![
            line  (10.0, 10.0, 20.0, 10.0),
            line  (20.0, 10.0, 20.0, 20.0),
            line  (20.0, 20.0, 10.0, 10.0),

            line  (30.0, 30.0, 40.0, 30.0),
            curve (40.0, 30.0, 50.0, 35.0, 60.0, 60.0, 70.0, 70.0),
            line  (70.0, 70.0, 80.0, 90.0),
            line  (80.0, 90.0, 30.0, 30.0)
        ];

        test_path_to_segments (setup_multiple_closed_subpaths (), expected_segments);
    }

    /* A lineto follows the first closed subpath, with no moveto to start the second subpath.  The
     * lineto must start at the first point of the first subpath.
     */

    fn setup_no_moveto_after_closepath () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);
        cr.close_path ();

        cr.line_to (40.0, 30.0);

        cr.copy_path ()
    }

    #[test]
    fn path_to_segments_handles_no_moveto_after_closepath () {
        let expected_segments: Vec<Segment> = vec![
            line  (10.0, 10.0, 20.0, 10.0),
            line  (20.0, 10.0, 20.0, 20.0),
            line  (20.0, 20.0, 10.0, 10.0),

            line  (10.0, 10.0, 40.0, 30.0)
        ];

        test_path_to_segments (setup_no_moveto_after_closepath (), expected_segments);
    }

    /* Sequence of moveto; should generate degenerate points.
     *
     * This test is not enabled right now!  We create the
     * path fixtures with Cairo, and Cairo compresses
     * sequences of moveto into a single one.  So, we can't
     * really test this, as we don't get the fixture we want.
     *
     * Eventually we'll probably have to switch librsvg to
     * its own internal path representation which should
     * allow for unelided path commands, and which should
     * only build a cairo_path_t for the final rendering step.

    fn setup_sequence_of_moveto () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.move_to (20.0, 20.0);
        cr.move_to (30.0, 30.0);
        cr.move_to (40.0, 40.0);

        let path = cr.copy_path ();
        path
    }

    #[test]
    fn path_to_segments_handles_sequence_of_moveto () {
        let expected_segments: Vec<Segment> = vec! [
            degenerate (10.0, 10.0),
            degenerate (20.0, 20.0),
            degenerate (30.0, 30.0),
            degenerate (40.0, 40.0)
        ];

        test_path_to_segments (setup_sequence_of_moveto (), expected_segments);
    }
     */
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::ops::MulAssign;
use approx::ApproxEq;
use slab::Slab;
use alga::linear::Transformation;
use alga::linear::ProjectiveTransformation;
use na::{self, DVector, Dim, Dynamic, Real, U1, Unit, VectorSliceMutN};
use ncollide::query::ContactKinematic;
use ncollide::query::closest_points_internal;

use object::{BodyHandle, BodyPart, BodySet};
use joint::JointConstraint;
use solver::helper;
use solver::{ForceDirection, IntegrationParameters,
             MultibodyJointLimitsNonlinearConstraintGenerator, NonlinearConstraintGenerator,
             NonlinearUnilateralConstraint};
use math::{Isometry, Point, Rotation, Vector};

struct ContactGeometry<N: Real> {
    world1: Point<N>,
    world2: Point<N>,
    normal: Unit<Vector<N>>,
    depth: N,
}

impl<N: Real> ContactGeometry<N> {
    pub fn new(world1: Point<N>, world2: Point<N>, normal: Unit<Vector<N>>, depth: N) -> Self {
        ContactGeometry {
            world1,
            world2,
            normal,
            depth,
        }
    }
}

pub struct NonlinearSORProx<N: Real> {
    _phantom: PhantomData<N>,
}

impl<N: Real> NonlinearSORProx<N> {
    pub fn new() -> Self {
        NonlinearSORProx {
            _phantom: PhantomData,
        }
    }

    pub fn solve(
        &self,
        params: &IntegrationParameters<N>,
        bodies: &mut BodySet<N>,
        constraints: &mut [NonlinearUnilateralConstraint<N>],
        multibody_limits: &[MultibodyJointLimitsNonlinearConstraintGenerator],
        joints_constraints: &Slab<Box<JointConstraint<N>>>, // FIXME: ugly, use a slice of refs instead.
        jacobians: &mut [N],
        max_iter: usize,
    ) {
        for _ in 0..max_iter {
            for constraint in constraints.iter_mut() {
                // FIXME: specialize for SPATIAL_DIM.
                let dim1 = Dynamic::new(constraint.ndofs1);
                let dim2 = Dynamic::new(constraint.ndofs2);
                self.solve_unilateral(params, bodies, constraint, jacobians, dim1, dim2);
            }

            for generator in multibody_limits {
                self.solve_generic(params, bodies, generator, jacobians)
            }

            for joint in &*joints_constraints {
                self.solve_generic(params, bodies, &**joint.1, jacobians)
            }
        }
    }

    fn solve_generic<Gen: ?Sized + NonlinearConstraintGenerator<N>>(
        &self,
        params: &IntegrationParameters<N>,
        bodies: &mut BodySet<N>,
        generator: &Gen,
        jacobians: &mut [N],
    ) {
        let nconstraints = generator.num_position_constraints(bodies);

        for i in 0..nconstraints {
            if let Some(constraint) = generator.position_constraint(params, i, bodies, jacobians) {
                let dim1 = Dynamic::new(constraint.dim1);
                let dim2 = Dynamic::new(constraint.dim2);

                let rhs = if constraint.is_angular {
                    na::sup(
                        &((constraint.rhs + params.allowed_angular_error) * params.erp),
                        &(-params.max_angular_correction),
                    )
                } else {
                    na::sup(
                        &((constraint.rhs + params.allowed_linear_error) * params.erp),
                        &(-params.max_linear_correction),
                    )
                };

                if rhs < N::zero() {
                    let impulse = -rhs * constraint.r;

                    VectorSliceMutN::new_generic_mut(&mut jacobians[constraint.wj_id1..], dim1, U1)
                        .mul_assign(impulse);

                    VectorSliceMutN::new_generic_mut(&mut jacobians[constraint.wj_id2..], dim2, U1)
                        .mul_assign(impulse);

                    // FIXME: the body update should be performed lazily, especially because
                    // we dont actually need to update the kinematic of a multibody until
                    // we have to solve a contact involvoing one of its links.
                    bodies.body_mut(constraint.body1).apply_displacement(
                        &jacobians[constraint.wj_id1..constraint.wj_id1 + constraint.dim1],
                    );
                    bodies.body_mut(constraint.body2).apply_displacement(
                        &jacobians[constraint.wj_id2..constraint.wj_id2 + constraint.dim2],
                    );
                }
            }
        }
    }

    fn solve_unilateral<D1: Dim, D2: Dim>(
        &self,
        params: &IntegrationParameters<N>,
        bodies: &mut BodySet<N>,
        constraint: &mut NonlinearUnilateralConstraint<N>,
        jacobians: &mut [N],
        dim1: D1,
        dim2: D2,
    ) {
        if self.update_contact_constraint(params, bodies, constraint, jacobians) {
            let impulse = -constraint.rhs * constraint.r;

            VectorSliceMutN::new_generic_mut(jacobians, dim1, U1).mul_assign(impulse);
            VectorSliceMutN::new_generic_mut(&mut jacobians[dim1.value()..], dim2, U1)
                .mul_assign(impulse);

            bodies
                .body_mut(constraint.body1)
                .apply_displacement(&jacobians[0..dim1.value()]);
            bodies
                .body_mut(constraint.body2)
                .apply_displacement(&jacobians[dim1.value()..dim1.value() + dim2.value()]);
        }
    }

    fn compute_contact_geometry(
        &self,
        body1: &BodyPart<N>,
        body2: &BodyPart<N>,
        constraint: &NonlinearUnilateralConstraint<N>,
    ) -> ContactGeometry<N> {
        let m1 = body1.position();
        let m2 = body2.position();

        let mut world1 = m1.transform_point(&constraint.local1);
        let mut world2 = m2.transform_point(&constraint.local2);
        let normal;
        let mut depth;

        match constraint.kinematic {
            ContactKinematic::PlanePoint => {
                normal = m1 * constraint.normal1;
                depth = -na::dot(normal.as_ref(), &(world2 - world1));
                world1 = world2 + normal.as_ref() * depth;
            }
            ContactKinematic::PointPlane => {
                let world_normal2 = m2 * constraint.normal2.as_ref();
                depth = -na::dot(&world_normal2, &(world1 - world2));
                world2 = world1 + &world_normal2 * depth;
                normal = Unit::new_unchecked(-world_normal2);
            }
            ContactKinematic::PointPoint => {
                if let Some((n, d)) = Unit::try_new_and_get(world2 - world1, N::default_epsilon()) {
                    depth = -d;
                    normal = n;
                } else {
                    depth = -constraint.margin1 - constraint.margin2;
                    normal = m1 * constraint.normal1;
                }
            }
            ContactKinematic::LinePoint(dir1) => {
                /*
                let mut shift = world2 - world1;
                let proj = na::dot(dir1.as_ref(), &shift);
                shift -= dir1.as_ref() * proj;
                world1 = world2 - shift;

                if let Some((n, d)) = Unit::try_new_and_get(shift, N::zero()) {
                    depth = d;
                    normal = n;
                } else {
                    depth = na::zero();
                    normal = Unit::new_unchecked(m1.transform_vector(constraint.normal1.as_ref()));
                }
                */
                unimplemented!()
            }
            ContactKinematic::PointLine(dir2) => {
                /*
                let mut shift = world1 - world2;
                let proj = na::dot(dir2.as_ref(), &shift);
                shift -= dir2.as_ref() * proj;
                world2 = world1 - shift;

                if let Some((n, d)) = Unit::try_new_and_get(shift, N::zero()) {
                    depth = d;
                    normal = n;
                } else {
                    depth = na::zero();
                    normal = Unit::new_unchecked(m1.transform_vector(constraint.normal1.as_ref()));
                }
                */
                unimplemented!()
            }
            ContactKinematic::LineLine(dir1, dir2) => {
                let world_dir1 = m1 * dir1.unwrap();
                let world_dir2 = m2 * dir2.unwrap();
                let (pt1, pt2) = closest_points_internal::line_against_line(
                    &world1,
                    &world_dir1,
                    &world2,
                    &world_dir2,
                );
                world1 = pt1;
                world2 = pt2;

                if let Some((n, d)) = Unit::try_new_and_get(world2 - world1, N::zero()) {
                    let local_n1 = m1.inverse_transform_vector(n.as_ref());
                    let local_n2 = m2.inverse_transform_vector(&-*n);

                    if constraint
                        .ncone1
                        .contains_dir(&-Unit::new_unchecked(local_n1))
                        && constraint
                            .ncone2
                            .contains_dir(&-Unit::new_unchecked(local_n2))
                    {
                        depth = d;
                        normal = -n;
                    } else {
                        depth = -d;
                        normal = n;
                    }
                } else {
                    depth = na::zero();
                    normal = m1 * constraint.normal1;
                }
            }
            ContactKinematic::Unknown => {
                depth = N::zero();
                normal = m1 * constraint.normal1;
            }
        }

        world1 += normal.unwrap() * constraint.margin1;
        world2 -= normal.unwrap() * constraint.margin2;
        depth += constraint.margin1 + constraint.margin2;

        ContactGeometry::new(world1, world2, normal, depth)
    }

    fn update_contact_constraint(
        &self,
        params: &IntegrationParameters<N>,
        bodies: &BodySet<N>,
        constraint: &mut NonlinearUnilateralConstraint<N>,
        jacobians: &mut [N],
    ) -> bool {
        let body1 = bodies.body_part(constraint.body1);
        let body2 = bodies.body_part(constraint.body2);

        let geom = self.compute_contact_geometry(&body1, &body2, constraint);

        constraint.rhs = na::sup(
            &((-geom.depth + params.allowed_linear_error) * params.erp),
            &(-params.max_linear_correction),
        );

        if constraint.rhs >= N::zero() {
            return false;
        }

        // XXX: should use constraint_pair_geometry to properly handle multibodies.
        let mut inv_r = N::zero();
        helper::fill_constraint_geometry(
            &body1,
            constraint.ndofs1,
            &geom.world1,
            &ForceDirection::Linear(-geom.normal),
            constraint.ndofs1 + constraint.ndofs2,
            0,
            jacobians,
            &mut inv_r,
        );

        helper::fill_constraint_geometry(
            &body2,
            constraint.ndofs2,
            &geom.world2,
            &ForceDirection::Linear(geom.normal),
            (constraint.ndofs1 * 2) + constraint.ndofs2,
            constraint.ndofs1,
            jacobians,
            &mut inv_r,
        );

        // May happen sometimes for self-collisions (e.g. a multibody with itself).
        if inv_r.is_zero() {
            constraint.r = N::one();
        } else {
            constraint.r = N::one() / inv_r
        }

        true
    }
}
<commit_msg>Fix point/line contact kinematic.<commit_after>use std::marker::PhantomData;
use std::ops::MulAssign;
use approx::ApproxEq;
use slab::Slab;
use alga::linear::Transformation;
use alga::linear::ProjectiveTransformation;
use na::{self, DVector, Dim, Dynamic, Real, U1, Unit, VectorSliceMutN};
use ncollide::query::ContactKinematic;
use ncollide::query::closest_points_internal;

use object::{BodyHandle, BodyPart, BodySet};
use joint::JointConstraint;
use solver::helper;
use solver::{ForceDirection, IntegrationParameters,
             MultibodyJointLimitsNonlinearConstraintGenerator, NonlinearConstraintGenerator,
             NonlinearUnilateralConstraint};
use math::{Isometry, Point, Rotation, Vector};

struct ContactGeometry<N: Real> {
    world1: Point<N>,
    world2: Point<N>,
    normal: Unit<Vector<N>>,
    depth: N,
}

impl<N: Real> ContactGeometry<N> {
    pub fn new(world1: Point<N>, world2: Point<N>, normal: Unit<Vector<N>>, depth: N) -> Self {
        ContactGeometry {
            world1,
            world2,
            normal,
            depth,
        }
    }
}

pub struct NonlinearSORProx<N: Real> {
    _phantom: PhantomData<N>,
}

impl<N: Real> NonlinearSORProx<N> {
    pub fn new() -> Self {
        NonlinearSORProx {
            _phantom: PhantomData,
        }
    }

    pub fn solve(
        &self,
        params: &IntegrationParameters<N>,
        bodies: &mut BodySet<N>,
        constraints: &mut [NonlinearUnilateralConstraint<N>],
        multibody_limits: &[MultibodyJointLimitsNonlinearConstraintGenerator],
        joints_constraints: &Slab<Box<JointConstraint<N>>>, // FIXME: ugly, use a slice of refs instead.
        jacobians: &mut [N],
        max_iter: usize,
    ) {
        for _ in 0..max_iter {
            for constraint in constraints.iter_mut() {
                // FIXME: specialize for SPATIAL_DIM.
                let dim1 = Dynamic::new(constraint.ndofs1);
                let dim2 = Dynamic::new(constraint.ndofs2);
                self.solve_unilateral(params, bodies, constraint, jacobians, dim1, dim2);
            }

            for generator in multibody_limits {
                self.solve_generic(params, bodies, generator, jacobians)
            }

            for joint in &*joints_constraints {
                self.solve_generic(params, bodies, &**joint.1, jacobians)
            }
        }
    }

    fn solve_generic<Gen: ?Sized + NonlinearConstraintGenerator<N>>(
        &self,
        params: &IntegrationParameters<N>,
        bodies: &mut BodySet<N>,
        generator: &Gen,
        jacobians: &mut [N],
    ) {
        let nconstraints = generator.num_position_constraints(bodies);

        for i in 0..nconstraints {
            if let Some(constraint) = generator.position_constraint(params, i, bodies, jacobians) {
                let dim1 = Dynamic::new(constraint.dim1);
                let dim2 = Dynamic::new(constraint.dim2);

                let rhs = if constraint.is_angular {
                    na::sup(
                        &((constraint.rhs + params.allowed_angular_error) * params.erp),
                        &(-params.max_angular_correction),
                    )
                } else {
                    na::sup(
                        &((constraint.rhs + params.allowed_linear_error) * params.erp),
                        &(-params.max_linear_correction),
                    )
                };

                if rhs < N::zero() {
                    let impulse = -rhs * constraint.r;

                    VectorSliceMutN::new_generic_mut(&mut jacobians[constraint.wj_id1..], dim1, U1)
                        .mul_assign(impulse);

                    VectorSliceMutN::new_generic_mut(&mut jacobians[constraint.wj_id2..], dim2, U1)
                        .mul_assign(impulse);

                    // FIXME: the body update should be performed lazily, especially because
                    // we dont actually need to update the kinematic of a multibody until
                    // we have to solve a contact involvoing one of its links.
                    bodies.body_mut(constraint.body1).apply_displacement(
                        &jacobians[constraint.wj_id1..constraint.wj_id1 + constraint.dim1],
                    );
                    bodies.body_mut(constraint.body2).apply_displacement(
                        &jacobians[constraint.wj_id2..constraint.wj_id2 + constraint.dim2],
                    );
                }
            }
        }
    }

    fn solve_unilateral<D1: Dim, D2: Dim>(
        &self,
        params: &IntegrationParameters<N>,
        bodies: &mut BodySet<N>,
        constraint: &mut NonlinearUnilateralConstraint<N>,
        jacobians: &mut [N],
        dim1: D1,
        dim2: D2,
    ) {
        if self.update_contact_constraint(params, bodies, constraint, jacobians) {
            let impulse = -constraint.rhs * constraint.r;

            VectorSliceMutN::new_generic_mut(jacobians, dim1, U1).mul_assign(impulse);
            VectorSliceMutN::new_generic_mut(&mut jacobians[dim1.value()..], dim2, U1)
                .mul_assign(impulse);

            bodies
                .body_mut(constraint.body1)
                .apply_displacement(&jacobians[0..dim1.value()]);
            bodies
                .body_mut(constraint.body2)
                .apply_displacement(&jacobians[dim1.value()..dim1.value() + dim2.value()]);
        }
    }

    fn compute_contact_geometry(
        &self,
        body1: &BodyPart<N>,
        body2: &BodyPart<N>,
        constraint: &NonlinearUnilateralConstraint<N>,
    ) -> ContactGeometry<N> {
        let m1 = body1.position();
        let m2 = body2.position();

        let mut world1 = m1.transform_point(&constraint.local1);
        let mut world2 = m2.transform_point(&constraint.local2);
        let normal;
        let mut depth;

        match constraint.kinematic {
            ContactKinematic::PlanePoint => {
                normal = m1 * constraint.normal1;
                depth = -na::dot(normal.as_ref(), &(world2 - world1));
                world1 = world2 + normal.as_ref() * depth;
            }
            ContactKinematic::PointPlane => {
                let world_normal2 = m2 * constraint.normal2.as_ref();
                depth = -na::dot(&world_normal2, &(world1 - world2));
                world2 = world1 + &world_normal2 * depth;
                normal = Unit::new_unchecked(-world_normal2);
            }
            ContactKinematic::PointPoint => {
                if let Some((n, d)) = Unit::try_new_and_get(world2 - world1, N::default_epsilon()) {
                    depth = -d;
                    normal = n;
                } else {
                    depth = -constraint.margin1 - constraint.margin2;
                    normal = m1 * constraint.normal1;
                }
            }
            ContactKinematic::LinePoint(dir1) => {
                let world_dir1 = m1 * dir1;
                let mut shift = world2 - world1;
                let proj = na::dot(world_dir1.as_ref(), &shift);
                shift -= dir1.as_ref() * proj;

                if let Some((n, d)) = Unit::try_new_and_get(shift, N::zero()) {
                    let local_n1 = m1.inverse_transform_vector(n.as_ref());
                    let local_n2 = m2.inverse_transform_vector(&-*n);
                    world1 = world2 - shift;

                    if constraint
                        .ncone1
                        .contains_dir(&-Unit::new_unchecked(local_n1))
                        && constraint
                            .ncone2
                            .contains_dir(&-Unit::new_unchecked(local_n2))
                    {
                        depth = d;
                        normal = -n;
                    } else {
                        depth = -d;
                        normal = n;
                    }
                } else {
                    depth = na::zero();
                    normal = m1 * constraint.normal1;
                }
            }
            ContactKinematic::PointLine(dir2) => {
                let world_dir2 = m2 * dir2;
                let mut shift = world1 - world2;
                let proj = na::dot(world_dir2.as_ref(), &shift);
                shift -= dir2.as_ref() * proj;
                // NOTE: we set:
                // shift = world2 - world1
                let shift = -shift;

                if let Some((n, d)) = Unit::try_new_and_get(shift, N::zero()) {
                    let local_n1 = m1.inverse_transform_vector(n.as_ref());
                    let local_n2 = m2.inverse_transform_vector(&-*n);
                    world2 = world1 + shift;

                    if constraint
                        .ncone1
                        .contains_dir(&-Unit::new_unchecked(local_n1))
                        && constraint
                            .ncone2
                            .contains_dir(&-Unit::new_unchecked(local_n2))
                    {
                        depth = d;
                        normal = -n;
                    } else {
                        depth = -d;
                        normal = n;
                    }
                } else {
                    depth = na::zero();
                    normal = m1 * constraint.normal1;
                }
            }
            ContactKinematic::LineLine(dir1, dir2) => {
                let world_dir1 = m1 * dir1.unwrap();
                let world_dir2 = m2 * dir2.unwrap();
                let (pt1, pt2) = closest_points_internal::line_against_line(
                    &world1,
                    &world_dir1,
                    &world2,
                    &world_dir2,
                );
                world1 = pt1;
                world2 = pt2;

                if let Some((n, d)) = Unit::try_new_and_get(world2 - world1, N::zero()) {
                    let local_n1 = m1.inverse_transform_vector(n.as_ref());
                    let local_n2 = m2.inverse_transform_vector(&-*n);

                    if constraint
                        .ncone1
                        .contains_dir(&-Unit::new_unchecked(local_n1))
                        && constraint
                            .ncone2
                            .contains_dir(&-Unit::new_unchecked(local_n2))
                    {
                        depth = d;
                        normal = -n;
                    } else {
                        depth = -d;
                        normal = n;
                    }
                } else {
                    depth = na::zero();
                    normal = m1 * constraint.normal1;
                }
            }
            ContactKinematic::Unknown => {
                depth = N::zero();
                normal = m1 * constraint.normal1;
            }
        }

        world1 += normal.unwrap() * constraint.margin1;
        world2 -= normal.unwrap() * constraint.margin2;
        depth += constraint.margin1 + constraint.margin2;

        ContactGeometry::new(world1, world2, normal, depth)
    }

    fn update_contact_constraint(
        &self,
        params: &IntegrationParameters<N>,
        bodies: &BodySet<N>,
        constraint: &mut NonlinearUnilateralConstraint<N>,
        jacobians: &mut [N],
    ) -> bool {
        let body1 = bodies.body_part(constraint.body1);
        let body2 = bodies.body_part(constraint.body2);

        let geom = self.compute_contact_geometry(&body1, &body2, constraint);

        constraint.rhs = na::sup(
            &((-geom.depth + params.allowed_linear_error) * params.erp),
            &(-params.max_linear_correction),
        );

        if constraint.rhs >= N::zero() {
            return false;
        }

        // XXX: should use constraint_pair_geometry to properly handle multibodies.
        let mut inv_r = N::zero();
        helper::fill_constraint_geometry(
            &body1,
            constraint.ndofs1,
            &geom.world1,
            &ForceDirection::Linear(-geom.normal),
            constraint.ndofs1 + constraint.ndofs2,
            0,
            jacobians,
            &mut inv_r,
        );

        helper::fill_constraint_geometry(
            &body2,
            constraint.ndofs2,
            &geom.world2,
            &ForceDirection::Linear(geom.normal),
            (constraint.ndofs1 * 2) + constraint.ndofs2,
            constraint.ndofs1,
            jacobians,
            &mut inv_r,
        );

        // May happen sometimes for self-collisions (e.g. a multibody with itself).
        if inv_r.is_zero() {
            constraint.r = N::one();
        } else {
            constraint.r = N::one() / inv_r
        }

        true
    }
}
<|endoftext|>


<commit_before>use test::Bencher;

use protocol::cmd::Cmd;
use protocol::cmd::Get;
use protocol::cmd::Resp;
use protocol::cmd::Set;
use protocol::cmd::SetInstr;
use protocol::cmd::Value;
use testlib::test_stream::TestStream;

use super::TcpTransport;

// Reading

#[bench]
fn bench_transport_read_cmd_get(b: &mut Bencher) {
    b.iter(|| {
        let cmd_str = "get x\r\n".to_string();
        let ts = TestStream::new(cmd_str.into_bytes());
        let mut transport = TcpTransport::new(ts);

        let cmd = transport.read_cmd().unwrap();
        assert_eq!(cmd, Cmd::Get(Get::one("x")));
    })
}

#[bench]
fn bench_transport_read_cmd_set(b: &mut Bencher) {
    b.iter(|| {
        let cmd_str = "set x 0 0 3 \r\nabc\r\n".to_string();
        let ts = TestStream::new(cmd_str.into_bytes());
        let mut transport = TcpTransport::new(ts);

        let cmd = transport.read_cmd().unwrap();
        let exp = Set::new(SetInstr::Set, "x", 0, 0, vec![97, 98, 99], false);
        assert_eq!(cmd, Cmd::Set(exp));
    })
}

// Writing

#[bench]
fn bench_transport_write_resp_value(b: &mut Bencher) {
    b.iter(|| {
        let ts = TestStream::new(vec![]);
        let mut transport = TcpTransport::new(ts);

        let val = Value::new("x", 15, "abc".to_string().into_bytes());
        let resp = Resp::Values(vec![val]);
        transport.write_resp(&resp).unwrap();
        let expected = "VALUE x 15 3\r\nabc\r\nEND\r\n"
                           .to_string()
                           .into_bytes();
        assert_eq!(transport.get_stream().outgoing, expected);
    })
}
<commit_msg>fix up transport benchmarks so they only time the relevant code path<commit_after>use test::Bencher;

use protocol::cmd::Cmd;
use protocol::cmd::Get;
use protocol::cmd::Resp;
use protocol::cmd::Set;
use protocol::cmd::SetInstr;
use protocol::cmd::Value;
use testlib::test_stream::TestStream;

use super::TcpTransport;

// Reading

use platform::time::sleep_secs;
#[bench]
fn bench_transport_read_cmd_get(b: &mut Bencher) {
    // Prepare a stream "long enough" since we can't tell iter() how many
    // iterations to use
    let mut input = vec![];
    for _ in 0..1000000 {
        let cmd_str = "get variable\r\n".to_string();
        input.extend(cmd_str.into_bytes());
    }

    let ts = TestStream::new(input);
    let mut transport = TcpTransport::new(ts);

    b.iter(|| {
        transport.read_cmd().unwrap();
    })
}

#[bench]
fn bench_transport_read_cmd_set(b: &mut Bencher) {
    // Prepare a stream "long enough" since we can't tell iter() how many
    // iterations to use
    let mut input = vec![];
    for _ in 0..1000000 {
        let cmd_str = "set variable 13 1 10 noreply\r\n0123456789\r\n".to_string();
        input.extend(cmd_str.into_bytes());
    }

    let ts = TestStream::new(input);
    let mut transport = TcpTransport::new(ts);

    b.iter(|| {
        transport.read_cmd().unwrap();
    })
}

// Writing

#[bench]
fn bench_transport_write_resp_value(b: &mut Bencher) {
    let ts = TestStream::new(vec![]);
    let mut transport = TcpTransport::new(ts);

    b.iter(|| {
        let val = Value::new("x", 15, "abc".to_string().into_bytes());
        let resp = Resp::Values(vec![val]);
        transport.write_resp(&resp).unwrap();
    })
}
<|endoftext|>


<commit_before>const IMPASSABLE_TILES: [[usize; 2]; 12] = [[1, 1], [2, 2], [2, 3], [2, 4], [2, 5], [3, 0], [3, 5], [4, 0], [4, 2], [4, 3], [4, 4], [4, 5]];

#[test]
fn path_finding_test_1() {
  use cgmath::Point2;
  use shaders::Position;
  use terrain::path_finding::calc_route;

  let expected_result_1: Vec<Point2<i32>> = vec![[0, 0], [1, 0], [2, 1], [3, 2], [4, 1], [5, 2], [5, 3], [5, 4], [5, 5]]
    .iter()
    .map(|e| Point2::new(e[0], e[1]))
    .collect();

  assert_eq!(expected_result_1,
             calc_route(Position::new([0.0, -1500.0]), Position::new([0.0, -1500.0 + 5.0 * 46.0]), &IMPASSABLE_TILES.to_vec())
               .map_or_else(|| vec![],
                            |(f, _)| f),
             "path_finding_test_1");
}

#[test]
fn path_finding_test_2() {
  use cgmath::Point2;
  use shaders::Position;
  use terrain::path_finding::calc_route;

  let expected_result: Vec<Point2<i32>> = vec![[3, 3], [3, 2], [4, 1], [5, 2], [5, 3], [5, 4], [5, 5]]
    .iter()
    .map(|e| Point2::new(e[0], e[1]))
    .collect();

  assert_eq!(expected_result,
             calc_route(Position::new([0.0, -1500.0 + 3.0 * 46.0]), Position::new([0.0, -1500.0 + 5.0 * 46.0]), &IMPASSABLE_TILES.to_vec())
               .map_or_else(|| vec![],
                            |(f, _)| f),
             "path_finding_test_2");
}
<commit_msg>Ignore linter issue<commit_after>#[allow(dead_code)]
const IMPASSABLE_TILES: [[usize; 2]; 12] = [[1, 1], [2, 2], [2, 3], [2, 4], [2, 5], [3, 0], [3, 5], [4, 0], [4, 2], [4, 3], [4, 4], [4, 5]];

#[test]
fn path_finding_test_1() {
  use cgmath::Point2;
  use shaders::Position;
  use terrain::path_finding::calc_route;

  let expected_result_1: Vec<Point2<i32>> = vec![[0, 0], [1, 0], [2, 1], [3, 2], [4, 1], [5, 2], [5, 3], [5, 4], [5, 5]]
    .iter()
    .map(|e| Point2::new(e[0], e[1]))
    .collect();

  assert_eq!(expected_result_1,
             calc_route(Position::new([0.0, -1500.0]), Position::new([0.0, -1500.0 + 5.0 * 46.0]), &IMPASSABLE_TILES.to_vec())
               .map_or_else(|| vec![],
                            |(f, _)| f),
             "path_finding_test_1");
}

#[test]
fn path_finding_test_2() {
  use cgmath::Point2;
  use shaders::Position;
  use terrain::path_finding::calc_route;

  let expected_result: Vec<Point2<i32>> = vec![[3, 3], [3, 2], [4, 1], [5, 2], [5, 3], [5, 4], [5, 5]]
    .iter()
    .map(|e| Point2::new(e[0], e[1]))
    .collect();

  assert_eq!(expected_result,
             calc_route(Position::new([0.0, -1500.0 + 3.0 * 46.0]), Position::new([0.0, -1500.0 + 5.0 * 46.0]), &IMPASSABLE_TILES.to_vec())
               .map_or_else(|| vec![],
                            |(f, _)| f),
             "path_finding_test_2");
}
<|endoftext|>


<commit_before>// src/common/mm_result.rs
//MM Result type

use std::fmt;

pub type MMResult<T> = Result<T, MMError>;

#[derive(Debug)]
pub struct MMError{
    kind:MMErrorKind,
    message: String
}

#[derive(Debug)]
pub enum MMErrorKind{
    Database,
    DAO,
    Validation,
    Other
}

impl MMError{
    pub fn new(msg: String, kind: MMErrorKind) -> MMError{
        MMError{
            kind:kind,
            message:msg
        }
    }
}
impl fmt::Display for MMError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.message)
    }
}
<commit_msg>Update MMResult documentation<commit_after>// src/common/mm_result.rs

/// MM Result type
/// Expands Result type for error handling in the API

use std::fmt;

pub type MMResult<T> = Result<T, MMError>;

#[derive(Debug)]
pub struct MMError{
    kind:MMErrorKind,
    message: String
}

#[derive(Debug)]
pub enum MMErrorKind{
    Database,
    DAO,
    Validation,
    Other
}

impl MMError{
    pub fn new(msg: String, kind: MMErrorKind) -> MMError{
        MMError{
            kind:kind,
            message:msg
        }
    }
}
impl fmt::Display for MMError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.message)
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use stb_image::bindgen::*;

use std::any::Any;
use libc;
use libc::{c_void, c_int};
use std::slice::raw::buf_as_slice;

pub struct Image<T> {
    pub width   : uint,
    pub height  : uint,
    pub depth   : uint,
    pub data    : Vec<T>,
}

pub fn new_image<T>(width: uint, height: uint, depth: uint, data: Vec<T>) -> Image<T> {
    Image::<T> {
        width   : width,
        height  : height,
        depth   : depth,
        data    : data,
    }
}

pub enum LoadResult {
    Error(StrBuf),
    ImageU8(Image<u8>),
    ImageF32(Image<f32>),
}

impl LoadResult {
    pub fn from_result(res: Result<LoadResult,Box<Any>>)-> LoadResult {
        match res {
            Ok(res) => res,
            Err(e)  => Error(e.to_str()),
        }
    }
}

pub fn load(path: &Path) -> LoadResult {
    let force_depth = 0;
    load_with_depth(path, force_depth, false)
}

fn load_internal<T: Clone>(buf : *T, w : c_int, h : c_int, d : c_int) -> Image<T> {
    unsafe {
        // FIXME: Shouldn't copy; instead we should use a sendable resource. They
        // aren't particularly safe yet though.
        let data = buf_as_slice(buf, (w * h * d) as uint, |s| { Vec::from_slice(s) });
        libc::free(buf as *mut c_void);
        Image::<T>{
            width   : w as uint,
            height  : h as uint,
            depth   : d as uint,
            data    : data}
    }
}

pub fn load_with_depth(path: &Path, force_depth: uint, convert_hdr: bool) -> LoadResult {
    unsafe {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        let path_as_str = match path.as_str() {
            Some(s) => s,
            None => return Error("path is not valid utf8".to_owned()),
        };
        path_as_str.with_c_str(|bytes| {
            if !convert_hdr && stbi_is_hdr(bytes)!=0   {
                let buffer = stbi_loadf(bytes,
                                        &mut width,
                                        &mut height,
                                        &mut depth,
                                        force_depth as c_int);
                if buffer.is_null() {
                    Error("stbi_loadf failed".to_owned())
                } else {
                    ImageF32(load_internal(buffer, width, height, depth))
                }
            } else {
                let buffer = stbi_load(bytes,
                                       &mut width,
                                       &mut height,
                                       &mut depth,
                                       force_depth as c_int);
                if buffer.is_null() {
                    Error("stbi_load failed".to_owned())
                } else {
                    ImageU8(load_internal(buffer, width, height, depth))
                }
            }
        })
    }
}

pub fn load_from_memory(buffer: &[u8]) -> LoadResult {
    let force_depth = 0;
    load_from_memory_with_depth(buffer, force_depth, false)
}

pub fn load_from_memory_with_depth(buffer: &[u8], force_depth: uint, convert_hdr:bool) -> LoadResult {
    unsafe {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        if !convert_hdr && stbi_is_hdr_from_memory(buffer.as_ptr(), buffer.len() as c_int) != 0 {
            let buffer = stbi_loadf_from_memory(buffer.as_ptr(),
                                                buffer.len() as c_int,
                                                &mut width,
                                                &mut height,
                                                &mut depth,
                                                force_depth as c_int);
            if buffer.is_null() {
                Error("stbi_loadf_from_memory failed".to_owned())
            } else {
                let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                ImageF32(load_internal(buffer, width, height, actual_depth))
            }
        } else {
            let buffer = stbi_load_from_memory(buffer.as_ptr(),
                                               buffer.len() as c_int,
                                               &mut width,
                                               &mut height,
                                               &mut depth,
                                               force_depth as c_int);
            if buffer.is_null() {
                Error("stbi_load_from_memory failed".to_owned())
            } else {
                let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                ImageU8(load_internal(buffer, width, height, actual_depth))
            }
        }
    }
}
<commit_msg>Updated to latest Rust: StrBuf -> String<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use stb_image::bindgen::*;

use std::any::Any;
use libc;
use libc::{c_void, c_int};
use std::slice::raw::buf_as_slice;

pub struct Image<T> {
    pub width   : uint,
    pub height  : uint,
    pub depth   : uint,
    pub data    : Vec<T>,
}

pub fn new_image<T>(width: uint, height: uint, depth: uint, data: Vec<T>) -> Image<T> {
    Image::<T> {
        width   : width,
        height  : height,
        depth   : depth,
        data    : data,
    }
}

pub enum LoadResult {
    Error(String),
    ImageU8(Image<u8>),
    ImageF32(Image<f32>),
}

impl LoadResult {
    pub fn from_result(res: Result<LoadResult,Box<Any>>)-> LoadResult {
        match res {
            Ok(res) => res,
            Err(e)  => Error(e.to_str()),
        }
    }
}

pub fn load(path: &Path) -> LoadResult {
    let force_depth = 0;
    load_with_depth(path, force_depth, false)
}

fn load_internal<T: Clone>(buf : *T, w : c_int, h : c_int, d : c_int) -> Image<T> {
    unsafe {
        // FIXME: Shouldn't copy; instead we should use a sendable resource. They
        // aren't particularly safe yet though.
        let data = buf_as_slice(buf, (w * h * d) as uint, |s| { Vec::from_slice(s) });
        libc::free(buf as *mut c_void);
        Image::<T>{
            width   : w as uint,
            height  : h as uint,
            depth   : d as uint,
            data    : data}
    }
}

pub fn load_with_depth(path: &Path, force_depth: uint, convert_hdr: bool) -> LoadResult {
    unsafe {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        let path_as_str = match path.as_str() {
            Some(s) => s,
            None => return Error("path is not valid utf8".to_owned()),
        };
        path_as_str.with_c_str(|bytes| {
            if !convert_hdr && stbi_is_hdr(bytes)!=0   {
                let buffer = stbi_loadf(bytes,
                                        &mut width,
                                        &mut height,
                                        &mut depth,
                                        force_depth as c_int);
                if buffer.is_null() {
                    Error("stbi_loadf failed".to_owned())
                } else {
                    ImageF32(load_internal(buffer, width, height, depth))
                }
            } else {
                let buffer = stbi_load(bytes,
                                       &mut width,
                                       &mut height,
                                       &mut depth,
                                       force_depth as c_int);
                if buffer.is_null() {
                    Error("stbi_load failed".to_owned())
                } else {
                    ImageU8(load_internal(buffer, width, height, depth))
                }
            }
        })
    }
}

pub fn load_from_memory(buffer: &[u8]) -> LoadResult {
    let force_depth = 0;
    load_from_memory_with_depth(buffer, force_depth, false)
}

pub fn load_from_memory_with_depth(buffer: &[u8], force_depth: uint, convert_hdr:bool) -> LoadResult {
    unsafe {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        if !convert_hdr && stbi_is_hdr_from_memory(buffer.as_ptr(), buffer.len() as c_int) != 0 {
            let buffer = stbi_loadf_from_memory(buffer.as_ptr(),
                                                buffer.len() as c_int,
                                                &mut width,
                                                &mut height,
                                                &mut depth,
                                                force_depth as c_int);
            if buffer.is_null() {
                Error("stbi_loadf_from_memory failed".to_owned())
            } else {
                let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                ImageF32(load_internal(buffer, width, height, actual_depth))
            }
        } else {
            let buffer = stbi_load_from_memory(buffer.as_ptr(),
                                               buffer.len() as c_int,
                                               &mut width,
                                               &mut height,
                                               &mut depth,
                                               force_depth as c_int);
            if buffer.is_null() {
                Error("stbi_load_from_memory failed".to_owned())
            } else {
                let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                ImageU8(load_internal(buffer, width, height, actual_depth))
            }
        }
    }
}
<|endoftext|>